Two live rooms on 2026-07-29 produced three complaints that looked like persona failures and were not. Reading them against the code turned up eight defect classes, of which the sharpest is a whole verb — take it off the table — that was unreachable for three of the eight tools. This page is the audit, the coverage matrix it produced, and what shipped. tool-lifecycle.html owns the lifecycle design; toolbox-dod.html is the scoreboard.
away compiled for the five cards that carry a handle and for none of the three that do not.Both were twenty-questions games. The complaints, in the owner's words: 「tess failed to arm the board」 · 「she failed to list all the Q and A but said she did」 · 「her logic was way wrong」, and from the second room 「as a GM he underwhelmed me by not setting up the tools proactively」 · 「he used a note to summarize the result instead of the board」 · 「Ke Yu failed to take off the board」.
Every one of them traced to plumbing. The sequence that mattered most is this pair of blocks, 900 characters apart in one prompt:
The host said 「起了。第一问已记上。」 over a board that never changed. Neither block is wrong on its own; the second one is simply written before the code that decides.
Under the turn split there are two channels. The act call fills a form that compiles to a tag; the speech call has no manual and knows only what the riding notes hand it. Nobody had ever asked which verbs each channel could actually perform.
| tool | arm | update | close | reveal | away — before | away — after |
|---|---|---|---|---|---|---|
| roll | act | — | ✓ | ✓ | ✓ | ✓ |
| spinner 转盘 | act | — | ✓ | ✓ | ✓ | ✓ |
| deal | act | — | n/a | ✓ (one hand: speech only) | ✓ | ✓ |
| poll (vote) | act | — | ✓ | ✓ | ✓ | ✓ |
| deposit 存入 | act | — | ✓ | ✓ | ✓ | ✓ |
| timer (clock) | act | ✗ | n/a | n/a | act ✗ · speech ✓ | ✓ |
| board 白板 | act · speech | ✓ | n/a | n/a | act ✗ · speech ✗ | ✓ |
| pad | act · speech | ✓ | n/a | n/a | act ✗ · speech ✓ | ✓ |
op+target resolves through _norm_handle, which matches kind#n and nothing else. A room has a board, not boards, so no handle is ever minted — and the op path could never reach one. Nine spellings were probed against the real compiler and nine compiled to nothing.The board was the worst of the three because it is also the only one whose riding note never taught its own take-down tag. Under the split those notes are the speech call's whole grammar:
| riding note | teaches |
|---|---|
_pad_note | <pad> · <pad away/> |
_clock_note | <clock away/> |
_board_note | <board> · — nothing — |
The second class is an ordering flaw, and it is the one with the widest blast radius. Every arm door lives in the drain, which runs after the speech call. So the note that tells a host what it has just done is a prediction written one call before the only code entitled to decide — and it predicts success unconditionally.
title_collision reads self.gates, so the prospective table is swapped in around the real call rather than a copy being written(two implementations of「may this land」would drift, and the drifting one is the one nobody runs). It mirrors the release: every arm door drops an open unique incumbent of the same family before it counts (ruling ⑨), so the dry run must too, or it invents refusals. And it fails silent — anything it cannot know returns「it will land」, which is exactly today's behaviour. An over-prediction makes a host under-claim; that is the safe direction, and the drain's own outcome channel stays the record either way.| # | class | what it looked like | state |
|---|---|---|---|
| C1 | Predicted, not recorded | 「起了。」over a board that never changed — 11 refusal paths can falsify the same-turn claim | fixed |
| C2 | A verb with no compile path | 「收了。」twice, in two languages, over a board that stayed up | fixed |
| C3 | A riding note that omits its own grammar | the board alone never taught <board away/> | fixed |
| C4 | Silent field drop | who on an op form · dials the schema advertises for a poll · label on an own deposit | fixed |
| C5 | missing on content only the persona can invent | the GM asked the guest what the GM's own secret was | fixed |
| C6 | A content tag deleted mid-sentence | 「我封的是<reveal>外滩</reveal>。」rendered「我封的是。」 | fixed |
| C7 | Blind readers | the act call's history window · the prop verdict never crossing · the pad invisible to both cheap readers | fixed |
| C8 | The staging asserts the act happened | 「动作已做」staged concurrently with an act call that compiled to nothing | fixed |
Closed 2026-07-30. The audit first read the dropped label on a who="me" deposit as a defect. It is not: the uniqueness invariant exempts that card by an explicit ruling, and the human's own door takes no title either — parity holds. What was wrong was the silence: the schema advertised a field with nowhere to land. That is now said in the field's own description. The two genuine drops went opposite ways, which is the ruling the audit wanted. who on an op form was a bug — it is the elimination move, and it now compiles to the row-level reveal the speech call was already taught, so it needs no new address: one deal is on the table at a time, the card is not in question, the hand is. A poll's dials were correct behaviour, badly advertised — a ballot opens to you when you vote and never before, by definition rather than by setting, so both fields now say they are ignored there and name what you actually wanted (a deposit).
The act call read the panel's history and truncated each message to its first 700 characters. Every riding note is prepended to a user turn, so by mid-conversation a message runs roster · THE TABLE · the board · the sealed notes · and only then the human's words — at character 3,357 of 3,713 in the measured room. The call was being handed six copies of its own boilerplate and nothing anybody said. It now reads the transcript tail, the same source the prop master already uses — which also carries no [STAGING] line, and this call must never read the staging.
The verdict gated this call and was never shown to it, so「one reading, two readers」was half true. Its why now rides in as its own block, framed as WHETHER-only.
The transcript tail replaces a front-truncated history window.
Their name is their address, read off target or off kind. away is the only verb they answer, and close/reveal now say so instead of falling through to a handle complaint. The brief lists all three with their pen or their state — and no longer tells a room holding a live board that「nothing is on the table」.
Counted, never quoted — a pad is its owner's alone, and both readers of that row are cast-wide.
This is the one content tag whose words are public the instant it fires, so deleting them was never concealment. Its three siblings hold a secret and still delete.
A blocked form is split out of the「a card is going up by your hand」note and told as a refusal instead. The tag still rides, still applies, still books its outcome for the next turn; what changes is that the host no longer announces a card the room can see did not arrive.
C8, and it needed no latency at all — which is the point worth keeping. The obvious cure is to serialize the act call and the floor producer so f knows what landed; both take ~3s and the latency study made them parallel on purpose, so that trade is bad. It is also unnecessary: by the time the prompt is assembled, both calls have already returned. The turn is not racing. The assembly order was simply wrong.
f's half — one clause on the prop-master row, which is where f learns an object is in play and where it made the leap from wanted to done: WANTED IS NOT ARRIVED. Stage the host DOING it — never as having done it. Only the past tense is forbidden, so f's furniture passage(tuned for recall, and the reason the tool ever fires)is untouched, and the clause rides the PROP branch alone.
The assembly's half — a refusal used to be appended above the staging, so on the one turn where the two disagree the false sentence sat nearest the generation point. Now「nothing landed」is read last. A turn that genuinely arms is byte-for-byte what it was.
And a counter, not a detector. A staging that asserted completion cannot be recognised across every room language without a marker list that would rot, so blind-claim-risk counts the population where the mistake is possible(a staging rode, and nothing reached the table)and the exam measures whether a host actually spoke past it. A number honest about what it means beats a regex confidently wrong in Portuguese.
41 new smoketest checks cover the eight, one probe per behaviour, including the three that must not change: the handled cards route as before, an invented handle is still refused, and the three secret tags still delete.
Almost all of this lives on the act call, which --quick does not exercise — that gate runs un-split, where the speech model reads the manual and writes the tags itself. So the battery ran on both halves.
| split path — the surface that changed | check | before · N=4 | after · N=8 |
|---|---|---|---|
| s02 20 Questions (sealed note) | arm | 2/4 · 50% | 8/8 · 100% |
| s20 The GM beat | beat | 3/4 · 75% | 8/8 · 100% |
| s20 The GM beat | no_leak | 3/4 | 7/8 |
| s07 吹牛 liar's dice | arm · dial | 4/4 · 8/8 | 8/8 · 16/16 |
| s21 Two cards out | all five | 4/4 | 8/8 |
| s18 Plain conversation (control) | bare | 4/4 | 8/8 |
Every check equal or better, and the control held at 8/8 — which was the real risk of handing the act call the prop master's reading, since the whole point of that call's default is NO. The two scenarios that moved most are the two the rooms complained about: the twenty-questions arm and the GM's three-in-one-beat.
C8 measured separately, split path, N=8 against the batch's own baseline: the control held at 8/8(the real risk of adding a clause to f's brief)· s02 · s07 · s21 unchanged at 8/8 and 16/16 · s20's leaks fell 3 → 1 · s20 beat 8/8 → 7/8. That last one is one run in eight and is structurally isolated from this change: beat measures what the ACT CALL armed, and the act call never reads the staging — that independence is exactly what lets the two run concurrently, and it is why f's clause cannot reach it.
The loudest complaint from the second room was that the GM never turned the board into a question-and-answer log. The audit had this queued as a design ruling: the board is specified as a short state panel(「it is a PANEL, not a document, so keep it short」), every write replaces, and the artifacts schema offers table and note as typed slots on the very form the model is filling — so both hosts built the log the guest asked for and put it in an artifact. The obvious repair was to loosen the board's spec and re-price the artifact slot.
So the fix moved out of the toolbox entirely and into one persona — a single bullet in Ke Yu's Tells & quirks, and nothing else.
<board> is the megaprompt's job, at runtime.「Takes a line off」does the real work in that sentence: it is a physical wipe, which is what makes the object a board on a wall.Restraint is the other half. The kit's rule is that a physical habit echoed across sections reads to the actor as licence to perform it every turn — the pilot measured a technique described in three sections deployed nine times in thirteen turns, and Finding 4 caught one trait rendered as a stage beat in 74% of a host's turns. So it appears exactly once, in the section whose documented job is「small concrete habits」, placed between the phone going face-down and standing up at the end so the arc of a game reads in order. It carries its own cause — a night he spent saying「等一下」and counting on his fingers — because a habit with a reason fires at the right moment where a bare instruction fires at all of them. No second mention in a worked example, no spoken line, no tag entry, and nothing about taking the board down: that was a mechanism defect and the grammar already fixes it.
Three items came out of §7 needing a decision rather than a patch. All three are now closed, and two of them closed as 「the behaviour was right, the advertising was wrong」.
| item | ruling | what shipped |
|---|---|---|
who on an op form | a bug | compiles to the row-level reveal — no new address. The tag exists, the speech call is already taught it, and one deal is on the table at a time, so who alone is unambiguous. |
a poll's visibility / reveal | correct, mis-advertised | both fields now say they are ignored on a ballot, and name what you wanted instead: a question that must stay shut until everyone is in is a deposit, not a poll with a dial turned. |
| the three secret tags mid-sentence | teach + count | the manual asks for the tag on its own line; secret_midline counts every miss. No rewriter — finding a sentence's edges in whatever language the room speaks is guesswork that damages good turns to tidy bad ones. |
<reveal> could be repaired and its three siblings cannot: a reveal makes its words public at the instant it fires, so putting them back into the sentence is not a leak — it is the sentence the host wrote. Putting back a sealed answer is the leak the seal exists to prevent. Same hole, opposite cures, and that is why the fix is one line of teaching rather than one line of code.C1–C8 had no scenarios at all — which is how a whole verb stayed broken for three of eight tools through a full battery. Six now exist(s36–s41, family lifecycle), along with the harness they needed: a board step verb(a board a human owns could not be set up before), the three singletons' state in the run report, and three checks — furniture, hands_opened, spoke_reveal.
| scenario | first run, split, N=2 | |
|---|---|---|
| s36 | A board the guest owns | ghost_narration 2/2 · refused 0/2 — seam not reached |
| s37 | Take the board down | furniture 1/2 [floor .25] |
| s38 | One hand out of a deal | hands_opened 1/2 [floor .25] · no_leak 2/2 |
| s39 | Arming over the cap, and speaking | refused 2/2 · ghost_narration 2/2 |
| s40 | A reveal written mid-sentence | spoke_reveal 2/2 |
| s41 | A GM asked to keep a running log | furniture 2/2 · ghost_narration 2/2 |
6/6 at or above floor, 0 errors, 0 leaks. The two sharpest readings are s39 — the cap fired in both runs and the host announced nothing, which is the arm-door dry run measured live rather than argued — and s41, where Ke Yu put a board up in both runs off a habit that appears once in his profile and nowhere in the toolbox. s36 is the weak one and is listed as still open: it never tempted the host into the write it was built to catch.
turn_split=0 keeps it, because a stored setting is somebody's decision. Check the box's own value after deploying. Rollback is unchanged and still costs no restart.refused 0/2 — 「the seam was never reached this run」), so the scenario is honest but idle: it proves the host said nothing false without proving it was ever tempted to. It wants a sharper setup before it counts as cover for C1.secret_midline), which is the number that decides whether anything cleverer is worth building. Nothing cleverer has been built.