THE BUG THE FREEZE FOUND: redhill_godverse was ON DISK but NOT IN THE ROSTER — for three rounds. The v5 provenance table needed real numbers, so I measured instead of carrying the v4 row forward. The count didn't match: 23 caches on disk, 22 rostered. The missing one was redhill_godverse — THE TOWN THE ENTIRE v5 EPOCH WALKS TO. Mine, squarely. index.json is Lane E's file (write_index()). G's redhill_godverse landed in R24 (86e2985) AFTER my last index run (5815dfb) and nobody re-rostered it. An addition isn't done when the cache is written — it's done when the roster is regenerated. That is the exact mirror of my own R24 lesson ("a retirement isn't done when the cache is deleted; it's done when the consumers are swept"): I wrote the lesson for deletions and missed its reflection for additions. WHY FOUR GREEN ROUNDS NEVER CAUGHT IT — a gate-shape lesson. Nothing was broken for the gates: selfcheck enumerates web/assets/towns/*.json DIRECTLY (so it saw the town; A even pinned its goldens) and F's crate smoke boots BY KEY (?town=redhill_godverse). The roster's only consumer is B's HUD selector (hud.js, my R20 ledger #2 design). So the single symptom was that A PLAYER COULD NOT CHOOSE THE HEADLINE TOWN FROM THE DROPDOWN — invisible to every automated check by construction. A gate that reads around the artifact under test cannot test it: the vacuous-gate species, one layer out. Fixed: re-ran write_index() -> 23 rostered, 23 on disk, 0 missing. Only index.json moved (every cache byte-identical again). selfcheck ALL GREEN 156,212, golden 0x3fa36874 untouched. qa.sh --strict --matrix 7 passed / 0 failed / 0 warn. -> F (#5, the tour): the money shot walks Musgrave Road into Monster Robot Party. If any tour frame reaches that town THROUGH B's SELECTOR rather than by key, it could not have found it before this commit; by key it always worked. Worth one glance at your framing path. -> B: the dropdown now carries both godverse towns. Your `${t.state ? ', ' + t.state : ''}` handles their empty state gracefully — nothing needed, and the defensive write is why this cost nothing cosmetically. -> G: your godverse caches carry no `state`, so they roster as state:''. Harmless (B degrades cleanly). For "Red Hill, QLD" in the picker, emit `state` — write_index() already prefers the cache's own field. PROVENANCE v5-FINAL. The ⟨v5.0-FINAL⟩ rows are measured, not inherited — the town-pack row still claimed v4's "22 towns / 1192 shops", stale since my R24 ballarat retirement and redhill build (now 21 real / 1196 shops / 299 heroes, + both godverse towns = 23 rostered). Added the two v5 art rows: the real-stock atlas (1 crate, 120 items, Monster Robot's own POS, sku_ ids) and the mint atlases (14 crates, 224 items, seeded from real dealgod listings, mint_ ids). These are the table's FIRST AMBER ROWS — everything before v5 was green web-ok; real product photography is the first asset class this project ships that a human must clear before public release. I VERIFIED MY OWN PROSE AND IT CAUGHT ME: I first wrote the mint crates as "6 record · 6 book · 3 toy" — that is the breakdown of all FIFTEEN crates, which includes Monster Robot's REAL record crate. The 14 mint crates are 5 record · 6 book · 3 toy. A count attributed to the wrong population, one line from being frozen into the release record. Every other claim in the table re-measured true (21/1196/299/8 states/23 rostered/roster==disk/72/37/120 items/224 items/both zones in-house-green). THE LICENCE LINE'S STORY, recorded as a mechanism. The amber rows are guarded by exactly one printed line, so the freeze says why it took two rounds to make honest: R23's glob matched 0 files and returned 0; R25's permissive `or` fallback let the print go silent while the check still passed — the flag stopped reaching a human on real product photos while the gate said OK. Now: one spelling, one lookup with one owner, and the line is COUNTED (judged N => N lines, or FAIL). Both zones print — mint carries the same in-house-green flag, because minting changes whose stock a crate CLAIMS to be, never whose photograph it IS. Frozen today at: atlas-QA OK — 15 per-shop atlas(es) valid, 15 licence line(s) shown, 0 warning(s). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.2 KiB
Town-cache data sources & licence (web/assets/towns/)
Lane E owns this file (ROUND17 ledger #6). Every real-town cache here is derived from
OpenStreetMap data and ships under OSM's licence. This notice + the license/attribution
fields on every <key>.json are the attribution that travels with the data.
Licence — OpenStreetMap, ODbL 1.0
© OpenStreetMap contributors. Data available under the Open Database License (ODbL) 1.0. https://www.openstreetmap.org/copyright · https://opendatacommons.org/licenses/odbl/1-0/
The caches are a produced work derived from OSM via the Overpass API (overpass-api.de), filtered
to on-theme shop=* points, deduped, suburb-filled, and type-mapped by pipeline/build_towns.py.
Attribution ships in-repo (this file) and in every cache ("license":"ODbL 1.0",
"attribution":"© OpenStreetMap contributors"). If a rendered/public build surfaces this data, keep
the "© OpenStreetMap contributors (ODbL)" credit visible.
Provenance table
index.json is the machine-readable roster (key/town/state/shops/roads) — read it rather than
hardcoding a list. Every cache carries the same terms; per-town numbers live in each cache's counts.
The pack: 21 real towns · 1196 shops · 299 heroes (+ Lane G's newtown_godverse and redhill_godverse
= 23 rostered in index.json), every one fetched from OSM Overpass with a bounded per-town bbox, ODbL
1.0, raw snapshots in _raw/ (shops + roads per town), fetched 2026-07-16 (redhill_real 2026-07-17).
⟨v5.0-FINAL⟩ roster fix (R27):
redhill_godverse— the town the whole v5 epoch walks to — was on disk but missing fromindex.jsonfor three rounds. G's cache landed after my lastwrite_index()run and nobody re-rostered it. Every gate stayed green becauseselfcheckreads the directory directly and F's smoke boots the town by key; only B's HUD selector reads this roster, so the sole symptom was that a player could not choose it from the dropdown. Mine to own: the index is Lane E's, and an addition isn't done when the cache is written — it's done when the roster is regenerated. (The mirror of R24's lesson, where a retirement wasn't done until the consumers were swept.) See LANE_E_NOTES R27.
| state | towns |
|---|---|
| NSW (6) | katoomba · newtown · glebe · marrickville · newcastle (Hamilton strip) · bowral |
| VIC (6) | fitzroy · brunswick · geelong · bendigo · castlemaine · daylesford |
| QLD (2) | westend · redhill (Monster Robot Party's real street — see below) |
| WA (2) | fremantle · northbridge |
| TAS (2) | hobart · launceston |
| SA (1) | adelaide |
| ACT (1) | braddon |
| NT (1) | darwin |
redhill_real — the v5 crate's real street (R24, ledger #3)
Red Hill, Brisbane QLD · centre -27.4553, 153.0064 · span 2.4 km · 36 shops (9 heroes + 27 texture,
−29 subsampled) · 884 roads · median NN 73 m, hub 5/36. Built because v5's 120 real records come from a
real shop — Monster Robot Party, 147 Musgrave Rd — and the shop had no street. Musgrave Road is in
roads[] (41 ways, primary + residential), which was the point of the round. This cache is the DONOR
Lane G runs godverse_town.py against → redhill_godverse.
The shop itself is not in OSM (no shop=music node in the bbox), so G injects it from the census —
it cannot arrive via this fetch. See LANE_E_NOTES R24 for the seating hazard handed to G/A.
Retired (R23, counted): toowoomba_real — D's clustering audit measured it DEAD (0 patronage finds
in 1417 checks); a re-bbox onto the Ruthven St heart fixed the spacing metric (median NN 396 → 89 m) but
made the hub worse (2/12 within 160 m, the pack's worst), and its densest 300 m cluster is only 3 shops.
Cache + raw snapshots removed; the config entry stays commented with the rationale. See LANE_E_NOTES R23.
Retired (R24, counted): ballarat_real — A's spacing warn caught it at median NN 255 m. Unlike
Toowoomba, Ballarat is not dead: 103 POIs in the bbox, densest 400 m disc = 47 of them. It fails a
different way — its live core and its heroes don't coincide. The dense disc is cafés/clothes/bakeries;
the op-shops sit 854 m, 1042 m and 1709 m out, so no bbox holds both. Measured at every span (real builds):
1.0 km → 8 shops / NN 184 m / hub 4/8 but zero op-shops (a thrift town with no thrift shop); 2.0 km →
12 / 186 m / 3-12; 3.0 km (as shipped) → 20 / 255 m / 4-20. Every row is worse than any shipped town
(darwin 68 m, glebe 60 m, redhill 73 m). The binding constraint is ours, not OSM's: with 2 heroes the 3×
texture cap keeps 6 of 47 POIs and the subsample is spatially blind, so survivors scatter at any span.
Cache + raw snapshots removed; config entry commented with the rationale. See LANE_E_NOTES R24.
The density widening (v4.0-beta, ROUND20 ledger #2)
The fetch covers the secondhand heroes plus the everyday main-street texture (bakery/cafe/deli/
newsagent/chemist/clothes/hardware/greengrocer/…), mapped to existing registry types per C's
LANE_C_PUB §6 table. Tasteful staples only — no vehicle/fuel, funeral, storage, industrial, or pure
services. cafe rides amenity=*; everything else is shop=*. Per John's subtle directive the
heroes are never subsampled and texture is capped at 3× the hero count (deterministic
sha256(townKey:osmId) rank); every drop is counted in each cache's counts.textureDropped.
index.json — the towns roster
{schema:"procity-towns-index/1", generated, license, attribution, towns:[{key, town, state, shops, roads}]}. Same ODbL terms as the caches. Consumers (B's selector) derive the town list from this
rather than hardcoding.
Raw responses (_raw/)
The raw Overpass JSON is cached in-repo (wrapped with fetchedAt, endpoint, query, bbox):
_raw/<key>.overpass.json (shops) and _raw/<key>.roads.overpass.json (OSM highway ways, schema v2).
Re-runs reuse the raw cache and never re-hit Overpass — the fetch is outward-facing network
(John-authorized scout, once per town). --refetch forces a deliberate re-fetch. selfcheck.js reads
only top-level *.json, so _raw/ is never loaded as a cache.
Roads — schema v2 (ROUND18, v4.0-alpha REAL ROADS)
A v2 cache carries roads[] — the town's real OSM street geometry (highway=* ways), same ODbL licence
and attribution as the shops. Fidelity cut (charter risk #4): the raw fetch grabs every ROAD_KIND
tier, but the emitted roads[] is the town street graph only — drivable roads + pedestrian malls;
service/track/footway/path/steps/cycleway are excluded (in Katoomba, 1461 of 2506 ways —
bushwalking tracks, sidewalks, stairs, driveways). The excluded tier stays in the raw response if a
tier is wanted back. katoomba_real is v2 (the alpha); the other towns' roads land as data-only.
Names — parody vs factual
Big trademarked charity/franchise chains are parodied in build_towns.py (Salvos→Slave-ohs,
Vinnies→Sinnies, Anglicare→Tanglecare, Cash Converters→Cashtheists, …) for the game's comic tone.
Independent shops keep their real OSM name — factual, publicly-mapped POI data under ODbL. No
private-individual data is carried (name/type/coordinate/suburb only).