diff --git a/THREADS.md b/THREADS.md index da7c55f..e69515d 100644 --- a/THREADS.md +++ b/THREADS.md @@ -504,4 +504,71 @@ Format: `[lane letter] YYYY-MM-DD — note` to a standstill in a hidden/background tab, so they are the only honest way to fast-forward or capture a storm from a headless browser — which is what this sprint's "90 s storm_02 run captured" acceptance needs. Same code path the rAF loop uses; no test-only branch that can drift. Everything I reported - above was measured through them. + above was measured through them. (Confirmed on my side — every number below came through them too.) + +[C] 2026-07-17 — **LANE C SPRINT 2 LANDED on `lane/c` — decisions 3 & 5, rain occlusion, + A's fog nit.** + Selftest **134/0/0** (was 121; +13 Lane C asserts). Rebased on gate-1 main. Four pushes, small commits. + Thanks A for doing my §C.5 for me with evidence — dispose() light restore verified, and you caught the + fog leak (see below). + +[C] 2026-07-17 — **DECISION 3 — gusts now descend; this is a real rebalance, LANE B read the numbers.** + Cloth pressure ∝ dot(wind, normal); a flat panel's normal points at the sky, so in a purely horizontal + wind the cheapest winning rig was "lie it flat and ignore the storm". Fixed: per-gust downdraft fraction + in storm JSON (`gusts.downdraft`, 0..1, validated), storm_02 0.3 / storm_01 0.18 / default 0.25, each + gust varying 0.6–1.4×. `wind.sample()` y is now negative during gusts; `speedAt()` stays horizontal (an + anemometer doesn't read falling air). Measured on YOUR rig shape `['h1','h3','p2','p1']`, storm_02, + 90 s, controlled A/B on the downdraft alone: + ``` + downdraft hardware first break peak load + 0.0 rated shackle never 1929 N + 0.3 rated shackle never 4165 N ← +116% peak, still survives + 0.0 shackle never 1929 N + 0.3 shackle t=20.8 s 6038 N ← now blows; didn't before + ``` + So the downdraft **more than doubles peak corner load** and moves the shackle (3200 N) from "survives" + to "blows". I did NOT touch a curve — this is decision 3 landing, and the §7 thesis still holds cleanly: + a **well-twisted mixed rig** (`['h1','t2','p1','t1']`, rated+shackle mix, tension 0.85) peaks at 3379 N + WITH the downdraft and keeps all four corners — twist sheds the descending air, flat catches it, exactly + the game. The downdraft sharpens the choice, it doesn't break it. **B: your decision-3 assert** (flat- + horizontal peak ≥ 60% of flat-pitched over 8 directions) should pass comfortably now; the wind-side + asserts are in c.test ('gusts carry a downdraft…', 'downdraft does not re-time the storm'). + ⚠️ **Determinism guarantee:** the vertical draws from its OWN rng stream so adding/tuning it can't shift + (t0, pow). Your hand-verified cascade (carabiner t=45.4, p2 t=56) is untouched — asserted. + +[C] 2026-07-17 — **DECISION 5 — `debris.pieces` FROZEN in contracts.js. B, this is your seam.** New + `Debris` + `DebrisPiece` typedefs and `DEBRIS_PIECE_FIELDS`; `checkContract('debris', …)` now runs. + Shape you can rely on inside `sail.step()`: `{x,y,z,vx,vy,vz,r,mass,model,hitPlayer,mesh}`, all SI so + `mass*v` is a real momentum. Three things the typedef spells out because they'll bite otherwise: + · Collision volume is a **sphere radius `r`** centred on (x,y,z) — a crate is boxy but a sphere is + what you can afford to test per node per frame. `y` is the CENTRE, rests at `heightAt(x,z)+r`. + · The array is **mutated in place** — pieces splice out on despawn. Read it fresh inside step(), don't + cache it across frames, don't hold a piece past the step it left in. `clear()` empties the array + rather than replacing it, so a reference you hold stays valid (asserted). + · Don't move `piece.mesh` — Lane C drives it from the sim each step; you'd be fighting me. + +[C] 2026-07-17 — **RAIN STOPS AT THE CLOTH (§C.3).** Garden visibly stays dry under the sail; verified in + the real game — twisted rated rig at t=18, **497 grid cells covered, 96% of the bed, live drops culled + under the cloth and falling in the open either side** (screenshot for DESIGN.md). Cost 0.041 ms/rebuild + ×10/s = **0.41 ms/s**, negligible vs your 0.63 ms frame. Reads `rig.pos`/`rig.tris` only — nothing new + from B. It projects the sail down the RAIN direction, so the dry patch sits downwind and walks off the + bed at the southerly change — free drama. + ❓ **LANE A — design call, not mine: which shadow drives garden HP?** `skyfx.rainShadowOver(bed)` (rain, + down-wind, what actually keeps the bed dry in a night storm) vs `rig.coverageOver(bed, world.sunDir)` + (sun, which at night is a number about nothing). I'd wire HP to the rain one and keep coverageOver for a + daytime/aesthetic readout, but it's your HUD/scoring — say the word and I'll match whatever you pick. + They agree when the sun is overhead and diverge exactly when the storm makes it interesting. + +[C] 2026-07-17 — **FOG — fixed, thanks A.** `dispose()` captured `scene.fog` by reference and `step()` + mutates that object in place, so handing it back restored nothing. Now captured by value (color/near/far) + and restored field-by-field; fog that skyfx created itself is removed rather than left behind. Asserted + in c.test with vacuity guards (the test first proves the storm actually moved sun + fog, THEN that + dispose put them back — a restore test where nothing moved passes forever and checks nothing). Your + rebuild-on-phase-change path is clean now in both directions. + +[C] 2026-07-17 — **OPEN: the B+C tuning session (B-4/C-4) still needs both of us in a room.** I have the + controlled harness above and the storms are in real m/s; what's left is your call on whether the *cheap + flat* cascade lands at a satisfying beat and whether storm_02's curve wants a nudge for the by-hand §7 + run. My position: curves are good as-is, the downdraft did the balancing work — but if you want the + carabiner rig to blow earlier/later for feel, that's a one-line data edit and I'll make it. Ping when + sail-side tuning is settled and we lock constants together. (weather_demo.html retired candidate: the + game IS the bench now — I'll delete it once we've used it for this session, not before.)