test/docs(floating): reconcile INTERACTION.md + smokes to resting-purity reality (S6)#160
Conversation
…el (S6) Reconcile the LOCKED interaction contract + related docs to the shipped floating-redesign reality (S1–S5 + S4b merged). Drop the always-visible "Ask pill" model; document: - resting state = just the cat on a transparent, ~80% click-through window; - the two body verbs (tap/hold = pet, sacred + unchanged; drag = move window); - the two summon paths (⌘⇧Space, or hover-dwell → #ask-handle menu → #menu-ask); - each tethered #roro-stage reaction: input bubble (#floating-ask/#ask-input), WorkingChip (#working-chip/#working-stop), AlertCard (#floating-error, classified errors), SpeechBubble (#roro-speech + the truthful "used what I remember about your setup" receipt), and the Ask·Memory·Project menu + tethered Memory/Project popovers; - the click-through mechanics (setIgnoreMouseEvents + the marker hit-test). Preserve the Gesture Design Laws (disambiguate by surface+button+state, never timing; always pettable; real interactions reset the sleep timer; gaze/hover never wakes the cat). Every id/claim cross-checked against the renderer/window code. Also sweep stale "pill" references to the summon paths in PRODUCT_PLAN, VERIFICATION, floating-redesign, and the paw-on-the-pixel plan/handoff. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rity reality (S6)
Packaged smokes — the innerText.includes('Roro') "not blank" proxy broke when
the pill was deleted (it passed off static index.html even if the renderer never
executed). Replace it in all four non-CI packaged smokes with the renderer-
executed signal the CI-gating memory smoke already uses: capture
stageMounted = !!document.getElementById('roro-stage') and assert THAT. Gate the
dom-ready poll on stageMounted too, so a snapshot can't race a blank frame
(epipe gated on static #topbar/#prompt-form + preload bridge — all present
before bootstrap runs). Files: epipe, model-setup, first-task, onboarding.
onboarding also had 3 PRE-EXISTING failures (reproduced on origin/main): it ran
in the default floating window, where S4b moves Settings into the hidden Project
popover, so #project-settings-toggle is present-but-hidden and its visibility
assertions failed. Add RORO_FLOATING_WINDOW=0 to exercise the framed onboarding
UI, matching the sibling packaged smokes (model-setup, first-task). The floating
pet's own surfaces stay covered by the on-screen smoke-floating-* suite. Not a
product bug — the moat surface is reachable via the hover menu.
floating-menu (c)/(d) — they clicked HIDDEN #menu-project/#menu-ask (the menu
steps aside when a popover opens; closeProject never re-shows the handle),
passing without proving the visible hit path. Restructure: dismiss the open
popover, re-hover the cat to RE-REVEAL the menu, assert the next item is visible
AND hit-tested (__roroClickThrough.decideAt over its rect → true) AND that the
re-reveal doesn't wake the cat, THEN click it.
All eight touched smokes run live + PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 35d23e6253
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // the hover-revealed Project popover (S4b), so those elements are present-but-hidden at rest. The floating | ||
| // pet's own surfaces are covered by the dedicated on-screen smokes (smoke-floating-*). Matches the | ||
| // sibling packaged UI smokes (model-setup, first-task). | ||
| env.RORO_FLOATING_WINDOW = '0'; |
There was a problem hiding this comment.
Keep onboarding smoke on the default window path
When this smoke sets RORO_FLOATING_WINDOW=0, it opts out of the packaged mode a real first-run user gets; src/main/window.ts makes the unset/default value the floating pet, while this script is still the documented verify:packaged-onboarding gate for the no-env first-run banner/config flow. A regression that only breaks the default floating packaged onboarding path would now pass here because the test exercises the legacy framed #controls layout instead; consider running both modes or adapting these assertions to the default floating popover path.
Useful? React with 👍 / 👎.
Two doc-accuracy findings: 1. INTERACTION.md said 'Clicking a menu item IS a real interaction' — but only Ask summons+pokes (wakes the cat); Memory/Project are utility clicks that intentionally do NOT poke/pet/wake (the tests assert no poke). Clarified. 2. PRODUCT_PLAN.md listed 'right-click or M: mute/unmute' as current law, but v0 default hides/absents mute (the onboarding smoke asserts Mute hidden; README narrows it to a voice dev flag). Gated the line as voice-dev-flag-only. Docs-only; tsc/vitest/eslint unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nt app (codex S6 round 2) Two more doc-accuracy findings — fitting for a truthfulness feature, the docs were themselves over-claiming: 1. INTERACTION.md said the receipt shows when a fact 'demonstrably shaped the turn'. The gate actually attests RECALL (a same-run status with factCount>0 || episodeCount>0, incl episode-only) — not proof a fact shaped the answer. Reworded to what the code verifies + an explicit 'never claims more than the pipeline can verify' note. 2. PRODUCT_PLAN.md still implied a voice-dev-flag-gated mute. window.ts:44 confirms there is NO RORO_*_VOICE reader in the app (voice extracted to packages/voice), so there is no mute UI/key path at all. Reframed the bullet accordingly. Docs-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…codex S6 round 3)
Round-2 fixed one instance; codex found the same overclaim repeated in
INTERACTION.md (the truthfulness invariant bullet) + floating-redesign.md (founder
decision 5 + the S5 slice bullet). All now say the receipt attests same-run RECALL
(a status with factCount||episodeCount>0) attached to run.completed.finalText —
never that a fact provably shaped the answer. The only remaining 'shaped' is the
explicit negation ('NOT that a specific fact provably shaped the answer').
Docs-only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…erclaims (codex S6 round 4) Comment/doc-only accuracy sweep (the 'central change ripples widely' pattern, one more layer): - The 'recalled fact demonstrably shaped the turn' overclaim also lived in SOURCE comments (speechBubble.ts, bootstrap.ts, index.css) — synced to 'memory was actually recalled that turn (same-run status + run.completed.finalText)'. - VERIFICATION.md + smoke-packaged-first-task called the framed dev window (which force RORO_FLOATING_WINDOW=0) the 'default typed surface' — but the default is FLOATING (window.ts). Reworded to 'framed dev typed surface'. - VERIFICATION.md said the natural memory smoke 'does not launch floating-window mode' — it DOES (default); reworded to 'launches the default floating window, inspects receipt STATE via the hook, does not prove the visible render'. - README mute line: no voice/mute path in the current app (voice extracted to packages/voice) — reframed like PRODUCT_PLAN. Comment/doc-only; tsc/vitest/eslint unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fs (codex S6 round 5) The central-UI change kept rippling into more docs + comments — codex found the same stale refs across RUN.md, HANDOFF.md, PUBLIC.md, and bootstrap/runLifecycle comments: - 190x200 → 360x420 click-through (RUN, HANDOFF; kept the ACCURATE historical 'old 190x200 window' / '190x200 cell' refs in avatar.ts/floatingLayout.ts/ tether.test.ts untouched). - 'compact Ask pill' / 'Stop pill on the cat body' → summoned input + tethered WorkingChip/Stop off-body (RUN, bootstrap:86, runLifecycle, the floatingAsk test name). - 'the only turn surface = typed prompt' → typed input = dev prompt + floating Ask (bootstrap:10). - 'default typed surface' → the framed dev surface (RORO_FLOATING_WINDOW=0) (PUBLIC.md). - mute-as-interaction-law → mute lives in packages/voice, absent in the current app (RUN.md). Comment/doc/test-name only; tsc/vitest/eslint unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…x S6 round 6) - floating-redesign.md (the build spec) described the PLAN in spots the impl diverged from: WorkingChip verb 'activityForEvent' → the shipped reuse of summarizeEvent; 'floatingAsk lifts into a DOM-free StageViews controller' → shipped simpler (mountFloatingAsk keeps its DOM shell + mounts stage islands, no controller needed); 'delete #floating-ask/#floating-error' → they KEEP their ids but migrate onto the stage as tethered islands (only #ask-pill deleted; #floating-stop→#working-stop). - RUN.md §5 Voice: the RORO_*_VOICE flags are not runnable from the root app (voice extracted to packages/voice; no app-side reader per window.ts) — added an 'Extracted' note so the pipeline docs read as packages/voice, not root-app flags. Docs-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gue fixtures, docs absorb the first dogfooding session (#162) * fix(eval): repair the eval runners' post-W7 artifact paths + pin the path family in CI Since the W7 core-split (#149) moved src/brain -> src/core/brain, both live runners still wrote/read their artifacts under the stale 'src/brain/eval' (runEval.ts latest/baseline writes; runProposalEval.ts baseline read + proposalLatest/proposalBaseline writes) and crashed ENOENT at the end of a full run. The directory now lives once in eval/paths.ts (EVAL_DIR + evalArtifactPath), both runners use it, and paths.test.ts pins that EVAL_DIR resolves to the directory the eval files actually live in (plus that the checked-in baseline.json exists there) — sabotage-verified: reverting EVAL_DIR to the stale path fails both tests. Also moves the two stale .gitignore scratch entries (latest.json / proposalLatest.json) to the real output location so runner scratch stays untracked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(eval): make deflect-on-vague measurable — 5 vague-initiative DECIDE fixtures (fixture-first) First founder dogfooding session (2026-07-05): 'create something interesting' made the 3B answer 'Let's brainstorm a fun project idea together' — a chat deflection that fails ROADMAP §6's lands-or-clarifies bar (do the task or ask a PERTINENT question). This adds the failure class to the eval WITHOUT touching decide (measure first, fix later): - DecideCase grows alsoAccept (a golden SET for lands-or-clarifies cases) + a 'vague-initiative' tag (the DECIDE-side analogue of BehavioralTaxonomy). - 5 fixtures (vague-interesting/-cool/-fun/-buildme/-impress) accept exactly {run_agent, clarify}; answer FAILS. Expected to fail against the current model — that is the point. - scoreDecision gains the optional alsoAccept set (red-first unit tests: a deflection still scores wrong_command). - fixtures.test.ts pins the class deterministically in CI: acceptance set is exactly {run_agent, clarify}, and every vague case must NOT be caught by the deterministic clarify gate (same loud-re-label discipline as the marker-less pin), so the fixtures keep measuring the MODEL. Live tier stays opt-in/report-only; the deterministic suites stay green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(eval): refresh the shape-stale baseline via --write-baseline (real Ollama, new fixtures included) OLLAMA_AVAILABLE=1 npm run eval:brain -- --write-baseline against local qwen2.5:3b — the sanctioned baseline workflow; baseline.json is never hand-edited. The old snapshot predated the W3 5→50 fixture expansion and the new runner output shape. Old → new headline numbers: - decide: 22/22 (100%) → 26/27 (96.3%; one wrong_command: run-writetest → answer — DECIDE streams at temperature 0.3, a run is a snapshot) - extract: 10/10 (100%) → 10/10 (100%), unchanged - behavioral value-quality: 2/5 (40%, the original 5-case set) → 26/35 (74.3%, the full expanded set — reproduces the #145 report-only number) - NEW keys now captured: behavioralNull 7/15 (46.7%; all 8 misses are hard-negative false_facts) + behavioralByTaxonomy (hard-negative 20% is the weak family; multi-fact/supersede/marker-less 100%) MEASURED TRUTH on the new vague-initiative cases: contrary to expectation, the current 3B lands-or-clarifies on all 5 (and 30/30 in a 3×-repeat probe with and without a memory section) — the fixtures therefore PIN the class against regression; the live 2026-07-05 deflection has not reproduced from paraphrased transcripts, so the fixture-block comment now records that and points the follow-up at promoting a RORO_TRACE capture of a real deflecting turn. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: absorb the dogfooding + floating/moat signal — LESSONS, HANDOFF, ROADMAP, VERIFICATION - LESSONS.md: new Dogfooding entry (2026-07-05) naming the four failure classes — deflect-on-vague / feedback-fade / working-illegibility / env-overrides-config — each with its file:line locus and fix status (2–4: the sibling dogfood-blocker slice; deflect-on-vague: fixture-first, with the measured 2026-07-06 twist that the paraphrased fixtures currently PASS, so the real repro needs a RORO_TRACE capture). - HANDOFF.md: §3 work log extended past W8 — the floating redesign (#153–#160, resting purity + truthful receipt), earn-the-moat (#161, codex finalText stitch + verify:memory-steered-real 5/5 vs 0/5), the first dogfooding session, and this signal-reconcile slice; §4 gains the refreshed-baseline numbers (the old bullets stay as the historical snapshot); §8 gains the corrected forward order (dogfood fixes → signing → legible-moment → executor-facts pilot → self-rehearsal → demo → stranger session). - docs/ROADMAP.md: Arc A §6 step 5 (founder dogfooding) marked STARTED 2026-07-05 with the four findings + the fixture-covered status of deflect-on-vague. - docs/VERIFICATION.md: the stale pre-W7 layout references in the cohort trace-review section (lines ~10–27) now point at src/core/… (the vitest command there was unrunnable). Stale paths in LATER sections of the file remain — out of this slice's scope, flagged in the handoff report. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(review): address the review panel — doc truthfulness + pin hardening (S-A round 1) Panel findings (all CONFIRMED, 0 false positives across the 5-hat review): - BLOCKER: four docs-of-record sites claimed feedback-fade was 'being fixed in the sibling dogfood-blocker slice' — it is NOT (it belongs to the upcoming legible-moment slice). LESSONS, HANDOFF x2, ROADMAP now say so honestly, and working-illegibility is split truthfully (sleep-mid-run half → dogfood-blockers; the distinct working pose → legible-moment). - LESSONS locus corrected: summoning the ask also pokes the presence clock, not only petting. - alsoAccept untag loophole closed: any DECIDE case widening its acceptance set must declare a failure-class tag (pinned in fixtures.test.ts) — an untagged alsoAccept was silent softening. - evalArtifactPath now __dirname-based (correct from ANY cwd, travels with the dir on a move); new source-grep pin: the runners must route through evalArtifactPath, no quoted hand-spelled eval dirs (the exact post-W7 breakage class), header-comment convention exempted. - Stale src/brain path sweep: cohortTraceReview.ts fixture pointer, COHORT_TRACE_TO_EVAL.md verify command, RUN.md:20, README.md x2, WS1 doc x2, ROADMAP live locus. tsc clean · 1104 passed / 12 skipped · eslint 0 errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD * docs: sweep stale PGlite/pgvector memory claims + the temp-0 eval claim (codex S-A round 1) Codex caught materially-false user-facing docs surviving the reconcile: README (6 sites) and RUN.md (4 sites) still described memory as an in-process PGlite+pgvector database at src/memory2 — deleted in W5 (#147); memory is encrypted files-as-truth + a rebuilt-on-launch in-memory vector index at src/core/memory2, embeddings via local nomic-embed-text. Also HANDOFF's eval header said 'temp 0' while decide actually streams at temperature 0.3 (brain/index.ts:190) — the same header the new baseline note's temp-0.3 explanation contradicted. And the crosslaunch proof pointer moved to src/core/orchestrator/. All claims now match the code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD * docs: complete the pre-core-split path sweep + fix dangerous embedder advice (codex S-A round 2) - RUN.md's embedder note was DANGEROUS post-W5: it described a fixed vector(N) DB column and told users to move/delete the memory dir when changing embedders — that dir now holds the durable encrypted memories (files-as-truth); vectors.jsonl is the zero-authority derived cache that re-embeds automatically. Rewrote to the true architecture. - README executor pointers (table + tree) → src/core/executor/. - VERIFICATION.md: ALL remaining pre-core-split paths fixed (memory2/executor/orchestrator test commands + module pointers); ROADMAP tracer pointer; PHASE2-TRUST-LOOP's runbook command fixed (adapter.test.ts was deleted in W5 — removed) and PROVEN to resolve (34 tests). - Exhaustive residual sweep across *.md + docs/: zero non-historical pre-split paths remain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD * docs: exists-checked path sweep — src/main→core/orchestrator (codex S-A round 3) Round-3 findings + a proactive exists-check sweep: ROADMAP's configStore/memoryContext pointers, the eval fixtures/score header comments, and 12 stale src/main/<file> references across the md corpus (all moved to src/core/orchestrator in W7) — now verified by an automated every-md-path-must-exist check returning zero stale refs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD * docs: last stragglers — PHASE2 adapter-successor pointer + eval-source comment paths (codex S-A round 4) PHASE2-TRUST-LOOP prose now names facade.test.ts as the successor to the W5-deleted adapter.test.ts; every src/brain|src/executor comment path inside src/core/brain/eval/* swept to core (grep-verified zero non-core refs remain). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD * docs: two path stragglers that escaped the exists-check shapes (codex S-A round 5) PHASE2's relative memory2/profileFacts pointer (no src/ prefix) and VERIFICATION's src/main/memoryHealth* wildcard — both shapes now covered in the sweep; ROADMAP's relative brain/index.ts ref fixed alongside. src/main/ipc*.test.ts verified VALID (ipc tests do live in src/main). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD * docs: precise privacy claim — the index is derived/plaintext, the FILES are encrypted (codex S-A round 6) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD * docs: embedder-switch remedy is delete-derived-index-only, not auto-re-embed (codex S-A round 7) vectorCache.ts:20 IDENTITY REFUSAL: a mismatched (embedModel, dim) header THROWS; the store does not silently re-embed. Remedy: delete the derived index/ subdir (zero-authority; next launch re-embeds from the durable encrypted files). My round-2 rewrite overstated the automation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD * docs: the PHASE2 gate command now runs facade.test.ts, matching its own prose (codex S-A round 8 — cap) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vsq543S6voPTUsGsEqZvnD --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
S6 — the FINAL slice of the floating-UI redesign. Reconciles the docs + smokes to the shipped reality (S1–S5 + S4b merged). No product code changes — docs + smoke scripts only.
INTERACTION.md (the LOCKED contract) — full rewrite
From the deleted-"Ask pill" model to pure-cat-at-rest: resting = just the cat on the transparent click-through window; tap/hold=pet (sacred), drag=move, tap never summons; summon via ⌘⇧Space or hover→#ask-handle menu→#menu-ask; each tethered #roro-stage reaction documented (input bubble, #working-chip, #floating-error AlertCard, #roro-speech + truthful receipt, Ask·Memory·Project menu + Memory/Project popovers). Gesture Design Laws preserved. Every id verified to exist in the code; stale "ask pill" refs across docs/ swept to 0.
Smokes reconciled against LIVE runs
body.innerText.includes('Roro')"not blank" proxy (the pill's text is gone) →stageMounted: !!#roro-stage(the renderer-executed signal), gating the dom-ready poll on it to avoid a capture race (per smoke-packaged-memory). All 4 PASS live.RORO_FLOATING_WINDOW=0(Settings moved to the floating popover in S4b; matches sibling packaged smokes) — a stale-smoke reconcile, not a product change.Gate
tsc clean · 1088 passed / 11 skipped (exact baseline) · eslint 0 errors · docs pill-refs 0.
🤖 Generated with Claude Code