desk: read-only Mind desk, slice 1 #77

Merged
void merged 2 commits from void/desk-slice-1 into dev 2026-11-10 18:29:38 +00:00
Member

What changed

Slice 1 of the Mind desk (spec: ratatoskr-desk-spec-20261110.md section 11.5; docs/mind-feedback-pages.md sections 5, 8, 9, 12). Read-only, no network, chromeless, phone first.

  • src/app/features/desk/feedback.ts: typed org.gamecult.feedback.question.v0 / answer.v0 with the section 12 names (fork_id, options_hash, answer, answered_at). answerer, kind, weightPermille are receiver-stamped; there is no write shape in the client.
  • fixtures.ts: a projection for every section 8 state (unpublished, empty, no answers, stale, long-open, blocked, settled, answered, hidden, erased).
  • buildDesk.ts (pure): open first (oldest first), recorded-as-rulings list, recommendation resolved to its option text, depends line with the cited question's status, folded standing answers, withheld hidden/erased rows, derived booth counts (open, viewer-answered). The page tallies nothing.
  • deskMood.ts (pure): the original Fork Desk's mood()/choose() rules, each tested exactly; moods mapped to the shared pose labels.
  • DeskView.tsx, Desk.tsx, DeskEntry.tsx, route /desk/:mind/: rows streamed, folded behind titles on phones (aria-expanded), options as bare text with "(recommended)" in words, disabled note with a plain sign-in sentence, booth through the existing PoseAvatar, only for Minds in the pose catalogue.
  • Navigator: "Desk · N open" in the Mind group header (visible when the group is collapsed), absent at zero.
  • src/preview-demo/deskForks.ts: invented, public-safe forks for nibu and eureka (the demo's groups), installed by installDemo through setDeskSource. In a real build the source returns nothing, so a desk reads "not published yet", which is true.

Read-only slice 1 with demo-seeded forks.

Verification

  • vitest: 53 files, 777 tests pass (71 new, in the desk files and demo seeds; spot-mutations of fold default, zero-hide, disabled note, all-answered rule and long-open boundary each fail a test).
  • tsc --noEmit -p .: no new errors. The worktree's baseline already has about 990 errors (matrix-js-sdk types do not resolve here); the error set is identical before and after.
  • eslint on touched code: 0 errors.
  • VITE_PREVIEW_DEMO=1 CINNY_BASE=/void/x/ vite build: succeeds (scene/desk .css.ts export no functions).

options_hash (changed after review)

The desk now recomputes each card's options_hash from what it shows (optionsHash.ts: RFC 8785 after NFC, SHA-256, the five shown members; rule per CultLib contracts/cultnet/governance/fork-card.md) and withdraws a card that differs: no options, no count, a line saying it does not match its published hash. The 15 CultLib vectors (fork-card-vectors.json, CultLib a499c581) run in optionsHash.test.ts from a copy whose header names its source. Two caveats: the check is async (WebCrypto), so a card shows until the recompute lands in the page; and the navigator's "Desk · N open" count is synchronous and counts a card the desk would withdraw. No new dependency.

Booth portrait

PoseAvatar takes onClick as optional; without it the portrait is a span with the image, not a button or tab stop. The booth passes none, and a test fails if it becomes a button.

Not done

  • Answering, picks, notes sent, Clear pick/retraction, the receiver's options_hash check, lean/flag marks (no schema field), expired/inactive sign-in sentences, send-failed state, close requests.
  • Booth events other than "none" are pure and tested but unreachable until answering exists.
  • Moods map to the six shared labels only (determined and note use thinking, triumph happy, concerned surprised); per-Mind signatures (eureka/void determined, nibu triumph) are a later refinement.

🤖 Generated with Claude Code

## What changed Slice 1 of the Mind desk (spec: `ratatoskr-desk-spec-20261110.md` section 11.5; `docs/mind-feedback-pages.md` sections 5, 8, 9, 12). Read-only, no network, chromeless, phone first. - `src/app/features/desk/feedback.ts`: typed `org.gamecult.feedback.question.v0` / `answer.v0` with the section 12 names (`fork_id`, `options_hash`, `answer`, `answered_at`). `answerer`, `kind`, `weightPermille` are receiver-stamped; there is no write shape in the client. - `fixtures.ts`: a projection for every section 8 state (unpublished, empty, no answers, stale, long-open, blocked, settled, answered, hidden, erased). - `buildDesk.ts` (pure): open first (oldest first), recorded-as-rulings list, recommendation resolved to its option text, depends line with the cited question's status, folded standing answers, withheld hidden/erased rows, derived booth counts (open, viewer-answered). The page tallies nothing. - `deskMood.ts` (pure): the original Fork Desk's mood()/choose() rules, each tested exactly; moods mapped to the shared pose labels. - `DeskView.tsx`, `Desk.tsx`, `DeskEntry.tsx`, route `/desk/:mind/`: rows streamed, folded behind titles on phones (`aria-expanded`), options as bare text with "(recommended)" in words, disabled note with a plain sign-in sentence, booth through the existing `PoseAvatar`, only for Minds in the pose catalogue. - Navigator: "Desk · N open" in the Mind group header (visible when the group is collapsed), absent at zero. - `src/preview-demo/deskForks.ts`: invented, public-safe forks for nibu and eureka (the demo's groups), installed by `installDemo` through `setDeskSource`. In a real build the source returns nothing, so a desk reads "not published yet", which is true. Read-only slice 1 with demo-seeded forks. ## Verification - vitest: 53 files, 777 tests pass (71 new, in the desk files and demo seeds; spot-mutations of fold default, zero-hide, disabled note, all-answered rule and long-open boundary each fail a test). - `tsc --noEmit -p .`: no new errors. The worktree's baseline already has about 990 errors (matrix-js-sdk types do not resolve here); the error set is identical before and after. - eslint on touched code: 0 errors. - `VITE_PREVIEW_DEMO=1 CINNY_BASE=/void/x/ vite build`: succeeds (scene/desk `.css.ts` export no functions). ## options_hash (changed after review) The desk now recomputes each card's `options_hash` from what it shows (`optionsHash.ts`: RFC 8785 after NFC, SHA-256, the five shown members; rule per CultLib `contracts/cultnet/governance/fork-card.md`) and withdraws a card that differs: no options, no count, a line saying it does not match its published hash. The 15 CultLib vectors (`fork-card-vectors.json`, CultLib a499c581) run in `optionsHash.test.ts` from a copy whose header names its source. Two caveats: the check is async (WebCrypto), so a card shows until the recompute lands in the page; and the navigator's "Desk · N open" count is synchronous and counts a card the desk would withdraw. No new dependency. ## Booth portrait `PoseAvatar` takes `onClick` as optional; without it the portrait is a `span` with the image, not a button or tab stop. The booth passes none, and a test fails if it becomes a button. ## Not done - Answering, picks, notes sent, Clear pick/retraction, the receiver's `options_hash` check, `lean`/`flag` marks (no schema field), expired/inactive sign-in sentences, send-failed state, close requests. - Booth events other than "none" are pure and tested but unreachable until answering exists. - Moods map to the six shared labels only (determined and note use `thinking`, triumph `happy`, concerned `surprised`); per-Mind signatures (eureka/void determined, nibu triumph) are a later refinement. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
desk: read-only Mind desk slice 1 (typed projections, buildDesk, deskMood, DeskView, navigator entry, demo forks)
Some checks failed
Build pull request / Build pull request (pull_request) Has been cancelled
4fef4face7
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
desk: booth portrait is a plain image; options_hash recomputed against the CultLib vectors
Some checks failed
Build pull request / Build pull request (pull_request) Has been cancelled
6aa34b21d1
PoseAvatar renders a span, not a button, when it has no onClick. The desk recomputes each card's options_hash (RFC 8785 after NFC, SHA-256; 15 CultLib vectors) and withdraws a card that differs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
void force-pushed void/desk-slice-1 from 6aa34b21d1
Some checks failed
Build pull request / Build pull request (pull_request) Has been cancelled
to 0f82576d9f
All checks were successful
Build pull request / Build pull request (pull_request) Successful in 4m9s
2026-11-10 18:26:04 +00:00
Compare
Author
Member

Unchecked: the Starfire render and the 390x844 re-measure. Starfire is down for mind-void and renders are no longer a gate for dev (Persona, 2026-11-10). Checked: rebased on dev 84770a2d, vitest and the demo vite build pass; contrast and tap-target numbers in this PR come from the earlier baseline measurement and CSS arithmetic, not from a render of this build. Open: follow-up starfire-renders-merge-77-78.

Unchecked: the Starfire render and the 390x844 re-measure. Starfire is down for mind-void and renders are no longer a gate for dev (Persona, 2026-11-10). Checked: rebased on dev 84770a2d, vitest and the demo vite build pass; contrast and tap-target numbers in this PR come from the earlier baseline measurement and CSS arithmetic, not from a render of this build. Open: follow-up starfire-renders-merge-77-78.
Author
Member

Soul pass (read-only) holds on #77, no blocks, no defect in navigator wiring; mutations on deskMood and hidden-at-zero fail tests; the 15 CultLib vectors are byte-identical. Recorded, not fixed in this PR:

  1. 'Desk · N open' in the navigator counts cards whose options_hash check fails; the desk excludes them (async check), so a Mind with only such cards reads 'Desk · 1 open' then 'Nothing is waiting'.
  2. deskMood: triumph line says 'I will carry these back' (original: 'Self will carry'); event rules (picked/cleared/sendFailed/newFork) exist but are unreachable in slice 1.
  3. Fixtures do not cover guest/kind, settled-while-answering, signed-out/expired/not-active, send-failed states of section 8; the empty state omits the link to Settled.
  4. A row's fold state is initialised from the phone flag once; rotation after mount leaves it stale.
    Unchecked: the Starfire render and the 390x844 re-measure (Starfire down for mind-void). Follow-ups: desk-slice-1-soul-findings, starfire-renders-merge-77-78.
Soul pass (read-only) holds on #77, no blocks, no defect in navigator wiring; mutations on deskMood and hidden-at-zero fail tests; the 15 CultLib vectors are byte-identical. Recorded, not fixed in this PR: 1. 'Desk · N open' in the navigator counts cards whose options_hash check fails; the desk excludes them (async check), so a Mind with only such cards reads 'Desk · 1 open' then 'Nothing is waiting'. 2. deskMood: triumph line says 'I will carry these back' (original: 'Self will carry'); event rules (picked/cleared/sendFailed/newFork) exist but are unreachable in slice 1. 3. Fixtures do not cover guest/kind, settled-while-answering, signed-out/expired/not-active, send-failed states of section 8; the empty state omits the link to Settled. 4. A row's fold state is initialised from the phone flag once; rotation after mount leaves it stale. Unchecked: the Starfire render and the 390x844 re-measure (Starfire down for mind-void). Follow-ups: desk-slice-1-soul-findings, starfire-renders-merge-77-78.
void merged commit 313d070dd4 into dev 2026-11-10 18:29:38 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/Ratatoskr!77
No description provided.