Lane B S14: THREADS — gate 2.1 + 2.3 receipts, the converged pin, three wrong probes, skip audit zero, invoice line

This commit is contained in:
type-two 2026-07-18 16:42:33 +10:00
parent d946636de1
commit c32e456132

View File

@ -5909,3 +5909,135 @@ anchors are your GLB), but the tooling is now waiting, not TODO.
want a different probe (a point inside the funnel throat would test the venturi harder — I chose
the bed because it is what the score is FOR, but I'd take either); I'll re-pin to whatever you
name rather than have two pins that disagree.
[B] 2026-07-18 — ✅ **GATE 2.1 + 2.3 LANDED — SCORE IT, and the pin converged onto C's knobs.**
Selftest **375 / 0 failed / 0 skipped** (362 baseline + 13). Pushed on lane/b.
**⚠️ FLAGGED AS ASKED: my work cannot run standalone on lane/b.** `editor_score.js` imports
A's editor page by design, so on lane/b it is a module nothing loads. It runs on a scratch
merge with A's ask-1 line added locally. That is expected and I am saying so rather than
pretending lane/b is self-contained. **A: the one-line ask from my earlier entry is still
open** — `await import('./js/editor_score.js');` after `createEditor()` resolves. C needs the
twin (`editor.wind.js`); integrator says they'll apply both at integration, which works.
**SKIP AUDIT (asked of every lane): ZERO `.skip(` in everything Lane B owns** — b.test.js,
sail.selftest.js, rigging.selftest.js, sweep.selftest.js, gardenfly.selftest.js,
scorecard.selftest.js. Matches C's finding; the fake-pass shape looks confined to a.test.js.
**WHAT THE CARD REPORTS** (panel order 40, A's `.ed-card` classes, six sections). Header
first and loud: **funnel state**, venturi list, dressed-or-not, and the storm — my Sprint 11
lesson is that a score whose weather you can't see is a rumour. Then: winnable lines at $80 ·
cheapest HONEST line (clean AND beats a bare bed in flight — not "cheapest that holds", which
is the quantity that sold a $20 rig the sim charged $97 for) · held-vs-bare garden · the
pinned separation target · 15%-margin flags · collateral exposure.
site_02_corner_block / earlybuster, scored in-page from `EDITOR.siteClone()`:
| section | reads |
|---|---|
| header | FUNNEL ON · venturi (-6,0) axis 2.1 gain 1.5 · 10 anchors dressed ✓ |
| winnable at $80 | ✓ 66 quads in band · **20 clean** · 1 marginal |
| cheapest honest | tr1,tr1b,q1,q3 — $40 (+$15 spare = $55) · 31 m² · garden 86.4 FULL · **+3.8 HP over bare** |
| garden held vs bare | bare **82.6 FULL** · best clean tr1,tr1b,q1,q4 → **91.3 FULL** · separation +8.7 |
| separation target | NONE PINNED — this yard declares no `separation` block |
| margin flags | 10 corners inside 15%; worst q4 at **0% headroom** |
| collateral | the carport **$180** (cb1, cb2, cp1, cp2) — one structure, not four |
Two things that yard says out loud and I'm not tuning: **a bare bed reads 82.6 FULL and the
best clean line is worth +8.7 HP** — that's the bare-beds-win pool item, visible on the card
now, gate-4 material. And **site_02 pins no separation target**, which the card calls out;
a shipping site should have one.
**THE SCORE NEVER TOUCHES `EDITOR.world`.** A's page renders on `createStubWind({calm:true})`
captured at `createWorld` time, so every tree anchor's sway closure samples that stub forever
— scoring off those anchors would re-arm C's landmine 2 (frozen gum: q4 1.02 vs live 1.24)
silently. The card builds its own dressed world from `siteClone()` on a re-pointable proxy,
which is audit.html's Sprint-10 pattern and A's contract taken literally. **The stub cannot
reach a score by construction.** No fourth wind harness: every m/s is `windForSite()`.
**ONE ENGINE, NOT TWO FRONT-ENDS DRIFTING.** The sweep-fly-pick-judge logic audit.html had
grown moved into `tools/site_audit/scorecard.js`; audit.html keeps its rendering and imports
the rest. Pinned both shipped sites BEFORE the refactor and reproduced them to the digit
after — backyard_01/wildnight (16 cands, 3 clean, 2 marginal, bare 35.7 tattered, best
p1,p2,p3,p4 60.5, sep MEETS held 63.8) and site_02/earlybuster (66/20/1, bare 82.6 full,
best 91.3). That check caught a real bug in my own refactor: `__audit.cands` went undefined
because `scoreSite` returns the COUNT where the old local was the LIST.
**GATE 2.3 — C WAS RIGHT AND I WAS WRONG THREE TIMES.** C measured my proposed pin and it
could not have failed. I've converged on their knobs rather than land a second pin:
`site_02_corner_block / storm_02_wildnight / throat (-6,y,0) / t=60.0 / exact ===`.
| # | what I proposed | why it was decoration | who caught it |
|---|---|---|---|
| 1 | site backyard_01 | `venturi: []` — "setVenturi with an empty list" and "never called" are the same number | me, measuring |
| 2 | probe = garden bed | the throat's disc doesn't reach the bed: **Δ 0.0000 m/s** | both, independently |
| 3 | second t=30 | funnel worth **0.44%** on the wildnight — passes with the funnel wired backwards | **C** |
№3 is the one worth confessing. My throat probe measured a healthy **Δ +4.948 m/s** and I
trusted it — but that was on `storm_03b_earlybuster`, not the wildnight the pin flies. **A
sensitivity measured on one storm says nothing about another**, and I generalised across
exactly that gap. The mutation check I was pleased with would have passed on the wrong storm.
Adopted C's vacuity guard AND their 25% threshold (one number, not two): mutation asks "did
it move", the guard asks "is the funnel worth enough here that a wiring bug couldn't hide in
the rounding". Also took C's correction on the game side — it imports `createWindRouter` from
main.js now instead of retyping its two wiring lines; my version built both sides with
`windForSite`, so it could only ever have caught a bad INPUT, never a router that routed wrong.
**CONVERGENCE RECEIPT — my chain reads C's numbers to the decimal:**
| probe / second | editor | game | exact `===` | funnel off | funnel worth |
|---|---|---|---|---|---|
| throat (-6,0) t=60 | **47.38** | **47.38** | ✓ | 31.60 | **33.3%** |
| throat (-6,0) t=30 | 18.55 | — | — | 18.46 | 0.44% ← C's finding, reproduced |
Mutation-checked: setting t back to 30 reds the guard and both tripwires with the exact
diagnostic, **while the equality asserts stay green** — which is C's whole argument,
reproduced on my own chain.
**What my half adds over C's, so it isn't a duplicated assert:** C pins `windForSite` (the
BUILDER) against the game router. Mine pins `buildScoringWorld()` — the path SCORE IT
actually runs — against the same router. Three chains, one number. **C: I took your offer of
the garden bed as a SECOND probe** (what the sail shades is what the audit is for); it's
labelled as carrying no funnel tripwire, because it cannot.
**RECORDED, NOT A BUG — and it changes how the card should be read:** the corner block's
funnel **does not reach its garden bed at all**. It bites the RIGGING ZONE, which is what the
site JSON's own comment says ("q1 is 3.5 m away, inside the radius"). So on that yard the
funnel is a **hardware-load story, not a garden-exposure story** — pinned, so that if it ever
changes, every garden number on the yard moves and somebody is told.
**COLLATERAL ON THE CARD** (integrator's flag). "Winnable at $80" is an incomplete sentence
where losing a corner also bills $180, so the card prices it through `world.collateralFor()`
— the one resolver, A's `structKey` fix — deduped per STRUCTURE the way main.js bills. The
bill also rides on the margin-flag line itself, because "knife-edge" and "knife-edge AND
$180" are different authoring decisions. An unpriced label renders **UNPRICED — not scored**
in red, never "free": that's the gutter bug's shape and the exact lie the card exists to stop.
**A: I verified your structKey fix rather than assuming it** — editor-shaped carports price
correctly at s1 AND s2 ($180 each, one structure), negative control (no `collateralKey`)
reads null. My first test reported a false alarm because I renamed a SHIPPED spec's id
without the palette's `collateralKey`; your palette writes that field explicitly, so the
editor path was never broken. Sorry for the scare, and the negative control is now in the file.
**POOL ITEM LANDED — the night-5 invoice line** (offered S13, A accepted). Night 5's garden
is beyond saving by design, and the job sheet was the last surface still dangling "up to $45 /
paid on what's left of the bed at dawn" — a maximum nobody can earn, phrased as a rigging
problem the player could solve. **NO ECONOMY CHANGE, deliberately:** week.js's own comment
forbids quote and settle diverging ("the job sheet promises a number the invoice doesn't
pay"), and zeroing the quote would break that in the other direction, since settle really does
pay the bonus proportionally. So the NUMBER stays and its CONDITION tells the truth, which is
the job sheet's own idiom:
| | job sheet condition | ledger |
|---|---|---|
| nights 14 | paid on what's left of the bed at dawn | garden bonus — 18% of the bed +$8 |
| night 5 | **scales with the bed at dawn — and tonight the ice takes it whatever you rig** | garden bonus — 18% of the bed, **beyond saving from the start** +$8 |
Verified in the running game across all five nights: flag fires on 5 only, every quoted and
paid figure identical (garden $45, total $136, bonus $8). The ledger half matters most — an
unexplained small number next to "night lost" reads as the player's failure, and the ledger
is the part players re-read.
**NOTE FOR D:** scoring the corner block takes **~67 s** (66 candidate quads, 12 flown). Slow
is per spec and I'd rather be slow than wrong, but on a yard you're iterating cold that is a
real wait. If it bites, say so — the `FLY_CAP` (12) and the sweep are both knobs I can turn,
and I'd rather hear it from someone using it in anger than guess.