diff --git a/F-progress.md b/F-progress.md index f7ab2a7..4a1e0ef 100644 --- a/F-progress.md +++ b/F-progress.md @@ -4,6 +4,61 @@ --- +## Round 37 (v8 WAVE 0 — THE FLOOR) — the budget of record settled · two vacuous gates repaired + +**0.3 — THE BUDGET OF RECORD: 292 draws / 124,793 tris. The audit was right and the spike was +right; they were measuring different BEARINGS.** Two sessions disagreed by 90 draws (280 walked vs +191 teleport-walk). Measured on one tree, one box: worst draw **per bearing**, 12 bearings × 102 +stations down the synthetic spine — **0° 284 · 30° 248 · 60° 208 · 90° 177 · 120° 196 · 150° 214 · +180° 211 · 210° 207 · 240° 178 · 270° 182 · 300° 223 · 330° 267.** **110 draws of spread from the +camera direction alone**, and the peak sits at **yaw 0 — the default argument of +`DBG.teleport(x, z, ry = 0)`.** The audit took the default and landed on the worst bearing; the +spike supplied a yaw and landed mid-range. Both numbers were correct; they were not the same +quantity. Lane B's independent R37 walk (276 draws / **99,880** tris) and mine (282 / **99,878**) +agree on triangles **to 2** — same frame, two harnesses. **Viewport is irrelevant** (1280×720 and +2560×1440 identical to the byte). The R+1 dispose window is worth **+19 draws** (31 vs 27 live +chunks), not the 60–80 folklore claimed — the other ~100 draws between bookmark and walked-worst are +*place* and *bearing*. **THE PIN** (default boot, `7bd96e5`): synthetic **292 draws** (night, 31 live +chunks) / 120,145 tris; `?classic=1` 269 / 90,580; corpus tri worst **124,793 on fitzroy_real** — +the audit's "99–124k" range confirmed at its top. **Margin: 8 draws, ~75k tris.** Only 8 frames of +810 exceed 280; classic never does. Also found: **`?r=3` measures 307 draws and breaches the ≤300 +law** (ungated override, filed). Independently confirmed B's kerb change at **+0 draws / −8 tris**. +Headless SwiftShader — but draw/tri counts are counted in JS, not by the GPU, and the viewport +control proves it; **frame TIME is still unmeasured on any real GPU and no proposal should claim it.** + +**0.3b — THE SHARED INSTANCE CAP: 256.** Measured: an `InstancedMesh` costs **+1 draw at every N +from 32 to 2048**, and `N × tris/instance` **always submitted** (the instance bounding sphere spans +the town — at N=2048 all 368,640 prop tris go down the pipe from anywhere). So draws are not the +constraint; triangles are. 256 × a 2–4 tri billboard cell = 512–1,024 tris = **0.5% of budget**; +CPU to rewrite all 256 matrices, **0.01 ms/frame**. Binding companions: **≤24 tris/instance at the +cap**, and **spend it proximity-first** — measured anchor supply runs synthetic 246 poles / 6.8 km +to bendigo_real **7,325 poles / 188 km**, so 256 sprayed town-wide on bendigo is one instance per +730 m and statistically unencounterable. + +**0.2 — `smoke_tram` REBUILT.** It asserted `!!getObjectByName('tram')`, printed a SKIP and returned +on absence, and **passed on the fenced path** because `tram.js:110-114` adds a named EMPTY group. +Now STRICT with four arms: RUNS (route/stops, and the body moves **19.8 m over 45 frames** under the +*shell's own* loop) · BEHAVES (an isolated tram, fixed dt, 400 s: dwell time accounts to **exactly +9 × 3.5 s**, max cruising tick 0.4665 ≤ SPEED·dt 0.45, every discontinuity bounded by 2·LANE with +≥1 end reversal, riding **3.2 m off Lane A's own main-edge centreline**) · GENUINELY ABSENT on the +fenced katoomba_real (0 stops, **0 group children**, 0 m moved) · OFF under `?tram=0`/`?classic=1`. +**Both controls demonstrated every run** — the run-predicate pointed at the fenced town and the +absence-predicate pointed at the running tram must each go red. + +**0.5 — `classic_regression` GETS A NETWORK ALLOW-LIST**, derived from the **v2.0 tag at gate time** +(`git ls-tree` + v2.0's own manifest), never a deny-list. **The brief's shape would have missed the +breach it was written for**: the R36 widening was `models/peds/woman_dj_01.glb` — *same-origin* — so +"four depot GLBs + same-origin" is green straight through it. `/models/peds` is enumerated by the +v2.0 tree (exactly the covenanted 21 files; today's dir holds 32). The nine depot fetches are +**baseline, not a breach** — proven by booting the actual v2.0 tree and capturing its wire. +**Control every run**: injecting the R36 breach itself plus a never-existed asset turns the clean +verdict into exactly 2 named violations. 🟠 **Carried for Fable:** classic's fetch surface is +**+6 files** vs the real v2.0 tree — 5 audio (R11 `f7dd44f`) + `assets/towns/index.json` (R20/R21). +Allowed on the list, printed every run, **UNRATIFIED**; F did not improvise a verdict on a +six-epoch-old fact. Full record: LANE_F_NOTES §37. + +--- + ## Round 36 (THE v7.0 CLOSE, wave 2) — the gate, the freeze, the tag **Zero alpha-blockers stood** (Fable's wave-0 naked-boot playtest walked the whole loop by hand), diff --git a/README.md b/README.md index c3b9175..8806bdb 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,8 @@ master off: | `?weather=0` · `?tram=0` · `?winmap=0` | **on** | seeded weather · the tram loop · the parallax interior-window shader | | `?roster=v1` · `?pop=N` | stream | chunk-streamed citizen density is the baseline; `?roster=v1` restores the fixed roster | | `?dig=0` · `?stock=real` | dig on | crate-riffle on record bins · real GODVERSE sleeves in the stock | +| `?verge=0` | **off** | reverts the ground to the **pre-kerb-ruling** geometry (bitumen painted to the full corridor). John's v8 ruling made the 9 m band between kerb and shopfront **footpath**; this flag keeps the old geometry available forever as the gate's falsifiability control — the poster-clearance leg is asserted to FAIL under it | +| `?r=N` · `?shadows=0\|1` | auto | streaming radius and the sun-shadow pass. **Auto is load-bearing**: a big town (>120 shops or >200 street edges) gets radius 2 with shadows off. Forcing `?r=3` on the default town measures **307 draws**, i.e. over the 300 gate — these overrides are diagnostics, not supported boots | | `?live=1` · `?live=` | **off** | **tier 2** — live stock from the GODVERSE server (sold-in-the-real-shop means gone in the game). Opt-in by design: absent ⇒ byte-identical to tier 1, and the game never asks a question it has no reason to expect an answer to | | `?noassets=1` · `?plansrc=osm` · `?mute=1` · `?dbg=1` | off | asset-free (zero network) · OSM plan source · silence · the `window.DBG` capture/soak harness | | `?plansrc=osm&town=` | — | boot a **real Australian town**: fixtures `melbourne`/`katoomba`/`silverton`, or a real OSM cache `bendigo_real`/`castlemaine_real`/`fremantle_real`/`katoomba_real`/`newtown_real` (ODbL, `web/assets/towns/SOURCES.md`). **REAL ROADS:** a cache with `roads[]` (schema v2) builds the CityPlan street graph from the town's **actual OSM streets**; without `roads[]` a cache marches onto synthetic avenues. Or just **pick a town from the HUD selector** — no URL needed | diff --git a/docs/LANES/LANE_F_NOTES.md b/docs/LANES/LANE_F_NOTES.md index cbf08cf..c24958a 100644 --- a/docs/LANES/LANE_F_NOTES.md +++ b/docs/LANES/LANE_F_NOTES.md @@ -2030,3 +2030,303 @@ that completed in those runs matched run 3's verdicts line for line.* RETIRED · v6 collision RETIRED (the 2 a.m. commits were the one contact, now swept + gated). - **Tag `v7.0`** — annotated, **LOCAL ONLY** (the R35 close law: the tag waited for hands, and the hands played twice). Fable reviews, pushes main + tag, writes the epoch retro. + +--- + +## §37 — R37: v8 WAVE 0, THE FLOOR. F items 0.3 (the budget of record) · 0.2 (`smoke_tram`) · 0.5 (the classic network allow-list) + +### §37.1 THE BUDGET OF RECORD — SETTLED. **292 draws / 120,145 tris. The audit was right; so was the spike; they were measuring different bearings.** + +**THE PIN.** Default boot · synthetic golden town (seed 20261990) · tree `7bd96e5` (post-kerb) · +walked the main-street spine · **1280×720, and the number is viewport-independent (proven below)**: + +| | worst frame | where | live chunks | note | +|---|---|---|---|---| +| **draws, DEFAULT** | **292** of 300 | x −4.1, z 318.3 (s = 728 m), **NIGHT** | **31** (R+1 dispose window at max) | tris at that frame: 81,623 | +| **tris, DEFAULT** | **120,145** of 200,000 | x 4.1, z 60 (s = 466 m), NIGHT | 28 | draws at that frame: 238 | +| draws, `?classic=1` | 269 | same point | 31 | tris there 52,058 | +| tris, `?classic=1` | 90,580 | same point | 28 | draws there 215 | +| clean-load bookmark (`street_noon`) | 162–164 | — | ~22 | what the suite has been quoting for 20 rounds | + +**The worst-draw frame and the worst-tri frame are NOT the same frame.** Quote them as two maxima, +never as one view. The real margin is **8 draws** and **~75k tris**. Spend triangles, not draws — +the charter's law survives its own re-measurement, and is now tighter than it was written. + +**ACROSS THE CORPUS** (bearing sweep, 12 bearings × 8 m stations, default boot, `7bd96e5`) — the +synthetic golden town is the **draw**-worst town we ship; a dense real town is the **tri**-worst: + +| town | shops / edges | worst draws | worst tris | live chunks | +|---|---|---|---|---| +| **synthetic** (golden) | 493 / 22 | **292** (night) · 282 (noon) | 120,145 | 31 | +| **fitzroy_real** | 139 / 2,408 | 200 (night) · 199 (noon) | **124,793** ← corpus tri worst | 33–35 | +| newtown_real | 67 / 1,626 | 162 (night) | 118,620 | 33–35 | +| melbourne (fixture, r=3 + shadows) | — | 226 (night) | 80,926 | 26 | +| katoomba (fixture) | — | 161 (night) | 43,366 | 10 | + +**So the audit's tri range "99k–124k of 200k" is CONFIRMED and now pinned at its top: 124,793 on +`fitzroy_real`.** Real towns are draw-cheap and tri-dear (a real OSM grid has no single long straight +corridor to line chunks up down, but carries far more road geometry); the synthetic town is the +opposite. **A proposal must state which of the two it is spending.** + +**Rarity, so nobody reads 292 as typical:** over 810 stations at 2 m along the spine, exactly +**8 frames of 810 exceed 280 draws at night, 1 of 810 at noon; `?classic=1` never does** (worst 269). +p50 is 177 draws / 62,975 tris at night. It is a real peak on a real walk, not a median. + +#### The 280-vs-191 discrepancy, resolved: **it is the CAMERA BEARING, and nothing else.** + +The two sessions disagreed by 90 draws because one of them turned the camera and the other did not. +Measured on one tree, one box, one afternoon — worst draw **per bearing**, 12 bearings × 102 stations +down the same spine (synthetic, default, noon): + +| bearing | 0° | 30° | 60° | 90° | 120° | 150° | 180° | 210° | 240° | 270° | 300° | 330° | +|---|---|---|---|---|---|---|---|---|---|---|---|---| +| worst draws | **284** | 248 | 208 | 177 | 196 | 214 | 211 | 207 | 178 | 182 | 223 | **267** | + +**110 draws of spread from the camera direction alone**, on identical positions. And the peak sits at +**yaw 0** — which is the *default argument* of `DBG.teleport(x, z, ry = 0)`. (The spread is a +synthetic-town property: its spine is one long straight corridor, so one bearing lines up 31 chunks. +On the real corpus the same sweep spreads only 141→200 on `fitzroy_real` and 113→162 on +`newtown_real` — a real OSM grid has no such corridor. Another reason to say which town you measured.) + +- The city-patterns audit walked with `DBG.teleport(x, z)` and got **280**. It landed on the worst + bearing by taking the default. Reproduced here at **282** (8 m stations) / **292** (2 m stations, night). +- Lane B's R37 A/B walk, same method, got **276 draws / 99,880 tris**. My fixed-yaw-0 8 m walk at noon + gives **282 draws / 99,878 tris** — **the triangle counts agree to 2** across two independent + harnesses. Same frame. B's 6 fewer draws are station phase (102 one-way stations vs my 204 + out-and-back, which lands 2 m off B's grid on the return leg and finds a marginally worse one). +- The animal spike supplied a yaw and got **191**; my facing-travel walk gets **205 (noon) / 215 + (night)**. Same measurement, mid-range bearing. The spike's conclusion ("I cannot reproduce 280") + was correct *and* its number was correct — they are different quantities. + +**So: the audit's 280 is VINDICATED and is the number to spend against — rounded up to 292.** The +spike's 191 is retired as the budget of record: it is a bearing-specific figure, not a worst frame. + +#### What the dispose window is actually worth: **+19 draws, not +60–80.** + +The audit's *mechanism* claim reproduces exactly — the worst frame does carry **31 live chunks** +(R = 2 on a BIG_CITY town, DISPOSE_R = 3), and I measure 31–32 on synthetic and 34–35 on +`newtown_real`. But teleporting *directly* to the worst point and standing there (clean arrival, 27 +live chunks, 400 frames, fully settled) reads **265**, against **284** for the same point walked into. +So the R+1 residue is **+19 draws ≈ 4.75 draws per extra live chunk**. The other ~100 draws +separating the bookmark from the walked worst are the *place* and the *bearing*, not the streamer. + +#### The second under-reporting mechanism, named because it will bite the next measurer + +`CitizenSim` acquires near-tier rigs on a **per-frame budget** (`sim.js`: `NEAR_MAX 24`, and the +comment "if it fails this frame, ride as an impostor instead"). A sampler that renders **one** frame +per station — which is what `DBG.teleport()` does, and what every bookmark-style measurement does — +photographs a half-dressed street. Measured: standing still at the same point for 260 frames climbs +**222 → 231 draws**, and a 1 m-per-frame walk (17 m/s, outrunning the streamer) reads **211** where a +settled walk reads **213** and a settled *turn* reads 284. Any future budget claim must state its +settle policy or it is not comparable. + +#### Sensitivity — the pin is only meaningful with the boot stated + +| variant | worst draws | worst tris | verdict | +|---|---|---|---| +| default (`r` auto = 2, shadows off) | 282 / 292 (noon/night) | 99,870 / 120,143 | **the pin** | +| **`?r=3`** | **307 / 317** | 100,618 / 120,891 | **BREACHES the 300 gate.** 38–48 live chunks | +| `?shadows=1` | 243 / 249 | 137,566 / **157,635** | +38 draws, +38% tris (the depth pass redraws casters) | +| viewport 2560×1440 vs 1280×720 | **282 / 292 — identical** | **identical to the byte** | **resolution is irrelevant**; both are 16:9, and three's culling is frustum-shaped, not pixel-shaped | +| `melbourne` fixture (not BIG_CITY ⇒ r = 3 + shadows) | 210 / 226 | 55,094 / 80,926 | the small-graph towns are cheap | +| `katoomba` fixture | — / 161 | — / 43,366 | — | +| `newtown_real`, facing travel | 139 / 148 | 89,887 / 107,694 | real towns are draw-cheap, tri-dear | + +**Finding for the round (not F's to fix): `?r=3` on the default town measures 307 draws and breaches +the ≤300 law.** `index.html:147` picks R = 2 for a BIG_CITY (>120 shops or >200 edges) and R = 3 +otherwise; the `?r=` override is ungated and no gate covers it. It is a diagnostic flag, not a +supported boot — F has documented it as such in the README flags table and files the question of +whether to clamp it. Same story, smaller, for `?shadows=1` (tris 157,635, still legal). + +#### Honest limits + +Everything above is **headless Chromium / SwiftShader**. That is *not* a caveat on these numbers: +`renderer.info.render.calls` and `.triangles` are counted by three.js in JavaScript, downstream of +nothing the GPU does — SwiftShader cannot change a draw count. The viewport control above confirms it +empirically (identical to the byte at 4× the pixels). **What headless cannot tell you is frame +TIME**, and this pin says nothing about it. Nobody has ever measured procity's frame time on a real +GPU, and no proposal this epoch should claim a millisecond figure. If John ever wants the ms number, +it needs a hand on a machine with a display; the draw/tri budget does not. + +#### The re-pin — where the number is asserted, and what each line should now say + +F re-pins **§37.1 (this section)**. The rest are other authors' files; **flagged, not edited**: + +| file · line | carries | verdict | +|---|---|---| +| `docs/V8_SOMEONE_LIVES_HERE.md:162` (Laws) | "the walked worst frame is 280/300; tris 99–124k of 200k; every proposal states its draw cost against **280**" | **UPGRADE to 292 / 124,793.** The law is right, the figures were low. 280 → **292** (8 draws of margin, not 20); the tri range's top is now measured, not estimated. | +| `docs/REVIEW_CITY_PATTERNS.md:25` | "peaks at 280 draws of 300 … the real margin is about twenty" | **VINDICATED, and tighten.** 280 reproduces at 282–292. "About twenty" → **eight**. Its 31-live-chunk mechanism claim also reproduces exactly. | +| `docs/REVIEW_CITY_PATTERNS.md:119` | "a main-spine control of 263 / 123,602" | consistent with this session (fixed-yaw walk, 282/99,878 noon · 292/120,145 night); no correction needed. | +| `docs/THE_FRONTIER.md:145` | "the draw budget of record is **280/300 walked**" | **280 → 292.** | +| `docs/ANIMALS_ANSWER.md:22,111` | "**191 default / 167 classic** … can't reproduce 280 … re-pin it first" | **RESOLVED, and the spike was not wrong** — 191 is a *bearing-specific* figure, correct for its method. Retire it as the budget of record; the spike's instruction ("re-pin it first") is now discharged. | +| `docs/CITY_SPEC.md:693` | "≤ 300 draw calls in street mode, ≤ 200k tris" | **UNCHANGED.** That is the *cap*, not the measurement. Still the law; we now sit 8 under it. | +| `tools/flags_check.py:47` `BASE_DRAWS, BASE_TRIS = 164, 66000` | classic's clean-load `street_noon` drift baseline | **UNCHANGED and deliberately not the budget of record** — it is a *bookmark* number for drift detection (currently reads 162), and this session is the proof that a bookmark under-reports a walk by ~120 draws. Left alone so the ±40% drift arm keeps working; do not confuse the two. | + +*Method + rig: [`tools/qa/budget_walk.py`](../../tools/qa/budget_walk.py) — a no-store port-isolated +server over a `git archive`'d tree (immune to the other lanes editing the shared working tree +mid-measurement), four methods (`walk` continuous-motion through the real rAF loop sampling every +frame · `sweep` position × bearing · `dwell` steady-state · `stepwalk` reproducing the audit's +`DBG.teleport` method), `--fixed-yaw`, `--viewport`, `--holdframes`, `--extra`.* + +**Independent confirmation of Lane B's `+0 draws` kerb claim.** Same method, same stations, pinned +`62c0a21` vs post-kerb `7bd96e5`: noon **282 → 282 draws, 99,878 → 99,870 tris**; night **292 → 292, +120,151 → 120,143**. +0 draws and −8 tris at the worst frame, measured by a harness B did not write. + +### §37.2 THE SHARED INSTANCE CAP — SETTLED: **256.** + +*One number, for any future town-wide standing layer (fauna, flock, street props, washing, litter). +Three proposals independently invented 120, 250 and "plus gulls" for the same layer; this ends that.* + +**Measured cost model** (`InstancedMesh` sprayed over an 800 m box, default boot, seg 2, re-rendered +per sample — note `DBG.info()` alone reads the *previous* frame, which is how a first cut of this +probe reported a triumphant +0 for everything): + +| N | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | +|---|---|---|---|---|---|---|---| +| draws | **+1** | +1 | +1 | +1 | +1 | +1 | +1 | +| tris, 2-tri cell | 64 | 128 | 256 | **512** | 1,024 | 2,048 | 4,096 | +| tris, 180-tri prop | 5,760 | 11,520 | 23,040 | **46,080** | 92,160 | 184,320 | 368,640 | +| CPU, rewriting every matrix | 0.005 ms | 0.005 | 0.01 | **0.01** | 0.015 | 0.015 | 0.05 | + +**+1 draw at every N, from 32 to 2048** — confirmed, so draws are *not* the constraint. **Triangles +are, and they are always submitted**: the instance-aware bounding sphere spans the whole town, so the +layer is effectively never frustum-culled — at N = 2048 standing in one street, all 368,640 prop +triangles go down the pipe. The cost is exactly `N × tris_per_instance`, everywhere, always. + +**THE CAP: N = 256 live instances per shared standing layer, one InstancedMesh, town-wide.** Because: + +1. **Triangles.** At the geometry these layers actually use (a 2–4 tri billboard cell), 256 costs + 512–1,024 tris — **0.3–0.5% of the 200k budget, ~1% of the measured 80k headroom**. Ten such + layers would still be under 2% of budget. The cap is generous where it is cheap. +2. **It carries a companion, or it means nothing.** The cost is `N × tris/instance`, so the cap is + binding only with a per-instance ceiling: **≤ 24 tris per instance at the cap** (6,144 tris, + ~3% of budget). A heavier mesh spends the same ceiling on fewer instances. A 180-tri prop at 256 + is 46,080 tris — **over half the entire measured headroom for one layer**, and it must not. +3. **Encounter density — the number is above the covenanted town's whole anchor set.** Measured + anchor supply (derived on the plan graph: a pole every 24 m of main+side, a tree every 18 m of any + edge): synthetic **246 poles / 366 trees over 6.8 km**; `darwin_real` 1,773 / 2,407; `katoomba_real` + 3,373 / 4,656; `newtown_real` 4,408 / 6,049; `fitzroy_real` 4,549 / 6,169; `bendigo_real` + **7,325 / 9,759 over 188 km**. So on the default boot 256 exceeds the entire pole set — the cap + never thins the layer there, the anchors do. On the real corpus 256 is **3–14% occupancy**. +4. **Therefore, binding corollary: the cap is spent PROXIMITY-FIRST, never sprayed town-wide.** + Allocate the 256 to the anchors nearest the camera and re-anchor on chunk build/dispose (Lane B's + R37 `ctx.onChunkBuilt`/`onChunkDisposed`, item 0.4 — now wired). A layer that scatters 256 + instances across bendigo's 188 km of road is one instance per 730 m and is *statistically + unencounterable* — the exact failure the review's magpie correction named. +5. **CPU is a non-issue at this cap**: 0.01 ms/frame to rewrite all 256 matrices, 0.06% of a 16.7 ms + frame. It only becomes interesting past ~2048. + +**Also re-confirmed while there** (the review's biggest strategic finding, reproduced independently): +**all five real towns sampled are 100% `use:'shop'` lots with the single district `mainstreet`.** +Synthetic carries six districts and `{shop 452, house 145, stall 40, yard 36, infill 7, anchor 1}`. +Every residential/market/yard idea is still synthetic-only until Ruling 2's civic fetch lands. + +### §37.3 `smoke_tram` — the vacuous gate, rebuilt (item 0.2) + +**What it was** (`flags_check.py:617-630`, R9 → R36): one assertion, +`!!scene.getObjectByName('tram')`; a printed SKIP and an early `return` on absence; warn-level. +Three faults, each fatal on its own: + +1. **It passed on the fenced path.** `tram.js:110-114` adds a **named EMPTY group** to the scene + before returning the no-op stub, so the single assertion is TRUE on every town where the tram + deliberately does not exist. The gate was green precisely where it was meant to be looking. The + repaired gate now *prints that as a standing record* on every run: + `[record] the pre-R37 assertion returns TRUE here — a 0-child group on a town with no tram.` +2. **SKIP-and-return on a missing subject** — vacuous-gate law, inside our own suite, since R9. +3. **It never asserted the tram was a tram** — no route, no stops, no motion. + +**What it is now — STRICT, four arms, both controls demonstrated every run:** + +- **RUNS** (default boot, synthetic): route resolved (6 main edges, 810 m, 172 shops fronted), + 2 stops, and — under the **shell's own rAF loop, nothing driven by the harness** — the body moves + **19.8 m over 45 frames across 45 distinct positions**. +- **BEHAVES** (an *isolated* tram built from the same plan into a throwaway scene, fixed dt = 0.05 s, + 400 s — so the shell's own tick cannot contaminate the integration): travels **3,300 m of an 810 m + route**; **9 stop dwells accounting for exactly 31.95 s of door time = 9 × DWELL 3.5 s**; max + cruising tick **0.4665 m ≤ SPEED·dt 0.45 m**; **4 end reversals**, each an exact 2·LANE lane swap, + and **every** discontinuity bounded by 2·LANE (0.681–6.402 m) so nothing else is teleporting it; + and it rides **3.2 m off the centreline (median, range 2.98–3.20)** measured against **Lane A's own + main-edge segments**, not against tram.js's polyline. LANE is 3.2. +- **GENUINELY ABSENT** on the fenced `katoomba_real`: `fenced: true`, **0 stops, 0 group children, + 0 m moved over 30 frames**, reason string on record. If katoomba ever stops being fenced the gate + **FAILS** with instructions to re-pick (R21: katoomba 3 / fremantle 2 / bendigo 1 shops fronted) — + it does not skip. An absence arm without a subject is the original bug wearing a new hat. +- **OFF**: `?tram=0` and `?classic=1` — `PROCITY.tram === null` **and** no `'tram'` in the scene. +- **CONTROL A**: the RUN predicate pointed at the fenced town's subject → **RED, required.** + **CONTROL B**: the ABSENCE predicate pointed at the running tram → **RED, required.** Both + predicates are extracted as functions for exactly this reason; each is *proven* to discriminate on + this tree in this run rather than asserted to. + +**Three findings for Lane B, filed not fixed** (B's file; none is a defect the gate should hide): +the end-of-line reversal **teleports the tram 6.4 m sideways** in one tick (`dir` flips ⇒ the LANE +offset mirrors) — a visible lane-swap pop at both ends; the stop snap moves it up to `EPS` = 2.5 m; +and at each polyline bend the lane offset kinks by `2·LANE·sin(θ/2)` (measured up to 0.68 m). All +three are bounded by 2·LANE and the gate now asserts exactly that, so any *new* discontinuity is red. + +### §37.4 `classic_regression` gets a NETWORK ALLOW-LIST (item 0.5) + +`classic_regression` had made **no network assertion at all** for 21 rounds — it watched the plan +fingerprint, the flags, the draws, the console, and nothing watched the wire. That is why R36's +fetch-surface widening needed a brand-new smoke to catch it. + +**The authority is git, not an opinion.** The allow-list is *derived from the `v2.0` tag at gate time*: + +- same-origin asset ⇒ its path must exist in `git ls-tree -r v2.0 -- web/`; +- depot asset (`digalot.fyi/3god/a/`) ⇒ its basename must appear in **v2.0's own** + `web/assets/manifest.json`; +- code (same-origin `.js`/`.mjs`/document) is allowed as a class — a module that fetches nothing is + not a fetch-surface change. Every **asset** is enumerated. `blob:`/`data:` are not network + (GLTFLoader mints one blob per embedded texture — 60+ of them, all noise). + +**THE BRIEF'S SHAPE WOULD NOT HAVE CAUGHT THE BREACH IT WAS WRITTEN FOR.** The round instructions +say "the four v2-era depot furniture GLBs plus **same-origin**". The R36 breach was +`/models/peds/woman_dj_01.glb` — **same-origin**. An allow-list with a same-origin free pass is green +straight through it. Here `/models/peds` is enumerated by the v2.0 tree, which contains **exactly the +covenanted 21 files** (17 `PED_NAMES.normal` + 2 comical + `walk.glb` + `idle.glb`) — git-verified: +v2.0's `rigs.js` roster is byte-identical to today's post-`2fd4c1c` list, and today's +`web/models/peds/` holds **32** files, so 11 post-v2 bodies/clips are excluded by construction. + +**The nine depot fetches are BASELINE, not a breach, and must never be "fixed" away.** Four street +(`bench` · `bin` · `bus_shelter` · `food_cart` — `furniture.js` `GLB_FILES`, byte-identical at +`24cef5a` and at `v2.0`) plus five record-shop fittings (`counter_till` · `crate_stack` · +`listening_booth` · `record_crate` · `wire_shelf`) reached through `useGLB: !NOASSETS`, whose wiring +in `index.html` is byte-identical to v2.0. Proven the hard way rather than argued: I checked out the +**actual v2.0 tree**, served it, booted it and captured its wire — it fetches the same nine. + +**Anti-vacuous arm**: a REQUIRED v2 core (the four depot street GLBs, `walk.glb`, `idle.glb`, a named +ped body, `manifest.json`) must all be observed, or the clean verdict is refused as unearned. + +**THE CONTROL, run every time, not once**: after the verdict is taken, the gate injects +**`models/peds/woman_dj_01.glb` — the R36 breach itself, replayed** — plus +`assets/gen/__gate_control_v8_palette.jpg`, a name that has never existed (a 404 is still a request +on the wire), and asserts the clean verdict becomes **exactly 2 violations, named**. Green: +`the allow-list DISCRIMINATES — … turned a clean verdict into exactly 2 violations`. + +#### 🟠 MEASURED AND CARRIED FOR FABLE: classic's fetch surface has a **post-v2.0 delta of +6 files** + +Booting the real `v2.0` tree and diffing its wire against today's `?classic=1`: + +| file(s) | landed | round | +|---|---|---| +| `assets/audio/ambience-street-day.ogg`, `-night`, `ambience-rain`, `music-record-shop`, `roomtone-retail` | `f7dd44f` | R11, the WebAudio engine | +| `assets/towns/index.json` | `078245f` → `4b01449` | R20/R21, the town selector | + +Nothing else. **They are allowed on the list** — they have shipped through 26 rounds and five tags, +and making the suite permanently yellow over settled behaviour is how a warn becomes wallpaper — but +they are **PRINTED every run** so they cannot go invisible, and they are **UNRATIFIED**. Ruling +needed: either they are part of what the covenant preserves (say so, and the list carries them by +right), or classic should not be fetching them (and they get gated like the DJ bodies were). +**F did not improvise a verdict on a six-epoch-old fact.** + +### §37.5 Housekeeping + +- **`flags_check.py --only `** for single-gate development runs. It prints a + `PARTIAL RUN … (NOT a suite verdict)` banner and a `PARTIAL-GREEN` verdict, so a subset can never + be mistaken for a suite pass in a log. `qa.sh` invokes `flags_check.py` with no arguments; unaffected. +- **README flags table** gains `?verge=0` (Lane B's R37 falsifiability control — B flagged that the + table is F's file) and a row for `?r=N` / `?shadows=0|1` naming the `?r=3` breach measured above. +- Regression check on the post-Lane-B tree (`7bd96e5`), the three gates this session touched or that + B's ground change could move: `classic_regression` · `default_boot_gate` · `smoke_tram` — + **0 fails / 0 warns.** Classic fp `0x5f76e76` holds at **162 draws / 16,642 tris**; the default + boot pins to gig golden `0xec7a2d39` at 131 draws / 23,382 tris; dig REACHABLE naked. The full + `qa.sh --strict --matrix` belongs to the later F session with the kerb gate, per the round order.