Lane A S18 gate 2 pickup: 🧵 THE FABRIC REACHES THE SIM — the F key was moving the paperwork and never the physics

B found gate 2's variable and it was in my file. rig.setFabric() had exactly one
call site (RiggingSession.commit) and the shipped path never reached it, because
rigSail went straight to rig.attach(). The game's rig has flown the waterproof
membrane at full wind load every night of every playtest while every card said
shade cloth.

Reproduced the bug here before fixing it: fresh boot read rig.porosity 0 against
session.fabric shade cloth (0.3). After the wire, through the real Enter key:
0.3 and 0.3, agreeing.

B's table now reproduces in the SHIPPED GAME — the third harness, and the one
that was lying. Night 5, the yard's pinned recipe by hand, committed with Enter:
p5 5.10 / p2 3.08 / p3 1.81 / p1 2.96, 0/4 lost, garden 63.5 inside the pinned
tattered-win band. B's bench: 5.11 / 3.07 / 1.78 / 2.97, 0/4. Before the fix the
same recipe broke p2 at 3.48 and p3 at 3.90 — D's cold play to the decimal.

Both routes, neither redundant: B's 4th argument is the better contract
(dev_rigging.html has no session and had the identical bug), but their commit()
passes it on lane/b — so on this branch the argument alone would have been inert
until integration, against B's own "until this lands the sim still flies the
membrane". rigSail takes the argument and falls back to session.fabric, the
expression this file already read for the paperwork. At merge the argument wins;
delete the fallback then.

⚠️ This makes the shipped game EASIER than every playtest ever run — the $80
clean-win line was tuned on cloth and played on membrane. D must re-fly the week.
⚠️ My retracted emergency balance number now has TWO contaminations pushing in
opposite directions, so its sign is unknown, not just its size. Fully withdrawn.

Selftest 539/0/0, unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-07-25 20:14:47 +10:00
parent d8d3ef983f
commit 2fd7b579b4
2 changed files with 111 additions and 2 deletions

View File

@ -10037,3 +10037,69 @@ anchors are your GLB), but the tooling is now waiting, not TODO.
checks the types the round-trip fixture actually PLACES, not every row in PALETTE, so a hidden
row adds no assert and reddens nothing. **Integrator: no action — the two halves fit at merge
with no third commit.**
[A] 2026-07-25 — 🧵 **GATE 2's PICKUP LANDED: THE FABRIC NOW REACHES THE SIM. B found it, and it
was in MY file.** `rig.setFabric()` had exactly one call site in the repo — `RiggingSession
.commit(rig)` — and **the shipped commit path never reached it**, because `rigSail` went straight
to `rig.attach()`. So `session.commit(rig)` ran in tests and benches ONLY, and the game's rig —
built once at boot as `new SailRig({anchors})`, the constructor's `porosity = 0` — **flew the
waterproof membrane at full wind load every night of every playtest**, while the prep panel, the
SCORE IT card, the HUD row, the invoice and every audit number said shade cloth. **The F key has
been moving the paperwork and never the physics** — honest exactly half the time, by coincidence:
pick membrane and the sim agrees with you by accident; pick cloth, the DEFAULT, and it does not.
**I REPRODUCED THE BUG IN MY OWN TREE BEFORE FIXING IT**, because a fix for a bug you have not
seen is a guess: on a fresh boot, `rig.porosity` **0** against `session.fabric` **shade cloth
(0.3)**. Then, after the wire, through the **real Enter key** on the real prep panel: `0.3` and
`0.3`, agreeing.
**AND B's TABLE NOW REPRODUCES IN THE SHIPPED GAME — the third independent harness, and it is
the one that was lying.** Night 5, backyard_01 × wildnight, the yard's pinned recipe by hand
(p5 rated / p1,p2,p3 shackle, $75, tension 1.0), committed with Enter, flown on
`SHADES.step(1/60)`:
| corner | B's bench, cloth 0.30 | THE GAME, cloth 0.30 (mine) | the game BEFORE this fix |
|---|---|---|---|
| p5 | 5.11 | **5.10** | 5.64 |
| p2 | 3.07 | **3.08** | 3.48 **BROKE** |
| p3 | 1.78 | **1.81** | 3.90 **BROKE** |
| p1 | 2.97 | **2.96** | 3.50 |
| lost | 0/4 | **0/4** | 2/4 |
Garden **63.5** — inside the pinned separation's own ~5564 tattered-win band. **Gate 2's
two-harness disagreement is closed in the shipped game**, `gardenfly`'s 0-lost pin is now true of
the thing a player actually plays, and D's cold play is vindicated as a real bug found by hand.
**I TOOK BOTH ROUTES AND NEITHER IS REDUNDANT.** B's filed hunk is the 4th ARGUMENT and it is the
better contract — `dev_rigging.html` has no session to reach into and had the identical bug. But
B's `commit()` passes that argument on **lane/b**, and on this branch `commit()` still calls
`onCommit` with three, so **the argument ALONE would have been an inert no-op here until
integration** — against B's own words, "until this lands the sim still flies the membrane". A fix
that waits for a merge to start working is not a fix yet. So `rigSail` takes the argument and
falls back to `rigging?.session?.fabric` — the expression this file already read for the
paperwork, so physics and invoice now read ONE source. **Integrator: at merge the argument wins
and the fallback agrees with it; delete the fallback then, not before.**
⚠️ **CARRYING B's WARNING, and sharpening it: THIS MAKES THE SHIPPED GAME EASIER THAN EVERY
PLAYTEST EVER RUN.** The $80 clean-win line and the wildnight's balance were **tuned on cloth and
played on membrane**. That is the correct direction — the cards were the promise and the promise
now holds — but every balance number in this repo's history was measured against a sail carrying
up to 2× the load its card claimed. **D must re-fly the week after this lands**, and D runs after
me. Nothing should be re-tuned off pre-fix numbers.
⚠️ **AND MY OWN RETRACTED BALANCE MEASUREMENT NOW HAS TWO CONTAMINATIONS, NOT ONE.** My
emergency-callout night (+$180, garden 84%) was flown against (1) a cloth clock frozen at
`attach()` — C's finding, B fixing — **and (2) the wrong fabric entirely**, this one. The two
push in OPPOSITE directions (the frozen clock understated load ~4×; the membrane overstated it up
to 2×), so the number is not merely soft, **its sign is unknown**. It stays fully withdrawn. B —
the $38 garden bonus I handed you is void twice over; re-measure once both fixes are in.
**ONE HONEST RESIDUAL, named rather than papered over.** The A-side wire lives inside `boot()`
behind a WebGL context, which is exactly the unreachability that let this bug live for five
sprints — so it is **verified by eyes and by the reproduction table above, not by an assert**.
B's `gate 2: the commit seam carries the FABRIC` pins the contract from the session end, which is
the half that can be reached. I did not extract `rigSail` to make two lines assertable (the
`rigRecordFor`/`answerableFor` precedent is for RULINGS with consequences, not for a wire), but
the standing risk is real and worth stating: **anything main.js does between `onCommit` and
`attach` is invisible to the suite.** If a third thing ever needs to ride that seam, extract it
then.

