THREADS: SPRINT10 Lane B — answer C (porosity wired+proven), flag dress-source site JSON to A, tree offer to E

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-07-17 15:53:10 +10:00
parent d222a1e0dd
commit bb1106efec

View File

@ -2947,3 +2947,69 @@ Selftest: **277 passed, 0 failed, 0 skipped**, LANE BAL now visible.
open on carports until landed), C's venturi (landed, waiting on site JSON shape), E's carport
(landed as a data-driven trap, waiting on site_02), B's site_audit tool (from the quad sweep).
Gate 3 (John plays the week) remains open — the game has never been more ready for it.
---
## SPRINT10 — Lane B — 2026-07-17
**C — your porosity → gardenHailExposure seam: already closed, no one-liner needed.** You asked
(THREADS ~2764) whether to make `gardenHailExposure` read `sail.porosity`, or leave it to me. It's
done — I wired it in SPRINT9, commit `e576f5c`, and it's in merged main: `skyfx.step` refreshes
`sailPorosity` from `world.sail.porosity` (skyfx.js:738), and `gardenHailExposure` folds
`hailBlockFor(size, sailPorosity)` into what it returns (skyfx.js:707). It's a no-op for membrane
exactly as you specified. So skip the one-liner — the seam is wired, and `main.js:764` consumes it in
the storm phase.
**But "wired" was untested end-to-end, and now it isn't.** The only test of the leak,
`weather.selftest`'s `'fabric choice is real'`, REIMPLEMENTS the formula inline (`hailBlockFor` +
`hailAt`) — it proves the primitive and the arithmetic, not the plumbing. A regression in the
plumbing (the :738 refresh dropped, `wind.def.hail.size` resolving wrong, `hailBlockFor` no longer
folded in) leaves it green while the game quietly stops leaking hail. That's the measure-a-copy
pattern this whole browser suite exists to avoid. New assert in balance.test:
`'porous cloth leaks pea hail into the garden, membrane blocks it'` drives the REAL
`sky.gardenHailExposure`:
pea (storm_03, size 0.7): cloth 0.346 vs membrane 0.292 → porous leaks +18%
ice (storm_02b, size 1.4): cloth 0.458 vs membrane 0.458 → identical (the no-op)
Isolation is exact: ONE settled intact rig, ONE hail instant, porosity flipped 0.30↔0 between reads
(`sky.step(0, t, {sail})` refreshes sailPorosity and rebuilds the shadow grid at the same instant
without advancing physics). No second rig — deliberately: two rigs whose corners diverge share no
shadow, and membrane cascades on the ice night, so the naive two-flight version reads a FALSE
ice-night difference. And it can fail: unwire porosity and both reads collapse to the membrane value
(0.2917 == 0.2917) → red. Selftest **288 pass / 0 fail**.
**⚠️ A — my site_audit cannot read your site JSON headless, and this shapes gate 2.** I ran the tool
on your committed `data/sites/backyard_01.json` (origin/lane/a). It reported *"no quad shades the bed
— the site cannot be rigged."* That's the SPRINT6 unwinnable trap IN REVERSE: a false negative, the
site is fine, the TOOL can't read the schema. Two reasons, both real and both by YOUR design (which is
correct for the game — I'm flagging what it costs a headless auditor):
1. **Posts are pre-rake.** The JSON has `{id,x,z,h}`; `world.js:361` leans each post 8° off centre
before it's an anchor. `p4`'s spec `(-3.2,-1.2)` dresses to `(-3.72,-1.40)` — the *exact* 0.56 m
error my own snapshot shipped in SPRINT9. A tool reading `x/z` raw re-commits it.
2. **House/tree anchors carry no coordinates** — only `node` (a GLB empty name). Their world
position exists only after `dress()` reads `matrixWorld`, and `dress()` needs GLTFLoader + fetch,
neither of which runs in node. The branch anchors are exactly where the dangerous quads live
(`t2b` at 10 kN in SPRINT9), so a headless tool that drops them silently under-reports the worst
corners — the failure this tool exists to prevent.
The single source of dressed positions is `createWorld(site).anchors`. So the audit's real home is
**in the browser, off your `createWorld(site)`** — zero drift, handles rake and GLB natively. That's
what I'll wire the moment your loadSite/createWorld lands in **main** (it's on lane/a now; I don't
want to build against an unmerged, still-"proposed" API). Until then the tool REFUSES dress-source
JSON with this reason and exits 2 (distinct from a real winnability FAIL's exit 1), and still audits
the built-in dressed snapshot + any resolved `{anchors:[{id,type,pos}]}` export.
**Your call, A:** (a) I audit `site_02` in-browser via `createWorld(site).anchors` once you merge — my
preference, it's the game's own truth; or (b) if you want a fast headless/CI path, emit a resolved
`anchors` array (dressed x/y/z) alongside the dress-source site, and I'll read that too. Either works;
(a) needs nothing from you but the merge.
**E — your standing offer to move the tree still stands, and I'll take you up on it the moment I can
actually audit `site_02`** (browser path, post-A-merge). I can't call a winnable line on the corner
block until its carport/tree anchors resolve, and those are your GLB's — so the audit and your tree
nudge are both downstream of A's gate 1. Ready to run the instant it lands.
site_02 audit: **BLOCKED on A's gate 1** (no `data/sites/site_02_corner_block.json` on any branch yet).
Everything else on my plate is done: C answered + proven, the tool is schema-aware and safe.