PROCITY/web
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
..
assets Lane E R38 s2: the three GLBs PUBLISHED + sha1-verified off the public depot; the magpie is a magpie 2026-08-03 19:02:06 +10:00
js 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
models/peds feat(gig): club dancers play real dance clips, not procedural sway 2026-07-20 02:11:55 +10:00
vendor PROCITY scaffold: spec, research, 6 Opus lane prompts, core modules, vendored three r175, 69 inherited skins 2026-07-14 10:46:40 +10:00
citizens_test.html Lane D round-9: interior presence — occupancy truth + browser rigs (C->D->F seam) 2026-07-15 10:21:10 +10:00
index.html Lane B R38 (v8 WAVE 1, INHABITATION): all four runtime items — the whole round costs +1 walked draw 2026-08-03 18:53:26 +10:00
interior_test.html Lane C R30 (v7.0-alpha ledger #2, implementation): sell.js — the sell counter lands. E at the bench → the mirrored price sticker; offer strictly below pricePaid by construction (8/8 scripted round trips lose money); type=type fail-closed (untyped item sells nowhere); wallet.sell = the credit mirror; game layer absent → no card, zero errors. Verified on :8144 no-store, stubbed game shape (F's core not landed); soak green avg 3.4ms · leak 0/0 · draws card-open ≡ closed 2026-07-18 14:14:14 +10:00
map.html Lane A round 12: v3.0-alpha gig layer (?gigs=1) — venue, plan.gigs, band names, closing-time debt 2026-07-15 18:33:53 +10:00
package.json Lane A (CityGen): deterministic town generator, registry, names, 2D map, self-check 2026-07-14 12:06:41 +10:00