diff --git a/F-progress.md b/F-progress.md index 8534782..0ad91b2 100644 --- a/F-progress.md +++ b/F-progress.md @@ -4,6 +4,28 @@ --- +## Round 20–21 (v4.0-beta THE FIVE TOWNS) — F never ran R20; closed R21 + +**R20: F never ran** (no gate, no tag) — the honest record is in LANE_F_NOTES §20. Unlike R18 (where F ran +and *held* on evidence), the slot simply didn't execute; the round also left C's door-soak, B's selector +index, and D's relocation finding open. R21 closed all four. + +**R21: the beta gate.** Waves [A,B,E] → [C,D] → [F]. All five lanes in; F gated: +- **Matrix 10 towns × 7 gates** — boot/determ/district/roads/**tram**/noassets green on all ten; selfcheck + 154141/154141; `qa.sh --strict` GREEN. +- **Tram dimension (new)** — B's R20 ruling verified exactly: Newtown runs 16 stops (was 149 — B's phantom + fix), Castlemaine 10; Katoomba/Fremantle/Bendigo **fenced** at 3/2/1 shops fronted. Needed a new seam: + the shell now exposes `window.PROCITY.tram` (B built `routeInfo` for F's smoke; nothing published it). +- **⚠ venue_night re-measure — recorded, premise falsified.** A's cap worked (posters 438→111) but the + density widening ate it: katoomba **200,965 (+965) → 221,935 (+21,935, +11%)**; bendigo 201k. Draws fine + (151/300). Filed as R22's first item (the tri-diet backlog already lives there). +- **Selector ruling** — always in the HUD (the towns *are* the product), + the corollary that F's harness + must hide the HUD for beauty shots (the R19 alpha shot's selector-in-frame was F's own gap). +- **Beta money shot** — [Fremantle's real street at golden hour](docs/shots/v4_beta/fremantle_mainstreet.png): + a corridor of shopfronts, footpaths, a crossing, and a genuinely busy crowd. Tag **`v4.0-beta`**. + +--- + ## Round 18–19 (v4.0-alpha REAL ROADS) — F held R18 correctly, then closed R19 **R18: F did NOT run — the gate would have failed by design, so F held the tag** and filed the failure list diff --git a/README.md b/README.md index 7dff6a2..9ded626 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,17 @@ master off: | `?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 | | `?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`). **v4.0-alpha REAL ROADS:** a cache with `roads[]` (schema v2) builds the CityPlan street graph from the town's **actual OSM streets** — walk Katoomba's real main street; without `roads[]` a cache marches onto synthetic avenues | +| `?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 | + +### v4.0-beta — the five towns, at density + +Five real Australian towns (**Katoomba, Newtown, Fremantle, Bendigo, Castlemaine — 292 shops**) boot on +their **actual OSM street graphs**, at real retail density: secondhand heroes keep their footfall while the +street around them gets ~4× busier (texture, never a takeover). Venues bias toward the retail cluster, the +tram runs only where it fronts a real high street (Newtown/Castlemaine — elsewhere it was "a highway bus", +so it's fenced), and the in-HUD **town selector** reads the towns index, so you can just pick one. Every +town: deterministic, districted, silent under `?noassets`, `?classic=1` still byte-identical to v2. +See [`docs/shots/v4_beta/`](docs/shots/v4_beta/) and the charter, [`docs/V4_REAL_MAP.md`](docs/V4_REAL_MAP.md). | `?seed=N` | `20261990` | town seed | **Release tour:** [`docs/shots/release_v3_1/contact.html`](docs/shots/release_v3_1/) — the money shots on diff --git a/docs/LANES/LANE_F_NOTES.md b/docs/LANES/LANE_F_NOTES.md index d778435..6a554f7 100644 --- a/docs/LANES/LANE_F_NOTES.md +++ b/docs/LANES/LANE_F_NOTES.md @@ -728,3 +728,66 @@ town selector. F ran two things: the opt-in `--matrix` warn-gate, not a blocking gate. Beta hardening: A caps posters per real town. The alpha's job was **real roads that boot, stream in budget in play, place a district, and read as a real place** — that shipped; the venue_night stress view is the one filed edge. + +--- + +## 20. Round 20 — v4.0-beta THE FIVE TOWNS (density). **F never ran — the honest record.** + +R20 widened the towns (E: katoomba 20→80, five towns to 292 shops, "subtle" enforced by construction), +proved the directive from the crowd side (D's A/B: heroes kept footfall 17→19 while the street got 3.8× +busier), capped posters 438→31 (A), and ruled the tram by shop adjacency (B: the alpha tram fronted **zero +shops on 4 of 5 real towns** — "it really was a highway bus"). Excellent round. + +**F did not run, and there was no tag.** Unlike R18 — where F ran the gate and *held* on evidence — R20's F +slot simply never executed. The round also left C's density door-soak undone, B's selector still hardcoding +`hud.js:11` instead of E's index, and D's relocation finding (katoomba's pub 1,000 m from the retail cluster +— a gig with no passing crowd) without an owner. R21 closed all four. + +## 21. Round 21 — the v4.0-beta CLOSE. F: the beta gate + the tag (ledger #6). + +Waves ran [A, B, E] → [C, D] → [F]. A biased `pickVenues` toward retail-cluster adjacency (D's finding) and +re-pinned once; B derived the selector from E's `index.json`; C soaked the five towns' doors at density; D +verified the relocation (**A's bias PASSES**); E pulled 22 towns / 1192 shops forward as non-gating data. + +### The matrix — 10 towns × 7 gates (`--matrix`) +`boot · determ · district · roads · tram · noassets` **green on all ten**. Two budget flags (below). +Selfcheck **154141/154141**, `qa.sh --strict` GREEN. + +### Tram (#6c) — B's R20 ruling verified exactly +| town | verdict | +|---|---| +| newtown_real | **runs, 16 stops** (B's phantom-stop fix: was 149) | +| castlemaine_real | runs, 10 stops | +| katoomba / fremantle / bendigo | **fenced** — 3 / 2 / 1 shops fronted, all < the 5-shop floor | + +New seam: the shell now exposes `window.PROCITY.tram` — B built `routeInfo` *for F's smoke* but nothing +published it. F owns index.html, so F wired it. The matrix reads `{fenced, stops, shopsFronted}`. + +### ⚠ The venue_night re-measure (#6b) — RECORDED, and the premise came out false +The brief expected A's poster cap to close F's R19 `+965`-tri edge. **It did not — it widened:** +| | R19 | R21 | +|---|---|---| +| katoomba_real venue_night | 200,965 (+965, **+0.5%**) | **221,935 (+21,935, +11%)** | +| bendigo_real venue_night | — | 201k (**+0.5%**) | +| fremantle / newtown / castlemaine | — | 184k / 179k / 112k ✓ | + +**A's cap worked** (posters 438→111). The cause is the *density widening*: katoomba 19→72 shops + D's 3.8× +busier street more than ate the savings. **Draws are fine everywhere** (151/300 — half budget); this is +tris-only, at the worst night stress view. Not a blocking gate (it rides the opt-in `--matrix` warn), and +the brief's instruction was "record the new number" — recorded. **Filed as R22's first item**, where the +tri-diet backlog (instrument LOD · tram tri diet) already lives. katoomba is the outlier: a 966-edge graph +carrying 72 shops. + +### Ruling (#6d) — selector gating: **always in the HUD**, not `?dbg`-gated +THE REAL MAP's product *is* the towns; gating their discovery behind a debug flag would hide the epoch's +headline feature. It's unobtrusive, shows friendly names, and lives in the HUD overlay. **Corollary (F's own +gap):** money shots must hide the HUD — the R19 alpha shot had the selector in-frame because F's harness +screenshotted the full viewport. The beta shot hides it. + +### The beta money shot (#6e) +[`docs/shots/v4_beta/fremantle_mainstreet.png`](../shots/v4_beta/fremantle_mainstreet.png) — Fremantle's real +street at golden hour: buildings lining both sides down the corridor, footpaths, a crossing, gum trees, +streetlamps, and a genuinely busy crowd (the density widening, visible). 126 draws / 167k tris, HUD hidden. +Posed by projecting the densest **spatial** shop cluster (10 shops within 60 m) onto its front edge and +standing on the road — per-edge shop counts are ~1 on a real graph, so "densest edge" is the wrong pose +heuristic for real towns. diff --git a/docs/shots/v4_beta/fremantle_mainstreet.png b/docs/shots/v4_beta/fremantle_mainstreet.png new file mode 100644 index 0000000..8f56528 Binary files /dev/null and b/docs/shots/v4_beta/fremantle_mainstreet.png differ diff --git a/tools/qa/town_matrix.py b/tools/qa/town_matrix.py index e4c3471..6d3805b 100644 --- a/tools/qa/town_matrix.py +++ b/tools/qa/town_matrix.py @@ -22,6 +22,10 @@ ROOT = pathlib.Path(__file__).resolve().parent.parent.parent PORT = 8130 HOST = f'http://127.0.0.1:{PORT}' STREET_DRAWS_MAX, STREET_TRIS_MAX = 300, 200_000 +# [R21 ledger #6c] B's R20 tram ruling: on a REAL-ROADS town the tram only runs if its best main chain +# fronts ≥5 shops — otherwise it's "a highway bus" and gets fenced. These two run; the other three are fenced. +TRAM_RUN = {'newtown_real', 'castlemaine_real'} +TRAM_STOPS_SANE = (2, 40) # B fixed the phantom-stop bug en route (Newtown: 149 → 16) # the matrix: (row-label, boot-query). Synthetic hero seeds + 3 fixtures + E's 5 real AU caches. MATRIX = ( @@ -49,11 +53,13 @@ async () => { D.shot('venue_night'); // busiest default view: the venue block at night await new Promise(r => setTimeout(r, 500)); const i = D.info(); + const tr = P.tram ? { fenced: !!(P.tram.routeInfo || {}).fenced, stops: P.tram.stops | 0, + shopsFronted: (P.tram.routeInfo || {}).shopsFronted } : null; // [R21] B's fence verdict return { name: plan.name, shops: (plan.shops || []).length, venues, gigs: (plan.gigs || []).length, posters: (plan.posters || []).length, determ: g1 === g2, draws: i.drawCalls, tris: i.tris, mode: rep.mode || (src === 'synthetic' ? 'synthetic' : 'marched'), - edges: (plan.streets.edges || []).length }; + edges: (plan.streets.edges || []).length, tram: tr }; } """ @@ -104,9 +110,20 @@ def run_town(new_page, query, label): # (mode='roads'); synthetic/fixture towns are marched/synthetic by design (always ✓). mode = d.get('mode', '?') row['roads'] = ((mode == 'roads') if is_real else True, f"{mode},{d.get('edges', 0)}e") + # [R21 #6c] tram: B's R20 ruling — a real-roads town runs the tram only if its best main chain fronts + # ≥5 shops; otherwise it's FENCED (empty tram group, 0 stops, no errors). Synthetic/fixtures always run. + t, key = d.get('tram'), (label.split('/', 1)[1] if '/' in label else label) + if is_real and key in TRAM_RUN: + row['tram'] = (bool(t) and not t['fenced'] and TRAM_STOPS_SANE[0] <= t['stops'] <= TRAM_STOPS_SANE[1], + f"run {t['stops']}st" if t else 'absent') + elif is_real: + row['tram'] = (bool(t) and t['fenced'] and t['stops'] == 0, + f"fenced/{t.get('shopsFronted', '?')}sh" if t else 'absent') + else: + row['tram'] = (bool(t) and not t['fenced'], f"run {t['stops']}st" if t else 'absent') except Exception as e: row.setdefault('name', '?'); row.setdefault('shops', 0) - for g in ('boot', 'determ', 'budget', 'district', 'roads'): + for g in ('boot', 'determ', 'budget', 'district', 'roads', 'tram'): row.setdefault(g, (False, str(e)[:24])) finally: pg.close() @@ -134,9 +151,9 @@ def main(): except ImportError: sys.exit('playwright not installed — tools/.venv/bin/python -m playwright install chromium') - print(f"\033[1mTOWN-MATRIX SMOKE\033[0m ({len(MATRIX)} towns × 6 gates (incl. the R19 roads dimension) · the v4 real-map scout evidence)") + print(f"\033[1mTOWN-MATRIX SMOKE\033[0m ({len(MATRIX)} towns × 7 gates (roads + tram dimensions) · the v4 real-map scout evidence)") srv = ensure_server() - GATES = ['boot', 'determ', 'budget', 'district', 'roads', 'noassets'] + GATES = ['boot', 'determ', 'budget', 'district', 'roads', 'tram', 'noassets'] rows = [] try: with sync_playwright() as p: @@ -170,7 +187,7 @@ def main(): if fails: print(f"\033[31m● {fails} gate failure(s)\033[0m across {len(rows)} towns — the matrix is not clean.") sys.exit(1) - print(f"\033[32m● MATRIX GREEN\033[0m — {len(rows)} towns (synthetic + fixtures + real caches) pass all 6 gates.") + print(f"\033[32m● MATRIX GREEN\033[0m — {len(rows)} towns (synthetic + fixtures + real caches) pass all 7 gates.") sys.exit(0) diff --git a/web/index.html b/web/index.html index 6946c33..b951660 100644 --- a/web/index.html +++ b/web/index.html @@ -448,6 +448,8 @@ window.PROCITY = { plan, scene, camera, renderer, chunks, lighting, player, skin // decide there's no gig layer at all). `.state` is a live getter: quiet|doors|on|done venuePresentation, // [Lane F R12] Lane B frontage + posters (null flags-off) venueQueues, queueCountOf, // [Lane F R13] Lane D outdoor queue per venue + count accessor (F's smoke reads it) + tram, // [Lane F R21] Lane B's tram — `.routeInfo` carries the R20 shop-adjacency verdict + // ({fenced, reason, shopsFronted}) + `.stops`; B built it FOR F's smoke. Null flags-off. // [Lane F R16 — THE FLIP] the flag-intent surface: what SHOULD be on this boot (the gates verify intent vs // reality). Default boot = all four flipped flags true; ?classic=1 = all false + classic true; each `=0` opts out. flags: { classic: CLASSIC, gigs: GIGS_ON, weather: flagOn('weather'), winmap: flagOn('winmap'), tram: flagOn('tram') },