# PROCITY — Round 39 instructions (from Fable, integrator) Date: 2026-07-26 · **R38 closed green — v8 wave 1 shipped and the town is inhabited** (21 palettes, 36 backyards, the magpie, six panning ambient layers; budget held at **292/300, eight draws of margin**, because the worst frame is a night frame and both new layers are zero at night). **JOHN HAS RULED: do the street names.** *"yes do street names for sure and what else can we get on with? just keep it going."* Round 39 opens **v9 — THE CITY IS THE GAME** with its two zero-draw keystones, and keeps every other lane busy on work that needs no ruling. Charters: [V9_THE_CITY_IS_THE_GAME.md](../V9_THE_CITY_IS_THE_GAME.md) (the hunt; read Fable's verification header first) · [SALE_RED_TICKET_DAY.md](../SALE_RED_TICKET_DAY.md) (the round and the Band Floor Law) · [V8_SOMEONE_LIVES_HERE.md](../V8_SOMEONE_LIVES_HERE.md) (in flight; wave 2 later). ## THE BINDING FACTS (verified by Fable — do not re-derive, do not contradict without numbers) 1. **17,835 of 19,132 road ways in the shipped caches carry a `name` — 93.2%.** Counted independently. `plan_osm.js:363` builds each way as `rawWays.push({ kind: roadEdgeKind(rd.kind), pl })` — it keeps the kind and the geometry and **discards `rd.name`**. Every real street in 23 Australian towns is in this repo and the game has never said one out loud. 2. **The names are recoverable without touching citygen's output.** Plan nodes ARE snapped projected way points (`plan_osm.js:361-372`, `SNAP=3`), so plan edges lie ON the named ways: median distance from a plan-edge midpoint to its nearest named way is **0.03–0.90 m** (worst town katoomba), and **97.8% of corpus shops (1,192/1,219) resolve to a street name**. 3. ~~**THE INTERIOR MARGIN IS SIX DRAWS, NOT 191.**~~ **CORRECTED IN-ROUND BY LANE C — the margin was 31, and is 21 after C's bin.** The direction was right (`index.html:349` ships `useGLB: !NOASSETS`, so the **default boot IS the GLB path** — that part stands and matters). The *number* was stale: `C-progress.md:841`'s "GLB-on 344" is **R9-era**. C measured today's tree before touching anything: **GLB-off 156 · GLB-on 319**, both `opshop/hall`. **Fable's error, owned:** I verified the claim's provenance (the doc does say 344) and not the measurement (the tree says 319). *A document is not a tree.* The house rule stands and I broke it: measure the thing, not the note about the thing. **And the real finding is bigger than the correction** — see the transmission entry in the close. 4. **Vertical movement is fiction.** `player.js:64` and `interior_mode.js:485` both write `y = EYE` unconditionally every frame on every path — no gravity, no floor query, no storey state, no floor height in any data structure. **Nothing this round proposes stairs.** 5. **Only record shops and market stalls have a diggable crate** — `kind:'bin'` is minted at `fittings.js:60`/`:75` (`recordBin`, `crate`) and used by exactly two recipes (`theme.js:38-39` record, `:196` stall). The op shop's `crateStack` is labelled *"back-room dressing"* in its own comment. **You cannot dig in an op shop**, in a game built on op-shop DNA. ## The ledger ### 39.1 — THE ADDRESS LAYER *(Lane A — the approved thing, and the prerequisite for everything else)* Recover the names and publish the vocabulary. A new **pure** module (no THREE, no fetch, no plan mutation): `createAddresses(plan, cache|null)` → `streetOf(edgeId)` · `localityOf(shopId)` → `{street, district, block, side, label}` · `cohort(predicate)` → `shopId[]`. - **Real towns:** street name by nearest named way to the edge midpoint (≤8 m tolerance). - **Synthetic:** no roads cache and only 22 edges → the label comes from `district.kind` + block: *"the market end"*, *"the arcade"*, *"the backstreets"*. **Same field, different supplier, one consumer contract** — this matters, because consumers must not branch on town type. - The synthesis proposes a **one-line** upgrade: write `norm.shift = {shx, shz}` at `plan_osm.js:510` into the **caller-supplied `opts.report` sink, never onto the plan object**, so it moves no golden and breaks no classic byte. **Take it if it is genuinely that clean; measure and report if it is not.** - **Goldens must not move.** State it plainly with your selfcheck numbers. If one moves, stop. - Publish the contract in LANE_A_NOTES §39 in your FIRST commit — B and C both consume it. ### 39.2 — THE FOG *(Lane B — the keystone, zero draws)* `minimap.js:52-63` draws **every lot in the plan from the first frame**, ungated: one M keypress hands over all 493 synthetic shops. Measured cost of earning that yourself: **5,330 m synthetic / 9,622 m fitzroy / 5,797 m northbridge** of walking — **4.8 / 8.7 / 5.3 game-days** at WALK 4.6 m/s against the 240-second day. - Gate the map to shops the player has **walked past**; discovery is **player state**, saved under the delta law (size it: 24 towns × N shops, bounded, and prove export/import + corrupt-reject). - **Frame the map to what you know.** The payoff is the reason to do it: a shop rectangle goes from **0.8×1.1 px to 29×39 px on bowral — a 35× legibility gain** (21× katoomba, 17× adelaide, 11× fitzroy). The map is currently useless on the 21 towns that are supposed to be 21 mental maps. - **BINDING corrections from the judges:** discovery is a **proximity probe, not `chunks.onChunkBuilt`** (real towns are all BIG_CITY ⇒ R=2, so the outermost live chunk centre is 128 m out and its far corner 181 m — chunk-built discovery would hand you shops you never saw). And classic-gate it **by construction**: `createMinimap(plan)` becomes `createMinimap(plan, game ? knownProvider : null)`, where a null provider is today's exact behaviour — the same pattern `ground.js` already uses, so `minimap.js` needs no flag test at all. - Consume A's `localityOf` for street labels on the map once A publishes. ### 39.3 — THE OP SHOP CAN'T BE DUG *(Lane C — the game's namesake activity)* PROCITY is built on thriftgod's op-shop DNA and **an op shop has no diggable bin**. Its recipe is clothes racks, metal shelves, a bookshelf, a trestle table and a `crateStack` its own comment calls back-room dressing. Meanwhile the dig — the crown jewel, soaked since v2 — fires only in record shops and market stalls. - **Measure first**: what can a player actually DO in each of the 12 shop types today? Enumerate it honestly (dig / pull-and-buy / nothing) and put the table in your notes. That table is the deliverable even if nothing else lands. - **Then the mechanism**: give the op shop a diggable bin (a bric-a-brac tub, a $2 book crate, a rummage bin — you own the fitting and the recipe). The *mechanism* is uncontroversial and yours. - **FLAG, do not decide: what is IN it.** Records mixed in? Books and toys through the existing pull-and-buy pack? Its own item class? That is a John taste call and it is the difference between "op shops now dig" and "op shops now dig *records*", which changes the game's economy. Propose, measure the options, and hold. - **Spend against SIX draws** (fact 3). Say what your bin costs and prove it. ### 39.4 — TWO MAGPIES, AND THE ARCADE'S ASSETS *(Lane E)* - **Settle the magpie** (filed from R38): B ships a 182-tri procedural bird with vertex-colour white; E published an 894-tri tinted GLB that reads properly. **Render them side by side at the size the bird is actually seen** (64/48/32 px, the same sheet form as your tint render) and recommend. Fable rules on the picture, not the prose. - **The arcade** is a real 42 m covered lane with **17 shops** and it is dressed as nothing — no props, no signage, no roof texture, no reverb. Generate its kit for a later round: a two-dollar- shop A-frame, a key-cutter sign, hanging shopfront signage, a tiled arcade floor skin. Same laws: $0, on-device, 🟢, provenance rows, and **size every asset by `tris × the instance count the consuming lane implies`** — the law your own `paling_fence` bought us. - Correct `magpie.js`'s two stale tri comments (154 vs measured 182) — **that is Lane B's file, so write the ask, do not edit it.** ### 39.5 — THE GATES AND THE CLOSE *(Lane F, last)* Gate 39.1–39.3 with falsifiability controls; full `qa.sh --strict --matrix`; round close. **No tag.** Specifically: prove the address layer resolves ≥97% of corpus shops and **fails loudly** on a town with no roads cache; prove the fog hides what has not been walked and **reveals what has** (both arms, or it is vacuous); prove classic and `?noassets` untouched; and re-measure the interior budget against fact 3 if C's bin lands. ## ROUND CLOSED (Fable) — **v9 IS OPEN. 10 passed · 0 failed · 0 warn · 0 skipped. No tag.** Selfcheck **157,647/157,647**, fingerprint `0x5f76e76`, **zero goldens moved**, MATRIX GREEN 10 towns × 7 gates. Three new gates added coverage without moving a single existing verdict. **THE TOWN KNOWS ITS OWN STREETS.** 1,192 of 1,219 corpus shops resolve to a real Australian street name — 97.8%, 100% on 17 of 23 towns — and **zero wrong names**, validated against a second independent resolver (857 shop-bearing edges, 0 disagree). Katoomba's map now says *Katoomba Street*. `map.html` had never rendered a real street in four epochs of holding the data. **THE MAP IS A MAP.** The fog costs **+0 draws AND +0 tris** (four fresh browsers, both orders, arms proven distinguishable first) and framing to what you know takes a shop from **0.83 × 1.11 px to 29.4 × 39.2 — 35× on bowral**. B's sharper measurement: an exact-palette count found **26,506 shop-coloured pixels on the synthetic and ZERO on Katoomba** — all 72 shops rasterised to not one pixel of their own colour. The map wasn't hard to read on real towns; it was drawing nothing. **THE FOURTH AND FIFTH INSTANCES OF THE SAME BUG.** `(−sin,−cos)` at `index.html:384`/`:450`: **not one door point in the entire corpus was on a footpath** (0/493, 0/72, 0/139, 0/30) — Lane D's peds have been ducking into the back fence since R8 — and the spawn put **0 shops in front of the player on 4 of 4 towns**, which is precisely the "faces dirt and building-backs" complaint from Fable's own R31 playtest, finally explained. Two characters; 0 → 4 on all four towns. **B wrote the lineage down (R13 `RY_FLIP` · R15 posters · R27 facades · R39 these two) with the keeper insight: *every instance was caught by a picture or by a consumer with a different convention, never by a metric — a heading has no falsifiable arm inside the file that computes it.*** And then the table paid for itself **inside the same round**: wiring E's magpie, B pointed a measurement at the heading *because the lineage said to*, and found instance five — E's bird faces +Z, the file flies −Z, **the magpie would have swooped tail-first**. First one ever caught before shipping. **THREE GLBs WERE SHIPPING AS GLASS.** `transmissionFactor: 1` forces three.js's transmission pre-pass — **every opaque draw issued twice**. E scanned all 103 GLBs: `bookshelf` (shipped and hurting), plus `longbench` and `streetlight` — **unwired STREET assets E had itself recommended to B**, where a pre-pass would have cost ~292 draws against eight of margin. Armed, not fired. Fixed at source with BIN sha1 identical, republished, sha1-verified off the public depot, **and gated**: `validate_manifest.py` now hard-fails on it. **THE INTERIOR MARGIN'S THIRD VALUE — and the epoch's cleanest lesson in three numbers:** **6** (a stale doc I quoted) → **21** (a correct measurement of a tree about to change) → **162** (the tree as it now stands). F re-measured through a true A/B — the shipped GLB vs a copy with the glass re-inserted, BIN identical — and got worst-room **329 → 188**: `opshop` −47%, `book` −49%, every other type 0. **The worst interior room is now `dept/auto` — a room with no bookshelf in it.** E's fix took, and it bought **+141 draws**. **THE OP SHOP CAN BE DUG** — `rummageBin`, 72/72 placed and reachable, 0 carves, rest-of-room byte-identical, **contents deliberately unarmed** (default boot: `kind:'prop'`, 0 dig targets) and held for John. Alongside it, C's table of what a player can actually do in each of 12 shop types — including that **the default boot contains not one buyable mesh anywhere**, and that `interactable:true` is not a verb. **Two self-caught errors worth keeping.** F aimed its transmission control at the plausible path (`web/assets/models/`) rather than the code path (`pipeline/_normalized/`) and **nearly filed a defect against Lane E on the strength of it** — *aim the control at the code path, not the plausible path*. And B, ordered to fix its own fallback magpie, made the change, measured it, found **true white went 33 → 28 px** (a downward-facing surface catches no sun, so the white it moved into view reads grey against E's 755) and reported it as a half-win **that strengthens the ruling against its own bird**. **F's judgement call, ratified:** it re-shot the spawn gates but **refused to overwrite `v7_tour/` and `v7_beta/`** — *re-shooting a tagged epoch's release tour on a v9 tree falsifies a record.* They stay as history. **Filed to R40 (gate gap, not a live defect):** `check_transmission()` skips any GLB with no local `pipeline/_normalized/` copy and never scans `web/assets/models/` — demonstrated live, the glass asset **passes rc 0** with the local copy removed. **A depot-only transmissive GLB — exactly the shape of `longbench`/`streetlight` — would ship unseen.** Also carried: A's D1–D4 · the matrix budget column is bookmark numbers · `?r=3` breaches at 307 ungated · the arcade's awning posts stand two rows 1.00 m apart down a 5.00 m lane and should be designed with the roof · should `?classic=1` show the town selector · **nobody in this loop has ears.** **Street budget: 292/300 stands** — both new layers are zero-draw and measured at zero, the spawn is a pose, the bin is interior. ## Laws Everything standing. This round: **zero draws is the requirement for 39.1 and 39.2** — they are information design and must cost nothing on the street · the interior margin is **six** · pathspec-atomic commits (four lanes share the tree) · no pushes, no tags — Fable pushes at close · every gate ships its control demonstrated. ⚠️ **Tree note:** a background session may still be editing `web/js/world/venue.js`. No lane touches it this round. ## Order 1. **Parallel: A (39.1, contract in the first commit) · B (39.2) · C (39.3) · E (39.4).** 2. **Then F (39.5).** ## Standing — for John, when he wants them The op-shop bin's **contents** (39.3) · whether the fog is default-on or a mode · and the v9 shape itself: the address layer and the fog are its first two layers, and the third (the unmarked door / semi-hidden retail) waits on how these two feel.