Draws one boundary — between what the rules can see and everything else a player experiences — and says which repository each belongs to as the simulator grows. "Ritual" becomes ornamentation: half the category is material rather than ceremonial, and "decoration" is already spoken for in this repo (a control that cannot fail). The test is not "does it have a decision in it" — choosing who deals is a decision and is ornamental. The test is whether the state hash moves, which reuses the instrument that already binds a trial note to a position. The part that earns its place in clay-borg rather than in a renderer's stylesheet: calling something ornamentation is a CLAIM THAT IT DOES NOT MATTER, and this project's register is a list of times that claim was wrong — quantity in Tokens.csv, F18's four unread files, SOLVE offered where it could not act. So a declaration carries a falsifier, and "provisional" is a state it must say out loud. Downstream may read, may not decide — ADR-0007 D5 restated at the repository boundary. The port to clay-animate is deliberately NOT designed: no consumer exists, and an interface built against an imagined client is the same defect as a gate that cannot go red. Five invariants, four checkable today. I3 — same seed and decisions produce a byte-identical recording at any pace through any renderer — is the falsifier for the whole split. CB-WP-0036 re-declared from L to M accordingly: the animation architecture that made it L has moved to clay-animate. No code had been written and the tier-L review had not been run, which is the only reason it could be re-scoped rather than unwound. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2.9 KiB
| id | kind | title | status | state_hub_workstream_id |
|---|---|---|---|---|
| CB-WP-0035 | product | A session that answers nothing | done | c4c2fcbe-064c-4c19-b851-1d8d5940a24c |
Purpose
structural tier S (one endpoint, one rejection handler; no rule, no
dependency, no artifact contract moved)
chaos d8 = 4 → no override
declared tier S
Declaration 6 of chaos window 3.
The report, and it is one defect not two
"I think the server timing out is not noticed by the client. And 'Play Again' does not report that the session is no longer available."
Both come from the same three characters. The script's request was
fetch(...).then(...).then(...) // and no .catch
so when the process had exited the promise rejected, the chain never
ran, and not even the status line moved. A dead server and a click that
did nothing were indistinguishable — which is why play again read as a
dead button and the linger timeout was invisible.
A request that cannot be answered is information, and it was being thrown away.
Task: notice, and say so
id: CB-WP-0035-T01
status: done
priority: high
state_hub_task_id: "7be2de30-1077-439a-8e70-a20031e9ba97"
Controls:
- both paths — pressing a control, and noticing without pressing anything, which is the timeout case;
- both pages, because the timeout matters most during play;
- the heartbeat carries the token, or a refusal every five seconds would seal a live session;
- mutation-proven: remove the
.catchand the status goes empty, which is the reported symptom exactly.
Done 2026-08-07. .catch(gone), plus a 5-second heartbeat against a
new /alive — its own path so a beat costs a few bytes rather than a
whole re-render. It does not extend the linger: that deadline is
absolute, so a tab left open still cannot hold the process open.
The harness had the same hole as the code. jsrun's fetch stub had
no .catch, so the branch that notices a dead server would have been
unreachable in every test — the very defect the stub's own comment
records from CB-WP-0024, where a then-chain that never invoked its
callbacks let "the page still looks live" survive. Teaching the stub
__failing, .catch and a recorded setInterval was the fix; writing
the script defensively instead would have repeated the trap.
The first cut wired the heartbeat into the ending page only. An unused
variable caught it — luck, not a control — so every_page_can_tell_the_ session_has_gone now asserts it on both.
Not done here
- Five seconds is a guess. Nothing measures how long a player tolerates a dead-looking page, and this pass did not find out.
- A brief network stall seals the page, the same as a dead server. For a loopback-only server that is nearly always the truth, but it is a false positive waiting for the first non-loopback deployment.