setPhase('storm', {at}) is the whole engine change: windTime() already returns
phaseT during a storm, tick() already ends at STORM_LEN, so an emergency night
is 60s long inside weather that is already working. No new phase.
EMERGENCIES, scheduled per night, not a POOL entry — a seventh pool entry would
re-roll every night's draw, and the one-variable law needs an author to place a
set-piece. Diffed the whole week against HEAD: exactly one line moved, and what
it replaced was corner_block_southerly — the same yard and the same storm as an
ordinary job. The job type is literally the only variable.
⚖️ Rulings: emergency rate ×2.0 (DESIGN.md line 29, canon, UNMEASURED-by-play);
a corner that ARRIVED broken bills nothing, wrecks nothing, books no warranty
and costs no standing (`theirs` on the rig record — without it the game charges
you for a cowboy's carabiner and books you a free callout to fix his work); the
inherited steel does not come home; the ute carries one free spare, or triage is
a verb with no object.
THE ONE-VARIABLE LAW IS NOW CODE: oneVariableOffences() accuses, offersFor()
throws, three-way vacuity guard. E's glasshouse cannot be the emergency's debut
stage no matter who wires what.
The DISPATCH is defined by its refusals: no schedule, no total, no AMOUNT DUE —
nobody costed this job. It prints the call, C's mid-storm read (feature-detected
through a namespace import), the rig that is already up with the down corners
marked ON THE GROUND, and the rate. Pinned in DOM, refusals included.
Seams live and waiting: B's breakCorner door, C's midStormRead, D's cutAway
event (tallied, carried to the settlement, printed on the invoice).
Selftest 535/0/0 — 528 + 7, the exact sum.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
John's ruling, 2026-07-25 ("it adds pressure"), wired end to end.
REP.STOOD_UP = -0.5, the exact mirror of REP.CLEAN: a stood-up client costs
you what a flawless night earns. Bounded above by REP.COLLATERAL so a broken
promise cannot outrank a wrecked carport. UNMEASURED per house rule; it is the
lever, not CLEAN.
isBooked(kind, night) — the diary is booked, the phone is not, and an emergency
in the diary's chair is not a booking. The first cut derived it from the night
alone and the pool yard came back booked; the probe caught it in one call.
take() records the broken promise, settle() charges it at dawn — charging inside
take() drops standing between the board and the sheet, and the fee is priced off
standing. That is the quote-vs-settle lie moved one card earlier.
Three surfaces off one ledger: the offer card prints the cost before the choice
in the client's own terms, the job sheet says they have not forgotten, the
invoice carries an OFF THE BOARD block. Two callouts and no booked job reads as
free, in words, with a vacuity guard behind it.
Selftest 528/0/0 — 522 + 6, the exact sum.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
site_04_pool_yard: E's ring (fourteen honest noes) east, the bed poolside, ONE
corroded post in the venturi channel where the NE corner wants steel. Authored
in the editor (palette shapes, iterative SCORE IT x3, canonical export).
Gauntlet: WINNABLE at $80 — 13 quads, 6 clean, 1 marginal; cheapest hold $40
(h1,t1b,p2,p3, 92.7 FULL, no rust); every 92%-cover line routes through c1 —
clean $65 rated on t1,p1,p2,c1, UNHOLDABLE on the two shapes that pull the eye
harder. audit.html over the shipped file reproduces the card to the digit.
Separation REFUSED with receipts (bare 83.7 FULL — mild-night canon, A's 0.4).
board.js (A's granted edit): pool_yard_southerly POOL entry with the audit
receipt. d.test: +5 pins (chosen-never-scripted, ring/rust facts, judged-XOR,
wreck apron, exposure $160). gardenfly.selftest (B's file, flagged): judged
walk 3 -> 4 in the same commit that ships the yard.
Selftest 515/0/0 (510 + 5, the count moved by exactly what was added).
Mutations: 1 full-suite (finding stripped -> DOUBLE red: B's walk 'UNJUDGED'
+ my XOR pin, 513/2), 10 probed (entry deleted/re-paired/receipt stripped/
scripted-slot, gnome unpriced/rust zeroed/fence priced, apron x3) — every one
red with its own words, controls green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gate 0 rulings (written, with reasoning, in THREADS):
- 0.4 hail-light balance: CANON. B's finding reproduces exactly ($4/$2 garden
spread), but the mild-night rig market buys the STEEL and the collateral, not
the bed — a cheap rig that fails on site_02 swings $184 and two stars against
the same rig holding, and the cheapest HOLDING line is $40, not the $20 floor.
Ruled for B's option (b): the separation block asks the wrong question on
those nights; the new shape is B's and is NOT this sprint. Rain drain-weight
lever declined at its proper price (full gauntlet re-measure, own gate).
- 0.4b gradeFor scraped/solvent >=3 STANDS on the seven-night shape, ruled on
the arithmetic (savable 6 → solvent is 4-6 dead, which is what the copy says).
- 0.3 score-header wording consulted for B (no code from me).
Gate 1 — the board: board.js (pure data, node-testable), week.offers()/take(),
seeded from week+night via contracts' mulberry32 — no Date.now, no Math.random.
An offer carries a whole NIGHT ENTRY and take() installs it, so sheet, quote,
invoice, ledger, warranty, rep and end card all read a chosen job through the
path they already had — seven surfaces, zero changed lines. Scripted spine runs
byte-identically when nothing is taken.
Gate 2 (data half) — constraints as night data, checked enum, premium ruled
(+25% anchor ban / +20% budget cap, both UNMEASURED and flagged cut-first),
stated on the offer, the job sheet and the invoice it was paid under. ONE
calloutFee() now serves quote() and settle(). Enforcement is B's.
Two bugs found off the suite: take() stored raw pool entries (crashed quote()
on a missing pay block) → normaliseNight() split so both doors share it; and
NIGHT 1 HAD NO BOARD — the splash bypassed it — found by looking, not testing.
Pool pairings audited in the browser before shipping; both constraints checked
for soft-lock against real holding lines.
Mutation-checked ×6. One did NOT go red: "every pool storm is preloaded" passed
with the POOL source deleted, because every pool storm is also in NIGHTS — the
same coincidence that hid the calm-day bug. stormsToPreload(nights, pool) split
so it can fail. Selftest 485/0/0 (474 + 11).