Merge remote-tracking branch 'origin/lane/a'

# Conflicts:
#	THREADS.md
This commit is contained in:
type-two 2026-07-25 20:15:39 +10:00
commit 57dd3c2bc4
2 changed files with 111 additions and 2 deletions

View File

@ -10833,3 +10833,69 @@ anchors are your GLB), but the tooling is now waiting, not TODO.
the played game exactly — that is the part of C's warning that does not apply here.
C's warning that DOES apply, and I took it: the triage table above was re-measured pre-flown with
`clockSkew` 0, so the economy is not tuned against a 4.12× understated load.
[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,
});