Some checks failed
ci / check (push) Failing after 4s
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>
80 lines
2.9 KiB
Markdown
80 lines
2.9 KiB
Markdown
---
|
|
id: CB-WP-0035
|
|
kind: product
|
|
title: "A session that answers nothing"
|
|
status: done
|
|
state_hub_workstream_id: "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
|
|
|
|
```js
|
|
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
|
|
|
|
```task
|
|
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 `.catch` and 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.
|