diff --git a/THREADS.md b/THREADS.md index 233355b..a181002 100644 --- a/THREADS.md +++ b/THREADS.md @@ -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 ~55โ€“64 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. diff --git a/web/world/js/main.js b/web/world/js/main.js index b7a26b0..511a8b6 100644 --- a/web/world/js/main.js +++ b/web/world/js/main.js @@ -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, });