Points at campaign joystick:campaign:self; flags the 1086aee deploy fact as
last-recorded (2026-08-22, ~100 commits behind HEAD); drops the stale E:
path and repixelizer-venv rehydrate command from the handoff.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
130 lines
13 KiB
YAML
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:
|
|
- ACTIVE, M1-critical (operator ruling 2026-10-18): Joystick H1, campaign joystick:campaign:self (branch eureka/joystick-h1). Joystick OAuth provider, joystick as a streampixels viewer provider, one locked refresh primitive for every provider replacing refreshLinkedIdentityCredentialIfNeeded.
|
|
- OPEN, behind H1: 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 1086aee01169bf60e8a492b2740db1c6f3e8cabf 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: Active work is Joystick H1 (campaign joystick:campaign:self). Last recorded Yggdrasil deploy (not verifiable from this repo; HEAD is far past it, see git): Yggdrasil runs the gamecult.heimdall.access plugin and encrypted loopback begin, complete, refresh, and logout plane at 1086aee01169bf60e8a492b2740db1c6f3e8cabf. Odin returns all four redacted discovery records, Ghostlight resolves the boundary through Odin, and live anonymous auth.begin is accepted without exposing claims or secrets.
|
|
next_action: Land Joystick H1 per campaign joystick:campaign:self and target joystick:target:r1 (worktree and branch eureka/joystick-h1). Then, still open, run 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.
|