diff --git a/B-progress.md b/B-progress.md index c200052..682978f 100644 --- a/B-progress.md +++ b/B-progress.md @@ -4,6 +4,32 @@ plus the game shell. It runs on my hand-written fixture **and** auto-integrates with Lane A's `generatePlan` (which landed mid-session). Everything below was verified live in a browser. +## Round 37 (v8 WAVE 0 §0.1 + §0.4) — THE KERB IS FOOTPATH, at +0 draws · commit `47db478` + +John's ruling landed as geometry. `ground.js` narrows the road quad to the carriageway and extends +the **existing** merged `footGeos` class inward to meet it, consuming Lane A's `vergeBand(e)[0]`. +- **+0 draws, proven not asserted**: identical draw count at every one of 102 walked spine steps + (worst frame **276 both**, sum **20,081 both**) and on `katoomba_real` (worst 100 both). + **Tris went DOWN** — −8 synthetic, −288 katoomba. The charter's "~2k tris" was an estimate against + a class that already existed; extending a quad re-parameterises it. Honest number, stated loudly. +- **14 of 14 gig posters were standing in painted bitumen. 0 are now.** No poster moved; the ground did. +- Surfaces verified by **raycast**: `main`@24 road 0–5 / footpath 5.25–15.25 · `side`@12 (72% of the + corpus) road 0–3 / footpath 3.25–9.5 · **`lane` degenerate `[4,4]` ⇒ pre-ruling geometry** · + **`arcade` all footpath, no road quad, no kerbs** · **residential keeps its grass nature strip**. + The lane case branches on `outer <= inner`, never on a band literal (Fable's mid-round correction). +- **A defect my own numbers could not see:** the first cut painted every intersection shut (a 12.5 m + footpath crosses the perpendicular *carriageway*, where a 3.5 m one only clipped a corner). All + numbers were green; the screenshot was not. Fixed by putting the carriageway on top under the flag. +- **`?verge=0` ships permanently** and is EXACT: ground vertex+UV hashes identical to the HEAD build, + and the same detector goes red on the default boot. +- **`?classic=1` is FENCED, not amended** (R31 dig-flip pattern): identical ground geometry AND + identical ground-only rendered pixels at three poses. → Fable's call if classic should be amended. +- **§0.4** — the chunk seam was never connectable: on HEAD `!!chunks.ctx === false`, so a consumer + holding only `PROCITY.chunks` had nowhere to attach. Now `chunks.onChunkBuilt(fn) → unsubscribe()` + (many consumers) + `chunks.ctx` (the documented single slot). 136 built / 144 disposed over a walk, + payload + key shape verified, throwing subscriber survives, and **zero behaviour change with no + subscriber**: a 102-step per-frame walk hashes `ceb1ec66` on both builds. `sim.js` untouched. + ## Round 30 (v7.0-alpha ledger #4) — THE COLLECTION UI + SLEEP surface · qa GREEN 6/6 The crate panel + game bar in `hud.js` (my DOM-overlay patterns), on F's §30.1 `PROCITY.game` diff --git a/docs/LANES/LANE_B_NOTES.md b/docs/LANES/LANE_B_NOTES.md index 8564346..9d75577 100644 --- a/docs/LANES/LANE_B_NOTES.md +++ b/docs/LANES/LANE_B_NOTES.md @@ -1,5 +1,134 @@ # LANE B — NOTES (measured) +## Round 37 (v8 WAVE 0 §0.1 + §0.4) — **THE KERB IS FOOTPATH: shipped at +0 draws, and tris went DOWN** + +**John's ruling is in the geometry. The road quad narrows from the whole 28 m corridor to the +carriageway and the EXISTING merged `footGeos` class extends inward to meet it — so the 9 m band +`registry.js` has called "verandah'd footpath" since R13, and that `buildings.js` has been building +an awning over for just as long, is finally paved. All 14 gig posters were standing in painted +bitumen on the boot every player gets; 0 are now. Not one poster moved — the ground did.** +Commit `47db478`, pinned at `lane-b/r37-kerb-footpath`. + +### The economy: `+0 draws` is proven, and the charter's tri estimate was wrong in our favour +True A/B, fresh boots, two **port-isolated no-store servers** — `:8178` serving HEAD (`ground.js` + +`chunks.js` restored from `git show HEAD:`), `:8177` serving the treatment — at 2560×1440. + +| | control (HEAD) | treatment | delta | +|---|---|---|---| +| synthetic ground | **5 draws** / 224 tris | **5 draws** / 216 tris | **0** / **−8** | +| walked spine, 102 steps @ 8 m — worst frame | **276** / 99,880 | **276** / 99,872 | **0** / −8 | +| …sum of draws over all 102 frames | **20,081** | **20,081** | **0 — identical at every step** | +| 8 bookmarks (`street_noon` … `warehouse_fringe`) | — | — | **0 draws each**, −8 tris each | +| `katoomba_real` ground | **4 draws** / 9,932 | **4 draws** / 9,644 | **0** / **−288** | +| katoomba walk, 120 steps — worst / sum draws | 100 / 7,703 | 100 / 7,703 | **0** | + +**The charter budgeted ~2 k tris and the honest number is negative.** That estimate was made against +a class that already existed; extending a quad's width re-parameterises it, it does not add geometry. +The only quads that change count are the ones the `arcade` case *removes* (−8 tris per arcade edge: +no road quad, no two kerbs, one footpath quad instead of two). 36 arcade edges on katoomba ⇒ −288. +Fill-rate improves for free — 18 m of every synthetic main street stops being painted as road. + +### Surfaces proven by RAYCAST, not by reading the code +Sampling every 0.25 m out from the centreline and recording the **topmost** ground hit: + +| edge | band (A's `vergeBand`) | what is actually painted | +|---|---|---| +| `main`@28 (synthetic) | [5, 14] | road 0–4.75 · kerb 5 · **footpath 5.25–17.5** · grass | +| `main`@24 (real) | [5, 12] | road 0–5 · **footpath 5.25–15.25** · grass | +| `side`@12 (real — **72% of the corpus**) | [3, 6] | road 0–3 · **footpath 3.25–9.5** · grass | +| `lane`@8 (real) | **[4, 4] degenerate** | road 0–4 · footpath 4.25–9 — **pre-ruling geometry** | +| `lane`@4 (synthetic) | [2, 2] degenerate | road 0–1.75 · kerb 2 · footpath 2.25–5.25 — **unchanged** | +| `arcade`@5 / @6 | [0, w/2] | **footpath from the centreline out. No road quad, no kerbs.** | +| **residential** `side`@14 | [3, 7] | road 0–2.75 · kerb 3 · **GRASS 3.25–6.75** · footpath 7–10.5 | + +**The `lane` case branches on `bandOuter <= bandInner`, never on a band literal** — Fable's R37 +correction landed mid-round and it was the right call: my brief said lanes are `[2,2]`, which is +synthetic-only; **56 real lane edges are `[4,4]`**. A literal would have been the same species of bug +this whole item exists to retire. Same reason the code consumes **`vergeBand(e)[0]`, not +`roadWidth(e)/2`**: both `roadWidth` and `edge.width` are *full* widths, one of the carriageway and +one of the corridor, and that collision is why the bug survived seven epochs — reading the same call +A's corrected gate reads means the gate and the geometry cannot drift apart. Inversion (`roadWidth > +edge.width`) is 0 of 31,039 corpus edges but a `side` under 6 m would do it, so `Math.min(…, half)` +guards it and lands such an edge on the degenerate path by arithmetic rather than by special case. + +### THE DEFECT I SHIPPED INTO MY OWN FIRST CUT, AND WHY THE SCREENSHOT CAUGHT IT +The first cut passed every number — +0 draws, −8 tris, posters clear, no console errors — **and +painted every intersection shut.** Four roads arriving at a pedestrian plaza; the carriageway simply +stopped at each junction. The cause is a 3.5 m assumption that was true for seven epochs: a footpath +outboard of the corridor only ever clipped the *far corner* of a crossing street, so footpath-over-road +(footpath y 0.02, road y 0.0) was invisible. At **12.5 m** the same strip crosses the whole of the +perpendicular **carriageway**. Fixed by putting the carriageway on top under the flag (`ROAD_Y` +0.0 → 0.04): roads run through junctions, footpaths stop at the kerb they meet — which is what an +intersection actually looks like. Verified on the real graph's **worst 4.3° junction** (R20's +measurement, still the worst on katoomba): clean, no z-fight, no holes; the near-parallel sliver +reads as a paved traffic island. Road-on-road overlap in the junction box is unchanged and still +invisible for R20's original reason — one skin, one y, uniform asphalt. +*The numbers were all green. Only the picture was wrong. `?verge=0` + a screenshot is why this round +did not ship a town whose streets don't connect.* +Shots: `docs/shots/laneB_r37_kerb/` — before/after at one pose (poster in the road → poster on the +footpath), before/after overhead at a degree-4 junction, street level, katoomba's 4.3° junction. + +### `?verge=0` — the control, proven EXACT rather than "similar" +It reverts to pre-ruling geometry and **stays in the codebase forever** (Lane F's falsifiability +control for the poster gate; A pinned its control to *the flag*, not to a line number). +- **Ground vertex+UV FNV hashes under `?verge=0` are identical to the HEAD build**, mesh for mesh: + `c4c72181 / c111d968 / 1a80ebcd / 12c1241b / fd0d3211`. Not "same draw count" — same vertices. +- **The same detector goes RED** on the default boot (`40c54d19 / a300d701 / bfa81387`), so the + green means something. Vacuous-gate law applied to my own verification. + +### CLASSIC IS FENCED, NOT AMENDED — and Fable has the call +`?classic=1` forces the ruling **off** (`!CLASSIC && params.get('verge') !== '0'` — the R31 dig-flip +pattern the other flipped flags ride), because a render-side ruling must not move a covenanted town's +output without an amendment ruling. Proven twice, and the second proof is the one that counts: +| | classic, HEAD build | classic, this build | default boot | +|---|---|---|---| +| ground geometry hashes | c4c72181 / c111d968 / 1a80ebcd / 12c1241b / fd0d3211 | **identical** | **differs** | +| **ground-only rendered pixels**, 3 poses (640×360 render target, everything but `ground` hidden) | 79df268c / 91564001 / a09d1e52 | **79df268c / 91564001 / a09d1e52** | **1f867636 / 405957ac / d51ca7c9** | +Hiding everything but the ground is what made this measurable: a full-frame pixel hash differed +between the two builds by ~30 draws and ~10 k tris **with the ground provably identical** — that was +citizens spawning on wall-clock time and a different prior chunk state, not my change. A pixel A/B +that includes a live sim is not an A/B. → **Fable: if classic should take the footpath too, that is +your amendment ruling and it is a one-token change (drop the `!classic` term).** + +### §0.4 — the chunk lifecycle seam: the producer was fine, the *handle* was missing +Diagnosis, measured on HEAD: **`!!PROCITY.chunks.ctx === false`.** The producer has fired +`ctx.onChunkBuilt` since R3 and Lane D's `sim.onChunkBuilt` has existed just as long, but `ctx` is +the shell's local object and `createChunkManager` never handed it back — so a consumer holding only +the manager (which is all `PROCITY.chunks` is) had **nowhere to attach**. LANE_D_NOTES §35 documents +`chunks.ctx.onChunkBuilt = …`, against a property that did not exist. That is the whole bug. +Two ways in now, both inert until used: **`chunks.onChunkBuilt(fn)` → `unsubscribe()`** (many +consumers — the single `ctx` slot is last-writer-wins and the v8 slate has several per-chunk systems) +and **`chunks.ctx`**, so the documented single-slot form works verbatim. + +| proof | result | +|---|---| +| events over a 40-step walk | **136 built · 144 disposed** | +| payload | `{cx, cz, buildings, furniture, data}`, `buildings`/`furniture` are Object3D, `data.lots` an array, and **`key === \`${cx},${cz}\`**` | +| a second consumer | fires too — **does not clobber the first** | +| the original `ctx` slot | fires, alongside the subscribers | +| `unsubscribe()` | **0** further events | +| a subscriber that THROWS | streamer survives, chunks keep building (guarded + `console.warn`) | +| **zero behaviour change when nobody subscribes** | a 102-step walk recording `[draws, tris, chunks]` **per step** hashes **`ceb1ec66` on BOTH builds** (`?verge=0` so the ground is identical too — any difference would be `chunks.js`) | +`sim.js` untouched (Lane D's file). The detail object is still allocated only inside the guard, so a +subscriber-free boot does the same two truthiness tests it has done since R3 and nothing else. + +### Honest notes / handed on +1. **The market plaza gets worse before John's amendment, and that is the standing item, not new + damage.** `ground.js` paints a 46×46 m brickpave square at the origin *on top of the spine road* + (charter §Standing #1). With the footpath now 12.5 m either side, more of that square reads as + pavement, and the carriageway (`ROAD_Y` 0.04) now paints over the plaza (0.015) where they cross. + I did **not** touch the plaza: it is awaiting John's ruling and picking a layer for it is a design + decision, not a consequence of this one. Recorded so nobody reads it as a regression from §0.1. +2. Real towns have **0 residential edges** (all lots `use:'shop'`, one `mainstreet` district — the + review's ruling-2 finding, confirmed from the runtime side), so the grass-verge branch never fires + there. It fires on 6 synthetic edges. When the civic fetch lands districts, nature strips appear + on real towns with no further code. +3. The four `THREE.PointerLockControls` console errors are the automation browser refusing Pointer + Lock on a synthetic click — environment, not code, same as R30. **0** other console errors on + every boot tested (default · `?verge=0` · `?classic=1` · `katoomba_real`). + +--- + ## Round 30 (v7.0-alpha ledger #4) — THE COLLECTION UI + the SLEEP surface: **shipped, verified against F's REAL core (nothing stubbed)** **The crate is on screen: cover thumb · title/artist · price paid · where + day found; count, day and