diff --git a/docs/LANES/ROUND4_INSTRUCTIONS.md b/docs/LANES/ROUND4_INSTRUCTIONS.md new file mode 100644 index 0000000..503671e --- /dev/null +++ b/docs/LANES/ROUND4_INSTRUCTIONS.md @@ -0,0 +1,232 @@ +# PROCITY — Round 4 lane instructions (from Fable, integrator) + +Date: 2026-07-14 · Written after all six lanes finished round 3. You are an Opus 4.8 agent +assigned ONE lane (read your session prompt). Read this file, your `docs/LANES/LANE__*.md` +spec, your `-progress.md`, and any `LANE_*_NOTES.md` addressed to you before touching code. + +Repo state as of these instructions: **everything committed on `main` at `bd40ec7`** +(Lane E's round-3 work was reviewed and landed by Fable — nothing of yours is uncommitted). +`tools/qa.sh --strict` **GREEN** (4/4 gates, selfcheck 1283/1283, manifest `--depot` 0 errors, +**all 22 GLBs live on the depot**). The only yellow: 5–10 benign storeys warnings per seed in +the consistency checker (proven stale by Lane A in R3 — fixed this round, see Lane F task 2). + +## Where we are + +v1 is integrated and playable: generated town (seed 20261990 → "Boolarra Heads", 493 shops), +streamed streetscape under draw budget, enterable interiors with GLB hero props, rig-fleet +peds + keepers, shop hours with closed-shop gating, 22 GLBs live on the depot, QA harness +green. **Round 4 is the v1-tag round.** Two gates block the tag: + +- **Gate 3 (budget): tris FAIL** — ~279k at the busiest intersection vs the ≤200k budget. + Cause: the 20 ped rig GLBs in `web/models/peds/` are ~1.1–2.5 MB (~45k tris) each. + → Lane E decimates, Lane D validates, Lane F re-measures. This is the critical path. +- **Gate 6 (shots): letterbox + poses** — `DBG.shot()` headless-composer letterbox bug + + 3 missing bookmark poses. → Lane B fixes, Lane F re-captures the v1 tour. + +Everything else this round is polish that makes the tag worth taking: closed-shop facade +visuals, the 4 new hero props actually appearing in rooms, impostor exposure sync. + +## Integrator decisions (so nobody blocks on them) + +1. **Ped decimation target: ≤3k tris per ped rig.** With the near cap at 24 rigs that bounds + the fleet's contribution to ~72k, leaving ~130k for the town — comfortably ≤200k. Use + `gltf-transform` `simplify` (meshoptimizer) — these are proper manifold skinned character + meshes, NOT TRELLIS shell-soup, so simplify works (the R3 shell-soup finding does not + apply). Preserve skinning weights + the separate `walk.glb`/`idle.glb` animation clips. +2. **Hero-prop tris stay as-is for v1** (25–77k). They are focal, one-per-room, and gate 3 + measures the street. The bake-to-lowpoly pass is a follow-up, NOT round-4 work — unless + Lane C's interior measurements show a single room blowing budget (then flag, don't fix). +3. **fal.ai fallback for glass-case + bus-shelter (~$2.70) stays parked.** Do NOT spend it. + Both have primitive fallbacks; John triggers the spend himself if he wants them. +4. **The depot is live and canonical** — `validate --depot` green, publish is done. Lane C: + validate GLBs through the normal `depot:` path (or `?localdepot=1`); the R3 `localBase` + shim and the `web/assets/_local_glb/` copy are obsolete (C task 3 removes the dir). +5. **v1 tag criteria**: all 6 gates green in §4 of LANE_F_NOTES → Lane F tags `v1.0` on main. + Nothing is pushed anywhere — tagging is local, John pushes. + +## Process rules (unchanged — they matter, agents run concurrently) + +- Lanes share ONE working tree. Never `git add .` / `git add -A` / `git commit -a`. Run + `git status` first; stage **only your files by exact path** (`git add ` then + `git commit -m ... -- ` — options BEFORE the `--`; new files must be `add`ed first) + and commit immediately. Touch nothing another lane has modified. +- After committing, pin a durable per-lane ref (`git branch lane-/round4- ` + and/or a tag) so a concurrent `git reset` can't orphan your work. +- Real repo path is `/Users/m3ultra/Documents/procity` (old prompts saying /Users/jing are wrong). +- Leave `bash tools/qa.sh --strict` GREEN before you finish. Update your `-progress.md`; + leave cross-lane notes in `docs/LANES/LANE__NOTES.md`, not silent edits to others' files. +- `procityprogress.txt` and `settings.local.json` in the tree root are untracked on purpose — + leave them alone, do not commit them. +- Dev server: `python3 -m http.server 8130 -d web` (may already be up on :8130 — reuse it). + +## Sequencing (who unblocks whom) + +``` +E1 (ped decimate) ──→ D2 (validate rigs) ──→ F3 (gate-3 re-measure) ─┐ +B2 (DBG.shot fix + poses) ──────────────────→ F4 (gate-6 shots) ─────┼─→ F5 (tag v1) +F1 (setExposure wire) ──→ D3 (verify sync) │ +F2 (storeys checker fix) ──→ A1 (confirm 0 warnings) │ +B1 (closed facades) · C1 (hero props in rooms) · E2 (asset re-exports) → C2 +``` +Start-of-round: E and B have the critical-path items — start E1/B2 immediately. F1/F2 are +small and early. Everything else is parallel. + +--- + +## Lane A (Citygen) — standby + two confirmations + +Small round again. Your R3 verdict (storeys warnings = benign corner anchors) drives F's +checker fix this round. + +1. **After F lands task F2** (the consistency-checker `permittedMax` scoping you specified in + LANE_A_NOTES.md): re-run `bash tools/qa.sh --strict` across ≥5 seeds and confirm the + storeys warnings are now **0** with no new false-negatives (deliberately test that a real + violation would still be caught — e.g. temporarily fake a `video@2` in a scratch copy of + the checker's input, NOT in the plan code). Confirm `GOLDEN.hash` still `0x098eec2b`. +2. **openLate contract audit**: F's night gate asserts `plan.shops.some(s => s.hours[1] >= 22)`. + Confirm across ≥5 seeds that (a) exactly ONE shop per town qualifies, (b) it is always the + video rental, (c) the threshold 22 matches your convention. If any seed violates it, fix in + plan.js + add a selfcheck assertion; if the convention differs, document the correct + predicate in LANE_A_NOTES.md for F. +3. Otherwise standby: answer cross-lane questions (LANE_A_NOTES.md is your channel). + +**Acceptance**: qa.sh consistency shows 0 storeys warnings (post-F2); golden hash unchanged; +openLate holds on ≥5 seeds or is fixed + asserted. + +## Lane B (Streetscape) — closed facades, shot harness, furniture verify + +1. **Closed-facade visual (§3.5 render side — the headline item).** Predicate is ready: + `window.PROCITY.isOpen(shop)` + `window.PROCITY.currentHour()`. When closed: dark/unlit + windows + a CLOSED plate (or shutter) on the facade; when open (esp. at night for the one + `openLate` video shop): lit windows. Also a "CLOSED" door tooltip on aim. Facade state must + update when the day segment changes (hook the same seam `lighting.js` uses — don't poll per + frame). Keep it batched: this must NOT break your facade atlas — aim for a per-instance + uniform/attribute or an overlay quad, not per-shop materials. Re-measure worst view ≤300 + draws with citizens after. +2. **Shot-harness fixes F requested (gate-6 blocker — do early).** In `dbg.js`: + (a) fix the headless-composer letterbox in `DBG.shot()` (shots come out letterboxed when + the composer runs headless — see F-progress R3 notes); (b) add the 3 missing named + bookmark poses F listed in LANE_F_NOTES §9 (check the exact names there — the tour wants + `street_noon`-style bookmarks incl. a night-neon and market pose). Verify by running + `python3 tools/shots.py` and eyeballing output. +3. **Furniture GLB footprint/collision verify (your R3 task 3, now unblocked).** F's §3.4 + manifest-GLB furniture upgrade is live. Verify street furniture placement: GLBs sit on + their reserved footprints, no sidewalk clipping, player collision sane, and the new + `novelty_record` street prop (manifest furniture #8) actually spawns somewhere sensible. + If it isn't placed by the streetscape yet, place it (record-store adjacency is the obvious + home). +4. Optional polish: fresh beauty stills for docs/shots/ once 1–3 land. + +**Acceptance**: at 22:00 only the video shop reads open and every other facade reads closed +(screenshot evidence); `shots.py` produces un-letterboxed shots incl. the 3 new poses; +worst-view draws ≤300 with citizens; qa.sh green. + +## Lane C (Interiors) — hero props into rooms + +Your R3 validated the 9 library fittings. The manifest now has **14 fittings** — the 4 new +hero props + cash_register are unmapped in `glb.js`. + +1. **Map + validate the new hero fittings** in `web/js/interiors/glb.js`: + - `arcade_cabinet` → video store (it's the focal prop) + - `listening_booth` → record store + - `drinks_fridge` + `milkshake_mixer` → milkbar (mixer is a counter-top item — it likely + sits ON the counter, not on the floor; check its manifest footprint/height and place + accordingly) + - `cash_register` → counter-top on the primitive counter (the till upgrade), all shop types + if it reads well, else the till-less ones + Reuse your R3 approach: real-metre scale clamped to footprint, per-kind yaw, fail-soft. + Load via the normal `depot:` path or `?localdepot=1` — all 5 are published and live. +2. **Sweep + soak with the new mappings on** (same bar as R3): 0 throws / 0 path-fails / + 0 determinism-fails / 0 leaks, worst build <50 ms. Screenshot each new prop in its room → + `docs/shots/laneC/` (extend the contact sheet). +3. **Cleanup**: delete `web/assets/_local_glb/` (your R3 validation copy — superseded by + Lane E's `?localdepot=1` + `stage_local_depot.py`). It's untracked; just `rm -rf` it. + Keep (don't remove) the `localBase` manifest hook if it costs nothing, but the dir goes. +4. **Measure a hero-prop room**: draws + tris inside the video store (arcade cabinet is 25–77k + tris territory). If any single room exceeds interior budget expectations, REPORT the number + in LANE_C_GLB_VALIDATION.md for E's future bake pass — do not block or fix. +5. **Standing by for E2**: when Lane E re-exports `record_crate` (currently broken) and the + ~2 m counter-with-till, re-map both and validate (may land late in the round or not at all — + don't wait on it). + +**Acceptance**: 4 new hero props (+cash_register) render in their rooms, planted, scaled, +facing right, stock/keeper unbroken; soak passes with them on; contact sheet updated; qa green. + +## Lane D (Citizens) — in-shell rig verify + decimation validation + +1. **In-shell §3.4 verification (now unblocked — F wired the fleet in R3).** In the real game + (`web/index.html`, not your test page): confirm peds AND keepers upgrade placeholder→rig + once the fleet loads; enter/exit 10+ shops and confirm `renderer.info.memory` returns to + baseline (your R3 leak proof, but in-shell); confirm determinism (same seed → same + identities) and `?noassets=1` still runs fully placeholder with zero fetches. +2. **Validate E's decimated peds (critical path — coordinates with E1).** When E stages the + decimated `web/models/peds/*.glb`: rigs still bind + animate (walk/idle), no skinning + explosions, silhouettes read at street distance, impostor atlas bakes clean, identity + variety intact. Measure per-ped tris (≤3k target) and re-run your determinism + leak + checks. Report the numbers in LANE_D_NOTES.md; F re-measures gate 3 after your OK. +3. **Verify exposure sync once F lands F1** (the `setExposure` call site you specified — + F did NOT wire it in R3, it's queued this round): at dusk/night, mid-tier impostors match + near-rig brightness through segment transitions, incl. across a placeholder→rig upgrade. +4. Chunk-streamed roster stays design-only (your R3 note). No implementation this round. + +**Acceptance**: rigs live in-shell and leak-free; decimated peds validated ≤3k tris each with +anims intact; exposure visually consistent across tiers at night; qa green. + +## Lane E (Assets) — ped decimation (critical path) + asset fixes + +1. **Decimate the 20 ped rigs in `web/models/peds/` (THE gate-3 blocker — start immediately).** + Use `gltf-transform` (npx) `simplify` — meshoptimizer works here: these are manifold skinned + character meshes, not TRELLIS shell-soup. Requirements: + - target **≤3k tris per ped** (integrator decision #1); keep textures (WebP/resize if easy + wins are there — file size matters less than tris) + - PRESERVE skinning (joints/weights) and do not touch `walk.glb` / `idle.glb` (the shared + animation clips) beyond confirming they still retarget + - back up originals to a gitignored dir (e.g. `pipeline/.peds_orig/` — add to .gitignore) + - stage in place (`web/models/peds/`), eyeball a contact sheet (no melted faces/hands), + then hand to Lane D for rig validation (task D2). Record before/after tris + method in + pipeline/AUDIT.md. +2. **Two asset re-exports for Lane C** (from LANE_C_GLB_VALIDATION.md): + - `procity_fit_record_crate_01.glb` — broken (undefined `uri` reference, won't parse). + Re-run normalize from source or regenerate; validate it loads in three.js before handing. + - counter: a **~2.0–2.3 m long counter WITH a till** (the R3 one is 4 m, till-less, and + squashes). Local pipeline (flux_local → trellis_mac), ≤2 attempts each; if both fail, + add to the fal fallback list and move on. + Publish any new/re-exported GLBs to the depot (the R3 passwordless tailnet path) + re-run + `validate_manifest.py --depot` → 0 errors. Note for C in LANE_E notes when live. +3. **Do NOT**: spend the fal.ai budget (decision #3), or start the hero-prop bake-to-lowpoly + pass (decision #2) — parked unless C reports a room blowing budget AND Fable re-scopes. + +**Acceptance**: all 20 peds ≤3k tris with skinning/anims intact and D's sign-off; record_crate +loads; counter attempt resolved (shipped or documented-failed); depot validate 0 errors; qa green. + +## Lane F (Integration) — wire-ups, gate closure, tag v1 + +1. **Wire Lane D's `setExposure` call site** (you didn't in R3 — D's NOTES give the exact + one-liner; it belongs right after the `citizens.setTimeOfDay(...)` call at + `web/index.html:244`): pass the shell's animated `renderer.toneMappingExposure` into + `citizens.setExposure(...)` on segment change. Verify with D (D3). +2. **Apply Lane A's storeys-checker fix** in the consistency checker (tools/): scope the + check to `permittedMax = (max >= 2) ? min(max + 1, 3) : max` per LANE_A_NOTES.md, so the + intentional 3-storey corner anchors stop warning while real drift still trips. Expect + consistency warnings → 0; A confirms (A1). +3. **Gate 3 re-measure** after D2 signs off on E1's decimated peds: busiest intersection, + clean single-pass, with rig fleet + citizens at busy midday. Need ≤300 draws AND ≤200k tris. + Record in the runbook gate table. +4. **Gate 6 closure** after B2: re-run `tools/shots.py` → 10 un-letterboxed beauty shots incl. + the 3 new poses → `docs/shots/v1_tour/` + contact sheet. Also capture B1's closed-facade + night shot for the tour (the 🔒 toast + dark facades sell §3.5). +5. **Tag v1.** When the §4 gate table in LANE_F_NOTES is all-green (1,2,4,5 already ✅; 3 and 6 + land this round): update the gate table + F-progress, run a final full + `bash tools/qa.sh --strict`, then `git tag v1.0` with a summary message. Do NOT push — + John pushes. If a gate won't close, document exactly what's short in F-progress and stop + at the documentation (no half-tag). +6. Ongoing: you own `web/index.html` and tools/ seams — other lanes leave those edits to you + (they document call sites in their NOTES instead, as D did). + +**Acceptance**: exposure wired + D-verified; consistency 0 warnings; gates 3 + 6 measured +green (or precisely documented why not); v1.0 tagged locally on an all-green qa run. + +--- + +*— Fable (integrator). Questions → leave them in your NOTES file addressed to Fable; I read +everything at round end. Commit atomically, pin your refs, leave it green.*