# LANE B — NOTES (measured) ## Round 40 (§40.3 + routed §40.4) — the ?r= flag learns its own law, classic keeps its shop window, and the fog gets its signage All numbers this section: today's tree, headless Chromium, fresh contexts, port-isolated no-store servers, 1280×720, seed 20261990 unless a town is named. Budget cells use **the pin method of record** (R37/R38: `budget_walk.py --method stepwalk --stepm 2 --fixed-yaw 0 --laps 2` = 802 stations down the main spine at yaw 0, the worst bearing). ### §40.3-1 — THE ?r=3 BREACH: re-measured 391, and the ruling is GATE, not shave **The carried "307" was a stale bookmark, as the round suspected — the true number is 391.** The R37-era 307/317 pin predates five rounds of default-on content; nobody had re-measured the override since. On today's tree, same method as the budget of record: | synthetic, pin method | noon (seg 2) | NIGHT (seg 5) | live chunks max | tris worst | |---|---|---|---|---| | default (`r` auto = 2) | **282** | **291** | 32 | 120,093 ✅ pin reproduced (R38: 282/292) | | `?classic=1` | — | **269** | 32 | 90,580 ✅ **byte-exact to the R38 pin** | | **`?r=3`** | **382** | **391** | **48** | 132,829 (tris legal) | **Why shave was refused, with the numbers:** the breach is structural, not fat. `?r=3` carries 45–48 live chunks against the default's 31 (R+1 dispose window over a 7×7 vs 5×5 set), and the excess is 91–100 draws. Lane B's per-chunk cost is already collapsed to ~1 draw per kind per chunk (facade atlas, merged instancing — R2 close-out); there is no 91-draw shave available in a diagnostic boot that is not a content cut to the DEFAULT town. Shaving a diagnostic override by making the shipped town poorer is backwards. **So the flag now documents its own budget law and qa asserts it (the round's option b):** - `index.html` (`[Lane B R40]`, the RADIUS block): any `?r=` **above** the auto radius declares `PROCITY.budget = { draws: 420, tris: 200000, radius, auto, diagnostic: true }` and prints a `console.warn` naming the law ("DIAGNOSTIC boot … ≤420 draws … not a supported boot"). At or below auto: `{ draws: 300, diagnostic: false }` — the street law, unchanged. - **The ceiling is 420** = 391 measured + ~7% for crowd/streamer jitter (the R37 lesson: settle policy and station phase move a walked worst by single digits). If the town grows past it, the gate goes red and the ceiling is re-pinned CONSCIOUSLY — that is what a pinned law is for. - `hud.js` warn threshold reads the boot's own law (`budget.draws`), so the readout stops shaming a documented diagnostic at 300 and starts telling the truth at 420. Default boots render identical DOM (same 300). - `dbg.js` `info().budget` carries the law, so **a harness asserts against the boot's declared ceiling, never a hardcoded 300**. - **`tools/qa/r40_lane_b.py` (NEW file — races no lane) is the enforcing gate**, all arms non-vacuous: default declares 300/not-diagnostic · `?r=3` declares 420/diagnostic + the warn fired · a night stepwalk under `?r=3` measures ≤ its own ceiling (read 386 ≤ 420 at 8 m stations) **and** > 300 (the exemption is load-bearing, not vacuous — if it ever reads ≤300 the gate prints "retire the exemption" rather than failing) · tri law unchanged (131,893 ≤ 200k) · 0 console errors. **→ Lane F: one line wires it into qa.sh** — and README.md's `?r=N` row still quotes 307; please update it to the law (391 measured R40, ceiling 420, gated + warned). ### §40.3-2 — CLASSIC'S TOWN SELECTOR: the ruling was already true by construction; now it is deliberate and gated Fable ruled classic SHOWS the selector ("information, not gameplay state"). Verified on today's tree: `?classic=1` boots with the selector **present and visible, all 27 options** (synthetic + 3 OSM fixtures + the 23-town real/godverse pack), its towns-fetch surface is **exactly the one named POST_V2_EXCEPTION** (`assets/towns/index.json`, Fable's R37 ruling), navigation preserves the query string so a town picked FROM classic STAYS classic, **zero draws** (a ``, so rebuilding the options never clears it). **→ Lane F:** unchanged from R19 — **no shell seam**, the selector is entirely `hud.js` (already built by `createHUD`), and it lives inside `#pc-hud` so `setVisible(false)` hides it for the beta money shot. Your R19 gating call (always-in-HUD vs `?dbg`) is still yours; one line either way. --- ## Round 20 (Fable's ROUND20 → Lane B) — the tram ruling + ground polish (ledger #3/#4, v4.0-beta) ### 1. The tram ruling (ledger #3) — route by SHOP ADJACENCY, fence per-town `tram.js` `spinePolyline` now walks from each dead-end of the main subgraph, **greedily taking the unused main edge that fronts the most shops** (`lot.frontEdge`), and keeps the best-scoring path (ties → longer). Component logic isn't needed — a walk can't leave its component. **Synthetic + fixtures are byte-identical, by construction and by measurement.** A synthetic main node has ≤2 mains so there's never a choice, and its two dead-ends tie exactly ⇒ strict `>` keeps the pre-R20 start ⇒ the same route. Verified by running the old and new logic against the same plan: **identical polylines** (Boolarra Heads: 7 points, 6 edges, 810 m, 172 shops fronted, 2 stops — unchanged). | town | shops | shops fronting mains | OLD route | NEW route | stops | tram | |---|---|---|---|---|---|---| | synthetic | 493 | 172 | 172 | **172** (810 m) | 2 | RUNS (unchanged) | | fixture melbourne / katoomba | 95 / 19 | 0 / 0 | 0 | 0 (378 m) | 3 | RUNS (unchanged) | | fixture silverton | 12 | — (0 mains) | — | — | 0 | no-op (unchanged) | | **REAL newtown** | 64 | 32 | **0** | **8** (1924 m) | 16 | **RUNS** | | **REAL castlemaine** | 22 | 11 | 1 | **6** (2184 m) | 10 | **RUNS** | | REAL katoomba | 69 | 7 | **0** | 3 (3784 m) | — | **FENCED** | | REAL fremantle | 79 | 4 | **0** | 2 (3054 m) | — | **FENCED** | | REAL bendigo | 35 | 7 | **0** | 1 (4376 m) | — | **FENCED** | The alpha tram fronted **0 shops on 4 of 5 real towns** — it really was a highway bus. Shop-adjacency improves every town, but on katoomba/fremantle/bendigo the best main chain still fronts <5 shops, so per Fable's fallback the tram is **fenced per-town**. **The fence keys off the REAL-ROADS signal (`edges > 200`), never shop count alone** — because the marched fixtures legitimately front **0 shops on their mains** (the marched spine is bare; the avenues carry the shops), so a naive shop-count fence would have killed their v2 tram. Synthetic (22 edges) and fixtures (15) are an order of magnitude under the threshold and can never be fenced. Threshold: `shopsFronted < 5`. ### 2. Bug found + fixed en route: phantom tram stops on real graphs The stop projection mapped **every shelter in the town** onto the route with no distance gate — harmless on synthetic (2 shelters, both on the spine), nonsense on a real graph: **Newtown produced 149 stops** (~9 min of pure dwell at points the tram never passes). Added a **30 m** gate (a shelter sits `halfRoad+1.7` ≈ ≤16 m off its own centreline, so every genuine stop survives): **newtown 149 → 16, castlemaine 37 → 10**; synthetic **2** and fixtures **3** unchanged. ### 3. Ground polish at real intersections (ledger #4) — measured, NO fix needed Real Katoomba: **325 degree-3+ junctions, 28 under 30°, worst 4.3°** (near-parallel). Viewed at grazing eye level (the worst case for z-fighting) the worst junction reads **clean — no z-fight, no gaps**: continuous tarmac, correct footpath/kerb. Why it holds: the layers are already y-separated (road `0.0` / footpath `0.02` / kerb `0.06`) so nothing co-plane-fights across layers, and road-on-road overlap at junctions is **invisible by design** — `OVERLAP = 1.5` makes strips overrun their nodes on purpose, and they share one skin, one y and one merged draw, so a UV mismatch can't read on uniform asphalt. - *Cosmetic only (v4.0 candidate, not a defect):* at ultra-acute (<10°) junctions the footpath/kerb strips of the two near-parallel roads double up on the sliver between them. Reads busy, not broken. ### 4. Selector polish (ledger #5) — BLOCKED on E E's `web/assets/towns/index.json` hasn't landed (`build_towns.py` still WIP), so `REAL_TOWNS` stays hardcoded this round. It's a one-line swap to `fetch('assets/towns/index.json')` when E lands. **→ Lane F (B→F tram verdict + selector):** tram **runs** on synthetic, all fixtures, **newtown** and **castlemaine**; **fenced** on **katoomba, fremantle, bendigo** (`routeInfo.fenced` + `reason` are exposed for your smoke). Selector gating (always-on HUD vs `?dbg`) is your call — one line either way. **→ Lane A (finding, with measurements):** only a small slice of shops front a **main** edge on real towns — katoomba **7/69**, fremantle **4/79**, bendigo **7/35**, newtown 32/64, castlemaine 11/22. The real high street is coming out classified **`side`**, which is *why* the tram must be fenced on three towns. If your main/side classifier promoted shop-dense ways to `main`, the fence would lift and the tram would find the actual high street. Worth a look beyond the tram: **`onMain` also gates `gigs.js pickVenues` pub placement**. --- ## Round 19 (Fable's ROUND19 → Lane B) — the town selector (ledger #4, beta pull-forward, non-blocking) Shipped the in-game town picker; verified fresh Chromium. **No `index.html` seam** — it lives in `hud.js`, which already owns its DOM overlay. ### `hud.js` town selector A compact `