PROCITY/docs/LANES
m3ultra f628bf581a Lane A R39 39.1: THE ADDRESS LAYER — 17,835 street names stop being dropped on the floor
The contract, published for B and C in LANE_A_NOTES §39 (first commit, per the half-day rule).

  createAddresses(plan, cache|null) → streetOf(edgeId) · localityOf(shopId) · cohort(pred)
                                     · streets() · stats()

New pure module web/js/citygen/address.js: ZERO imports, no THREE, no fetch, no DOM, no module
state, no plan mutation. Two suppliers, ONE consumer contract — a real town fills `label` from the
cache's named ways, the synthetic fills it from district.kind + block. Consumers must never branch
on town type; that constraint is the design.

MEASURED (Fable's binding facts re-derived independently, all three land exactly):
· 19,132 road ways, 17,835 named (93.2%)
· median plan-edge-sample → nearest named way 0.03–0.90 m (worst katoomba)
· 1,192 / 1,219 corpus shops resolve to a street name (97.8%); 29,865/30,986 edges named (96.4%)
· all 27 unresolved shops front a way OSM genuinely leaves unnamed (adelaide 21 arcade) — null is
  the honest answer and the module returns it rather than borrowing a neighbour's name

TWO DEPARTURES FROM THE SYNTHESIS, both with numbers:
· the shift is recovered EXACTLY (node↔waypoint lattice intersection), not voted for. The proposed
  centroid-align + nearest-waypoint vote returns the WRONG shift on 5 of 23 towns (braddon,
  fremantle, hobart, northbridge, westend) — island culling drags the plan centroid off the
  cache's. A wrong shift renames every street in the town. Exact on 23/23, nothing to tune.
· the resolver samples FIVE points along an edge, not the midpoint — a midpoint cannot tell a
  street from the street that crosses it.

THE ONE-LINE UPGRADE: TAKEN. plan_osm.js writes norm.shift = {shx,shz} into the normalization log,
reaching the caller only via the existing opts.report sink — never onto the plan. It is a
cross-check, not a dependency: selfcheck compares plan_osm's published shift against address.js's
independently recovered one and fires on a 0.01 m disagreement.

GATES (+240 checks), each proven to fire on a broken world:
· 0 wrong street names on 884 shop-bearing edges, against an INDEPENDENT way-membership resolver
  (857 agree, 0 disagree). Corpus-wide 4/30,986 disagree — all 2D-stacked ways, none carrying a
  shop — PINNED at 4, not asserted > 0.
· CONTROL: with roads[].name stripped (exactly the pre-change state) the layer resolves 0 streets.
· CONTROL: no cache ⇒ supplier 'district', visible in stats(), never a silent wrong name.
· createAddresses does not mutate the plan — asserted byte-for-byte, per town.
· tolerance 8 m, and the finding that sets it: correctness SATURATES AT 6 m (857 agreeing frontage
  names at 6, 8, 12, 16 and 24 m). Every metre past 6 buys only a name borrowed from an unnamed
  way; it can never buy a correction.

Additive: getTownCache(key) — index.html registers the cache and drops its reference, so roads[]
was unreachable downstream. Read-only, no new state, no shell change.

GOLDENS: NOTHING MOVED, ZERO RE-PINS. selfcheck 157,407 → 157,647 ALL GREEN, fingerprint 0x5f76e76.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 20:32:43 +10:00
..
FABLE_TO_LANE_G.md
LANE_A_CITYGEN.md
LANE_A_NOTES.md Lane A R39 39.1: THE ADDRESS LAYER — 17,835 street names stop being dropped on the floor 2026-08-03 20:32:43 +10:00
LANE_B_NOTES.md
LANE_B_STREETSCAPE.md
LANE_C_AUDIO.md
LANE_C_GLB_VALIDATION.md
LANE_C_INTERIORS.md
LANE_C_NOTES.md
LANE_C_PUB.md
LANE_D_CITIZENS.md
LANE_D_NOTES.md
LANE_E_ASSETS.md
LANE_E_NOTES.md
LANE_F_INTEGRATION.md
LANE_F_NOTES.md Lane F R38 (v8 WAVE 1, CLOSE): the budget did NOT move — 292/300 stands, and four gates ship with four controls 2026-08-03 19:48:45 +10:00
LANE_G_GODVERSE.md
ROUND3_INSTRUCTIONS.md
ROUND4_INSTRUCTIONS.md
ROUND5_INSTRUCTIONS.md
ROUND6_INSTRUCTIONS.md
ROUND7_INSTRUCTIONS.md
ROUND8_INSTRUCTIONS.md
ROUND9_INSTRUCTIONS.md
ROUND10_INSTRUCTIONS.md
ROUND11_INSTRUCTIONS.md
ROUND12_INSTRUCTIONS.md
ROUND13_INSTRUCTIONS.md
ROUND14_INSTRUCTIONS.md
ROUND15_INSTRUCTIONS.md
ROUND16_INSTRUCTIONS.md
ROUND17_INSTRUCTIONS.md
ROUND18_INSTRUCTIONS.md
ROUND19_INSTRUCTIONS.md
ROUND20_INSTRUCTIONS.md
ROUND21_INSTRUCTIONS.md
ROUND22_INSTRUCTIONS.md
ROUND23_INSTRUCTIONS.md
ROUND24_INSTRUCTIONS.md
ROUND25_INSTRUCTIONS.md
ROUND26_INSTRUCTIONS.md
ROUND27_INSTRUCTIONS.md
ROUND28_INSTRUCTIONS.md
ROUND29_INSTRUCTIONS.md
ROUND30_INSTRUCTIONS.md
ROUND31_INSTRUCTIONS.md
ROUND32_INSTRUCTIONS.md
ROUND33_INSTRUCTIONS.md
ROUND34_INSTRUCTIONS.md
ROUND35_INSTRUCTIONS.md
ROUND36_INSTRUCTIONS.md
ROUND37_INSTRUCTIONS.md
ROUND38_INSTRUCTIONS.md Fable (integrator): ROUND 38 CLOSED — v8 wave 1, the town is inhabited; 292/300 stands (the worst frame is night, both new layers are zero at night) 2026-08-03 19:50:16 +10:00
ROUND39_INSTRUCTIONS.md Fable (integrator): round-39 instructions — v9 opens: THE ADDRESS LAYER + THE FOG (John's ruling), plus the op-shop dig gap and the magpie settle 2026-08-03 20:13:43 +10:00