PROCITY/docs/LANES/ROUND7_INSTRUCTIONS.md

15 KiB
Raw Blame History

PROCITY — Round 7 lane instructions (from Fable, integrator)

⚠ SUPERSEDED by ROUND8_INSTRUCTIONS.md (2026-07-14). Round 7 is complete — roster flipped to default, ?stock=real live, harness strict, v2.0-beta tagged (4feba02). B (weather) and A (osm parity) slipped — round 8 carries both §Lane A and §Lane B verbatim; everything else is historical reference only.

Date: 2026-07-14 · Written after the Fable round-6 review (6948372) and the v2.0-alpha tag. You are an Opus 4.8 agent assigned ONE lane (read your session prompt). Read this file, your lane spec, your <X>-progress.md, and NOTES addressed to you first.

Repo state: everything committed on main at 6948372 = v2.0-alpha. tools/qa.sh --strict GREEN 5/5 (incl. the v2 flags harness at warn level). Four v2 flags live, default-off: ?plansrc=osm · ?winmap=1 · ?dig=1 · ?roster=stream. Goldens: synthetic 0x3fa36874, osm 0x34cfdec0. Interior law ≤350 draws/room (worst 313, sweep asserts). 27 procity GLBs live. fal balance ~$21.36. Tags v1.0/v1.1/v2.0-alpha await John's push.

Theme: the flip round + the content firehose

