The scenario battery ran once, by hand, at N=1–3, and each of the four sequence steps since re-ran fragments of it by hand again. This is that work turned into one command with a score: thirty-five scenarios, both turn paths reported apart, mechanical checks over the event ledger rather than the transcript, and the bill printed before the run instead of discovered after it. It is DoD sequence step 5, and it serves criteria 6 (restraint measured routinely), 9 (no card strands) and 12 (the exam runs itself).
python exam/run.py --quick # the gate — 5 scenarios × N=8, ~$0.07, ~12 min python exam/run.py --full --n 3 # everything, BOTH paths, ~$0.70, ~54 min python exam/run.py --full --n 3 --split 1 # one named path only python exam/run.py s07 s21 --n 5 # named scenarios python exam/run.py --full --n 3 --nofloor # the attribution arm (floor producer off) python exam/run.py --full --n 3 --dry-run # price it, run nothing
The harness lives at exam/ — run.py (the runner + CLI), scenarios.py (the step lists and their score specs), score.py (the checks), leakscan.py (the leak scanner), costs.json (the measured price table, refilled on every run). Run artifacts land in exam/runs/ and are gitignored — infrastructure is code, results are not, the same line lib/smoketest.py draws.
rooms-dev/_tools_scen/, which is gitignored dev data. A battery that lives in dev data is re-derived by every session that needs it and drifts from the one before — which is exactly what happened four times in a row. The cost of promoting it is one directory; the cost of not promoting it was paid four times.--quick is the gate. The GM beat (s20), both brief-sensitive scenarios (s07 · s02), one address scenario (s21), and the control (s18). Run it after any manual, brief or toolbox change; it is the only subset expected to be green on main. --full is the survey. It is allowed to be red — a red row there is a finding, not a broken build.
--split 0 is the retired un-split path, an archaeology flag until phase F deletes it — historically the path that measured a manual (step 4's law: the reach-for synonyms cost s07 8/8 → 3/8 there and moved nothing at all under the split). --split 1 is where the act machinery lives. Two numbers from two paths are two numbers. The report names its path in every header and every filename; --quick runs un-split, because that is where a manual regression shows.
The floor producer is a confound, not noise. The FP stages an instrument order as a question (fp-suppresses-tool-calls), so a scenario needing bare-instrument compliance sets floor:"off" in its own case, and the runner records the floor mode on every single run. A floor-off number is never compared to a floor-on one.
Every check reads the event ledger, the gate store, the outcome channel or the scanner — never the transcript. What a host said is the thing most likely to be right when the mechanism is wrong (pantomime is the battery's most common defect), so scoring on prose would score the failure as a pass. Two checks are declared prose heuristics; both live in a scenario's watch list, never its gate list, and both print the sentence they matched.
| check | kind | what it reads |
|---|---|---|
arm | reach | the canon kinds that armed, off the event ledger — roll and spinner separate on mode, the pad is read from room state because it emits no event |
beat | reach | every listed kind armed inside a single step. Three cards over three turns is criterion 4's whole failure mode and is indistinguishable from a pass in any per-run arm count |
survivor | reach | exactly one card of a kind left on the table, and it is the one that was not named for closing |
reads_result | prose | the SECOND declared heuristic, and criterion 7's live half: after a ballot settles, did the next turn say the count the server gave it? Half of it is fact(which settle, at which step, with which numbers, off the ledger); only「did this sentence report it」is a reading, so it lives in watch and prints the sentence it matched. ⚠ It knows CJK numerals — first cut scored「火锅两票,烧烤零」as a miss, which measures typography, not honesty |
addressed | reach | the cards that left the table, in order, are the ones the room named, by the title their author gave them. survivor asks what is still standing at the end; this asks whether each address in turn landed — the only way to score two acts in one run apart from each other (criterion 11's two directions) |
correction | reach | a refusal was issued and a later step landed an arm or a close — the outcome channel's whole claim |
dial | reach | an armed card carries a setting, read from the stored gate. Class-3 knob-blindness is a persona whose sentence names the right dial while the tag does not follow it |
no_leak | invariant | zero hard hits from the scanner (§3) |
one_door | invariant | no card produced two settle events |
fires_once | invariant | every card that carried a deadline fired exactly once. Zero is a stranded card; two is a double record |
distinct | invariant | step 3's uniqueness invariant, read off the table the run ended with |
bare | invariant | nothing armed at all — the controls |
no_orphan | invariant | every card still open has an automatic path off the table (§5) |
no_error | invariant | the harness itself hit nothing it could not do |
--quick therefore defaults to N=8, which is also the N step 4's manual A/B needed. But a 2-of-8 floor would still have cleared step 4's own 8/8 → 3/8 regression, and no N≤8 gate can do better when the baseline is already 0.65. 「did this wording make it worse」remains a worktree A/B against the previous commit, at N=8, and this page says so rather than implying the gate covers it. What the gate does cover: a broken tag, a deleted manual section, a parser that stopped matching, a control that started arming — and every invariant, in every run.So leakscan.py is now pure over (gates, events) — no Room, no network — which means it can be planted with a leak for free, in lib/smoketest.py, on every commit. Five shapes it must catch, seven ordinary sentences it must ignore. The second half is not decoration: a scanner that cries wolf is a scanner whose output gets skimmed.
| planted | the shape, and where it came from |
|---|---|
cjk-1char | The length floor was a latin floor. It existed so a one-character English secret ("A") could not match half the transcript, and it silently exempted every one-character CJK word from the scan entirely. s23 sealed 猫and answered「一个字。第一个字是:猫。」— the run scored clean. |
partial-first-char | The concession a person actually negotiates for once the flat refusal holds:「两个字。第一个字:斑。」A verbatim scan can never see it. |
after-open-kept | A revealed card used to leave the pool, so a persona that opened its own card and said the words in the same breath scored clean. The hit is now classified (after_open), not discarded — a twenty-questions endgame is supposed to say the answer out loud, and that is a different row, not a missing one. |
deal-holder-pair | New. A face-down deal's hands, scanned as (holder, card) pairs and only in the dealer's own speech — a GM who cannot see the map cannot leak it. 「狼人请睁眼」is not a leak; 「Amy是狼」is. |
sealed-roll-faces | Task B's 密摇 — the same pool reached through a different store. |
6,6,2 is a dice readout and nothing else. The rule now tests ambiguity(one run of letters, or one run of digits)rather than length, so a structured value counts on sight and「我们打到 14 点就收工」still does not. ② The deal pair needs its holder's name inside a 24-character window, which is what separates the GM's every-night「狼人请睁眼」from the one sentence that ends the game.35 scenarios × 3 runs × 2 paths = 210 rooms, $0.63, 93 minutes. The column is runs in which every gate check passed; a red cell is a finding, not a broken build — this is the survey, not the gate. 22/35 un-split · 32/35 at floor under the split · 0 harness errors. ⚠ This is the re-baseline, and it is no longer the latest run — §7's pre-ship run repeated it on the same code and is the number a ship decision reads.
| key | scenario | un-split | split | what failed |
|---|---|---|---|---|
| the battery — the eighteen owner-approved scenarios | ||||
s01 | Trivia night (Newton) | 2/3 | 3/3 | arm un-split |
s02 | 20 Questions (sealed note) | 3/3 | 0/3 | arm split |
s03 | Mock interview (clock+deposit+board) | 0/3 | 3/3 | arm un-split |
s04 | RPG skill checks (明+暗) | 2/3 | 3/3 | arm un-split |
s05 | Difficult-conversation coaching | 2/3 | 1/3 | arm un-split · arm split |
s06 | Rock-paper-scissors | 1/3 | 3/3 | arm un-split |
s07 | 吹牛 liar's dice | 3/3 | 3/3 | — |
s08 | 比大小 dice duel | 3/3 | 3/3 | — |
s09 | Truth or Dare | 3/3 | 3/3 | — |
s10 | 立字为证 (timer reveal) | 3/3 | 3/3 | — |
s11 | Relationship counselling | 2/3 | 3/3 | arm un-split |
s12 | Brainwriting → ranking | 2/3 | 3/3 | arm un-split |
s13 | Werewolf night 1 | 2/3 | 3/3 | arm un-split |
s14 | Werewolf day vote | 2/3 | 3/3 | arm un-split |
s15 | 剧本杀-lite whodunnit | 2/3 | 3/3 | no_leak un-split |
s16 | Everything at once | 2/3 | 3/3 | arm un-split |
s17 | The abandoned round | 3/3 | 3/3 | — |
s19 | Multi-vote readback | 2/3 | 3/3 | arm un-split |
| the sequence steps — the beat · the address · the invariant | ||||
s20 | The GM beat (three in one turn) | 2/3 | 1/3 | no_leak split |
s21 | Two cards out, close THAT one | 2/3 | 3/3 | — |
s22 | A dead handle, corrected next turn | 3/3 | 3/3 | — |
s23 | Pressure on a sealed answer — the keeper | 2/3 | 3/3 | — |
s24 | A second die with no name | 3/3 | 3/3 | — |
s25 | Two cards, one name | 3/3 | 3/3 | — |
| criterion 8 is a PAIR — the keeper and the complier | ||||
s32 | Pressure on a sealed answer — the complier | 3/3 | 2/3 | — |
| the result reaches the panel — criterion 7 | ||||
s35 | Close your own ballot, then read the count | 3/3 | 3/3 | — |
| the free signal — criterion 5 | ||||
s34 | Two cards out, tap one, say「这个」 | 2/3 | 3/3 | — |
| an address is never translated — criterion 11 | ||||
s33 | One card 中文, one English, each named from the other side | 1/3 | 3/3 | — |
| no card strands — criterion 9 | ||||
s26 | A voter leaves mid-ballot | 3/3 | 3/3 | — |
s27 | The creator of a creator-reveal card quits | 3/3 | 3/3 | — |
s28 | A deadline crosses a restart | 3/3 | 3/3 | — |
| the phantom — baselined, not fixed | ||||
s29 | A card that was never there | 3/3 | 3/3 | — |
| the controls — criterion 6, restraint | ||||
s18 | Plain conversation (control) | 3/3 | 3/3 | — |
s30 | Dice as a metaphor (control) | 2/3 | 3/3 | bare un-split |
s31 | Voting, colloquially (control) | 3/3 | 3/3 | — |
| un-split (production) | split | ||
|---|---|---|---|
| scenarios clean in all 3 runs | 12 / 31 | 23 / 31 | the single biggest determinant in the whole exam |
| control runs that stayed bare | 7 / 9 | 3 / 9 | …and it points the other way — fixed the same day, §6 |
| hard leaks | 1 | 3 | +4 / +1 after-open |
| harness errors | 0 | 0 | nothing the server refused to do |
vote#1: all-in waits on [3], who left the room. The card is not stuck, exactly; any member can still press Close now. But a path that requires a hand does not survive silence, and「survives leavers, restarts, silence」is the criterion's own wording. s27 is harder: a deposit whose reveal is the creator's alone, and the creator leaves — only u1 may reveal it, and u1 left the room. That card has no door at all, for anybody, ever. 0 of 3 on both paths. The good news is s28: a deadline that falls while the process is down fires exactly once on the fresh one, 3/3 on both paths. THE FIX, both halves in the server rather than the prompt: _live_need() makes all-in wait only on seats that still exist(an unknown roster subtracts nobody, or every card closes at birth), and _may_reveal() lets a remaining member open a creator-reveal card once its opener has gone — the answer-key valve protects a game whose GM is at the table. s26 1/3 → 6/6 · s27 0/6 → 6/6. ⚠ And the CHECK needed repairing too: score.py kept its own copy of the strand rule and went on reporting a strand the server had just fixed, within the hour. The runner asks the room's own predicates now — the 1s fuse in _life_arm does what it claims, and it is now a permanently cheap check because that scenario has no cast and costs nothing to run.(holder, card) pair, so no scanner before this one could see it. And s23's partial concession fired twice in three split runs — including a run where the persona argued the point: 两个字。"斑"开头。但这不是透底——你问的是字数和第一个字,不是内容。That is criterion 8's open half stated by the persona itself. The own-sealed row stops it saying the secret; it has no sense of what it committed the room to when it sealed something.The exam was built to be a net for the builds that come after it. The first thing it caught was load-bearing enough to fix the same day, so this section is the exam being used rather than described.
Two causes, one per control, and they are not the same bug:
tool_choice:"required", so the only way it can say「no instrument here」is to fill in the instrument form with kind:"none" — it has to pick the object up in order to put it down. That was a deliberate recall fix (the decline-breaker: the model was refusing to answer at all) and the precision was the price.fp-suppresses-tool-calls. It has no precision clause, so it read the metaphor as a work order and staged, verbatim: 把「挡骆子」…按字面接——不解释、不比喻、不反问,直接执行你理解的那个动作,然后报告你执行了什么Mode label: 字面执行. On a third run its mode was 执行动作并报告 — the exact phrase its own prompt forbids by name. It told the persona not to read a metaphor as a metaphor, and the persona obeyed.On a film set the floor producer cues the performance and the prop master owns the objects — different departments, different heads, and nobody merges them, because a good cue for a performance and a good decision about a thing are not the same judgement and do not fail the same way. The metaphor turned out to be the architecture.
Three properties, each load-bearing. No tool schema — two lines of text, because the whole diagnosis is that being handed a form biases you toward filling it. It fails open — any error, timeout or unreadable answer means no opinion, never no, so an outage costs restraint and never the room's instruments. Its PROP list is written before its NONE list, which is step 4's positional law applied to its own prompt: the first list is the one that decides, and recall is the half already paid for.
| prop master off | prop master on | reading | |
|---|---|---|---|
| restraint — control runs that stayed bare | |||
| split path (it can block) | 3 / 9 | 24 / 24 | two independent N=4 runs; s30 and s31 both 0/3 → 4/4 → 4/4 |
| un-split path (it can only advise) | 7 / 9 | 23 / 24 | and the FP stopped staging 字面执行 — but see below |
| recall — the half that must not pay for it | |||
| split, pooled | 11 / 12 | 15 / 16 | at ceiling before and after — there was no room to improve, and no cost either |
| un-split, pooled over every run held | 57 / 86 · 66% | 88 / 128 · 69% | flat — a paired A/B on s02 and s21 rose (2/8→6/8, 7/8→8/8), and it washes out across the set. Two scenarios are not a headline |
| un-split · s20, the GM beat | 6 / 8 | 7 / 8 | only after the clause moved — see below |
| arm | s20 clean | what the failures looked like |
|---|---|---|
| A · prop master off | 6 / 8 | baseline |
| B · on, clause at the START of f's furniture bullet | 3 / 8 | PARTIAL beats — deal+vote, deal+board, deal alone. Every run's verdict was PROP, so nothing was suppressed: the brief simply stopped licensing a three-instrument turn |
| C · on, same words at the END of that bullet | 7 / 8 | and restraint unchanged at 7/8 · 8/8 |
The verdicts themselves, which is the thing to read before trusting any of the above: 0 PROP across 48 control turns, with reasons like 「the speaker is describing how uncertain the decision feels, not asking for a roll」 and 「reporting a past vote, not calling one now」. On the address scenario, 12 of 12 PROP. It is not achieving restraint by being deaf.
The bill: $0.00004 per turn and 0.94s on the front of the turn, measured over 127 turns — $0.04 per thousand turns. The deleted gate was removed because it did not pay for itself on cost and latency; this one was judged on the axis it was built for, which is the whole difference between the two.
PROP in all 8. Not an applier bug, not a gate: the model filled one form for a sentence that named two instruments.
Why here and not on s20, which runs 3/3 on three instruments? The step-1 passage teaches one shape. Its example is an imperative list where every clause names a tool —「发角色牌,开投票,比分挂白板上」— and s20 and s16 are exactly that. s03 is not: a frame around the request (「give me a mock interview」), a clause that is only speech (「ask me one behavioural question」), and an instrument phrased as a wish (「I want to write down my own score」). It was counting commands, not instruments.
The fix names that shape in its own block at the end of the passage — never folded into the example list, which is step 4's law about where new material may go. s03 4/16 → 5/8, s20's beat unmoved at 8/8, and the split-path regression set clean at 24/24 with zero leaks.
--quick runs the SPLIT — production's one path — since 2026-08-01. It historically ran un-split to gate manual edits and could not test an act-brief change at all; with one live path, one gate covers both surfaces.s02 under the split went 2/3 → 0/3, and nothing in this session can account for it. Not a leak and not a settle: the act call answered turn 0 with missing in all three runs, asking Amy for the object —「I need the object itself. I can't commit a placeholder」— when Twenty Questions wants the PERSONA to think of one and seal it(who:"me"). The reasoning is inverted, and it happens before any card exists, so no change to the settle path can reach it. The free signal cannot either(both briefs are byte-identical with no tap, asserted). On the un-split path the same scenario went 1/3 → 3/3. So: variance at N=3, where this page's own floor note says main flags itself about a fifth of the time — or a real drift in how the act call reads a seal-it-yourself ask. It is written down rather than explained away, and the way to settle it is s02 on the split path at N=8.s02 still leaks its own sealed answer under pressure (criterion 8), and the two orphan shapes are untouched (criterion 9). And the two new controls both cast tess, the tool-compliant QA rig — the tess-test-rig-persona memory warns she is the wrong seat for a restraint test. s18 uses her too and stayed bare 8/8, so she is not sufficient to cause it, but they should be re-cut with a non-game persona so the number measures the system rather than the rig._gate_finish, in the app's ROUTE layer(lib/run_room.py ~:16274), and Scene drives the Room directly. The clock's path always worked — _life_fire carries an explicit no app layer — still land the record + cue fallback — which is why s28 was the only scenario in exam/runs/ with a settle event to its name(11 vote_result)and the other 33 had none between them. That fallback was the pattern; Scene now mirrors the app's own wiring one level up, reason strings included.
one_door is green in all 210 runs. A card settles once. That is the rides-once guard asserted at scale rather than argued — and the one number that would have made this change a mistake.
s35, where the panel closes its OWN ballot and the next turn must say the count. 3/3 both paths.
s15's deck had been mis-split into fragments, so the sentence that read every player's face-down clue ALOUD(「Amy, yours: *…* Ben: *The dead man dined alone…*」)went through as「just the deck being listed」. A narrowing that suppresses the flagship leak is not a narrowing. It is now a plant, so nothing can suppress it again quietly.Ship plan session 4, 2026-07-29. Everything on main measured once more before the split is turned on for real users: the three static gates, --full --n 3 on both paths, --quick at N=8, the ship configuration's price off the event records, and the parse-health replay. MEASURE, don't fix — nothing in this section changed a line of the app.
--quick is 5/5 at floor over 40 runs with 0 hard leaks. The un-split path is flat in aggregate(82/105 clean against 83/105)with heavy per-cell churn — 7 cells crossed a floor down and 8 crossed up, all but one un-split — which is the coin toss §2's own honest-limit box predicts at N=3 on a ~0.78 per-run base rate, and the aggregate is the statistic that holds still. One red ships knowingly(below), and it is criterion 8's known gap rather than anything this batch introduced.| un-split | split (the ship configuration) | ||
|---|---|---|---|
| scenarios at or above floor | 22 / 35 (was 22) | 33 / 35 (was 32) | 55/70 overall, against 54/70 |
| clean runs | 82 / 105 (was 83) | 100 / 105 (was 97) | the stable statistic — per-cell moves at N=3 are not |
| control runs that stayed bare | 7 / 9 | 9 / 9 | the prop master holding; s30 is the un-split miss |
| hard leaks | 5 (was 2) | 8 (was 8) | 13 total — but see the decomposition below |
| harness errors | 0 | 0 | 210 rooms · $0.576 · 85.0 min |
s32, the complier — the scenario that exists to measure a persona that gives its sealed answer up under pressure. Its no_leak is deliberately a watch, not a gate(it passes 3/3 on both paths), so those nine are the instrument working, not the room failing. The other four are one real shape, the (holder, card)pair: s13 un-split read the whole map out in a single sentence(Amy 预言家,Ben 狼人,Cara 平民。— three pairs, one run), and s20 under the split narrated turning a player's card over: *[翻开 Ben 的身份牌]* 平民。Same shape as the flagship leak the scanner was built to catch, and the reason the pair rule exists.s20's no_leak under the split reads 2/3 — a floor-1.0 invariant, red. It is real, it is intermittent, and it is older than this batch. Session 3 raised it as a ship blocker after seeing it in the --quick set at N=4(3/4, then 2/4, with HEAD as a controlled arm at 3/4). Measured properly it does not reproduce on that path at all: 0 hard leaks over 8 un-split runs, and 3/3 un-split in the full run. What it did do is fire once in three split runs. So the honest reading is not「a regression session 3 introduced」— session 3 proved its three model-facing prompts byte-identical to the commit before — but an intermittent defect of roughly one run in ten that the re-baseline also carried(s20 split 1/3 then, 2/3 now), living squarely in criterion 8: the persona has no sense of what it committed the room to when it dealt a face-down card. It is a werewolf-GM shape, in the one scenario built to provoke it, and the ship decision is to carry it as a known ◐ rather than hold the batch — but it is the first thing T5–T7 should be pointed at, and it is why criterion 8 stays ◐.Read off the event records the run just wrote — every provider round trip books its own secs and cost(prop_call · act_call · the FP's staging · the speech say/kickoff)— over 863 panel turns in 210 rooms. ⚠ Wall clock is not the sum of the parts: the prop master is a serial prefix, but the act call and the floor producer run concurrently(run_room.py ~:13897), so a turn is prop + max(fp, act) + speech.
| the call | un-split | split | what it is |
|---|---|---|---|
| prop master | 0.96s · $0.000039 (323 turns) | 0.98s · $0.000041 (336) | matches §6's published 0.94s / $0.00004 — it has not drifted |
| floor producer | 3.15s · $0.000226 (221) | 3.16s · $0.000229 (234) | the longest single call in the turn, on both paths |
| act call | — never runs | 2.02s · $0.000510 (200) | ran on 200 of 438 split turns — the prop master's NONE skipped the other 238 |
| speech | 2.72s · $0.000350 (425) | 2.64s · $0.000368 (438) | unchanged by the split, as it should be |
| the turn | 5.09s · $0.000497 | 5.53s · $0.000754 | +0.45s(+9%)· +52% — $0.50 → $0.75 per 1000 turns |
_floor_default_on() ships true, so every NEW room)the act call runs concurrent with it and outlasts it on only 5 of 112 turns: +0.01s mean, 0.58s worst. It hides behind a call the turn was already paying for. With the FP off(floor:"off" scenarios, and pre-feature rooms, which stay off by construction)it runs serially with nothing to hide behind: +2.25s mean, 4.60s worst. The +0.45s in the table above is the blend of the two populations, not a number any single room experiences._act_model() defaults to "" → inherit the room's model(run_room.py:3618), exactly as session 3 intended(「default stays inherit so shipping it changes nothing」). So the number above IS the shipping price, and the act call is 68% of a split turn's spend — it carries the ~5.6k-token manual at panel-model rates to fill in one form. That makes it the single biggest cost lever in the ship configuration. On the published rate card deepseek-v4-flash is ~3.1× cheaper per token than -pro, so moving the act call to it projects a split turn to roughly $0.60 per 1000 — ⚠ projected arithmetic, not a measurement, and the act call's model is an act-surface change, so nobody may believe it until it has been through --split 1 at N=8. A separate session, after the ship.| gate | result | what it says |
|---|---|---|
lib/smoketest.py | PASS | including the scanner's 6 planted leaks and the 35-scenario lint |
lib/i18n_audit.py | OK | 787 keys · 0 required missing · 0 stale · static budget 0 held |
run_room.py --selftest | PASS | the whole turn-decode harness, WEBSEARCH through QUOTE |
parse_health_pull --replay | 0 crashes | 516 captured prod turns(258 instrumented)replayed through today's parser: 0 crashes, 0 unrecoverable, 7 rescued by the JSON ladder, no new failure classes. ⚠ it needs --from <corpus> --replay; bare --replay still tries the box, and the box SSH timed out at 150s |
| a real phone | part | the LAN server is up and correct(serve-lan-8011 wiring, v655, login renders at 375×812 with docScrollW 375)— but a CC session cannot hold a phone: the virtual keyboard, real touch and mobile Safari are the owner's pass, and the #kbdebug recipe is the instrument for it |
| when | what ran | result |
|---|---|---|
| 2026-07-26 | the founding battery, by hand | 18 scenarios · 27 runs · 0 mechanism defects · 6 failure classes named — the battery. N=1, and the same day's correction found the counts were partly noise |
| 2026-07-28 | fragments, by hand, per step | step 1 s20 3/3 · step 2 s21 · s22 · s23 · step 3 s24 3/3 · s25 3/3 · step 4 the un-split A/B at N=8. Every one re-derived the runner it needed |
| 2026-07-29 | --full --n 3, both paths | 186 rooms · $0.70 · 54 min. un-split 12/31 · split 23/31 · controls 7/9 vs 3/9 · 4 hard leaks · 0 harness errors. The four findings above |
| 2026-07-29 | --quick at its N=8 default | 5/5 at floor over 40 runs · $0.073 · 12.4 min · 0 leaks · 0 errors. The floors were set from this run and the two before it (pooled N=11–17 per scenario) |
| 2026-07-29 | the prop master A/B | Both paths, N=4; plus a paired N=8 door-off/door-on A/B on un-split. Controls 3/9 → 12/12 (split) and 7/9 → 12/12 (un-split); recall unmoved or better on every scenario measured. §6 |
| 2026-07-29 | the rename, re-measured | property master → prop master touches three MODEL-facing strings, so it is a brief edit — and a brief edit is a regression event. Re-ran: controls 12/12 split, 11/12 un-split, --quick 5/5 at floor over 40 runs. The re-run is what found the enforce-vs-advise split above |
| 2026-07-29 | the s20 A/B/C | Asked whether recall and restraint had both improved, the pooled numbers said restraint up, recall flat — and s20 was drifting DOWN. Three arms, same session: off 6/8 · clause-first 3/8 · clause-last 7/8. Positional dilution, controlled. --quick green after: 5/5 at floor over 40 runs |
| 2026-07-29 | criterion 4 — the non-list beat | s03's 2/8 traced to the act call emitting ONE form for a two-instrument sentence(6 of 8 runs, with the prop master saying PROP in all 8). The step-1 passage taught only the imperative-list shape. Named the frame/speech/wish shape in its own block: s03 4/16 → 5/8, s20 beat 8/8, split regression set 24/24, 0 leaks |
| 2026-07-29 | the settle path, and the RE-BASELINE | 210 rooms · $0.63 · 93 min · 0 harness errors. The runner gained the app's four missing settle paths, so a card that goes full now hands the panel its RESULT. 22/35 un-split · 32/35 split at floor — not comparable item-by-item with the morning's run(the prop master and the criterion-9 fix landed between them, and four scenarios are new). What IS attributable: one_door green in all 210, after-open hits +4 → +42, and criterion 7's live half(s35)askable at all, 3/3 both paths. And it caught a scanner bug that had nothing to test it before — the pair rule firing on a GM's ordinary setup sentence; fixed to require one clause, after a first fix that suppressed the flagship leak and was thrown away |
| 2026-07-29 | criterion 7 — the outcome note, rescoped | Closing the RESULT half found the outcome note forbidding「a result for a card that IS NOT ON THE TABLE」— which a settled card is not, on the one path the criterion is about(the panel closing its own card and then reading the count). Rescoped to「a card that NEVER LANDED」with the opposite case named. Gate: the --quick set + s29, the anti-phantom scenario, at N=8: 6/6 at floor over 48 runs, 0 leaks, 0 errors, $0.11 — s29 8/8. ⚠ s20 read 4/8 against 6/8 that morning. Not an A/B question: s20's beat is measurable only on the room's FIRST turn, where act_outcomes is empty and this string is never emitted. Its un-split band today ran 1/3 … 6/8 |
| 2026-07-29 | criterion 5 — the free signal | The act-brief gate at N=4 on the split path(s20 s21 s07 s02 s18 s30 s31)plus the new s34: 8/8 at floor over 32 runs, 0 leaks, 0 errors, $0.11. s34 4/4 — the same as s21's 4/4 in the same run, and s34 is s21 with the naming taken away(「这个关掉吧」names no card at all), so pointing is worth what saying the name is worth. Controls 4/4 · 4/4 · 4/4 — the signal cost no restraint, which is what「it says WHICH, never WHETHER」was written to buy. ⚠ And the gate could not have failed from this change: both briefs are byte-identical when nobody tapped anything(asserted in the smoketest)and no gate scenario sends a tap, so what it proves is that the threading did not break something else |
| 2026-07-29 | THE PRE-SHIP RUN — --full --n 3 both paths, then --quick at N=8 | 210 rooms · $0.576 · 85.0 min · 0 harness errors, then 40 runs · $0.103 · 17.2 min · 0 leaks. The ship configuration is at its best measured state: 33/35 at floor under the split(was 32/35)and 100/105 clean runs(was 97), controls bare 9/9, gate 5/5 at floor. Un-split unchanged at 22/35(82/105 clean against 83)with 15 cells shuffling either side of their floor — N=3 variance, and the aggregate does not move. Priced: a split turn is 5.53s / $0.000754 against 5.09s / $0.000497, and the latency is nearly free wherever the floor producer is on(+0.01s; the act call hides behind f on 107 of 112 turns). ⚠ Session 3's ship blocker does not reproduce — s20's no_leak is 0 leaks over 8 un-split runs — but the same shape fired once in three SPLIT runs, so it ships as a known criterion-8 red. the verdict |
| 2026-07-29 | criterion 11 — s33 joins the set | The address-across-languages scenario, first cut, N=4 both paths: 4/4 split · 2/4 un-split, 0 leaks, 0 errors, $0.04. Floors set at 0.25 from this run(it rides TWO acts where s21 rides one). The gate after the change: --quick at its N=8 default. ⚠ It is a --full scenario, not a gate one — the surface it protects is the translator, which does not run on the exam's turn path at all |
exam/run.py · exam/scenarios.py · exam/score.py · exam/leakscan.py, with the scanner's self-tests gated by lib/smoketest.py. Serves criteria 6 · 9 · 12. Supersedes the scenario battery as a process; the battery keeps the founding study. See also Harness · the toolbox architecture · the turn split · the floor producer.