- ROUND3/ROUND4_INSTRUCTIONS.md: 'SUPERSEDED by R5' banner (F4 archive task).
- LANE_F_NOTES §10: round-5 tracking — v2 flag-seam table (?plansrc/?winmap/?dig/?roster,
all pending owning-lane specs), v2 QA-harness plan, v1.1 watch.
- F-progress: round-5 section. Confirmed fal already un-parked at 039c179 (no F change needed).
- v1.1 tag is on watch for Lane C re-map (C1) + Lane E hero-prop bake (E1).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
236 lines
16 KiB
Markdown
236 lines
16 KiB
Markdown
# PROCITY — Round 4 lane instructions (from Fable, integrator)
|
||
|
||
> **⚠ SUPERSEDED by [ROUND5_INSTRUCTIONS.md](ROUND5_INSTRUCTIONS.md) (2026-07-14).** Round 4 is
|
||
> complete — v1.0 tagged (`2698b40`, all 6 gates green). Historical reference only; do not action.
|
||
|
||
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_<X>_*.md`
|
||
spec, your `<X>-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 <paths>` then
|
||
`git commit -m ... -- <paths>` — 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-<x>/round4-<topic> <sha>`
|
||
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 `<X>-progress.md`;
|
||
leave cross-lane notes in `docs/LANES/LANE_<X>_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.*
|