Lane E R18 (v4.0-alpha): the other 4 towns' road geometry (data-only) + Overpass retry

Newtown/Fremantle/Bendigo/Castlemaine now schema v2 with roads[] (1086/622/1552/397 real streets),
same fidelity cut (street tier only). Data-only: only katoomba gates the round; A hardens against these.
build_towns.py: added Overpass retry/backoff (public API 504s under load — hit one mid-run).

The poster-clearance finding is SYSTEMATIC: it reproduces on all 5 real-road towns, every seed (23
checks, -0.9 to -4.7m), confirming it's plan-level poster placement (A's pickVenues/POSTER_CLEAR), not
town data. Scoping holds: only the real/* v2 path fails; synthetic + fixtures + classic + default boots
stay green. A's one fix generalizes to all five. ODbL: raw roads committed, SOURCES.md current.

-> Lane A: all 5 towns' roads live; the systematic poster finding is yours to resolve + re-pin goldens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-07-16 16:32:10 +10:00
parent dbb52c2390
commit 10db373e67
10 changed files with 786425 additions and 20 deletions

View File

@ -35,9 +35,18 @@ plan-level poster placement, not cache errors. Not a fidelity artifact either: t
real primary town streets, so trimming roads wouldn't fix it. Golden settles after A's fix (pre-fix
value `0x6014a8e6`). Handshake E→A: **katoomba roads live + this finding**.
**Other 4 towns:** roads produced + committed as data-only (A hardens against them as they land; only
katoomba gates the round). Roads are ODbL (© OSM contributors); raw responses committed, `SOURCES.md`
updated with the roads tier + the fidelity cut.
**Other 4 towns** (data-only; A hardens against them, only katoomba gates): all now v2 —
newtown_real 1086 roads, bendigo_real 1552, fremantle_real 622, castlemaine_real 397 (dense/regional
towns → bigger graphs; real data, A's DP + density classification handle it). Roads are ODbL, raw
committed, `SOURCES.md` updated. (Robustness: `build_towns.py` gained Overpass retry/backoff — the
public API 504s under load.)
**The finding is SYSTEMATIC** — the spine-poster clearance fails identically on **all 5** real-road
towns, every seed (23 checks, 0.9 to 4.7 m). That it reproduces across five different real street
grids confirms it's **plan-level poster placement, not town data** → squarely A's (`pickVenues` /
`POSTER_CLEAR`). Scoping holds: **only the `real/*` v2 path fails — synthetic + fixtures + classic +
default boots are all green** (roads[] is the only changed path, per the alpha law). A's one fix
generalizes to all five.
## Round 17 — v3.2 THE SCOUT: real town caches + the verify fix ⟨v3.2 amendment⟩

View File

@ -17,7 +17,7 @@ attribution ships IN every cache (`license`/`attribution`) + `SOURCES.md`. Hours
registry supplies them at plan time (contract shop = {id,name,type,lat,lon,suburb}). Overpass is an
outward-facing fetch (John-authorized scout, once per town, raw cached).
"""
import os, sys, json, re, math, time, datetime, urllib.request, urllib.parse
import os, sys, json, re, math, time, datetime, urllib.request, urllib.parse, urllib.error
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TOWNS_DIR = os.path.join(ROOT, "web", "assets", "towns")
@ -98,6 +98,22 @@ def haversine_m(a, b):
return 2 * R * math.asin(min(1.0, math.sqrt(h)))
def overpass_post(q):
"""POST an Overpass query with retry/backoff — the public API 504s / times out under load."""
req = urllib.request.Request(OVERPASS, data=urllib.parse.urlencode({"data": q}).encode(),
headers={"User-Agent": UA})
for attempt in range(4):
try:
with urllib.request.urlopen(req, timeout=180) as r:
return json.load(r).get("elements", [])
except (urllib.error.HTTPError, urllib.error.URLError, TimeoutError) as e:
if attempt == 3:
raise
wait = 15 * (attempt + 1)
print(f" Overpass {getattr(e, 'code', type(e).__name__)} — retry {attempt + 1}/3 in {wait}s")
time.sleep(wait)
def fetch_raw(key, bb, refetch):
"""Return the raw Overpass elements list, cached in-repo so re-runs never re-fetch."""
os.makedirs(RAW_DIR, exist_ok=True)
@ -110,10 +126,7 @@ def fetch_raw(key, bb, refetch):
f'({bb["minLat"]:.5f},{bb["minLon"]:.5f},{bb["maxLat"]:.5f},{bb["maxLon"]:.5f});'
f'out center;')
print(f" [{key}] fetching Overpass (bounded {bb['minLat']:.3f},{bb['minLon']:.3f}{bb['maxLat']:.3f},{bb['maxLon']:.3f})")
req = urllib.request.Request(OVERPASS, data=urllib.parse.urlencode({"data": q}).encode(),
headers={"User-Agent": UA})
with urllib.request.urlopen(req, timeout=150) as r:
els = json.load(r).get("elements", [])
els = overpass_post(q)
fetched = datetime.date.today().isoformat()
json.dump({"fetchedAt": fetched, "endpoint": OVERPASS, "query": q, "bbox": bb, "elements": els},
open(path, "w"), indent=1)
@ -132,10 +145,7 @@ def fetch_roads_raw(key, bb, refetch):
f'({bb["minLat"]:.5f},{bb["minLon"]:.5f},{bb["maxLat"]:.5f},{bb["maxLon"]:.5f});'
f'out geom;')
print(f" [{key}] fetching Overpass roads (highway ways, bounded)")
req = urllib.request.Request(OVERPASS, data=urllib.parse.urlencode({"data": q}).encode(),
headers={"User-Agent": UA})
with urllib.request.urlopen(req, timeout=150) as r:
ways = json.load(r).get("elements", [])
ways = overpass_post(q)
json.dump({"fetchedAt": datetime.date.today().isoformat(), "endpoint": OVERPASS, "query": q,
"bbox": bb, "elements": ways}, open(path, "w"), indent=1)
time.sleep(2)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff