PROCITY/docs/LANES/ROUND39_INSTRUCTIONS.md

127 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.030.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.** `index.html:349` ships `useGLB: !NOASSETS`, so
the **default boot is the GLB path**, and `C-progress.md:841` records that sweep at **GLB-on
344** against the ≤350 cap. Any interior work in any epoch spends against **six**.
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.139.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.
## 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.