Lane B R37 notes: LANE_B_NOTES §37 + B-progress — the kerb ruling measured, the junction defect recorded, the chunk seam diagnosed

The measurement tables (+0 draws at every walked step on two towns, tris DOWN not up, the
raycast surface table, the ?verge=0 and classic hash pairs, the §0.4 hook proofs), plus
three things worth keeping:
 - the defect my own numbers could not see (every intersection painted shut; all metrics
   green, only the picture wrong) and why ?verge=0 + a screenshot caught it;
 - a full-frame pixel A/B is not an A/B while a live sim is in the frame — hiding
   everything but `ground` is what made the classic covenant measurable;
 - the market plaza reads worse under the wider footpath, and that is the STANDING item
   awaiting John's amendment, not new damage from §0.1.
This commit is contained in:
m3ultra 2026-08-03 16:42:48 +10:00
parent 47db478a51
commit 79177bc77c
2 changed files with 155 additions and 0 deletions

View File

@ -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 05 / footpath 5.2515.25 · `side`@12 (72% of the
corpus) road 03 / footpath 3.259.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`

View File

@ -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 04.75 · kerb 5 · **footpath 5.2517.5** · grass |
| `main`@24 (real) | [5, 12] | road 05 · **footpath 5.2515.25** · grass |
| `side`@12 (real — **72% of the corpus**) | [3, 6] | road 03 · **footpath 3.259.5** · grass |
| `lane`@8 (real) | **[4, 4] degenerate** | road 04 · footpath 4.259 — **pre-ruling geometry** |
| `lane`@4 (synthetic) | [2, 2] degenerate | road 01.75 · kerb 2 · footpath 2.255.25 — **unchanged** |
| `arcade`@5 / @6 | [0, w/2] | **footpath from the centreline out. No road quad, no kerbs.** |
| **residential** `side`@14 | [3, 7] | road 02.75 · kerb 3 · **GRASS 3.256.75** · footpath 710.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