Round 6 built the machinery; round 7 turns two keys:

  1. ?roster=stream becomes the DEFAULT. D's readiness memo says it's deterministic, leak-free, hours-aware, and composes — gated only on one optimisation (the ped sub-mesh merge, so full density fits the draw budget). E merges, D validates, F flips.
  2. Real stock enters the dig (the reason this system exists — V2_IDEAS #1, deferred twice): a curated GODVERSE content pack feeds C's stockAdapter behind ?stock=real, so the crates you riffle hold real record sleeves instead of parody canvas.

Plus: the flags harness graduates warn → strict, B ships weather, A hardens osm mode. End-of-round milestone: v2.0-beta (F tags; criteria in decision #6).

Prime-law amendment (read carefully — the baseline moves this round)

The v2 prime law ("default boot stays v1-identical") gets its first deliberate, versioned exception: when F flips the roster default, the default boot changes. Protocol (decision #1): the flip commit and the flags-off-baseline re-pin happen in ONE F-owned commit, with the old baseline recorded in the commit message. Plan goldens do NOT move (0x3fa36874 / 0x34cfdec0 — the plan layer is untouched by the roster). Any other lane whose feature would move the default boot: that's still a land-blocker — the exception is the flip only.

Integrator decisions (so nobody blocks)

  1. Roster-flip protocol: E1 (sub-mesh merge) → D1 (validate + full-density numbers) → F1 (flip default; keep ?roster=v1 as the escape hatch back to the fixed roster; re-pin the flags-off draws/tris baseline in the same commit). Order is strict — no lane pre-empts the flip.
  2. Real-stock scope: read-only content, NO economy backend. E builds the pack offline from GODVERSE (~/Documents/dealgod/GODVERSE.md — recordgod's 185k vinyl w/ images is the target): curate ~200400 sleeves per record-shop archetype (+ optional small packs for book/toy if cheap), bake into atlas textures + a JSON index (id, title, artist, price band, atlas UV), publish atlases to the depot like any asset. C consumes behind ?stock=real through the existing stockAdapter seam. Buying stays a stub. ?noassets and flag-off behavior untouched. No runtime network beyond the existing depot path; no databases; nothing from GODVERSE checked into the repo except the built pack index if it's small. Parody-name law: run titles/artists through the same no-real-trademarks screen as everything else — if the source data is real-world metadata, parody-transform it in the pack builder (deterministic).
  3. Weather is B's round, behind ?weather=1: seeded per-day weather state (clear / overcast / rain), rain particles + wet-ground response, wind sway on awnings/trees if cheap. The sky domes for it already exist in web/assets/gen/. Tram loop is a stretch goal ONLY if weather lands early (?tram=1, instanced, one path over B's bus_shelter stops, no traffic sim).
  4. Harness graduates to strict (F, after the flip lands): a red flags-harness now fails qa.sh. New flags this round (stock, weather, tram if it lands) enter at warn and graduate next round.
  5. fal: no new spends. Broken-prop re-gen clause (≤2 attempts, logged) still stands.
  6. Tag v2.0-beta (F, end of round) when: roster default-on + escape hatch verified · flags harness strict + green · ?stock=real riffles real sleeves in a record shop · ?weather=1 rains · qa strict green. If stock OR weather slips, tag anyway with what landed and note it — same no-hostage rule as always.

Process rules (unchanged)

  • ONE shared working tree. git status first; stage only your files by exact path; options before --; add new files first; commit immediately; pin a durable lane ref.
  • Leave qa.sh --strict GREEN. Update <X>-progress.md; cross-lane asks in your NOTES.
  • F owns web/index.html + tools/; document call sites for F.
  • procityprogress.txt / settings.local.json stay untracked.
  • Repo /Users/m3ultra/Documents/procity; GODVERSE reference ~/Documents/dealgod; dev server :8130.

Sequencing

E1 (ped sub-mesh merge) ──→ D1 (validate + density numbers) ──→ F1 (FLIP + re-pin baseline)
E2 (GODVERSE stock pack) ──→ C1 (?stock=real in the dig) ──────→ F2 (strict harness + new smokes)
B1 (?weather=1) · A1 (osm parity + 2nd town) ── parallel ──────→ F3 (tag v2.0-beta)

E has both feeder tasks — start E1 immediately (it gates the flip), E2 right after. F1 lands before F2 (strict) so the baseline only re-pins once.


Lane A (Citygen) — osm mode to parity + a second town

The Melbourne import works; make osm a first-class citizen, not a demo.

  1. Selfcheck parity: parameterize the full selfcheck suite by plan source so osm plans get the same invariant coverage as synthetic (lots/shops integrity, hours contract, exactly-one openLate, storeys ranges, determinism, <100ms). Wire so qa.sh runs both (F already pins both goldens — extend the checks behind them).
  2. A second fixture town: extract another AU town from the thriftgod cache (different scale/shape than inner-Melbourne — a smaller coastal or regional strip is ideal) → ?plansrc=osm&town=<key>. Same laws: checked-in module fixture, zero network, deterministic, pinned golden per town (give F the hashes).
  3. Document the "add a town" recipe in LANE_A_NOTES (fixture extraction → module → golden pin) so future towns are mechanical.
  4. Watch for: osm towns must satisfy the SAME downstream contracts (openLate exactly-one, registry types, hours sanity) — if a real town's data fights a contract, the importer normalizes it (and logs what it changed), the contract doesn't bend.

Acceptance: full selfcheck green on every (source, town); second town boots end-to-end; recipe documented; both plan goldens unchanged, new town's golden pinned; qa green.

Lane B (Streetscape) — weather

?weather=1 (decision #3). Seeded, deterministic, cheap.

  1. Weather state: seeded per (citySeed, day) — clear / overcast / rain (weights feel AU-plausible). Expose window.PROCITY.weather for other lanes (D may thin crowds in rain later; not this round).
  2. Rain: a particle layer (instanced/points, ONE draw), audible-later, camera-following; wet ground = roughness/darkening response on street surfaces; puddle sheen if cheap. Sky: pick the matching dome from the existing sky-*.jpg set (summer storm / grey drizzle are already in web/assets/gen/).
  3. Wind: subtle sway on awnings + trees during overcast/rain if it fits the budget — vertex-shader time offset, not per-frame CPU.
  4. Budget + composition: worst view ≤300 draws with weather on; works with winmap (rain outside a lit window is the money shot — screenshot it), night, and interiors (rain audio/visual stops inside; interiors are separate scenes so mostly free).
  5. Stretch ONLY if 14 land early: ?tram=1 — one instanced tram/bus on a seeded main-street loop over your bus_shelter stops, door-stop pause at each. No traffic sim.

Acceptance: ?weather=1 deterministic per seed/day; rain + wet ground + matching sky render; ≤300 draws; composes with winmap/night; flag-off identical; screenshots (incl. rain-through-window); qa green.

Lane C (Interiors) — real sleeves in the crates

?stock=real (decision #2). The stockAdapter seam you built in v1 finally eats.

  1. Define the pack contract with E (you own the consumer side): what the JSON index + atlases must provide per item (title/artist/price-band/atlas+UV). Put the agreed schema in LANE_C_NOTES first so E builds against it — a half-day handshake beats a rework.
  2. Consume: when ?stock=real and the pack is available (depot or ?localdepot=1), record-shop bins draw sleeves from the pack (seeded pick per bin — same seed, same crate contents) instead of parody canvas; the dig riffle shows real covers + pack titles/prices; the pull-out card shows title/artist/price.
  3. Laws: deterministic per shop.seed · leak-free (atlas textures dispose with the room or share via the loader cache — prove with the soak) · ≤350 draws (atlas = the sleeves stay batched; assert via drawSweep) · ?noassets and flag-off untouched · fail-soft (pack missing → parody canvas, warn once).
  4. Extend the dig soak: ?dig=1&stock=real enter/riffle/exit × N rooms, zero leaks, determinism.
  5. If E's pack covers book/toy too, wire those shelves as a bonus — record shops are the acceptance bar.

Acceptance: riffling a bin with ?stock=real shows real (parody-screened) sleeves with titles/prices, deterministic + leak-free + ≤350 draws; fail-soft proven; contract doc'd; qa green.

Lane D (Citizens) — validate the merge, hand F the flip

  1. D1 — validate E1's merged peds (the flip gate): rigs bind + animate (walk/idle), silhouettes/materials intact, impostor bake clean, identity variety preserved. Then the numbers: draws-per-near-rig before/after, worst-view draws/tris at FULL density (?roster=stream, no reduced-density concession), 30-chunk soak leak-free. Write the go/no-go into LANE_D_NOTES with the exact figures — F flips on your word (decision #1).
  2. Full-density defaults: with the merge in, set the stream path's density/near-cap defaults to the values your memo said full density needs — these become the shipping defaults when F flips.
  3. Post-flip verification (after F1 lands): default boot runs the streamed roster — re-run your determinism + far-field-density + leak checks on a NO-FLAG boot; verify the ?roster=v1 escape hatch actually restores the fixed roster.
  4. Do NOT start rain-behavior/schedules/queues — crowds react to weather in a later round.

Acceptance: merged peds validated with published numbers; go/no-go memo written; after the flip, no-flag boot passes your full check suite; escape hatch verified; qa green.

Lane E (Assets) — the two feeders

Both critical-path. E1 gates the flip; E2 gates the stock. In that order.

  1. E1 — ped sub-mesh merge (START IMMEDIATELY). Per-ped GLBs carry multiple primitives/materials → multiple draws per near rig. Merge to (ideally) ONE primitive + one atlased material per ped: gltf-transform join/palette/instance pipeline — preserving skinning (joints/weights), morphs if any, and compatibility with the shared walk/idle clips. Backup originals (gitignored), process all 19, verify each loads + binds in the vendored GLTFLoader, record before/after draws+tris in AUDIT.md, hand to D.
  2. E2 — the GODVERSE stock pack. Build pipeline/build_stock_pack.py: read recordgod data from ~/Documents/dealgod (fixture-extract like A's pattern — the pipeline reads the local dataset at build time; NOTHING queries it at runtime), curate 200400 sleeves (image quality + variety), parody-transform titles/artists deterministically (the no-real-trademarks law applies to metadata too), bake atlas PNG/WebPs + JSON index to C's schema (wait for C's contract note — it's their task 1), publish atlases to the depot, stage for ?localdepot=1. Provenance in AUDIT.md (source dataset, count, transform). Small packs for book spines / toy boxes only if the record pack lands early.
  3. On-call: B may want a rain-streak sprite or puddle texture (procedural first — generate only if truly needed, flux_local, free).

Acceptance: E1 — all peds single-draw (or documented floor), skinned + animating, D signs off; E2 — pack published + staged, index validates against C's schema, parody screen run, provenance logged; qa green (incl. your own provenance-drift gate).

Lane F (Integration) — flip, tighten, tag

  1. F1 — the roster flip (after D1's go). In web/index.html: streamed roster becomes default; ?roster=v1 restores the fixed roster; ?roster=stream stays accepted (now a no-op). Same commit: re-pin the flags-off regression baseline (draws/tris snapshot) to the new default boot, old values in the commit message (prime-law amendment). Plan goldens untouched. Then boot no-flags + escape hatch and eyeball both.
  2. F2 — harness to strict (after F1). Flags harness failures now fail qa.sh. Add smokes for the new flags as they land: stock=real (enter record shop, open dig, assert non-parody sleeve count > 0), weather=1 (boot, assert particle layer + wet response active, 0 errors), tram=1 if B ships it. New flags enter at warn (decision #4), existing four + flags-off are strict.
  3. F3 — tag v2.0-beta (decision #6 criteria): summary tag message with the flip baseline note; update flags table + runbook + F-progress. Local; John pushes (remind him v1.0/v1.1/v2.0-alpha are also still unpushed).
  4. Marshal: this round has two hard sequams (E1→D1→F1, E2→C1) — if a lane stalls, flag it in F-progress early rather than at round end. The R5 lesson (silent no-show) now has a harness for code, but not for schedule — you're the schedule harness.

Acceptance: default boot = streamed roster with re-pinned baseline + working escape hatch; harness strict + green with new-flag smokes; v2.0-beta tagged on a green tree; runbook/flags table current.


— Fable (integrator). Two keys turn this round: the town gets permanently busier, and the crates get real. Both have hard sequencing — respect the arrows, commit atomically, pin your refs, leave it green.