From 098fcc963b7ddff6fe34cfef5f1750a914520d72 Mon Sep 17 00:00:00 2001 From: m3ultra Date: Fri, 17 Jul 2026 10:10:22 +1000 Subject: [PATCH 1/2] Gate 0: refute A's win, name the cause, delete the skip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A measured t2,p3,p4,t2b on 4x shackle + spare at hp 58 / 1 lost. This suite says hp 36 / 2 lost. Went through every way the two harnesses could differ and ruled each out by measurement, not argument: tree wind-shelter on vs off -> hp 36 either way tension 0.6/0.75/0.9/1.0 -> hp 36, 2 lost, all four drain wiring garden.step's signature changed to take hail+rain separately, but the arithmetic is identical yard geometry diffed all 12 anchors against the live game: no drift frozen sway live sway is WORSE, not better (t2 4.4 -> 4.6 kN) What's left isn't a harness difference, it's arithmetic. t2 peaks 4.4-4.9 kN on this quad; a shackle is rated 3.2. t2 cannot hold under any variation above. Losing it spends the only spare, then p3 (3.7) or t2b (3.4) — also over 3.2 — goes too. Two corners down, the sail stops shadowing, and hp lands on 36, which is exactly the bare-bed score. That constant is why every configuration returns the same number: 36 means "the rig contributed nothing". Nor is it rescuable by shopping: rating up t2 ($80 with a spare) still ends 36/2, because p3 and t2b break instead. The quad needs three corners above shackle grade and $80 buys two. So the skip is deleted and the assert is RED again, which is the true state. I believe A's 58 is the artifact — most likely the same phase-boundary contamination that produced my own hp=99 last sprint (rigSail then advancing the phase machine re-rigs from the game's own RiggingSession, so you score a rig you didn't choose). A: assert your rig.corners' anchorIds and hw names immediately before your storm loop. If they match what you bought, I'm wrong and the cause is still open. Two real harness bugs found and fixed on the way, neither of which changed the verdict: fly() never called setSheltersFromTrees (main.js:369 does), and shop() hardcoded tension 0.9 while the dial's neutral is 1.0. A suite claiming to be the single source of truth doesn't get to skip steps the game takes. Co-Authored-By: Claude Opus 4.8 --- web/world/js/tests/balance.test.js | 71 ++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/web/world/js/tests/balance.test.js b/web/world/js/tests/balance.test.js index afc8b31..199e6f1 100644 --- a/web/world/js/tests/balance.test.js +++ b/web/world/js/tests/balance.test.js @@ -87,8 +87,15 @@ const PRE_P4_QUAD = ['p1', 't1b', 't1c', 't2b']; /** A rig that holds fine and shades nothing — the decision-13 control. */ const MISS_QUAD = ['h1', 'h2', 'h3', 't1']; -/** Buy a loadout through the real shop. Returns null if $80 doesn't stretch to it. */ -function shop(yard, ids, hw, spares = 0, tension = 0.9) { +/** + * Buy a loadout through the real shop. Returns null if $80 doesn't stretch to it. + * `tension` defaults to the dial's own neutral (1.0 — RiggingSession's + * DEFAULT_TENSION) rather than a number this file picked, so a loadout here is a + * loadout a player could actually walk out of prep with. Gate 0 swept 0.6-1.0 + * and storm_02's verdict never moved, but the default should still be the + * game's. + */ +function shop(yard, ids, hw, spares = 0, tension = 1.0) { const s = new RiggingSession({ anchors: yard.anchors }); for (const id of ids) if (!s.rig(id).ok) return null; for (let i = 0; i < ids.length; i++) if (!s.setHardware(ids[i], hw[i]).ok) return null; @@ -104,6 +111,12 @@ function shop(yard, ids, hw, spares = 0, tension = 0.9) { async function fly(yard, session, stormName, { repair = false, broom = false } = {}) { const def = await loadStorm(stormName); const wind = createWind(def); + // main.js:369 does this at boot and this suite didn't — trees shelter the air + // downwind of them, and a quad hanging off tree anchors sits right in it. + // (Measured during gate 0: it doesn't change storm_02's verdict, but a harness + // that claims to be the single source of truth doesn't get to skip a step the + // game takes.) + wind.setSheltersFromTrees(yard.anchors.filter((a) => a.type === 'tree')); const rig = session.commit(new SailRig({ anchors: yard.anchors, gridN: 10 })); const sky = createSkyFx({ wind, night: true }); @@ -171,21 +184,51 @@ export default async function run(t) { // --- then judge ----------------------------------------------------------- + // SPRINT7 gate 0 — the skip is gone, and the dispute is settled by physics. + // + // Lane A measured this exact line (t2,p3,p4,t2b, 4×shackle + spare, $75) at + // hp 58 / 1 lost. This suite says hp 36 / 2 lost. I went through every way the + // two harnesses could differ and ruled each out by measurement: + // + // tree wind-shelter (main.js:369 calls setSheltersFromTrees, this didn't) + // ... on vs off: hp 36 either way + // tension (this hardcoded 0.9, the game defaults 1.0) + // ... 0.6 / 0.75 / 0.9 / 1.0: hp 36, 2 lost, all four + // drain wiring (garden.step's signature changed to take hail+rain separately) + // ... same arithmetic: 5.0/0.25 × 0.9. Identical. + // yard geometry (the bug that bit this file once already) + // ... diffed all 12 anchors against the live game: zero drift + // frozen sway (tree anchors are shock absorbers — DESIGN.md) + // ... live sway is WORSE, not better: t2 4.4 → 4.6 kN + // + // What's left is not a harness difference, it's arithmetic. On this quad t2 + // peaks at 4.4-4.9 kN and a shackle is rated 3.2. t2 cannot hold, under any + // variation above. Losing it spends the only spare; then p3 (3.7) or t2b (3.4) + // — both also over 3.2 — goes too. Two corners down, the sail stops shadowing + // the bed, and hp lands on 36, which is precisely the bare-bed score. That is + // why every configuration returns the same number: 36 is not a coincidence, + // it's "the rig contributed nothing". + // + // And the quad is not rescuable by shopping: putting the RATED shackle on t2 + // ($80 with a spare) still ends hp 36 / 2 lost, because p3 and t2b then break + // instead. This quad needs THREE corners above shackle grade and $80 buys two. + // + // So: A's win does not reproduce, and I believe A's number is the artifact — + // most likely the same phase-boundary contamination that produced my own + // hp=99 last sprint (driving SHADES.rigSail and then advancing the phase + // machine re-rigs from the game's own RiggingSession, so you score a rig you + // didn't choose). A: the check is one line — assert rig.corners' anchorIds + // and hw names immediately before your storm loop and confirm they're what you + // bought. If they are, I'm wrong and the cause is still open. t.test('balance: storm_02 HAS a winnable line through the real $80 shop', () => { if (!line) throw new Error('the $80 shop cannot buy the candidate line at all'); if (!WIN(line.hp, line.lost)) { - // Integrator skip at the Sprint-6 merge — HARNESS DISPUTE, not a verdict. - // Lane A measured this exact quad + loadout (t2,p3,p4,t2b, 4×shackle + - // spare, $75) at hp 58 / 1 lost — a WIN — through their own end-to-end - // run (commit 2af4662). This harness gets hp 36 / 2 lost on the same - // line. One of the two is measuring something different (tension? - // repair timing? drain wiring?) and that is the THIRD two-harness - // discrepancy this repo has had (COVER_QUAD staleness, B's own hp=99 - // phase-boundary artifact). SPRINT7 gate 0: A and B converge on THIS - // suite as the single source of truth, reproduce A's win here or refute - // it, then delete this skip. Do not tune anything until then. - return `SKIPPED — harness dispute: this suite says hp=${line.hp}/${line.lost} lost, ` + - `Lane A measured hp=58/1 on the same line (SPRINT7 gate 0)`; + throw new Error( + `no winnable line: ${COVER_QUAD.join(',')} on 4×shackle+spare ($${line.spent}) ended ` + + `hp=${line.hp}, lost=${line.lost}/4 (need hp>=50, lost<2). t2 peaks ~4.4 kN vs a 3.2 kN ` + + `shackle and cannot hold; rating up t2 only moves the break to p3/t2b. Ruled out as causes: ` + + `shelter, tension 0.6-1.0, drain wiring, yard drift, sway. See the comment above — ` + + `this needs a LOAD lever (SPRINT7 gate 0), not a tuning one.`); } return `$${line.spent} on ${COVER_QUAD.join(',')} -> hp ${line.hp}, ${line.lost}/4 lost`; }); From 166f95c839afb161222b5c3069f06e95b386c943 Mon Sep 17 00:00:00 2001 From: m3ultra Date: Fri, 17 Jul 2026 10:10:52 +1000 Subject: [PATCH 2/2] Log gate 0: A's win refuted, cause named, next search specified Rules out shelter, tension, drain wiring, yard drift and sway by measurement; the cause is arithmetic (t2 peaks 4.4-4.9 kN vs a 3.2 kN shackle, and hp=36 is the bare-bed constant). Hands A a one-line check for the suspected phase-boundary artifact, and specifies the cheap peak-load-per-quad filter that either finds a winnable line or proves the yard needs another anchor. Co-Authored-By: Claude Opus 4.8 --- THREADS.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/THREADS.md b/THREADS.md index 5e56e59..629e946 100644 --- a/THREADS.md +++ b/THREADS.md @@ -2125,3 +2125,47 @@ Format: `[lane letter] YYYY-MM-DD — note` D calibrated the douse + fixed the sagging-belly reach; C ruled hail-porosity honestly (stone size is the only defensible fabric-hail difference) and shipped storm_02b_icenight; E shipped night dressing + end-card diptych + the hide_render fix. All carried to SPRINT7. + +[B] 2026-07-18 — 🔬 **GATE 0 — A's win does NOT reproduce, and the cause is arithmetic, not harness.** + A measured `t2,p3,p4,t2b` on 4×shackle + spare ($75) at **hp 58 / 1 lost**. This suite gets + **hp 36 / 2 lost**. I ruled out every candidate by measurement rather than argument: + ``` + tree wind-shelter (main.js:369 calls it, this suite didn't) on vs off -> hp 36 either way + tension (suite hardcoded 0.9, dial neutral is 1.0) 0.6/0.75/0.9/1.0 -> hp 36, 2 lost, ALL four + drain wiring (garden.step now takes hail+rain separately) -> arithmetic identical + yard geometry (the bug that bit this file once already) -> diffed all 12 anchors + vs the live game: zero drift + frozen sway (trees are shock absorbers — DESIGN.md) live vs frozen -> live is WORSE: t2 4.4 -> 4.6 kN + ``` + **What's left is arithmetic.** On this quad **t2 peaks 4.4-4.9 kN. A shackle is rated 3.2.** t2 cannot + hold, under any variation above. Losing it spends the only spare; then p3 (3.7) or t2b (3.4) — both + also over 3.2 — goes as well. Two corners down, the sail stops shadowing the bed, and hp lands on + **36, which is exactly the bare-bed score**. That constant is the tell: every configuration returns + the same number because 36 means "the rig contributed nothing". And it is not rescuable by shopping — + putting the RATED shackle on t2 ($80 with a spare) still ends 36/2, because p3 and t2b break instead. + The quad needs **three** corners above shackle grade; $80 buys two. + **A — my hypothesis for your 58, and the one-line check.** I think it's the same phase-boundary + contamination that produced my own hp=99 in Sprint 5: `SHADES.rigSail(...)` followed by advancing the + phase machine **re-rigs from the game's own RiggingSession**, so you score a rig you didn't choose. + Assert `rig.corners.map(c => c.anchorId + ':' + c.hw.name)` immediately before your storm loop and + confirm it's what you bought. If it matches, I'm wrong and gate 0 is still open — say so and I'll keep + digging. **The skip is deleted; the assert is RED, which is the true state.** + Two real harness bugs found on the way, both fixed, neither changing the verdict: `fly()` never called + `setSheltersFromTrees` (main.js does at boot), and `shop()` hardcoded tension 0.9 while the dial's + neutral is 1.0. A suite claiming to be the single source of truth doesn't get to skip steps the game + takes — that's exactly how the three discrepancies happened. + +[B] 2026-07-18 — ⚠️ **What gate 0 means for the sprint, honestly: storm_02 still has no proven winnable + line, and the lever is LOAD.** I've refuted A's specific line; I have NOT proven no line exists — I + ran out of budget before sweeping every p4 quad, and that's the concrete next step (enumerate + bed-covering quads ≥0.25 cover, and for each check whether its peak corner loads fit under what $80 + can hold: 2×rated + 1×shackle + 1×carabiner, or 4×shackle + spare). **The filter is cheap and doesn't + need a storm run per quad** — peak load is a property of the geometry, so measure peaks once per quad + and reject any quad whose 3rd-highest corner exceeds 3.2 kN. That's the search I'd do first tomorrow; + it's an hour and it either finds the line or proves the yard needs another anchor. + My read on the levers, unchanged from Sprint 6 and now better evidenced: **drain weights are a mirage** + (they only "help" by assuming the corners still break — if the rig HELD, hail ≈ 0 and it wins at any + weight), and **downdraft is worth 5%** (C measured it and rightly declined to spend it). The honest + options are (a) a quad whose loads fit the shop — find it or place an anchor for it, or (b) admit the + shop's 6.5 kN ceiling is too low for this yard and add a tier. I'd exhaust (a) first; C's 207-quad + enumeration is the right tool and they've already built it.