From 2fd4c1cf7964b0f08683d3a237d7554089cd1c78 Mon Sep 17 00:00:00 2001 From: m3ultra Date: Sat, 25 Jul 2026 23:20:52 +1000 Subject: [PATCH] =?UTF-8?q?Lane=20D=20R36=20w2.5=20(Fable=20ruling):=20CLA?= =?UTF-8?q?SSIC=20KEEPS=20ITS=20PEOPLE=20=E2=80=94=20the=205=20DJ=20bodies?= =?UTF-8?q?=20gate=20out=20of=20=3Fclassic's=20pool?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit b339402 appended the 5 trellis'd DJ bodies to PED_NAMES.normal unconditionally, so ?classic=1 fetched them and its seeded crowd pool widened 17->22 (F's held §36.4 warn). Ruled option (b): the five gate OUT of classic, mirroring the sit/look/dance !CLASSIC clip gates. classic is the v2 town INCLUDING ITS PEOPLE; the DJs walk every other boot. MECHANISM (rigs.js only — zero shell edits): PED_NAMES.normal restored to the covenanted base 17 (exact pre-July-20 list); the five move to PED_NAMES.djs; loadPedFleet gains djs = dance (default tracks the existing dance flag, which the shell already passes as !CLASSIC). Roster = djs ? [...normal, ...djs] : normal — the five APPEND, so no base slot renumbers: default boot's 22-list is byte-identical to the pre-ruling list and classic's 17-list is byte-identical to pre-b339402. pickRig maps through pool.length, so 17 restores the exact pre-July-20 crowd mapping, not merely the width. MEASURED (fresh contexts, port-isolated no-store servers, seed 20261990): - ?classic=1: ZERO of the 5 DJ GLBs fetched (21 ped-GLB fetches = 17+2 bodies + walk+idle) · pool 17 normal / 19 all · 129-citizen census all base-17 u comical, zero DJ · 0 console errors. - default: all 5 fetched · pool 22/24 · 37 DJ-bodied street peds · F's organic gig proof preserved (pinned seed's venue crowd includes dj_phrtt_01 + woman_dj_02) · 0 console errors. - IDENTITY vs pre-July-20: classic booted on a shadow tree with b339402^ rigs.js — full 129-citizen (id, pedRoll, pedIndex, pedName) census BYTE-IDENTICAL to the gated tree's classic boot. Same crowd, ped for ped, as before July 20. Known side effect (noted §36): citizens_test.html passes no opts -> its dev harness shows 17+2; not a covenanted surface, {djs:true} restores it if wanted. Co-Authored-By: Claude Fable 5 --- docs/LANES/LANE_D_NOTES.md | 42 ++++++++++++++++++++++++++++++++++++++ web/js/citizens/rigs.js | 23 ++++++++++++++++----- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/docs/LANES/LANE_D_NOTES.md b/docs/LANES/LANE_D_NOTES.md index da91944..297a6d6 100644 --- a/docs/LANES/LANE_D_NOTES.md +++ b/docs/LANES/LANE_D_NOTES.md @@ -6,6 +6,48 @@ _rotOnly/head-bone normalize/upgradeStreetPeople). Measurements on the M3 Ultra --- +## ROUND 36 (wave 2.5) — CLASSIC KEEPS ITS PEOPLE: the DJ bodies gated out of `?classic` + +**The ruling (Fable, on F's §36.4 held warn):** `b339402` (July 20) appended the 5 trellis'd DJ +bodies (`woman_dj_01/02/03`, `dj_techno_01`, `dj_phrtt_01`) to `PED_NAMES.normal` UNCONDITIONALLY — +so `?classic=1` fetched them and its seeded crowd pool widened 17→22, six epochs after the covenant +froze. Ruled option (b): the five gate OUT of classic's pool, mirroring the sit/look/dance `!CLASSIC` +clip gates. Classic is the v2 town INCLUDING ITS PEOPLE; the DJs walk every other boot. + +**Mechanism (D's call — one file, `rigs.js`, per the wave-2.5 pathspec law):** +- `PED_NAMES.normal` is restored to the covenanted **base 17** (exact pre-July-20 list, order + preserved). The five move to a new `PED_NAMES.djs` extension list. +- `loadPedFleet` gains **`djs = dance`** — a new opt whose DEFAULT tracks the existing `dance` flag. + The shell already passes `dance: !CLASSIC` (index.html:194), so the classic-ness signal arrives + with ZERO shell edits: classic ⇒ `dance:false` ⇒ `djs:false` ⇒ no DJ fetch, 17-pool; default ⇒ + `djs:true` ⇒ all 22. Separable for callers wanting clips without bodies (or vice versa). +- The roster is built `djs ? [...normal, ...djs] : normal` — the five APPEND, so no base slot is + renumbered in either mode: the default-boot 22-list is byte-identical to the pre-ruling list, and + classic's 17-list is byte-identical to pre-b339402. `pickRig` maps `r01 * 997 % pool.length`, so + pool LENGTH is crowd identity — 17 restores the exact pre-July-20 mapping, not merely the width. +- Known side effect (accepted, noted): `citizens_test.html` calls `loadPedFleet` with no opts ⇒ + `dance:false` ⇒ its dev-harness roster shows 17+2, not 22+2. It is not a covenanted surface; a + future D round can pass `{djs:true}` there if the harness wants the five back. + +**Measured (fresh contexts each, port-isolated no-store servers :8971 current / :8972 pre-b339402 +shadow tree, seed 20261990):** + +| check | `?classic=1` (gated) | default boot (gated) | +|---|---|---| +| DJ-GLB fetches | **0 of 5** (21 ped-GLB fetches total = 17+2 bodies + walk+idle) | **5 of 5** | +| pool | **17 normal** / 2 comical / 19 all | **22 normal** / 24 all | +| crowd census | 129 active, 129 named, **19 distinct — all base-17 ∪ comical, zero DJ** | 153 named street peds incl. **37 DJ-bodied** (techno 13 / w01 8 / phrtt 7 / w03 6 / w02 3) | +| gig crowd (F's organic proof) | n/a (gig layer absent) | **preserved** — pinned seed's venue crew (12) includes `dj_phrtt_01` + `woman_dj_02` in the crowd | +| console errors | **0** | **0** | + +**The pre-July-20 identity check (the R29 lesson: measure, don't assume):** booted `?classic=1` on a +shadow tree whose `rigs.js` is `b339402^` (everything else current), same seed, same server law. +Roster arrays identical; the full 129-citizen census — every `(id, pedRoll, pedIndex, pedName)` +tuple — is **byte-identical** to the gated tree's classic boot. Classic's crowd is not just 17-wide; +it is the SAME crowd, ped for ped, as before July 20. (This held by construction — the five were +appended, so gating them off restores both list content and length — but it is now held by +measurement too.) + ## ROUND 29 — v6 SPIKE 1: `look.glb` bound and wired — peds glance (wave 0) *PROCITY-D, 2026-07-17. The spike finally reaches the game: E's `look.glb` (mesh-free, 65 joints, 6.5 s diff --git a/web/js/citizens/rigs.js b/web/js/citizens/rigs.js index c13dba7..7a21d24 100644 --- a/web/js/citizens/rigs.js +++ b/web/js/citizens/rigs.js @@ -14,12 +14,17 @@ import { clone as skeletonClone } from 'three/addons/utils/SkeletonUtils.js'; import { loadGLB } from '../core/loaders.js'; // The 19 rigged peds (17 normal + 2 comical) copied byte-identical from 90sDJsim into web/models/peds/. +// [R36 wave 2.5 — Fable ruling on F's §36.4 hold] `normal` is the CLASSIC-COVENANTED base 17 (the exact +// pre-July-20 list, order preserved — pickRig maps r01 through pool.length, so the length IS the identity). +// The 5 trellis'd DJ bodies (b339402, fbx_to_ped, 4k tris) live in `djs` and join the roster only when +// loadPedFleet's `djs` opt is on — they are APPENDED, so the default-boot pool is byte-identical to the +// pre-ruling 22-list and `?classic=1` is byte-identical to pre-July-20 (fetch surface AND crowd identity). export const PED_NAMES = { normal: ['man_worker_hivis_01', 'man_suit_01', 'man_casual_01', 'man_casual_02', 'man_casual_03', 'man_grunge_01', 'man_elder_01', 'man_athletic_01', 'man_bouncer_01', 'man_soldier_ww2_01', 'man_dj_streetwear_01', 'woman_casual_01', 'woman_casual_02', 'woman_business_01', - 'woman_athleisure_01', 'woman_smart_01', 'woman_chef_01', - 'woman_dj_01', 'woman_dj_02', 'woman_dj_03', 'dj_techno_01', 'dj_phrtt_01'], // trellis'd DJ bodies (fbx_to_ped, 4k tris) + 'woman_athleisure_01', 'woman_smart_01', 'woman_chef_01'], + djs: ['woman_dj_01', 'woman_dj_02', 'woman_dj_03', 'dj_techno_01', 'dj_phrtt_01'], // gated: dance-scene bodies, NOT in classic's pool comical: ['comical_luchador_01', 'comical_boy_01'], }; @@ -56,7 +61,12 @@ function loadRig(ref) { // sit.glb fetch would break the ?classic=1 zero-fetch-delta covenant — F passes sit:true on the gig/default // boot, sit:false (default) under ?classic. Absent/off → fleet.sitClip stays null and the drummer falls // back to the standing-sunk hack, so this never breaks a boot. Does NOT touch fleet.ready / determinism. -export function loadPedFleet(base = 'models/peds/', { sit = false, look = false, dance = false } = {}) { +// `opts.djs` (R36 w2.5): admit the 5 trellis'd DJ bodies into the normal roster. DEFAULTS TO `dance` — +// the shell already passes `dance: !CLASSIC`, so the classic-ness signal arrives without a shell edit and +// the bodies ride the same `!CLASSIC` gate as the sit/look/dance clips: `?classic=1` fetches none of the +// five and keeps the covenanted 17-pool; every other boot gets all 22. Separable for callers that want +// dance clips without the bodies (or vice versa). +export function loadPedFleet(base = 'models/peds/', { sit = false, look = false, dance = false, djs = dance } = {}) { const fleet = { normal: [], comical: [], all: [], // all = normal ++ comical, stable index for the impostor atlas walkClip: null, idleClip: null, sitClip: null, lookClip: null, danceClips: [], @@ -66,10 +76,13 @@ export function loadPedFleet(base = 'models/peds/', { sit = false, look = false, // order (and thus every pickRig index + identity signature) depends on GLB load-completion timing, // which varies per run/machine and silently breaks "same seed → same crowd". Compact after all // settle (filter(Boolean) preserves the fixed relative order, so a missing file is deterministic too). - const nSlots = new Array(PED_NAMES.normal.length).fill(null); + // R36 w2.5: the DJ bodies extend the roster AFTER the base 17, so gating them off shortens the pool + // without renumbering a single base slot — classic's pickRig mapping is the pre-July-20 one exactly. + const normalNames = djs ? [...PED_NAMES.normal, ...PED_NAMES.djs] : PED_NAMES.normal; + const nSlots = new Array(normalNames.length).fill(null); const cSlots = new Array(PED_NAMES.comical.length).fill(null); const jobs = []; - PED_NAMES.normal.forEach((n, i) => jobs.push(loadRig(`${base}${n}.glb`).then(r => { + normalNames.forEach((n, i) => jobs.push(loadRig(`${base}${n}.glb`).then(r => { if (r) { r.pedName = n; nSlots[i] = canonRig(r); } }))); PED_NAMES.comical.forEach((n, i) => jobs.push(loadRig(`${base}${n}.glb`).then(r => { if (r) { r.pedName = n; cSlots[i] = canonRig(r); } })));