PROCITY/docs/LANES/ROUND39_INSTRUCTIONS.md
2026-08-03 22:49:04 +10:00

206 lines
15 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.**~~ **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.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.
## 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 D1D4 · 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.