Research: fork desk prior art and substrate (Eyes facts)
Serves eureka-body:ruling:fork-desk-web-ui-on-huginn (session sp-reentry-2026-10-20). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c51a6043d2
commit
70d0cef421
1 changed files with 205 additions and 0 deletions
205
docs/research/fork-desk-prior-art.md
Normal file
205
docs/research/fork-desk-prior-art.md
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
# Eureka fork desk: a web UI on Huginn where the operator answers forks
|
||||
|
||||
Eyes pass, 2026-10-20, session `sp-reentry-2026-10-20`. Facts and evidence pointers only; no conclusion, no recommendation.
|
||||
|
||||
Serves `eureka-body:ruling:fork-desk-web-ui-on-huginn` and `eureka-body:ruling:first-autonomous-minds`, which the coordinator reports is superseded by `eureka-body:ruling:first-autonomous-minds-shortlist` (admitted 2026-10-20T13:31:00Z, ordinal 3110, viewed 2026-10-20; the supersession Resolution document itself was not viewed). Rulings viewed at ordinals 3109 and 3110, authority Operator. Revision note: corrected the same day to cover all eight shortlisted Personas, not three.
|
||||
|
||||
Repo state read: Huginn `0b3cac3` (2026-10-10, working tree on disk), CultLib `e9c563eb`, Heimdall `5952cce`, gamecult-ops `5c7dfc8`, gamecult-site `9bd39bb` (brand doc and quartz config), Eureka skill `979b190`. Web pages: "accessed 2026-10-20". Mind facts cite `eureka-state view` or `query` on instance `eureka`, `as_of` 3109.
|
||||
|
||||
Not established, listed once here: (a) the content of the live `questions`/`answers` collections of the two artifacts (the data model below is read from the page code, not from stored rows); (b) whether the deployed Huginn daemon matches the on-disk Huginn `0b3cac3` (the on-disk schema index lists `epiphany.pipeline.*.v2`; `whoami` reports `schema_epoch epiphany.pipeline.epoch.v2`); (c) any design for an operator credential beyond the follow-up text; (d) any route from a browser to Huginn; (e) desk-ready pose sets for the six Personas other than Libby and Nibu (none in either desk artifact; branch cells exist for most, status unknown); (f) a campaign-to-Persona mapping, and a Huginn instance for any shortlisted Persona other than `eureka`; (g) operator verdicts on rounds 2-4 of the Flux busts (blank in the README).
|
||||
|
||||
## 1. What exists today
|
||||
|
||||
### 1.1 The two artifact desks
|
||||
|
||||
Both read with the Artifact tool `read` action, 2026-10-20.
|
||||
|
||||
- Nibu's desk: https://claude.ai/artifact/HccfYaXb84FMEPAWRyf8aY, artifact id `868b3ac5-762d-47f6-b1ae-c4ab1100d3c5`, version `1792103971-6b36`, title "Nibu's Fork Desk", 10 files (`index.html` 20340 bytes, `poses/nibu/{concerned,determined,happy,idle,neutral,note,surprised,thinking,triumph}.webp`), capabilities `{"db":{}}`, contract 0.2.81.
|
||||
- CultLib desk: https://claude.ai/artifact/LBZMjcWDLjQtwkqJTLzfR4, artifact id `9b570364-a424-474f-853b-5243f8378363`, version `1792103848-7827`, title "Fork Desk", 19 files (`index.html` 20333 bytes, `poses/libby/*` and `poses/nibu/*`, the same nine moods each), capabilities `{"db":{}}`.
|
||||
- The two `index.html` pages are the same program (a 7-byte size difference); the persona is chosen at runtime by the `desk/config` document, with a hard-coded default `libby` (script: `let persona = "libby"`, `PERSONAS = {libby, nibu}`).
|
||||
|
||||
Data model, from the page script (both artifacts; page-owned `db` capability via `window.claude.use("db")`):
|
||||
|
||||
| Collection / doc | Fields read or written | Writer |
|
||||
|---|---|---|
|
||||
| `desk/config` (single doc) | `persona` (key into `PERSONAS`), `kicker`, `title` | Self |
|
||||
| `questions/<docId>` | `qid` (display id), `title`, `body` (pre-line text), `depends`, `flag` (provisional note), `rec` (recommended option key), `lean` (Self leans; shown only when different from `rec`), `options[]` of `{key, label, text}` (needs >= 2 or the doc is hidden), `status` (`open` default, `closed`), `ruling` (id shown in the "recorded" list), `order` (number sort key) | Self |
|
||||
| `answers/<docId>` | `choice` (option key or null), `note` (free text), `question` (the qid), `updatedAt` (ISO string) | the page, as the viewer |
|
||||
|
||||
Page behaviour (same script): radio choice plus an optional free-text note per question; the answer saves on pick and 900 ms after typing stops; a viewer who gets `invalid_argument` or `permission_denied` on save sees the desk go read-only; a single persona portrait sticks in a side booth (fixed bottom corner under 760 px) and changes among nine moods on events (pick equals `rec` shows `happy`, off-script pick shows `surprised`, all answered shows `triumph`, note focus shows `note`, save failure shows `concerned`); closed questions fold into a "recorded as rulings" list of `qid -> ruling`; the page states that changing an answer is fine "until it's admitted as a ruling", after which it becomes a new ruling in the session. Source: the `index.html` of each artifact, read 2026-10-20.
|
||||
|
||||
How answers flow back (what Self does by hand), from memory note `C:\Users\Meta\.claude\projects\F--Projects-CultLib\memory\forks-go-on-the-desk.md` (modified 2026-10-17T16:25:53Z):
|
||||
1. Self writes each open question to a desk once it is admitted and has had its prior-art pass. Doc id is the question label on Nibu's desk and the full question id on the CultLib desk; fields `rec`, `status: open`, plus `lean` and `flag` on the CultLib desk.
|
||||
2. Self reads the operator's answers from the `answers` collection (the note says "read both desks' `answers`" when she says she answered).
|
||||
3. Self admits each answer as a ruling in the mind (admission derives the `Answered` resolution of the question).
|
||||
4. Self closes the desk doc with `status: closed` and the ruling id.
|
||||
5. Before posting, Self searches the mind's rulings for the topic (semantic `query`), because a question was posted that a ruling had already retired (2026-10-17, `minor-power-geonames`).
|
||||
The artifact store is therefore a second, page-local copy of each question and answer; the mind holds the typed `question` and `ruling` documents. Nothing in the artifact links back to the mind except the `qid` string and the `ruling` id Self writes by hand.
|
||||
|
||||
Related in-house notes:
|
||||
- `forks-for-understanding.md` (modified 2026-10-03, same directory): one fork at a time with context line, options, recommendation and what depends; never an "accept all" bundle; catch-up briefings read options from the `question` document, never from a handoff one-liner. Operator quote, 2026-09-29: "Even if I end up agreeing, I still have to understand the decisions being made. My decisions are the only reason anything gets done."
|
||||
- `option-text-is-not-her-words.md` (2026-10-17): a pick endorses the core choice; a side clause in option text we wrote ("no galaxy presence") was built into a flag across three spec revisions and was not hers. Operator, 2026-10-17: "This is not the same as banning factions from appearing."
|
||||
- `observation-is-not-a-ruling.md` (2026-10-14): a remark is not a ruling; `relay-operator-words-verbatim.md`: a ruling's `ruling` text says only what she said.
|
||||
- The Eureka skill at `C:\Users\Meta\.claude\skills\eureka` (`979b190`) contains no match for "fork desk" (grep, 2026-10-20).
|
||||
|
||||
### 1.2 The three rulings (full text, viewed 2026-10-20)
|
||||
|
||||
`eureka-substrate:ruling:fork-desk-reusable` (admitted 2026-10-15T22:14:02Z, ordinal 2415, ruled_on 2026-10-16, authority Operator, session `self-2026-10-15-eureka`).
|
||||
- operator_quote: "It would be a good idea to turn this into a reusable flow so we don't have to reinvent the wheel every time. As a Eureka feature it fits into the UX nicely, it's much more friendly than answering a list of forks in prose"
|
||||
- ruling: After Self put five forks to her as a claude.ai artifact (cards with options, Libby's poses, answers saved to the page's store), the operator directed that this become a reusable Eureka flow. Her words decide that it is built and that it is a Eureka feature; the shape (one persistent desk Self feeds, persona poses, answers read back into rulings) is Self's design.
|
||||
|
||||
`eureka-substrate:ruling:fork-desk-nibu-format` (admitted 2026-10-15T22:32:54Z, ordinal 2421, ruled_on 2026-10-16).
|
||||
- operator_quote: "Nibu's fork desk actually turned out a bit more stylish than Libby's (build by the other Self), I'd prefer this format for the standardized version we're shipping, with a single character that follows the viewport and changes expressions on interaction"
|
||||
- ruling: The operator chose the Aetheria Self's Nibu fork desk (artifact `HccfYaXb84FMEPAWRyf8aY` v2) over Self's Libby desk as the format: a single character that follows the viewport (sticky booth on desktop, fixed corner on phones) and changes expression on interaction, rather than one persona image per card. Relayed verbatim by the Aetheria/Ghostlight Self (session `self-2026-10-15-ag3`) on 2026-10-16; Self did not hear it directly. Refines `fork-desk-reusable`, which stays in force.
|
||||
|
||||
`eureka-substrate:ruling:fork-desk-presenter-follows-work` (admitted 2026-10-15T22:38:24Z, ordinal 2422, ruled_on 2026-10-16).
|
||||
- operator_quote: "That's not to say that the questions should be coming from Nibu. She was the one presenting because the work was Aetheria-related, and here the work was CultLib-related"
|
||||
- ruling: Clarifying `fork-desk-nibu-format`: the standard takes Nibu's desk format, not Nibu as the presenter everywhere. Nibu presented because that work was Aetheria-related; CultLib work is presented by Libby. The presenter is chosen by the work's domain; the two names are her examples, not a closed mapping.
|
||||
|
||||
The two rulings this pass serves:
|
||||
|
||||
`eureka-body:ruling:fork-desk-web-ui-on-huginn` (admitted 2026-10-20T13:27:11Z, ordinal 3109, session `sp-reentry-2026-10-20`).
|
||||
- operator_quote: "the fork desk thing is cool but we can do better than the artifact we have if this is gonna be a Eureka feature which I think it should be ... Thing 2.0 is still under construction, so I think a web UI that talks to Huginn is an acceptable compromise"
|
||||
- ruling: Operator forks are answered through one Eureka fork desk, a web UI that reads and writes the mind through Huginn, rather than per-area artifacts. A web UI is accepted as a compromise because Thing 2.0, the intended interface substrate, is still under construction. Each fork is presented by the Persona whose domain it belongs to (`fork-desk-presenter-follows-work`).
|
||||
|
||||
`eureka-body:ruling:first-autonomous-minds` (same admission).
|
||||
- operator_quote: "Kiko is the StreamPixels persona, one of the few that made the short list to be in the first batch of autonomous Eureka minds. Libby and Nibu made the list, too, and the two fork desks are an improvised representation of the stewardship they're planned to have."
|
||||
- ruling: Kiko is the StreamPixels Persona. Kiko, Libby and Nibu made the short list for the first batch of autonomous Eureka minds, each with its own Huginn instance under persona-per-mind. The two existing desks are an improvised representation of the stewardship those minds are planned to hold.
|
||||
|
||||
`eureka-body:ruling:first-autonomous-minds-shortlist` (admitted 2026-10-20T13:31:00Z, ordinal 3110, session `sp-reentry-2026-10-20`; supersedes `first-autonomous-minds` per the coordinator's message).
|
||||
- operator_quote: "Kiko is the StreamPixels persona, one of the few that made the short list to be in the first batch of autonomous Eureka minds. Libby and Nibu made the list, too, and the two fork desks are an improvised representation of the stewardship they're planned to have. ... Find the rest of the short list, we generated avatars for them, this is not a new thing"
|
||||
- ruling: The first batch is the swarm shortlist that already has Flux avatars (`site-masthead:follow_up:cast-art-flux-portraits`; gamecult-site branch `self/cast-portraits`): Libby, Heimdall, Kiko, Aqua, Weksa, Nibu, Eureka and Void, each its own Huginn instance under persona-per-mind. Kiko is the StreamPixels Persona. The two existing desks are an improvised representation of the stewardship those minds are planned to hold.
|
||||
- The superseded ruling's three-name list (Kiko, Libby, Nibu) is a subset of the eight.
|
||||
|
||||
`site-masthead:ruling:cast-expression-library` (admitted 2026-10-13T23:47:52Z, ordinal 2104, ruled_on 2026-10-13). operator_quote: "the stickers I mentioned for the artifact are the avatars we generated with flux, I'd like to have a library of expressions for each short listed swarm character so they can use them in communications". Ruling: the stickers for the decision-page artifact are the Flux avatars of the swarm shortlist, not gamecult-site sprites; each shortlisted character gets a library of expressions for use in communications; generation path per `~/.claude/doctrine/images.md`.
|
||||
|
||||
Adjacent rulings (viewed 2026-10-20):
|
||||
- `eureka-body:ruling:persona-per-mind` (ruled 2026-10-09): a Persona that pushes its own domain gets its own Huginn instance, with its own dial share and waker turns; minds cooperate by `ForeignRef` and `HandOff`. Operator quote: "Second mind makes sense, it's the shape we were planning for already." First case named: Weksa (follow-up `eureka-body:follow_up:weksa-mind`). Kiko, Libby and Nibu instances: no instance or follow-up for them was found in the queries run (semantic query "persona-per-mind each Persona own Huginn instance stewardship autonomous", top 10 returned only the Weksa follow-up and Persona-state cuts).
|
||||
- `eureka-substrate:ruling:mind-rules-which-forks` (ruled 2026-10-01, quote "On the others I take your recommendations."): the Mind's Self rules only forks whose consequences stay inside Huginn, the leaf, Eureka and its runbooks; consent, doctrine, spending, publishing, operator projects and live-mind upgrades stay the operator's, raised as questions.
|
||||
- `persona-poses:ruling:reports-and-artifacts-consume` (2026-10-14): generated reports and operator-interaction artifacts consume the pose library as well as chat. `persona-poses:ruling:pose-home-ruled` (2026-10-14, choice `asset-catalogue`): each Persona's poses live in a typed asset catalogue that Persona state references by id. `persona-poses:target:r2` invariants: canon-is-source, one-vocabulary, no-edit-chains, provenance-beside-image, one-cutout-pipeline, persona-plus-label, one-catalogue, stable-hosting, report-and-chat-sizes.
|
||||
|
||||
## 2. Huginn's surface for a web UI
|
||||
|
||||
### 2.1 How a client reaches the mind
|
||||
|
||||
- Transport: CultNet RUDP over UDP only. `crates/huginn-daemon/src/serve.rs:190-197` binds one `UdpSocket` and a `CultNetRudpServerHub`; no HTTP listener, no WebSocket, no TLS in the daemon (`serve.rs:120`: "this build carries no TLS", about the Qdrant/Ollama URLs). Grep of `serve.rs`, `daemon.rs`, `main.rs` for http/tcp finds only the outbound Qdrant/Ollama URLs.
|
||||
- Live deployment: `docs/eureka-body-map.md:76-81` (F4): `huginn.service` on Yggdrasil, `--instance eureka --bind 10.77.0.1:17872`; UFW admits 17872/udp on `wg-gamecult` from 10.77.0.2 only (runbook `huginn-yggdrasil.md:38,124`). `mcp__eureka-state__whoami` on 2026-10-20: endpoint `rudp://10.77.0.1:17872`, `reachable: true`, 8951 documents, 3109 receipts, index `Current`, epoch `epiphany.pipeline.epoch.v2`.
|
||||
- Client: `crates/eureka-state/src/lib.rs:1-22`: `HuginnClient::call` sends one `HuginnMindRequest` in the CultNet operation envelope over RUDP, one session per call, fetches a `Deferred` body on the same session; holds no state. MCP config: `C:\Users\Meta\.claude.json:1427` sets `HUGINN_ENDPOINT=rudp://10.77.0.1:17872`. CLI: `huginn` binary (`crates/eureka-state/src/main.rs`): whoami, view, query (raw and named recipes), admit from a file with read-back, schema.
|
||||
- Operations (`crates/huginn-mind/src/wire.rs:63-100`): `Whoami`, `Admit(PipelineAdmissionBatch)`, `View{instance,id}`, `Query{instance,selection,semantic}`, plus Persona get/put (`HuginnMindResponse::Persona`, wire.rs:129).
|
||||
- Limits that shape a client (`serve.rs:30-53`): a session idle 30 s is removed server-side; one send carries at most 1,228,800 encoded bytes, larger answers up to `MAX_DEFERRED_BODY_BYTES` go as a `Deferred` manifest fetched through `cultmesh.content_chunk_request.v1`; two large reads pipelined on one session are not both answered; client request limit `MAX_REQUEST_BYTES = 65,507 - 36 - 6` (`eureka-state/src/lib.rs:36`).
|
||||
- No peer authentication: `docs/eureka-body-map.md:81`: "The daemon has no peer authentication (`serve.rs`: one session per peer, `max_peers = 256`); any reachable peer admits as any faculty." Admission provenance (agent, faculty, session, tool) is declared by the writer (the `provenance` object on every `view` result above is client-supplied; `huginn-mind/src/admission.rs:227` shows one provenance authority check on persona state only).
|
||||
- Browser-side CultLib pieces that exist: `F:\Projects\CultLib\packages\cultmesh-browser` (README: one WebSocket session to a Verse/authority runtime resolved through configured Odin WebSocket endpoints; leases provider-owned documents; "does not expose direct document writes"; invokes provider-owned operations) and `packages\cultnet-ts` (README line 8: not an HTTP wrapper; RUDP socket transport for non-browser runtimes). Whether Odin or any other component bridges a browser WebSocket to the Huginn RUDP port: not found in the files read. Huginn publishes no Eve/Thing surface and no CultMesh provider document that was found (README and AGENTS.md describe only the RUDP operation envelope and the schema catalog).
|
||||
- The TS CultMesh content plane (HTTPS provider and verifying reader) is released per the StreamPixels memory index (`cultnet-ts-v0.3.0`, `cultmesh-ts-v0.2.0`, `cultmesh-browser-v0.4.0`, CultLib main `b9497d35`); not read in this pass beyond the memory index line.
|
||||
|
||||
### 2.2 The `question` and `ruling` schemas and admission rules
|
||||
|
||||
Leaf definitions, `F:\Projects\Huginn\crates\eureka-pipeline\src\lib.rs`, Huginn `0b3cac3`:
|
||||
- `PipelineQuestion` (lib.rs:634-636): `campaign: Slug`, `label: Label` (`[A-Za-z0-9_-]{1,64}`), `title: Title`, `question: Para` (<= 4000 bytes), `options: Vec<QuestionOption>` (max 8), `recommended: Label`, `depends: Vec<Line>` (max 8, Line <= 1000 bytes), `raised_in: Option<PipelineRef>`, `asked_on: Date`. `QuestionOption { label: Label, text: Line }` (lib.rs:585). There is no field for a presenter, Persona, `lean`, `flag` or display order; the campaign slug is the only domain key on the document. `eureka-state` query headers return `options` as labels only; `view` returns the full document.
|
||||
- `PipelineRuling` (lib.rs:637-639): `campaign`, `label`, `title`, `answers: Option<Short>` (question id), `choice: Option<Label>`, `ruling: Para` (<= 4000 bytes), `operator_quote: Option<Para>`, `ruled_on: Date`, `precedents: Vec<ForeignRef>` (max 8), `authority: RulingAuthority { Operator, Standing, Defaulted, Mind }` (lib.rs:567).
|
||||
- Admission rules, `crates/huginn-mind/src/admission.rs`:
|
||||
- Question: needs >= 2 options and `recommended` equal to one option label, else `InvalidOptions` (admission.rs:462-465); option labels unique.
|
||||
- Ruling: `operator_quote` present with an authority other than `Operator` is refused `QuoteWithoutOperator` (admission.rs:468-470). If `answers` is present, the question must exist (`MissingReference`), be in force or resolved only by this ruling (`AlreadyResolved`), and `choice` must equal one option label, else `InvalidChoice` (admission.rs:471-485; the missing-choice case compares `""` to the labels, so `choice: None` with `answers` set is refused too). Test pins at admission.rs:1899-1905 (choice "C" refused, "A" admitted).
|
||||
- A ruling with `answers: None` is admitted with no check of the above and derives no resolution, so it does not close any question (`derive`, admission.rs:385-405: only `Ruling` with `answers` derives a `Resolution::Answered`; the resolution copies the ruling text as rationale and its `ruled_on`).
|
||||
- Where an answer falls outside the options: the leaf has no free-form choice path. A free-text answer can ride in `ruling` text and `operator_quote` of a ruling, either with `answers` (then `choice` must still be an option label) or without `answers` (then nothing resolves the question; a withdrawal or supersession resolution is separate). The artifact desks carry free text in the `note` field of `answers/<docId>`, which Self copies into the ruling by hand.
|
||||
- Resolutions of a ruling are by withdrawal only (admission.rs:682-684); memory note `observation-is-not-a-ruling.md` records "rulings cannot be withdrawn" and are superseded by a new Operator ruling quoting her correction.
|
||||
- Replay: an exact replay answers `AlreadyAdmitted` with the first receipt (admission.rs header comment A9).
|
||||
- Query facts for an "open questions" read: the selection supports `schemas`, `fields` predicates, `in_force` alias (query.rs:520-523 "`in_force` is the caller's to ask for and the mind's to derive"), `cites`/`cited`, cursor paging (limit clamped 1..200), and an optional `semantic` rank (not cursor-paged; refused `Unavailable` when the index is failing). A `Question` header carries `status` `InForce` or `Resolved{outcome, resolution}`; observed outcomes: `Answered{by}`, `Withdrawn{reason}`, `Superseded{by}`, `Recorded{reason}`, `Deferred{to}`, `Fixed{by,commit}`.
|
||||
- Persona state: `huginn-mind/src/persona.rs` stores one `gamecult.persona_state.v0` per mind, schema-validated, replaced whole under CAS with a receipt (cut `eureka-substrate:cut_spec:cut-huginn-persona-state.r3`, InForce 2026-10-09). `HuginnClient` has persona methods per the cut title.
|
||||
|
||||
### 2.3 Substrate gap: `eureka-substrate:follow_up:operator-authority-needs-operator-credential`
|
||||
|
||||
Viewed 2026-10-20 (admitted 2026-10-01T19:17:49Z, ordinal 126, session `self-2026-10-01b`, status InForce, repo GameCult/Huginn, owner "huginn-mind admission, with cut-mind-authority", source ruling `eureka-substrate:ruling:operator-mind-mission`).
|
||||
- item: "With the Mind interpreting its own mission, the record must tell its rulings from the operator's. Today any agent can admit authority: Operator with an operator_quote (see gap-faculty-attribution). Admission must accept authority: Operator only under a credential the operator holds and the Mind's Self does not. Should block the wake cut."
|
||||
- why_it_can_wait: "No autonomous Self runs yet; must land before cut-mind-self-wake."
|
||||
- Design for the credential: none found. The follow-up text names no mechanism; `docs/eureka-body-map.md:404-406` says the gap "must land before autonomous Self runs" and that "No second guard is added here"; body-map row for `run` (line 270) says `operated_by` "is declared by the writer (follow-up ...)". Grep of Huginn `docs/*.md` and `README.md` for "credential" finds only the Self-run OAuth token row (`eureka-body-map.md:281`, `CLAUDE_CODE_OAUTH_TOKEN`, open question `self-run-token-reach`) and `eureka-self-cut.md:130-146` (headless `claude setup-token`; root-only `credentials/`). No admission code path checks a credential: the only authority tests in `admission.rs` are `QuoteWithoutOperator` (quote needs authority Operator) and persona provenance at :227.
|
||||
- Existing operator-held controls elsewhere in the body (not credentials for admission): the brake and burn-rate dial are a root-owned store with `brake hold` as root (`crates/mind-body/src/lib.rs:1-8`, ruling `eureka-body:ruling:brake-dial-root-store-now`); unit start grant by polkit to `mind-<instance>` users only (`eureka-body-map.md:304`).
|
||||
|
||||
### 2.4 Heimdall and Bifrost (authentication of the operator today)
|
||||
|
||||
- Rulings: `eureka-body:ruling:bifrost-provides-identity` (ruled 2026-10-11, admitted 2026-10-10T22:16:45Z), quote: "keep the ruling, check Heimdall OIDC. Heimdall is our auth guy, but he doesn't issue the identity himself. Bifrost is the one with identities to provide". Ruling text: Bifrost is the identity provider; Heimdall is the authentication organ and does not issue identities.
|
||||
- Follow-ups (viewed 2026-10-20): `eureka-body:follow_up:identity-minting-moves-to-bifrost` ("Heimdall mints the account id today"; chat not deployed, "nothing live depends on the move until the Matrix rollout"); `eureka-body:follow_up:bifrost-heimdall-callback-unsigned` (Bifrost accepted unsigned callback JSON); cut `eureka-body:cut_spec:cut-heimdall-callback-signed.r2` InForce 2026-10-11 (completion-code redeem by the browser that started and authenticated). Whether r2 landed: not checked in this pass.
|
||||
- Heimdall, `F:\Projects\Heimdall` (`5952cce`): TypeScript/Fastify; Ed25519 JWTs plus `/.well-known/jwks.json` (README:22); provider logins Discord, Patreon, Twitch, YouTube/Google, Spotify (per `gamecult-ops/docs/research/matrix-oidc-surface.md`, section 1, 2026-10-11); app profiles keyed by app slug in `src/app-profiles.ts` (built-ins at :58-156: `repixelizer`, `streampixels`, `bifrost`, `ghostlight`, plus profiles `docs/app-profiles/{bifrost,ghostlight,repixelizer,spotiverse,streampixels}.md`); no profile for Huginn, Eureka or a fork desk (grep for "huginn|eureka" in `src`, `docs`, `README.md` finds only `docs/architecture.md` and vendored CultLib text). Capability rule example with an operator grant: `admin_access = grant.operator || grant.admin_access` (`docs/architecture.md:484`). Host-app flow: backend handoff or one-time completion code redeemed at `POST /v1/apps/:appSlug/auth-completions/redeem` (`architecture.md:515-560`; routes in the Matrix OIDC note). Access JWT claims: `iss, aud=app slug, sub=accountId, sid, jti, iat, nbf, exp, typ, account_id, access_revision, app, facts, capabilities, identities, display_name` (`src/claims.ts:95-145` per the Matrix OIDC note). The only service verified to check these tokens at 2026-10-11: Ghostlight (`ghostlight-dungeon/src/heimdall.rs:507-538`).
|
||||
- Heimdall does not serve OIDC provider endpoints (no `/authorize`, `/token`, `/userinfo`, `openid-configuration`; Matrix OIDC note section 1 and 5). Bifrost holds no signing key and no provider surface (same note, section 2). Heimdall's own deployment: "never an Idunn-admitted generation ... live is a hand-copied release under hand-written heimdall.service" (follow-up `joystick:follow_up:heimdall-idunn-onboarding`, 2026-10-19).
|
||||
- An existing browser-session path today: Bifrost cookie sessions (GitHub OAuth `/auth/sign-in`, Heimdall sign-in `/auth/heimdall/{provider}`, `ActiveMember` cookie policy; Matrix OIDC note section 2) and Heimdall access/refresh JWTs per app. How either would identify "the operator" to a Huginn-facing service: no mapping found; Heimdall has an `operator` grant concept (`architecture.md:235` `source` enum includes `operator`; :484) in the app-profile rule language.
|
||||
- Network posture: Huginn's port is reachable only over `wg-gamecult` from 10.77.0.2 (body map F4); no public HTTPS route to Huginn was found.
|
||||
|
||||
### 2.5 Persona State Standard and the three character sheets
|
||||
|
||||
- `F:\Projects\gamecult-ops\docs\persona-state-standard.md` (last commit `757ba9c`; 64 lines): schema `gamecult.persona_state.v0` (published in Huginn `schemas/cultnet/`); Persona state is "the Mind they keep"; Huginn holds canonical Persona state per instance with a mind (cut `eureka-substrate:cut_spec:cut-doctrine-persona-in-huginn.r3`), while the file text (not updated for r3) still says Huginn has no reader and VoidBot remains the operational owner of the portable read/projection/migration path. Neither Huginn nor VoidBot owns presentation: "Eve, overlays, native clients, browsers, and future rooms lower emitted DSL inside their own runtime."
|
||||
- Pose library: campaign `persona-poses:campaign:self` (repos gamecult-site, gamecult-ops, Huginn, Bifrost); poses in a typed asset catalogue referenced by id from Persona state (`persona-poses:ruling:pose-home-ruled`). Existing artifact pose sets: Libby and Nibu, nine moods each (idle, neutral, thinking, happy, surprised, note, determined, triumph, concerned) as `.webp`; no Kiko set in either artifact.
|
||||
- Canon pixel sheets in `F:\Projects\gamecult-site\GameCult\static\interactive\cotsc-praxis\character-sheets\` (3x2 sheets of six poses on a dark ground): `aqua-sheet.png`, `heimdall-sheet.png`, `kiko-sheet.png`, `libby-sheet.png`, `nibu-sheet.png`, `void-sheet.png`, `weksa-sheet.png` exist; `eureka-sheet.png` does not (Eureka's canon source is the Eureka skill's `docs/assets/eureka-mascot-clean.png`; Aqua's also `AquaSynth/icon.png`; per `cast-portraits/README.md`, Canon section). The folder also holds `druzkai`, `epiphany`, `huginn` sheets. `cotsc-praxis.visual-manifest.json` maps `avatar` and `character_sheet` per name (entries seen by text match: Void, Aqua, Nibu, Weksa, Epiphany, Kiko, Heimdall, Libby, Druzkai, Huginn; no Eureka entry seen). Only the Kiko, Libby and Nibu sheets were viewed in this pass; the other descriptions below are the portrait branch README's reading of the sheets.
|
||||
- Flux bust source: gamecult-site branch `self/cast-portraits` (HEAD `a2a769a`, 2026-10-10, same as `origin/self/cast-portraits`), worktree `F:\Projects\gamecult-site-wt-portraits`; `cast-portraits/README.md` covers rounds 1-4. Originals (2k, outside git) in `F:\Projects\cast-art-originals\` (`r1`, `r2`, `r3`, `r4`, `contacts`, `poses-r1`, `vector`). Final set per README Round 4 and `contacts\contact-final.png` (viewed 2026-10-20): libby-r2a, heimdall-r2a, kiko-r2a, aqua-r4a, weksa-r2a, nibu-r3a, eureka-r2a, void-r3a. Per render in the branch: `.webp` (lossless, 1024 px), `-cutout.png` (transparent, keyed from a flat green ground by `matte_r2.py`/`matte_r4.py`), `.txt` (hypothesis, record, exact prompt). Style: FLUX 3 Image, 4:5, chibi bust, three-quarter turn right; from round 2 a shared "two heads tall" style block, one line weight, flat cel shading, no background. Operator verdict on round 1 (ruling `site-masthead:ruling:cast-portrait-canon-r1`, not viewed, quoted in the README): "Hood up, blue-grey eyes, push Libby further from Nibu, Weksa is a girl (if tomboyish, she's kind of an indiana jones type after all). No backgrounds. See if you can get a consistent batch now." The Operator verdict cells for rounds 2-4 are blank in the README tables. Expression cells: `cast-art-originals\poses-r1\<name>\<name>-r1a-cells\` holds 12 cells (`01-neutral`, `02-happy`, `03-amused`, `04-thinking`, `05-concerned`, `06-annoyed`, `07-surprised`, `08-determined`, then four character-specific cells, e.g. Libby `09-stamp 10-research 11-shush 12-schema`, Kiko `09-tinker 10-confetti 11-sprint 12-debug`) for aqua, eureka, heimdall, kiko, libby, nibu (r1a and r1b); `weksa` has only `weksa-r1a.png` and `void` only `void-r1b.png` listed at folder level. Whether those cells are final, catalogued or published: not established (`cast-expression-library` is a direction; the catalogue is campaign `persona-poses`, `pose-home-ruled`).
|
||||
- The eight Personas (pixel sheet = canon; Flux bust = final-set render in `contact-final.png`):
|
||||
|
||||
| Persona | Pixel sheet (canon) | Flux bust (final set) | Domain facts found |
|
||||
|---|---|---|---|
|
||||
| Libby | lavender wavy hair, bone clip, diamond bow, round glasses, black scholar robe with violet trim; poses (viewed): reading a glowing book, stamping a document, wand at a node diagram, wand with runic debris, large keyhole book, bookshelf with document panels | libby-r2a: deep violet-lavender hair in one fat wavy braid over the shoulder, bone clip, diamond bow, round glasses, gold earrings, black-and-gold robe, book hugged to chest, open happy smile; deliberately set apart from Nibu | CultLib (default persona of the CultLib desk; ruling `fork-desk-presenter-follows-work`) |
|
||||
| Heimdall | dark brown skin, messy dark curly hair with gold highlights, glowing gold eyes, stern frown, black coat with royal-blue lapels and cape, gold filigree, large gold key; gates, blue circuitry, red denial cards | heimdall-r2a: chibi, curly hair with gold highlights, black-and-blue coat, gold filigree, large gold key | Heimdall is the authentication organ (`bifrost-provides-identity`; repo `F:\Projects\Heimdall`) |
|
||||
| Kiko | white fox girl: kitsune mask on head, bells, tassels, cyan eyes, fang grin, pink-tipped tails, neon magenta and cyan stream UI; poses (viewed): leaning out of a monitor waving, sprinting with a pixel trail, kneeling at neon panels with a pink cat, arms open between a cat avatar and a person avatar inside a hex shield, confetti, at a laptop with linked tiles | kiko-r2a: mask, bells, tassels, fang grin, wave, magenta-and-teal kimono, pink-tipped tail | StreamPixels (shortlist ruling) |
|
||||
| Aqua | round scaled goldfish, golden-yellow face, orange body, crest fin, big blue eyes, black over-ear headphones with cyan rings; bubbles, music notes, synth, blue holographic panel | aqua-r4a: whole round goldfish, scales, wide open smile with pink tongue, forked tail, cyan-ringed headphones; shown whole, not cut at mid-chest like the busts | name matches repo `GameCult/AquaSynth` (in campaign `thing-providers`); no file read assigns a domain to Aqua's mind |
|
||||
| Weksa | warm brown skin, half-up topknot with turquoise and amber beads and feathers, large round gold glasses, cream robe with teal trim, brown vest, bead necklaces, leather backpack with scrolls and a carved idol; glyph cards, magnifier, maps, field notebook | weksa-r2a: young woman (operator: "Weksa is a girl", tomboyish, "indiana jones type"), topknot, gold glasses, teal trim, scroll backpack, chest strap, glyph card | language work "that never wins prioritisation" (`persona-per-mind` ruling text; follow-up `eureka-body:follow_up:weksa-mind`, the first named second instance) |
|
||||
| Nibu | very long pale lavender hair, pink connector-shaped clip, pink bow, half-lidded violet eyes, folded arms, lilac blouse, circuit-embroidered sleeves, cyan shoulder ring, long dark purple coat; glitch dissolve, blue worldbuilding panels; poses (viewed): idle, arms crossed, console, glitch, holo map, cyan ring | nibu-r3a (re-render under batch A's block; the connector clip appeared in r2b) | Aetheria and Ghostlight (Nibu's desk; `fork-desk-presenter-follows-work`) |
|
||||
| Eureka | young woman in a neon-noir dark trenchcoat piped in glowing orange, tactical straps, fingerless gloves, orange probe and lantern; mascot `docs/assets/eureka-mascot-clean.png`; no pixel sheet | eureka-r2a: hood up (round-1 verdict), orange-piped hood, black hair with one orange streak, blue-grey eyes, chest rig, probe | the Eureka mind itself (instance `eureka`) |
|
||||
| Void | small figure in a pointed indigo-violet hood, pure-black face with two tall white oval eyes, thick frayed orange scarf, dark gloves; spiral portal door, glowing violet document | void-r3a: pointed hood, black face, white oval eyes, frayed orange scarf, gloves | `gamecult-site/docs/gamecult_void_dossier.md:1-8`: a dossier "Voice: Void, speaking from inside the work" about GameCult, Eve, Bifrost; no other domain for Void found |
|
||||
|
||||
- Domain routing facts: the `question` document carries `campaign` and no presenter field (section 2.2); no campaign-to-Persona mapping document was found in the mind. Campaign groups seen: StreamPixels (`web-customize`, `rps`, `motion-pipeline`, `joystick` shared with Heimdall); Aetheria and Ghostlight (`aetheria-release`, `aetheria-ew`, `aetheria-fauna`, `aetheria-gravity`, `asura`, `brush-tree`, `ghostlight-verse`); CultLib (`cultlib-gaps`, `variants`, `cultmath-tapes`, `cultmesh-ts-content`, `brokkr-msgpack`); Idunn/Bifrost/Heimdall-owned (`idunn-watchdog`, `idunn-reincarnation`, `idunn-deploy-provenance`, `concept-mill-votes`); Eureka's own (`eureka-substrate`, `eureka-body`, `persona-poses`, `site-masthead`); Thing (`thing`, `thing2`, `thing-family`, `thing-providers`, `thing-verse`). Only instance `eureka` exists (`whoami`); `weksa-mind` is an open follow-up; no instance or follow-up for the other six was found.
|
||||
- Pose facts: both desk artifacts ship nine moods for Libby and Nibu only (idle, neutral, thinking, happy, surprised, note, determined, triumph, concerned) as `.webp`; no desk pose set exists for Heimdall, Kiko, Aqua, Weksa, Eureka or Void.
|
||||
|
||||
### 2.6 Thing 2.0 status
|
||||
|
||||
- Campaigns: `thing2:campaign:self` ("Thing 2.0: more Things, fewer things", repos Eve and gamecult-ops, admitted 2026-10-10T17:39:50Z); target `thing2:target:r1` invariants: one-solver, closed-commands, compose-not-kind, core-owns-text, rasterizer-backend-private, live-state-core, geometry-parity, narrow-consumer-contract, born-thing-ids, consumer-port-carries-rename. Family campaigns `thing-family` (renderers: ThingUnity, ThingFlutter, ThingElectron, ThingTui, ThingPlugins, ThingConformance, CultLib, Ymir), `thing-providers`, `thing-verse` (Odin, Ghostlight, Heimdall, Muninn, Mimir, Gjallar, Hermodr, Bifrost); `thing:campaign:self` (rename of Eve).
|
||||
- Rulings (all Operator, 2026-10-10): `thing:ruling:thing2-one-solver-taffy` (direction: closed primitive set, one Taffy layout solver, one closed render-command list, thin backends, live typed CultMesh state binding in core; evidence file `F:/Projects/thing2-foundation-prior-art.md`); `thing:ruling:thing2-thing-owns-text` (core owns text shaping, editing/IME, focus, accessibility tree); `thing2:ruling:code-home` (Thing 2.0 lives in the Eve repo renamed Thing); `thing2:ruling:port-cutover` (consumers cut over one at a time); `thing:ruling:wire-rename-freeze-fold` (wire rename frozen, folded into Thing 2.0).
|
||||
- Cut specs: the rename cuts (`kernel-schemas-contracts`, `kernel-lowering-scripts`, `voidbot-wire`, `thingtui-wire`, `thingelectron-wire`, `thingflutter-wire`, `thingplugins-wire`, `thingconformance-wire`, `cultlib-wire`, `aquasynth-wire`, `repixelizer-wire`, `kernel-prose`) are Resolved `Withdrawn` ("Wire rename frozen and folded into Thing 2.0"); `thing:cut_spec:cut-site-prose.r2` InForce ("Thing 2.0 described as in construction"); `thing:cut_spec:cut-deck-site-page.r1` InForce. Follow-ups `thing2:follow_up:tour-evecanvas-card`, `thing2:follow_up:site-thing1-surface`.
|
||||
- No Thing 2.0 implementation cut spec, cut report or released backend was found in the query results (semantic query on the Thing 2.0 terms, top 20 across cut_spec/target/follow_up). Operator, 2026-10-20: "Thing 2.0 is still under construction" (`fork-desk-web-ui-on-huginn`).
|
||||
- Doctrine in `F:\Projects\CLAUDE.md` (GameCult defaults): operator interfaces are Eve/CultUI composition graphs published through CultMesh and lowered by browser/native/TUI renderers; "Do not invent parallel HTTP/status-card summaries unless they are explicitly marked as temporary probes feeding a proper CultMesh surface." The Thing 2.0 surfaces a desk would overlap: composition graph publication, live typed state binding, command-result validation (target invariants `live-state-core`, `compose-not-kind`), and the browser lowering (Thing 1 web lowering existed in the Eve repo per the withdrawn `kernel-lowering-scripts` spec; `thing:cut_spec:cut-deck-site-page.r1` puts a Thing deck on gamecult.org).
|
||||
|
||||
## 3. Prior art: a human rules on decisions an agent raised
|
||||
|
||||
All web pages accessed 2026-10-20.
|
||||
|
||||
### 3.1 Decision records
|
||||
|
||||
- adr-tools (https://github.com/npryce/adr-tools): numbered Markdown ADRs in `doc/adr` by default; `adr new -s 9 <title>` creates an ADR that supersedes ADR 9 and updates ADR 9's status; statuses and template fields are not listed on that page.
|
||||
- Log4brains (https://github.com/thomvaill/log4brains): ADRs as Markdown in the git repo, published as a static site (`log4brains build`, local `log4brains preview` with hot reload); statuses given as proposed, accepted, deprecated, superseded; an ADR is otherwise immutable, only its status changes; metadata guessed from raw text and git logs (CI needs full history); default template MADR; planned features include a decision backlog and ADR editing from the UI.
|
||||
- MADR (https://adr.github.io/madr/): sections Context and Problem Statement, Decision Drivers, Considered Options, Decision Outcome (chosen option and justification), Consequences, Confirmation (how compliance is verified), Pros and Cons of the Options, More Information; optional front matter `status`, `date`, `decision-makers`, `consulted`, `informed`; statuses proposed, rejected, accepted, deprecated, "superseded by" another ADR.
|
||||
- In-house equivalent: mind `question` (context, options, recommended, depends, raised_in) -> `ruling` (authority, quote, precedents) -> derived `Resolution` (`Answered`, `Superseded`, `Withdrawn`); records are typed documents with receipts, not files (Huginn `README.md` Authority section).
|
||||
|
||||
### 3.2 Review and approval queues
|
||||
|
||||
- GitHub pull request reviews (https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/about-pull-request-reviews): three review states (Comment, Approve, Request changes); administrators can require approvals before merge via protected branches; CODEOWNERS auto-requests review from owners of changed code. The fetched page does not cover stale-review dismissal or the review-to-commit tie.
|
||||
- Gerrit (https://gerrit-review.googlesource.com/Documentation/config-labels.html): label votes (Code-Review -2..+2, Verified -1..+1); -2 blocks submit, +2 enables it; submit requirements define submittability; votes are tied to a patch set, and on a new patch set a vote is copied forward only if it matches the label's `copyCondition` (for example `changekind:NO_CODE_CHANGE`, `changekind:TRIVIAL_REBASE`); non-copied votes become "outdated", the uploader is notified and the voter is added to the attention set.
|
||||
- Linear Triage (https://linear.app/docs/triage): an inbox for issues from integrations or outside the team; actions Accept (to default status, optional comment), Decline (Canceled, optional explanation), Mark as duplicate (merge into an existing issue), Snooze (hidden until a chosen time or new activity); triage responsibility can rotate by on-call schedule (Business and Enterprise plans); the page does not describe automatic decline or snooze.
|
||||
|
||||
### 3.3 Agent harnesses with a human approval step
|
||||
|
||||
- LangGraph `interrupt()` (https://docs.langchain.com/oss/python/langgraph/interrupts): saves graph state through a checkpointer, returns a JSON-serializable payload to the caller (`__interrupt__` or `stream.interrupts`); resume with `Command(resume=...)` on the same `thread_id`; the node restarts from its beginning on resume, so code before `interrupt()` must be idempotent; interrupts must be called in the same order each time; patterns: approve or reject, review and edit, tool interrupts (approve, edit arguments, cancel), input validation by re-entering the node, parallel interrupts keyed by interrupt id; optional response schema validates resume values (`langgraph>=1.2.12`). (An older URL, langchain-ai.github.io/langgraph/concepts/human_in_the_loop/, returned only a redirect.)
|
||||
- OpenHands confirmation mode (https://docs.openhands.dev/sdk/guides/security): policies `AlwaysConfirm`, `NeverConfirm`, `ConfirmRisky(threshold)`; pending actions put the conversation in `WAITING_FOR_CONFIRMATION`; approve by `conversation.run()`, reject by `conversation.reject_pending_actions("reason")` with the reason returned to the agent; an LLM security analyzer rates actions LOW/MEDIUM/HIGH/UNKNOWN; `conversation.execute_tool()` bypasses both analyzer and policy.
|
||||
- OpenAI Agents SDK human-in-the-loop (https://openai.github.io/openai-agents-python/human_in_the_loop/): `needs_approval` (bool or async callable per call); a paused run exposes `result.interruptions` (`ToolApprovalItem`: agent, tool, arguments); `result.to_state()` serializes (`to_json`/`to_string`); `state.approve(interruption)` or `state.reject(interruption, rejection_message=...)` per call, sticky with `always_approve`/`always_reject`; resume with `Runner.run(agent, state)`; docs state serialized state is not authenticated, so reviewer identity and authorization must be verified before resuming.
|
||||
- Claude Agent SDK (https://code.claude.com/docs/en/agent-sdk/user-input): `canUseTool` fires for tool approval and for `AskUserQuestion`; callback may stay pending indefinitely, or a `PreToolUse` hook `defer` decision lets the process exit and resume from the persisted session; responses: allow (optionally `updatedInput`), allow with `updatedPermissions` (approve and remember), deny with a message the agent sees; `AskUserQuestion` input is 1-4 questions with 2-4 options each (`question`, `header` <= 12 chars, `options[{label, description, preview?}]`, `multiSelect`), the answer is a map from question text to chosen label (arrays or comma-joined for multi-select), free text goes in the answer value, optional `response` for a general reply; options may carry an HTML preview (`previewFormat: "html"`); not available in subagents; `PermissionRequest` hook can notify Slack, email or push.
|
||||
- Claude Code permission modes (https://code.claude.com/docs/en/permission-modes): `default` (prompts for edits, shell, network), `acceptEdits`, `plan` (edits blocked until a plan is approved), `auto` (classifier reviews actions, ask rules still prompt), `dontAsk` (would-prompt calls are denied), `bypassPermissions`.
|
||||
- HumanLayer (https://github.com/humanlayer/humanlayer): the repo page states "the code here is pretty much all deprecated" and points to a rebuild at humanlayer.com; topics human-in-the-loop, claude-code; 11.7k stars. The approval API (`require_approval`, `human_as_tool`) was not shown on the fetched page; not established here.
|
||||
- Other Claude-side precedent in this environment: Claude Code `AskUserQuestion` (as used by Self in this session family, memory `forks-for-understanding.md`: "one AskUserQuestion per fork") is the question channel the desks replaced for open forks.
|
||||
|
||||
### 3.4 Known failure modes (sourced)
|
||||
|
||||
- Approval fatigue and rubber-stamping: Anthropic engineering post (https://www.anthropic.com/engineering/claude-code-auto-mode): "approval fatigue, where people stop paying close attention to what they're approving"; users approve 93% of permission prompts.
|
||||
- Automation bias and explanation limits: Green, "The Flaws of Policies Requiring Human Oversight of Government Algorithms" (Computer Law & Security Review 2022; https://arxiv.org/abs/2109.05067): surveys 41 policies; reports that most research finds people cannot reliably oversee algorithms, that people defer to automated tools and increase attention to the factors an algorithm emphasizes, and that explanations and transparency do not reliably improve oversight. EU AI Act Article 14(4)(b) (https://artificialintelligenceact.eu/article/14/): overseers must remain aware of the possible tendency to over-rely on system output (automation bias), notably where the system provides recommendations.
|
||||
- Questions without context: Claude Code and SDK question forms bound questions to 1-4 per call and 2-4 options with a short label (`header` <= 12 chars); in-house record: the operator asked to understand each decision ("My decisions are the only reason anything gets done", 2026-09-29, `forks-for-understanding.md`), and a handoff one-liner lost "options and decision context" (operator, 2026-10-03, same note: "I want options and decision context to survive next time.").
|
||||
- Answers losing provenance: the OpenAI SDK documents that serialized approval state is unauthenticated and caller must verify reviewer identity; Huginn's own record has the same shape (no peer authentication, writer-declared provenance, `operator-authority-needs-operator-credential`); the artifact desks write `answers` with no identity beyond the artifact viewer and `updatedAt`, and Self re-types them into a ruling; two in-house wording losses: option text clauses read as rulings (`option-text-is-not-her-words.md`, 2026-10-17), a paraphrase replacing her words (`relay-operator-words-verbatim.md`, 2026-09-30 and 2026-10-07); a remark admitted as a ruling (`observation-is-not-a-ruling.md`, 2026-10-13); a verbatim relay that Self did not hear directly (`fork-desk-nibu-format` ruling text).
|
||||
- Stale questions: Gerrit marks votes outdated when a new patch set is not copy-eligible and adds the voter to the attention set; Linear Triage offers Snooze until time or new activity and Decline with a comment; LangGraph/OpenAI/Claude SDK pause states persist until resumed (the Claude SDK callback "can stay pending indefinitely"). In-house: a question already retired by a ruling was posted to the desk (2026-10-17, `minor-power-geonames`, memory `forks-go-on-the-desk.md`); an answer on one desk was missed because only the other was read (2026-10-17, same note); "So much work gets left hanging and never comes up until I bring it up" (operator, 2026-10-10, `work-left-hanging.md`). Huginn has no question expiry or review date; `eureka-substrate:follow_up:mind-standing-decay` (admitted 2026-10-01) records that Mind rulings never age and names review dates as future work.
|
||||
- Cross-desk fragmentation: two desks with separate stores and separate `answers` collections is the state the ruling `fork-desk-web-ui-on-huginn` names ("rather than per-area artifacts").
|
||||
|
||||
## 4. GameCult brand constraints a desk would need
|
||||
|
||||
Sources: `F:\Projects\gamecult-site\docs\brand-design-language.md` (last commit `9bd39bb`, 2026-10-02; the note says the code wins over it) and `F:\Projects\gamecult-site\site\quartz.config.ts` lines 22-62 (`configuration.theme`, same commit).
|
||||
|
||||
- Typefaces (quartz.config.ts:25-39): header and title Montserrat (header weights 100 200 300 400 600; title weights 100 200 300, "thin only", no bold title), body Ubuntu (300 400 500 700 plus italic; running text at 300, emphasis step 500), code IBM Plex Mono. IBM Plex Mono is also a display face: uppercase, letter-spaced 0.06em-0.18em for eyebrows, labels, table headers, metadata (brand note "Typography").
|
||||
- Palette (quartz.config.ts:41-62; note "Palette"; Quartz `light` is the background and `dark` is the text): ground `#07111a`; panels and borders `#16212c`; muted `#63758a`; body `#b7c7d9`; headings `#eef5ff`; accent `#ff8a2a`; links and info `#59b7ff`; highlight `rgba(89,183,255,.14)`; text highlight `#ff8a2a55`.
|
||||
- Ground wash: `#07111a` is the midpoint; the body layers three radials (orange at 78% 14%, violet `#6d60ff` at 18% 10%, blue at 52% 0%) over `linear-gradient(180deg, #03070d 0%, #07111a 44%, #09141f 100%)` with intensity `--gamecult-wash` (1 on `/`, 0.5 elsewhere); a flat `#07111a` "loses the thing that makes it recognisable".
|
||||
- Single dark theme by decision: `lightMode` and `darkMode` identical; `color-scheme: dark` forced; no light mode; paint every colour explicitly, skip `prefers-color-scheme`, and set an explicit background.
|
||||
- Surfaces: no cards; grouping by whitespace, type hierarchy and one hairline `--gamecult-rule` as `border-top: 1px solid`, named by a mono uppercase tracked label (`.gamecult-kicker`); an aside is a left rule with no fill; list rows separate by the same top rule; hover turns a title `--secondary`.
|
||||
- Layout: one centred column, `--gamecult-column` 72rem, applied once as `.page` max-width; nothing placed beside it on site pages.
|
||||
- Rules for use outside the site (note "Applying this outside the site"): Montserrat 100-200 titles carried large, Ubuntu 300 prose, IBM Plex Mono uppercase tracked for small structural labels, ground `#07111a` plus the radial wash on large surfaces, rules `rgba(148,163,184,.22)`, body `#b7c7d9`, headings `#eef5ff`, one accent `#ff8a2a`, `#59b7ff` for links and informational state.
|
||||
- No semantic colour set: no defined success, warning or error colour; anything needing status colour is inventing it, and should stay distinct from `#ff8a2a`. The existing desk artifact adds `--ok: #6fd3a0` (index.html of both artifacts, `:root`), `--tint` per persona (`#c3a4ff` Libby, `#b79cff` Nibu) and panels `#111c27`, none of which are brand config tokens.
|
||||
- Ritual Paper (Georgia serif, cobalt and amber) is a scoped variant for three essays; the note says not to use it for ordinary pages, dashboards or documents.
|
||||
- The desk artifacts' own header comment says "Single dark GameCult look by brand decision"; their mood-pose images are `.webp` assets hosted inside the artifact (`stable-hosting` is a persona-poses target invariant for the library, so the artifact-hosted copies are not its catalogue).
|
||||
Loading…
Reference in a new issue