View File

@ -837,7 +837,46 @@ export async function boot(opts = {}) {
sailView = null;
}
async function rigSail(anchorIds, hwChoices, tension = 1.0) {
/**
* **SPRINT18 gate 2 THE FABRIC REACHES THE SIM. B FOUND IT; THIS IS THE
* PICKUP, AND IT IS THE WHOLE FIX.**
*
* `rig.setFabric()` had exactly ONE call site in the repo `RiggingSession
* .commit(rig)` — and **the shipped commit path never reached it.** The rigging
* UI's `commit()` calls `onCommit(...)`, and this function went straight to
* `rig.attach()`. So `session.commit(rig)` ran in TESTS AND BENCHES ONLY, and
* the sim's rig built once at boot as `new SailRig({anchors})`, the
* constructor's `porosity = 0` **flew the WATERPROOF MEMBRANE at full wind
* load every night of every playtest**, while the prep panel, the SCORE IT
* card, the HUD row, the invoice and every audit number said "shade cloth".
* **The F key has been moving the paperwork and never the physics**, and it was
* honest exactly half the time by coincidence: pick membrane and the sim agrees
* with you by accident; pick cloth the DEFAULT and it does not.
*
* B's table on the wildnight's pinned recipe, one variable: cloth 0.30 loses
* **0/4**; membrane 0 loses **p2 at 3.48 then p3 at 3.90** which is D's cold
* play to the decimal, and the site's own `_playedReference`. So **the harness
* that was lying was the GAME**: the bench flew the fabric the cards promised,
* every audit number stands, and D's play found a real bug rather than an
* artefact. It also retires C's `AUDIT.MARGIN` residual with the fabric held
* equal, bench and full game chain agree to three decimals on all four corners.
*
* **BOTH ROUTES, deliberately, and neither is redundant:**
* · the ARGUMENT is B's filed hunk and the better contract `dev_rigging.html`
* has no session to reach into and had the identical bug.
* · the SESSION FALLBACK is what makes this LIVE ON lane/a TODAY. B's
* `commit()` passes the 4th argument on lane/b; on this branch `commit()`
* still calls `onCommit` with three, so the argument alone would be an inert
* no-op until integration and B's own words are "until this lands the sim
* still flies the membrane". A fix that waits for a merge to start working is
* not a fix yet. `session.fabric` is the expression this file already reads
* for the paperwork, so the physics and the invoice now read ONE source.
* When B's rigging.js merges the argument wins and the fallback is dead weight
* that agrees with it. Delete the fallback then, not before.
*/
async function rigSail(anchorIds, hwChoices, tension = 1.0, fabric) {
const cloth = fabric ?? rigging?.session?.fabric;
if (cloth) rig.setFabric(cloth);
rig.attach(anchorIds, hwChoices, tension);
disposeSailView();
sailView = await createSailView(rig);
@ -945,7 +984,11 @@ export async function boot(opts = {}) {
camera: cameraRig.object,
domElement: canvas,
world,
onCommit: (ids, hw, tension) => { void rigSail(ids, hw, tension); },
// SPRINT18 gate 2 — the fabric rides through with the steel. B's filed hunk,
// verbatim; `fabric` is undefined on bare lane/a (their commit() passes it,
// and that lands at integration) and rigSail falls back to session.fabric so
// the sim flies the right cloth on both branches. See rigSail's note.
onCommit: (ids, hw, tension, fabric) => { void rigSail(ids, hw, tension, fabric); },
onMessage: pushEvent,
panel: true,
});