PROCITY/docs/LANES/LANE_E_NOTES.md
m3ultra 081755bb71 Lane E round 8 (E1+E2): book/toy stock packs + pack-QA gate
E1: build_stock_pack.py generalized over kinds — record (256x256 sleeves), book
(96x256 tall-thin spines), toy (256x256 boxes), per-kind parody word banks, same
build-time/parody/atlas/index laws. Book+toy sample packs built + staged (?localdepot)
+ indexes committed to pipeline/packs/ so Lane C wires book/toy shelves now. Parody
deterministic + no distinctive-token leak across all 3 kinds.
E2: validate_pack.py QA gate (wired into validate_manifest -> qa gate 3) — bad UV /
empty title / bad price_band / dangling atlas / dup id fails qa (proven). qa strict
GREEN 5/5.
Real 150-250-item packs blocked on GODVERSE_DSN (flagged to Fable); samples are
placeholders in the real index format. No fal spend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 02:27:50 +10:00

174 lines
12 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.

# LANE E — cross-lane notes
## Round 8
**→ Lane C (E1 — book + toy packs staged for you):** `build_stock_pack.py` is generalized over kinds;
book/toy **sample packs are staged** (`web/assets/models/stock_{book,toy}_{index.json,atlas_00.webp}`,
`?localdepot`) + indexes committed to `pipeline/packs/`. Same schema you proved for records — wire
book/toy shelves through the stockAdapter, fail-soft per kind. **Cell geometry:** record 256×256
(square), **book 96×256 (tall-thin spine)**, toy 256×256 (box). You read `uv` (I confirmed from your
notes), so render each kind on its own shelf geometry; the index also carries `cell_w`/`cell_h` if
useful. `artist` carries author (book) / brand (toy). These are **synthetic placeholders** (real index
format) until the DSN lands — your fail-soft + wiring are unaffected when real covers swap in.
**E2 — pack-QA gate is live** (`validate_pack.py` in qa gate 3 via validate_manifest): a bad bake
(bad UV/price-band/empty title/dangling atlas) fails qa. If you add index fields, tell me and I'll
extend `REQUIRED`.
**→ Fable (blocker, flagged early per the slip rule):** the **real** book/toy/record packs need
**`GODVERSE_DSN`** (dealgod Postgres — up on :5432; builder reads it from env, I don't hunt creds).
One command per kind once set (`--kind book --from-db --count 200`). Pipeline + parody + atlas + QA
gate all proven on samples; not blocking C (samples staged). No fal spend.
## Round 7
**→ Lane D (D1 — the flip gate): merged peds ready to validate.** `web/models/peds/*.glb` (19 rigs)
are merged to **ONE draw each** (1 primitive + 1 atlased material) — fleet **92→19 draws**, at the
24-rig near cap **116→24**. Method: Blender join + UV-pack + EMIT-bake all materials into one 1024
atlas (`pipeline/merge_ped.py`). **Skinning + skeleton preserved** — 65 joints intact on all 19,
`walk`/`idle` untouched, so clips retarget unchanged. I verified in the vendored GLTFLoader: all 19
load as SkinnedMesh + bind walk; `man_suit` poses to byte-identical dims vs the original (skin
deforms unchanged); `man_athletic` (3-mat) atlas eyeballed correct. Please do the full pass
(silhouettes/materials/impostor bake/identity variety) + the **full-density draws/tris numbers** for
F's flip. Pre-merge peds backed up (gitignored) at `pipeline/.peds_r6/` if you need a diff; per-ped
in `pipeline/_peds_merge.json`. **If any ped's atlas/silhouette reads wrong, name it — I re-run that
one** (per-ped `atlas` size is tunable; a couple with dense detail could go 2048).
**→ Lane C (E2 — stock pack): pipeline built + PROVEN, sample staged for you now.**
`pipeline/build_stock_pack.py` produces the pack (parody-transform → atlas WebPs + JSON index). A
**24-sleeve sample pack is staged at `web/assets/models/stock_record_{index.json,atlas_00.webp}`**
wire `?stock=real` against it NOW (real index format, synthetic covers), and the real covers drop in
unchanged. **Proposed index schema** (I built to this — confirm/adjust in LANE_C_NOTES and I'll match
`INDEX_FIELDS`):
```json
{ "version":1, "atlas_px":2048, "cell":256, "atlases":["stock_record_atlas_00.webp"],
"items":[ {"id":"rec_0000","title":"Neon Suburbs","artist":"Trev Wollemi","price":39,
"price_band":"collector","atlas":"stock_record_atlas_00.webp","uv":[0,0,0.125,0.125]} ] }
```
`uv` = [u0,v0,u1,v1] into the named atlas (origin top-left); price_band ∈ bargain/standard/collector/grail.
Seeded pick per bin is yours (same shop.seed → same crate). Fail-soft: pack missing → parody canvas.
**→ Fable (E2 blockers — flagging mid-round per your schedule-harness note):** the real 200-400 pack
needs two things I can't self-serve: (1) **`GODVERSE_DSN`** — the dealgod Postgres dsn/creds (Postgres
is up on :5432; I read it from env, don't hunt creds) → `--from-db --count 300`; (2) **C's schema**
confirmation. Both external. The pipeline + parody law + atlas are done and proven on `--sample`; the
real pack builds in one command once the DSN lands. Not blocking C's consumer wiring (sample staged).
## Round 6
**E1 done**`publish.py` now merges into `_published.json` (no more R5 clobber); `--verify` +
post-publish drift-check vs the live depot; `validate_manifest.py` fails if a manifest GLB isn't in
`_published.json`. Record verified 27==depot. All 27 procity GLBs stay live + recorded.
**→ Lane B / Lane C — I'm on-call for the props I shipped:**
- **B:** if `bus_shelter` / `bin` need a scale, origin, or facing tweak once placed on the street
graph, tell me the exact issue (current: bus_shelter 2.33×1.41 m / 2.4 m, bin 0.57×0.68 m / 1.0 m,
both base-origin minY=0). I can re-normalize + re-publish same-name (idempotent, merge-safe now).
- **C:** if `glass_case` / `magazine_rack` / `crate_stack` read wrong in-room (scale, the fal
glass_case's interior clutter, the magazine_rack density), flag it. A *broken*-prop fal re-gen is
pre-authorized ≤2 attempts (decision #5) — I'll log any spend in AUDIT. Footprints in the manifest;
all base-origin. Mapping guidance for the 3 orphans is in the Round-5 → Lane C section below.
## Round 5
### → Lane C: hero props BAKED to ≤8k tris — re-measure the record interior
The 6 heavy TRELLIS props are re-baked and **live on the depot** (same filenames, footprints
unchanged, so **no re-map needed** — they upgrade in place):
| prop | tris before → after |
|---|---|
| drinks_fridge | 77k → 8.0k |
| milkshake_mixer | 73k → 8.0k |
| listening_booth | 54k → 8.0k |
| counter_till | 32k → 8.0k |
| novelty_record | 26k → 8.0k |
| arcade_cabinet | 25k → 8.0k |
**Fleet 288k → 48k tris.** Method: voxel-remesh → decimate → Cycles base-colour bake (see
`pipeline/bake_lowpoly.py`, AUDIT R5). Verified loading in the vendored GLTFLoader; base colour
baked (no separate metallic/normal maps → also dodges the record_crate dangling-texture class).
**Please re-measure the record interior** (was ~273k tris in your R4 note) and record the new
number in LANE_C_GLB_VALIDATION.md — it should drop by ~most of the prop weight.
### → Lane C: 3 new fittings LIVE (fal Hunyuan) — glass_case + magazine_rack
The two remaining primitive-only fittings are now real GLBs on the depot (≤8k, base-colour baked):
- **`glass_case`** (`procity_fit_glass_case_01.glb`, 1.08×1.42 m, 1.0 m tall) — timber base + glass
panels + items inside. Registry ids `glass_case` (toy/dept) + `glass_cabinets` (pawn) both alias
to it. → add `glass_case`/`glassCase` (+ your pawn cabinet kind) → `'glass_case'` in `KIND_TO_GLB`.
- **`magazine_rack`** (`procity_fit_magazine_rack_01.glb`, 0.54×0.44 m, 1.2 m tall) — tiered timber
rack w/ magazines (milkbar/pawn). Registry `magazine_rack` aliases to it. → map your kind → `'magazine_rack'`.
- Both base-origin, verified loading in the vendored GLTFLoader. `manifest.fittingAliases` also maps
`fridge`→`drinks_fridge` and `listening_corner`→`listening_booth` if you iterate registry ids.
### → Lane B: new street props — `bus_shelter` + `bin`
- `procity_street_bus_shelter_01.glb` (`furniture.bus_shelter`, 2.33×1.41 m, 2.4 m, ≤8k, base-origin).
Solid painted-steel shelter (back wall + roof + bench) — place at bus-stop spots along the footpath.
- `procity_street_bin_01.glb` (`furniture.bin`, 0.57×0.68 m, 1.0 m, 3k) — red council wheelie bin, an
obvious town-furniture gap. Map `bin` in your furniture GLB-upgrade path if you want it on footpaths.
- **B3 resolved:** `novelty_record` is now **8k** (was 26.5k) via the E1 bake — re-measure the busy view.
All furniture GLBs base-origin + footprint-accurate; fail-soft as usual.
### → Lane C also: `crate_stack` for floor piles / dig
`procity_fit_crate_stack_01.glb` (`fittings.crate_stack`, 0.71×0.72 m, 0.9 m, 3k) — a stack of 3
plastic milk crates, good for record-store floor dressing or the dig scene. Optional; map a kind to
`'crate_stack'` if useful.
### → Fable: E1 (bake) + E3 (fal) status
- **E1 bake DONE + committed** — 6 props ≤8k, published. Feeds C's re-measure + your v1.1 tag.
- **E3 fal DONE** — glass_case + bus_shelter + magazine_rack generated on fal Hunyuan v2, **~$0.64
total** (log in AUDIT R5), ≤2 attempts each, all baked ≤8k + published. Guardrail held (nothing
else on fal). `validate --depot` 0 err. Last two primitive-only fittings retired.
- **E2 depot growth** next (v2-serving library props).
---
## Round 4
## → Lane D (task D2): decimated peds ready to validate
The 19 ped rigs in `web/models/peds/` are decimated and staged (committed `518678d`, ref
`lane-e/round4-peds`). Please validate rig binding + animation:
- **≤3k tris each** (range 15642805; per-ped before/after in `pipeline/_peds_decim.json`).
Fleet total **924k → 46.5k tris** (48.6k → 2.45k avg). At the 24-rig near cap ≈ **≤67k**.
- **Skinning preserved**: `JOINTS_0`/`WEIGHTS_0` intact; **skeleton unchanged** (nodes + 65
joints identical to source on every ped I checked), so the shared `walk.glb`/`idle.glb`
clips retarget unchanged. **`walk.glb`/`idle.glb` were NOT touched.**
- Method: `gltf-transform weld``simplify --ratio 0.05 --error 0.12` (meshoptimizer — works
because these are manifold skinned meshes, not R3 TRELLIS shell-soup). Contact sheet:
`docs/shots/laneE/peds_decimated.png` (silhouettes/textures clean at street distance; fingers
merge + faces flatten as expected at 3k, no melting).
- Originals backed up (gitignored) at `pipeline/.peds_orig/` if you need a before/after diff.
If any rig fails to bind/animate or a silhouette reads badly, tell me the file(s) and I'll
re-run that one with a gentler error (0.08 keeps ~50% more tris but still <5k). Then F re-measures
gate 3 after your sign-off.
## → Lane C: E2 asset re-exports
1. **`procity_fit_record_crate_01.glb` FIXED.** Root cause of your `undefined 'uri'` crash: the
material's `metallicRoughnessTexture` + `occlusionTexture` both pointed at a **sourceless
texture** (the packed AO/roughness map failed to encode to WebP during normalize; base-colour
+ normal were fine). Fix: `pipeline/fix_glb_textures.py` strips material slots that reference a
sourceless texture (orphaning it three.js loads textures lazily, so no crash). **Verified it
loads in the real vendored `GLTFLoader`** (meshes=1, tris=5000, textures ok) alongside a
bookshelf control. Re-published to the depot re-map `record_crate`/`recordBin` in `glb.js`
(they should already be mapped) and it'll upgrade instead of falling back.
2. **counter-with-till — LIVE.** New fitting `counter_till` (`procity_fit_counter_till_01.glb`):
**1.61 × 0.64 m footprint, 1.15 m tall**, timber counter + cabinet doors + period beige till on
top (flux_local concept trellis_mac, on-device). Fixes the R3 4 m till-less counter that
squashed. **Verified it loads in the vendored `GLTFLoader`** (32k tris TRELLIS shell-soup floor,
within decision-#2's 2577k for focal props) and **live on the depot** (`validate --depot` 0 err).
**In `glb.js` re-add `counter` to `KIND_TO_GLB` mapping to `'counter_till'`** (NOT the old
`counter` = balcao, which is a 4 m long bar counter kept for shops that want it). The manifest
`fittingAliases.counter` `counter_till` too. It's base-origin (minY=0), so your footprint-fit +
floor-plant works unchanged; at a 1.42.0 m counter slot it scales to a believable ~1.01.4 m
tall counter.
## → Fable: status
- **E1 (gate-3 critical path): DONE.** Peds 3k, committed + pinned. Unblocks D2 F3.
- **E2a record_crate: DONE + verified** (loads in vendored GLTFLoader). Re-published.
- **E2b counter: in progress** (local, on-device no fal spend per decision #3).
- Not doing: fal.ai spend (glass-case/bus-shelter stay parked), hero-prop bake-to-lowpoly.