Heimdall/notes/fresh-workspace-handoff.md

272 lines
14 KiB
Markdown
Raw Normal View History

2026-04-26 05:18:35 +01:00
# Fresh Workspace Handoff
This is the re-entry packet for this repo (path: whatever the checkout is; it has moved drives before).
2026-04-26 05:18:35 +01:00
It is intentionally short. Historical proof belongs in git history and the
distilled `state/evidence.jsonl` ledger; the shared architecture belongs in
`docs/architecture.md`; the forward build order belongs in
`docs/implementation-plan.md`.
## Rehydrate
From the repo root:
```powershell
python .\tools\heimdall_state.py status
2026-04-26 05:18:35 +01:00
Get-Content '.\state\map.yaml'
Get-Content '.\notes\fresh-workspace-handoff.md'
Get-Content '.\docs\architecture.md'
Get-Content '.\docs\implementation-plan.md'
git status --short --branch
git log --oneline -5
Get-Content '.\state\evidence.jsonl' -Tail 8
```
Do not trust this file for the exact live HEAD. Always check git.
## Active Work
Joystick H1 is merged and live (PR GameCult/Heimdall#1; campaign
`joystick:campaign:self`). Next: `joystick:follow_up:h1-joystick-consent-round-trip`, then
StreamPixels S0/S1 (other sessions). Open Heimdall follow-ups, by id:
`joystick:follow_up:cross-process-failed-refresh-marker`,
`joystick:follow_up:connect-start-needs-app-auth`,
`joystick:follow_up:heimdall-idunn-onboarding`,
`joystick:follow_up:joystick-viewer-signin-public-bot`. The Ghostlight KLTST
canaries below stay open, behind them.
2026-04-26 05:18:35 +01:00
## Current Orientation
Yggdrasil runs Heimdall `d51fa6b`, hand-deployed 2026-10-19 15:51Z;
gamecult-ops `210a1af` records backup, rollback and provenance. Facts below
about Odin, Ghostlight and CultLib pins were verified at `1086aee` (2026-08-22)
and are not re-verified at `d51fa6b`.
- At `1086aee01169bf60e8a492b2740db1c6f3e8cabf` Heimdall ran with CultLib
`5cefa0db0079a8e3ee22f29d7b9e6e5aa60912a9`
- Heimdall publishes four redacted access records to Odin under unique keys:
`eve:provider:heimdall`, `heimdall:command-boundary`,
`eve:plugin:gamecult.heimdall.access`, and `heimdall:transport-profile`
- Odin `b4f9a2e95f0b41cebdeddc49223781d1d3c7b42a` persists and returns all four;
it does not proxy private commands or receive claims
- Ghostlight `b515ca90c25573005a616244143803b37f2d06ec` resolves the boundary through
Odin and accepted a live canonical anonymous `heimdall.auth.begin`; its unit
has no direct Heimdall endpoint
- `gamecult.heimdall.access` now has a manifest, advertisement, schemas,
fixtures, executable `describe`/`validate`/`project` ABI, and browser
reference adapter
- Heimdall persists OAuth attempts and serves authenticated
`heimdall.auth.begin` / `heimdall.auth.complete` / `heimdall.auth.refresh` /
`heimdall.auth.logout` through loopback
CultNet/RUDP on port `4101`
- private commands are source-runtime, app-secret, expiry, nonce, and
idempotency bound; their MessagePack payloads and completion claims are
AES-256-GCM wrapped
- the Ghostlight app profile now requires its caller-owned Discord role policy;
Heimdall evaluates it and Ghostlight remains owner of local sessions,
memberships, and campaigns
- refresh verifies the exact persisted session revision before reissuing a
claim; logout expires that session and advances its revision, so a stale or
racing refresh cannot resurrect revoked custody
2026-04-26 12:50:07 +01:00
- this repo now has a first stateful Heimdall service slice
2026-04-26 05:18:35 +01:00
- the canonical shared architecture lives in `docs/architecture.md`
2026-04-26 12:25:11 +01:00
- the concrete HTTP/JWKS contract lives in `docs/service-contract.md`
2026-04-26 05:18:35 +01:00
- app profiles live under `docs/app-profiles/`
- the key boundary is explicit:
2026-04-26 12:25:11 +01:00
- Heimdall owns OAuth, linking, managed provider credential custody, grants,
entitlement refresh, and signed claim issuance
2026-04-26 05:18:35 +01:00
- app-domain data stays app-owned by default
2026-04-26 11:41:27 +01:00
- host apps verify signed claims locally for routine auth instead of calling
Heimdall on every request
2026-04-26 12:50:07 +01:00
- the landed service now exposes:
2026-04-26 12:25:11 +01:00
- `/.well-known/jwks.json`
- `/.well-known/heimdall-configuration`
- `/v1/oauth/{provider}/start`
- `/v1/oauth/{provider}/callback`
- `/v1/apps/{appSlug}/auth-completions/redeem`
- `/v1/apps/{appSlug}/sessions/refresh`
2026-04-29 15:00:55 +01:00
- `/v1/apps/{appSlug}/managed-credentials/resolve`
2026-04-26 12:50:07 +01:00
- the Discord callback path now performs real code exchange, identity
resolution, auth persistence, entitlement evaluation, audit logging, and
claim issuance for the Repixelizer slice
- browser-style auth handoff now uses a one-time completion code posted back to
the opener, with backend redemption instead of fragment-token handoff
2026-04-26 17:00:57 +01:00
- same-host or Yggdrasil-reachable app integrations can now ask Heimdall to
deliver the auth result directly to an app backend callback endpoint, leaving
the browser with only status/attempt signaling
- signing keys can now load from a persisted file path and bootstrap that file
on first boot when explicitly enabled
- managed provider tokens are now sealed at rest with AES-256-GCM instead of
being dumped into "encrypted" columns raw like an insult
- `src/verifier.ts` now provides a small local JWT verifier seam for app
backends
2026-04-29 11:51:29 +01:00
- Repixelizer has consumed the backend-callback flow in its hosted web layer:
it creates local auth attempts, asks Heimdall to start OAuth, receives the
direct backend callback, verifies Heimdall Ed25519 access tokens locally, and
adopts httpOnly local sessions
2026-04-29 12:41:43 +01:00
- Heimdall is now deployed on Yggdrasil at `https://heimdall.gamecult.org`
behind nginx/TLS with Postgres storage, file-backed signing-key bootstrap,
configured token custody, and public health/discovery/JWKS checks passing
- Repixelizer is now deployed on Yggdrasil at
2026-04-29 14:39:11 +01:00
`https://repixelizer.gamecult.org` with Heimdall mode enabled, Discord and
Patreon as public providers, required access enabled, and queue protection
enabled
- Repixelizer public auth-start returns Discord and Patreon authorization URLs
using the Heimdall callback and Repixelizer backend handoff
- Repixelizer auth now has a refresh path: Heimdall issues signed refresh
tokens with access claims, `/v1/apps/{appSlug}/sessions/refresh` reissues
short-lived access claims, and Discord/Patreon provider tokens refresh inside
Heimdall before entitlement re-evaluation
2026-04-29 15:00:55 +01:00
- Twitch and YouTube now have generic OAuth exchange and identity runtimes
- GitHub is still catalogued, but its callback runtime is not implemented
- StreamPixels now delegates viewer and creator Twitch/YouTube OAuth to
Heimdall, redeems Heimdall completion codes server-side, writes its own
viewer sessions and connector bindings, and resolves current provider access
tokens from Heimdall without storing refresh tokens locally
- Spotiverse now delegates Spotify OAuth to Heimdall. Heimdall has a
`spotiverse` app profile and `spotify` provider runtime; Spotiverse stores a
local Heimdall account binding and resolves current Spotify access through
`/v1/apps/spotiverse/managed-credentials/resolve` without storing provider
refresh tokens.
2026-06-08 21:04:51 +01:00
- Bifrost now has a `bifrost` app profile for Discord/Patreon member access.
Bifrost sends caller-owned KTLST Discord role and Patreon tier policies
through trusted backend-callback OAuth starts; Heimdall owns provider
OAuth/token custody and configured backend callback allowlisting.
2026-06-09 20:22:58 +01:00
- Bifrost patron support sync now reuses Heimdall's existing linked Patreon
identity and membership reader. `POST /v1/apps/bifrost/patron-support/sync`
is app-authenticated, refreshes the stored Patreon credential if needed,
reads active paid Patreon tier evidence, and emits a signed
`RecurringSupportSnapshot` to Bifrost's
`/heimdall/patron-support/events` intake.
- Public Yggdrasil Heimdall has been deployed with the Spotiverse/Spotify code
path, Spotify provider credentials, a Spotiverse shared secret, and an
allowlisted loopback portal callback at
`http://127.0.0.1:18796/auth/heimdall/callback`.
- Heimdall and StreamPixels are deployed on Yggdrasil for the StreamPixels
migration slice; Twitch callback handling has been patched so provider token
`scope` can be either a space-delimited string or an array
- live StreamPixels Twitch sign-in through Heimdall has succeeded on Yggdrasil
and Heimdall audit showed callback success, completion creation, and
completion redemption
- the ignored local `secrets/heimdall-service.env` artifact now has
`GC_ACCESS_PROVIDER_TWITCH_*` and `GC_ACCESS_PROVIDER_YOUTUBE_*` populated
for the StreamPixels migration slice
2026-04-26 11:41:27 +01:00
- the intended first deployment shape is a Heimdall service on Yggdrasil behind
nginx, not an embedded cross-runtime shared library fantasy
- Heimdall now writes a daemon-owned boundary witness store at
`GC_ACCESS_CULTCACHE_PATH` containing provider advertisement, command
boundary, transport profile, and daemon-health summary state
- Heimdall can now publish `heimdall.cultnet-rudp-provider-health` to Idunn
over `cultnet.transport.rudp.v0` when `GC_ACCESS_IDUNN_RUDP_HEALTH` is
configured; HTTP `/healthz`, JWKS, discovery, systemd, and nginx routing
remain compatibility witnesses
- Since `1086aee` Heimdall persists its private
provider-health identity at `/srv/heimdall/keys/provider-health-identity.cc`
and publishes canonical signed health independently of the slower Verse
snapshot cadence. Idunn owns the exact root trust binding, authenticated
admission, lifecycle decision, and redacted public `.cc` projection.
- Odin commit `b4f9a2e95f0b41cebdeddc49223781d1d3c7b42a` retains the RUDP health
reliability cut and registers Heimdall's command-boundary, plugin, and
transport schemas so the typed catalog can persist rather than silently drop
them. Live proof returned all four exact Heimdall records.
2026-04-26 05:18:35 +01:00
## Critical Doctrine
- Persistent state is the agent's mind.
- Cut stale architecture notes as ruthlessly as stale code.
- Do not mistake "shared auth" for "shared database."
2026-04-26 11:41:27 +01:00
- Do not mistake "shared auth service" for "every guarded route must call the
mothership."
2026-04-26 05:18:35 +01:00
- If compaction hits before boundary findings are persisted, that work is gone.
Re-gather it instead of pretending continuity happened.
## Next Real Move
The Active Work follow-ups first. Everything below is the standing queue.
2026-04-26 05:18:35 +01:00
Do not continue implementation automatically from a rehydrate-only request.
The Idunn/swarm health transport cut is live. Do not regress Heimdall to
unsigned `idunn.daemon_health`, merge its private key into Idunn, or make HTTP
health an authority. The next product work is the Bifrost and remaining browser
verification listed below.
The active Ghostlight deployment cut is complete. The next Ghostlight work is a
real separate-account KLTST completion/refresh/logout canary, followed by the
eight-account Session Zero privacy and actor-binding smoke. Keep port `4101`
loopback-only and treat any claim, token, completion, app secret, or account
state in Odin/CultMesh/browser output as a release-blocking fault.
If the user asks to continue on Spotiverse, the current next move is the real
browser `/auth/login` flow through public Heimdall. The Yggdrasil SSH tunnel
must include reverse forward
`spotiverse-callback:18796:127.0.0.1:8796`, and local Spotiverse must point at
`https://heimdall.gamecult.org` with the matching `HEIMDALL_APP_SECRET`. Verify
managed credential resolution after login. Spotiverse should not regain local
Spotify OAuth token storage.
If the user asks to continue on StreamPixels, the current next move is real
browser verification:
2026-04-29 15:00:55 +01:00
- verify viewer claim/link through `https://streampixels.gamecult.org/auth/connect`
- Twitch viewer sign-in has already passed once; continue with YouTube and
connector attachment verification
2026-04-29 15:00:55 +01:00
- verify creator connector attach from an admin creator session
- confirm StreamPixels persists local profile/connector binding state while
Heimdall retains provider token custody
- if a provider callback fails, inspect Heimdall audit events and StreamPixels
service logs before touching app/domain boundaries
2026-04-29 15:00:55 +01:00
Repixelizer still needs its real browser OAuth verification:
2026-04-29 12:41:43 +01:00
- open `https://repixelizer.gamecult.org/app/`
2026-04-29 13:07:44 +01:00
- start Discord sign-in with an account that has the `KLTST` or
2026-04-29 14:39:11 +01:00
Patreon-synced `Inner Sanctum` role, or Patreon sign-in with a currently
entitled tier titled `Inner Sanctum`
- confirm Repixelizer sends its app-owned provider policy in the
2026-04-29 13:22:01 +01:00
backend-callback OAuth start
2026-04-29 14:39:11 +01:00
- confirm Heimdall receives the provider callback and evaluates entitlement
2026-04-29 12:41:43 +01:00
- confirm Repixelizer receives the backend callback, verifies the Heimdall
token, adopts a local httpOnly session, and gates hosted/queue routes
- confirm the Discord authorization URL requests only `identify
guilds.members.read`
2026-04-29 11:51:29 +01:00
Launch policy is role-gated on purpose: the GameCult Discord can remain public,
2026-04-29 13:07:44 +01:00
but Repixelizer access is limited to members with either `KLTST` or the
2026-04-29 13:22:01 +01:00
Patreon-synced `Inner Sanctum` role. Repixelizer owns that role policy through
its own runtime env and sends it to Heimdall during backend-callback OAuth
start; Heimdall owns provider OAuth mechanics and claim issuance, not the
per-app role list.
2026-04-26 05:18:35 +01:00
2026-04-29 14:39:11 +01:00
Patreon access is title-gated on the currently entitled tier title
`Inner Sanctum`; do not use currency amount as the durable policy because
currencies are weird little traps.
2026-06-08 21:04:51 +01:00
Bifrost needs browser verification after deployment:
- configure Heimdall with
`GC_ACCESS_APP_BIFROST_BACKEND_CALLBACK_URLS=https://bifrost.gamecult.org/auth/heimdall/callback`
- configure Heimdall with `GC_ACCESS_APP_BIFROST_SHARED_SECRET_FILE`,
2026-06-09 20:22:58 +01:00
`GC_ACCESS_BIFROST_PATRON_SUPPORT_ENDPOINT=https://bifrost.gamecult.org/heimdall/patron-support/events`,
and `GC_ACCESS_BIFROST_PATRON_SUPPORT_SECRET_FILE`, each naming a credential
file
2026-06-08 21:04:51 +01:00
- configure Bifrost with `Heimdall__DiscordGuildId`,
`Heimdall__DiscordAllowedRoleIds__0=<KTLST-role-id>`, and
`Heimdall__PatreonTierTitle=Inner Sanctum`
2026-06-09 20:22:58 +01:00
- configure Bifrost with the matching `Heimdall__PatronSupportIntakeSecret`
2026-06-08 21:04:51 +01:00
- start Discord sign-in from `https://bifrost.gamecult.org/` with a user that
has the KTLST cult-member role
- start Patreon sign-in with a user that has the configured active tier
- confirm Bifrost creates/updates a local account and active standard
membership while Heimdall keeps provider token custody
2026-06-09 20:22:58 +01:00
- trigger `/v1/apps/bifrost/patron-support/sync` for that linked Heimdall
account and confirm Bifrost records a Patreon recurring-support snapshot
without owning Patreon webhook or token custody
2026-06-08 21:04:51 +01:00
2026-04-26 05:18:35 +01:00
## Immediate Re-entry Instruction
After compaction, first rehydrate and reorient from the listed files and git
state. Wait for the user's next instruction unless they explicitly say to
continue.