PROCITY/web/assets/towns
m3ultra 483a4b75c6 Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix
Ledger #4 (warm-up): publish.py --verify no longer false-flags non-procity_ published assets
(sit.glb, vintage-cash-register). It compares the _published.json name record against the depot's
full file list (fetch_depot_files) instead of a procity_ prefix filter; only OUR namespace flags as
unrecorded. --verify now: all 39 recorded assets live.

Ledger #6 (the scout): new pipeline/build_towns.py ports thriftgod build_city()'s Overpass route to
per-town caches in A's procity-town-cache/1 contract. 5 real compact AU towns under web/assets/towns/
(katoomba/newtown/fremantle/bendigo/castlemaine, 6-21 shops, spans <2.4km): bounded Overpass query ->
raw cached in-repo (re-runs never re-fetch) -> dedupe/suburb-fill/parody (trademarked chains only;
indie shops keep real OSM names)/type-map. Deterministic (byte-identical re-run, no RNG). ODbL:
SOURCES.md licence table + license/attribution on every cache. All 5 boot through the full
structural+gig suites (selfcheck 16596/16596 green; synthetic golden 0x3fa36874 unmoved). Overpass
fetch John-authorized (Standing #2).

-> Lane A: caches live under web/assets/towns/; pin the per-town goldens selfcheck printed (katoomba
   0x61760542 newtown 0x95978b45 fremantle 0xee9fd09a bendigo 0x5e3e76a6 castlemaine 0xf1a628a1) +
   feed through plan_osm. E->A handshake.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 14:49:40 +10:00
..
_raw Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix 2026-07-16 14:49:40 +10:00
bendigo_real.json Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix 2026-07-16 14:49:40 +10:00
castlemaine_real.json Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix 2026-07-16 14:49:40 +10:00
fremantle_real.json Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix 2026-07-16 14:49:40 +10:00
katoomba_real.json Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix 2026-07-16 14:49:40 +10:00
newtown_real.json Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix 2026-07-16 14:49:40 +10:00
README.md Lane A round 17: v3.2 the town-cache contract (published first) + plan_osm hardened for real data 2026-07-16 14:32:14 +10:00
SOURCES.md Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix 2026-07-16 14:49:40 +10:00

Real town caches — the home (web/assets/towns/)

Lane A owns the contract; Lane E fills this directory (ROUND17 ledger #6, the real-map scout).

Each real Australian town is one file, <key>.json, in the town-cache contract shape — the processed output of pipeline/build_towns.py (Overpass → dedupe/suburb/parody-name/seeded-hours). plan_osm.js marches it exactly like the checked-in fixtures in web/js/citygen/osm_fixture.js; the scout proves the existing CityPlan contract eats real data — no new plan fields, no new geometry.

The contract (authoritative: validateTownCache() in web/js/citygen/plan_osm.js)

{
  "schema": "procity-town-cache/1",
  "key": "katoomba_real",                    // matches the filename; distinct from the hand-made fixture key
  "town": "Katoomba",                        // display name
  "source": "osm",
  "license": "ODbL 1.0",                     // REQUIRED — OSM is ODbL
  "attribution": "© OpenStreetMap contributors",
  "generator": "pipeline/build_towns.py",    // optional provenance
  "fetchedAt": "2026-07-16",                 // optional
  "center": { "lat": -33.71, "lon": 150.31 },// REQUIRED — the equirectangular projection origin
  "bbox": { "minLat": …, "minLon": …, "maxLat": …, "maxLon": … },  // optional metadata
  "counts": { "raw": 512, "shops": 96 },     // optional metadata
  "shops": [
    { "id": 318855426, "name": "Canty's Bookshop", "type": "book", "lat": -35.32, "lon": 149.18, "suburb": "Fyshwick" }
    // …
  ]
}

Hard requirements (else the cache is rejected and does not boot):

  • center.{lat,lon} finite numbers.
  • shops an array of MIN_TOWN_SHOPS (6) entries (up to 4 venues + the one openLate landmark + a spare).
  • every shop has finite lat/lon.

Absorbed as warnings (still boots): a blank name defaults to the type label; an unknown type remaps to opshop; duplicate ids; and — importantly — a cache spanning > 5 km warns "likely more than one town". A cache MUST be ONE compact town: an over-broad Overpass bbox marches into an unusable multi-km strip (the R17 mega-strip risk — a whole region of 2,918 shops became an 11.6 km avenue). Bound the query.

type should be a registry SHOP_TYPE (record/opshop/toy/book/video/pawn/milkbar/dept/stall); build_towns.py maps OSM shop=* tags to these (unknowns land on opshop).

Provenance (Lane E)

OSM data is ODbL. Ship attribution with the data: this README, a SOURCES.md (E's licence table), and the license/attribution fields on every cache. Cache the raw Overpass responses too so re-runs never re-fetch.

Wiring

  • plan_osm.generatePlanOSM(seed, key, { cache }) marches a cache directly; registerTownCache(key, cache) adds it to the runtime registry so osmTownKeys() and generatePlanFor(seed, 'osm', { town: key }) see it.
  • web/js/citygen/selfcheck.js auto-loads every *.json here: validates it, runs the full structural + gig suites across the hero seeds, and pins a per-town golden (unpinned → prints the value to paste).