Heimdall/state/map.yaml
Meta Vens 5952cce8a0 State: live d51fa6b proven by a human Twitch sign-in; Joystick consent remains
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:03:17 +02:00

130 lines
13 KiB
YAML

project:
name: Heimdall
status: active
phase: streampixels_migration
premise: >
Build Heimdall as one reusable GameCult auth authority service for OAuth,
linked identities, local sessions, grants, and capability claims without
mixing in app-domain audience or product data.
objective:
primary: >
Create a shared auth authority service that Repixelizer, StreamPixels, and
future GameCult-hosted experiments can consume.
current: >
Publish the Heimdall Eve access plugin and private CultNet authentication
plane, then migrate Ghostlight onto app-local sessions without moving
campaign or membership authority into Heimdall.
constraints:
- Heimdall owns auth/control-plane authority; app-domain data stays app-owned by default.
- Prefer a same-host Heimdall service on Yggdrasil over duplicated per-app provider stacks.
- Host apps verify signed claims locally for routine guarded routes.
- App profiles stay thin; the shared architecture note owns the main model.
- StreamPixels audience and creator data must not be absorbed into a shared auth store.
invariants:
- The map is canonical and slow-changing.
- Scratch is temporary and disposable.
- Evidence is durable and distilled; routine activity logs belong in git history and commit messages.
- Heimdall owns OAuth, local sessions, grants, entitlement refresh, capability evaluation, and audit surfaces.
- App-domain data stays with the host app unless there is a deliberate, source-grounded reason to share it.
- Host apps verify signed claims locally and keep resource ownership checks local.
- StreamPixels can reuse shared auth authority without centralizing streamer-audience data.
- Spotiverse consumes Spotify as a Heimdall-managed credential; Spotiverse does not own Spotify refresh-token custody.
- Heimdall's first Odin/Eve daemon boundary publication remains secret-safe: it writes only provider advertisement, command boundary, transport profile, and daemon-health summary state, not per-account auth truth.
- Heimdall owns its persistent provider-health signing identity and signed observations; Idunn owns root-bound admission and the public provider-health projection. Unsigned health is never lifecycle authority.
- Heimdall owns OAuth attempts and completion redemption; the Eve access plugin and browser can project or carry one opaque handle but cannot grant access.
- Private auth commands are app-secret, source-runtime, expiry, nonce, and idempotency bound; sensitive completion claims remain AES-GCM wrapped until the app backend receives them.
- Refresh and logout are exact persisted-session transitions. App/account custody and access revision must match; logout advances the revision and stale refresh cannot recreate the session.
- Persistent state cruft is the same failure class as architecture cruft.
data_flow:
observe:
- task request
- shared architecture note
- app profile bindings
- current app/runtime seams in Repixelizer and StreamPixels
- Yggdrasil host topology and nginx/service shape
process:
- rehydrate from canonical state
- choose one bounded architecture or implementation slice
- keep auth authority and app-domain data boundaries explicit
- keep routine route auth local after claim verification
- record only belief-changing evidence
- commit or backtrack
cut:
- reject shared-data creep
- reject duplicated auth blobs per app
- reject per-request auth round-trip chatter
active_subgoals:
- Joystick H1 is merged and live (PR GameCult/Heimdall#1, d51fa6b; campaign joystick:campaign:self). Open follow-ups by id: joystick:follow_up:h1-joystick-consent-round-trip (next), cross-process-failed-refresh-marker, connect-start-needs-app-auth, heimdall-idunn-onboarding, joystick-viewer-signin-public-bot. StreamPixels S0/S1 run in other sessions.
- OPEN, behind the H1 live round-trips: pressure the deployed Ghostlight gamecult.heimdall.access integration with two- and eight-account human canaries.
- Keep the shared architecture explicit and separate from app profiles.
- Preserve the default boundary that app-domain data remains app-owned.
- Align the plan to Heimdall as a Yggdrasil-hosted authority service.
- Publish Heimdall daemon health and boundary state for Idunn/Odin without moving auth truth out of Heimdall.
- Verify the Discord and Patreon Repixelizer auth paths with real provider credentials, stable signing, persistent storage, and live browser callback verification.
- Wire StreamPixels through Heimdall for Twitch/YouTube (Joystick joins under H1) viewer identity and managed creator-provider credentials without moving StreamPixels domain state into Heimdall.
accepted_design:
- `gamecult.heimdall.access` owns access-gate representation and browser navigation semantics; it has no access-grant or provider-state authority.
- Heimdall's loopback CultNet operation service owns authenticated auth begin/complete commands, while retained HTTP integrations remain supported for existing consumers.
- Ghostlight refresh and logout use the same private CultNet boundary; refresh re-evaluates the caller-owned KLTST policy and logout revokes exact Heimdall session custody.
- `docs/architecture.md` is the canonical shared architecture note.
- `docs/service-contract.md` records the concrete HTTP/JWKS contract of the landed service slice.
- `docs/app-profiles/*.md` are thin app bindings, not duplicate brains.
- Heimdall owns provider OAuth, identity linking, signed local sessions, grants, entitlement refresh, capability evaluation, and audit events.
- Host apps own their domain data, runtime state, and product-specific resources.
- Host apps verify signed claims locally for routine route authorization.
- A shared Heimdall store, if it exists, should hold auth/control-plane truth only.
- Repixelizer is the first auth-blank hosted-app binding.
- StreamPixels is the migration case that proves shared authority must not imply audience-data centralization.
- The first service skeleton is a standalone TypeScript/Fastify app with Ed25519 JWT signing, JWKS discovery, signed OAuth `state`, and app-profile-driven shared capability evaluation.
- The first stateful slice adds durable auth/control-plane storage plus a real Discord callback path for Repixelizer.
- Repixelizer has consumed the Heimdall backend-callback flow in its hosted web layer; Heimdall no longer needs to wait on Repixelizer refactoring before live Discord launch work.
- Heimdall is deployed on Yggdrasil at `https://heimdall.gamecult.org` with nginx/TLS, Postgres storage, file-backed signing-key bootstrap, configured token custody, and passing public health/discovery/JWKS checks.
- Heimdall now issues signed app refresh tokens alongside short-lived access claims and exposes `/v1/apps/{appSlug}/sessions/refresh` so app backends can reissue local claims without restarting provider OAuth.
- Discord and Patreon provider access tokens can refresh inside Heimdall before Repixelizer entitlement re-evaluation.
- Repixelizer is deployed on Yggdrasil at `https://repixelizer.gamecult.org` with `GC_ACCESS_MODE=heimdall`, `GC_ACCESS_ALLOWED_PROVIDERS=discord,patreon`, required access, queue protection enabled, app-owned Discord guild/role policy, and app-owned Patreon tier-title policy sent to Heimdall during backend-callback OAuth start.
- StreamPixels viewer and creator provider OAuth should start through Heimdall; StreamPixels redeems one-time completion codes, owns local profile/connector binding, and resolves current provider access tokens from Heimdall by app-authenticated managed-credential calls.
- Bifrost is a Heimdall app profile for Discord/Patreon member access. Bifrost owns the KTLST Discord role policy and Patreon tier policy; Heimdall owns provider OAuth, token custody, entitlement evaluation, and configured backend callback trust.
- Bifrost patron support sync reuses Heimdall's existing linked Patreon identity and membership reader. Heimdall turns active paid Patreon tier evidence into signed support facts; Bifrost owns point/tier/vote derivation.
- Heimdall's first runtime Verse cut publishes a service-owned CultCache boundary store and optional Idunn RUDP health pulse; full redacted auth-document witness export remains a later pass.
landed_baseline:
- Heimdall publishes its redacted provider, command boundary, Eve plugin, and transport profile through Odin under globally unique record keys; Ghostlight resolves that boundary instead of owning a direct endpoint.
- Yggdrasil runs Heimdall d51fa6b (hand-deployed 2026-10-19 15:51Z; gamecult-ops 210a1af holds backup, rollback and provenance; prior 1086aee) with CultLib 5cefa0db0079a8e3ee22f29d7b9e6e5aa60912a9; live Ghostlight auth.begin through Odin discovery is accepted.
- The Heimdall access plugin, persistent OAuth attempts, encrypted private CultNet commands, conformance fixtures, and browser reference adapter are implemented and locally verified.
- Exact-session refresh validation and logout revocation are implemented; stale or racing refresh cannot resurrect a revoked session.
- Shared architecture extracted into its own repo and renamed to Heimdall.
- Repixelizer and StreamPixels app-profile notes created.
- Repo-local state, handoff, and compaction scaffolding created.
- Initial Heimdall service skeleton landed with discovery, JWKS, OAuth start/callback contract surfaces, and claim issuance scaffolding.
- Durable auth persistence landed for accounts, linked identities, sessions, grants, entitlement snapshots, and audit events.
- The first real provider slice landed for Discord callback exchange, identity resolution, entitlement evaluation, and session/claim issuance for Repixelizer.
- Signing-key persistence/bootstrap, managed token encryption at rest, and a local verifier seam landed for the first real consumer integration pass.
- Direct backend callback handoff landed as the preferred same-host app-consumer path, with browser completion-code exchange retained as fallback.
- Signed session refresh landed for app-facing claims: refresh tokens remain Heimdall-issued, provider refresh tokens remain sealed in Heimdall, and callers can provide app-owned entitlement policies for re-evaluation.
- Repixelizer's hosted web layer now creates Heimdall auth attempts, receives direct backend callbacks, verifies Heimdall Ed25519 access tokens locally, and adopts httpOnly local sessions.
- Heimdall now has generic Twitch and YouTube OAuth callback runtimes plus an app-authenticated managed-credential resolve endpoint for app-owned connector runtimes.
- StreamPixels now starts viewer and creator Twitch/YouTube OAuth through Heimdall, redeems Heimdall completion codes server-side, writes its own viewer sessions and creator connector bindings, and leaves provider refresh-token custody in Heimdall.
- Spotiverse now has a Heimdall app profile and Spotify provider runtime for managed credential custody.
- Bifrost now has a Heimdall app profile for Discord/Patreon member access, and backend callback trust is checked through configured app callback allowlists before legacy app-specific defaults.
- Heimdall exposes `POST /v1/apps/bifrost/patron-support/sync` as an app-authenticated bridge from linked Patreon membership evidence to Bifrost's signed patron support intake endpoint.
- A read-only `gamecult.eve.provider_advertisement.v1` export now advertises Heimdall provider/app surfaces plus redacted CultCache witness document paths for Odin/Eve discovery.
- Heimdall now writes a daemon-owned `GC_ACCESS_CULTCACHE_PATH` boundary store containing provider advertisement, command boundary, transport profile, and daemon-health summary state, and it can publish `heimdall.cultnet-rudp-provider-health` to Idunn over `cultnet.transport.rudp.v0` when configured.
- Heimdall now persists a machine-bound Ed25519 provider-health identity, publishes canonical `idunn.signed_daemon_health.v1` records on an independent sequential pulse loop, and is admitted by Idunn through an exact root trust binding.
rejected_paths:
- name: per_app_auth_copy_paste
reason: duplicates the same provider/session sludge across every experiment
- name: per_request_auth_round_trip
reason: turns shared auth into a noisy bottleneck instead of local claim verification
- name: shared_user_data_swamp
reason: reusing auth mechanics does not justify centralizing app-domain audience or product data
current_status:
summary: Yggdrasil runs Heimdall release d51fa6b (hand-deployed 2026-10-19 15:51Z, gamecult-ops 210a1af), which includes Joystick H1 (PR #1). The plugin and encrypted loopback begin, complete, refresh and logout plane, the Odin discovery records and Ghostlight resolution were verified at 1086aee (2026-08-22) and are not re-verified at d51fa6b.
next_action: Run joystick:follow_up:h1-joystick-consent-round-trip, then StreamPixels S0/S1 (other sessions). Still open behind that: separate-account KLTST completion, refresh, logout, privacy, and stale-attempt canaries through the deployed Ghostlight Eve host; keep provider credential rotation on the operator list because prior tool output exposed OAuth secrets.