diff --git a/.github/release-notes.md b/.github/release-notes.md index 216ba42c..c9f087d7 100644 --- a/.github/release-notes.md +++ b/.github/release-notes.md @@ -8,7 +8,7 @@ > The full single-player campaign runs at a steady 60 fps with audio (music + > SFX) playing throughout, on Windows and Linux including Steam Deck, and it > is completable end to end: the whole campaign has been playtested through -> all 21 missions (Agent difficulty). It's an early public cut: all 21 solo +> all 20 missions (Agent difficulty). It's an early public cut: all 20 solo > missions load and run crash-free, but the known issues below are real; > feedback is very welcome. **This is a pre-1.0 release, not a finished > product** — expect rough edges and missing features until v1.0; see the diff --git a/.github/social-preview.html b/.github/social-preview.html index 4b6115e4..2050c42c 100644 --- a/.github/social-preview.html +++ b/.github/social-preview.html @@ -126,7 +126,7 @@
Status: RELEASED v0.3.0 — WINDOWS · LINUX · STEAM DECK
- Statistics:All 21 solo missions — full campaign completed in playtesting + Statistics:All 20 solo missions — full campaign completed in playtesting ~230 game-code units, compiled unmodified ~24k lines C/C++  ·  ~7k Python (port layer + tools) 199 findings root-caused  ·  two coding agents, one human, part-time diff --git a/.github/social-preview.png b/.github/social-preview.png index 59a0844b..60ae6e0e 100644 Binary files a/.github/social-preview.png and b/.github/social-preview.png differ diff --git a/AGENTS.md b/AGENTS.md index 1c53f3bd..680ee103 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,8 +51,9 @@ Run `/linkcheck` for this sweep. Record new findings in `docs/dev/findings.md` - **Phase 0–1.5:** done. Build system, boot chain, OS-shim layer, fast3d integration, first frames, full intro rendering. -- **Phase 2 (rendering):** in progress. All 21 solo levels load + render + - survive an unattended window; front end (menu → mission select → briefing → +- **Phase 2 (rendering):** in progress. All 20 solo missions (plus the + ending-credits sequence, `-level_54`) load + render + survive an + unattended window; front end (menu → mission select → briefing → start) is functional; file-backed EEPROM saves work. Cosmetic defects are parked in `docs/dev/GRAPHICS-BACKLOG.md`. - **Phase 3 (audio + input):** input layer done (`port/src/input.c`); polish diff --git a/README.md b/README.md index 6afe004d..69febc4f 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,10 @@ listed plainly there. ## Status **v0.3.0 - playable, with known rough edges.** The full single-player -campaign is completable end to end (all 21 missions, Agent difficulty, -playtested), at a steady 60 fps; all 21 solo missions load, render and run -crash-free, verified on Windows, Linux and real Steam Deck hardware. Feedback +campaign is completable end to end (all 20 missions, Agent difficulty, +playtested), at a steady 60 fps; all 20 solo missions — plus the +end-of-campaign credits sequence — load, render and run crash-free, verified +on Windows, Linux and real Steam Deck hardware. Feedback is very welcome. What a release actually installs (no networking, no telemetry, no ROM or @@ -84,8 +85,8 @@ game's logic: [Security & fidelity status](docs/security-and-fidelity-status.md) **Working:** boot sequence and front end (menu → mission select → briefing → start), front-end menu navigation on the left stick to match the F10 overlay -(D282); all 21 solo missions load, render and are crash-free (full campaign -playtested end to end at Agent difficulty); steady 60 fps +(D282); all 20 solo missions load, render and are crash-free (full campaign +playtested end to end at Agent difficulty, including the ending sequence); steady 60 fps (software RSP off the presentation critical path); full audio: in-level music and SFX; keyboard + mouse (click-to-lock, proportional aim mode, a single simplified sensitivity control) and a modern dual-stick controller layout; automatic widescreen FOV scaling; Bond is fixed in cutscenes (no more diff --git a/docs/dev/GE-ENV-PROBES.md b/docs/dev/GE-ENV-PROBES.md index c9259f5a..deea09d4 100644 --- a/docs/dev/GE-ENV-PROBES.md +++ b/docs/dev/GE-ENV-PROBES.md @@ -3,7 +3,7 @@ Every `getenv("GE_…")` in the tree. The table prose is hand-curated; **`tools_pc/gen_env_probes.py`** re-greps the live sites and reports drift (NEW / GONE vars + a fresh file:line map) — run it before trusting the -File:line cells. Last reconciled 2026-09-21 (GE_D235 added, D235 fix wired; GE_D288 refined per M-155 follow-up; GE_D75V added for the Nintendo-logo vertex-slot investigation, M-195). All are **env-gated**: unset = zero behavior +File:line cells. Last reconciled 2026-09-21 (GE_D235 added, D235 fix wired; GE_D288 refined per M-155 follow-up; GE_D75V added for the Nintendo-logo vertex-slot investigation, M-195; GE_D322 pool-telemetry probe added). All are **env-gated**: unset = zero behavior change, so they are safe to leave in a release build (they only cost a `getenv` on the guarded path). "Dead" below means *the finding it was built for is closed* — the probe is strip-candidate scaffolding, not that it does diff --git a/docs/dev/LEVEL-PLAYTEST.md b/docs/dev/LEVEL-PLAYTEST.md index 92754c3b..4753d680 100644 --- a/docs/dev/LEVEL-PLAYTEST.md +++ b/docs/dev/LEVEL-PLAYTEST.md @@ -47,7 +47,7 @@ Objective status: `src/game/objective_status.c` - Notes / defects: ``` -## 21 solo levels (mission order — numbers = `-level_XX`) +## The 20 solo missions (+ ending sequence; mission order — numbers = `-level_XX`) | # | Level | -level | Briefing asset | |---|---|---|---| @@ -71,7 +71,14 @@ Objective status: `src/game/objective_status.c` | 18 | Cradle | 41 | UbriefcradZ | | 19 | Aztec | 28 | UbriefaztZ | | 20 | Egypt | 32 | UbriefcrypZ | -| 21 | Cuba | 54 | (post-Egypt unlock) | +| — | *Ending sequence* ("Cuba") | 54 | not a playable mission — cast/credits stage (D129) | -(Mission table: `front.c:433`. Cuba = `LEVELID_CUBA`, not in the standard -folder list — unlocked after Egypt.) +(Mission table: `front.c`, `mission_folder_setup_entries` — exactly 20 +playable missions; the game's own enum says it, `SP_LEVEL_MAX // 20` in +`bondconstants.h`). "Cuba" (`-level_54`, `LEVELID_CUBA`) is **not** a +selectable mission: after the final mission the front end jumps straight to +it for the extended cast display + credits scroll +(`front.c` `selected_stage = LEVELID_CUBA` → `do_extended_cast_display(TRUE)`; +`bondviewRenderCredits`, D129). Older docs and sweep logs count it as a 21st +"level" — the campaign is 20 missions; "21/21" sweep results mean 21 stage +boots, of which 20 are missions.) diff --git a/docs/dev/LEVEL-STATUS.md b/docs/dev/LEVEL-STATUS.md index 1df06f67..bb217a57 100644 --- a/docs/dev/LEVEL-STATUS.md +++ b/docs/dev/LEVEL-STATUS.md @@ -1,4 +1,10 @@ -# LEVEL-STATUS — 21 solo-level load+render sweep (WS4) +# LEVEL-STATUS — level load+render sweep (WS4) — 20 solo missions + ending sequence + +**Counting note:** the campaign is **20 playable missions** (`SP_LEVEL_MAX // +20` in `bondconstants.h`; `mission_folder_setup_entries` in `front.c` has +exactly 20 entries). The sweep's 21st boot target, "Cuba" (`-level_54`, +`LEVELID_CUBA`), is the end-of-campaign cast/credits stage (D129), not a solo +mission — so "21/21 PASS" below means *21 stage boots*, 20 of them missions. Method: bare `./build-pc/ge007.x86_64.exe -level_XX` (per-level `-m*` pools auto-injected, D121), `GE_PCDUMP="80-260:40"`, ~24 s watchdog then diff --git a/docs/dev/V0.4.0-PLAN.md b/docs/dev/V0.4.0-PLAN.md new file mode 100644 index 00000000..6f6e769e --- /dev/null +++ b/docs/dev/V0.4.0-PLAN.md @@ -0,0 +1,339 @@ +# v0.4.0 Plan — local working document (NOT pushed; update as items move) + +Created 2026-09-21 from a fresh triage of `findings-index.csv`, +`GRAPHICS-BACKLOG.md`, `docs/BACKLOG.md`, `ROADMAP-1.0.md` (M-139 phase order), +`QOL-INVENTORY.md`, and the 2026-09-20 HANDOFF. + +**Release goal (user-set):** fix everything that still makes the port not 1:1 +with the N64 original; *then* improvements outside the OG game, plus stability. +Sequencing follows M-139's R → Q → F order, split into four phases below. + +## Baseline + +- **v0.3.0 is shipped** (tag on origin at `4827bc86`); `main` is 7 docs-only + commits ahead. Branch `release/v0.4.0` off `main` when Phase 1 starts. +- All 20 solo missions (plus the ending-credits sequence) load/render/crash-free; campaign completable end-to-end + (Agent, playtested). Steady 60 fps. Audio done. Saves done. +- Known-issue list = README "Known issues" section (D252, D303, D245, D308/ + D306, D307, D311, D318 disclosure, D75, D236, widescreen-stretch, D249, + D240/D241, D257/D259/D281 AllUnlocked caveat). + +## Triage of every open item (as of this triage) + +### Bucket A — Fidelity (port diverges from N64 behavior/appearance/sound) + +| ID | Item | State / notes | +|----|------|---------------| +| D320 | 17 aim-hold AI lists in 8 levels carry the as-authored D318 softlock race; Facility `ai_19`, Control `ai_9`, Depot `ai_12` high/med-high | Static sweep done; **live probe-verification owed** (GE_D318T-style timeline on the 3 lists). If one freezes: generalize `d318watchdog.c` (parameterize list/offset/chr/entityid), not per-list copies. N64 softlocks permanently — watchdog stays a port-side recovery, disclosed like D318. | +| D252 | Rainbow particles still intermittent on both platforms after the vertex-buffer fix | Second cause unrooted; prime suspect `import_texture_rgba16` fire-tile width/height from tile line size (32×7 vs 16×14). README known issue. | +| D245 | Water seam between two patterns, moves with view (REOPENED) | M-142 probe: tc-shift k flips during ordinary rotation; opt-in `GE_D245_FIXEDSHIFT` candidate build-verified, needs A/B vs N64 reference before making it default. | +| D303 | Wrong extra long muzzle flash (M16 + others) | Reported only, not investigated. | +| D306/D308 | Z-fighting: Dam intro/truck wheels + general/broader instances | Two reports, likely one family; investigate together. | +| D307 | In-level security camera props face backwards on some levels (Bunker) | Reported only. | +| D236 | Surface 1 billboard trees render as a solid wall of texture | Longest-running graphics bug (16+ passes). IA4 I2:A2 decode + AC-edge fixes are **in-tree uncommitted** and owe a game-wide IA4 regression sweep — commit or shelve decision first. Second-pass suspects: fog range > TEXTLOD/mip > density/culling > palette; D276 reframed oml=0xc81049d8/fmt=3 as primary suspect. | +| D235 | Wrong textures after death/restart (level reload), multiple levels | State-leak on re-entry: texture pool / CI-cache not fully reset. Needs fresh-boot-vs-reload confirmation + surfaces + screenshot, then instrument `texInitPool`/CI-cache clear. | +| D288 | Silo intro: huge flat untextured triangle sweeps the frame (frames ~562–741 of bare `-level_20`) | Visually confirmed + precisely bounded; root cause unknown. | +| D294 | Statue: CCCP monument ground renders solid black, self-recovers in 10–30 s | Not investigated. | +| D291 | Dam: texture glitches when the truck drives past | Not investigated. | +| D249 | Distant geometry drops out on Streets/Egyptian at default FOV | M-142 ruled out far-clip + LOD-multiplier; narrowed to portal/room-visibility BFS. **First check overlap with D271's portal-culling fix** (branch state, see Phase 0). Needs live screenshot+location. | +| D195 | Control: transparency/alpha-blended surfaces render wrong (glass partitions, holographic displays) | Not investigated; RM-XLU / AC-THRESHOLD / Z-write-ordering neighborhood. | +| D197 | Character face textures wrap around the head instead of clamping (Silo, intermittent) | `G_TX_CLAMP` → GL mapping + non-PoT shifts (D167 family). Try `Video.WrapFix=1` on a repro first. | +| D182(2)/D176(b) | File-select background degrades after round-trip (comb/interlacing); Surface tree-line static — shared "texture pitch/shear" defect | M-36 Family A; `import_texture_*` line-size assumption. Distinct from the disproven D183 hypothesis. | +| D176(a) | Sky: RDPHALF tri-raster decode; horizon-band coverage (Defect 2) still open | Path B draft in `scratchpad/sky.patch`, phase-fold fix applied, **never visually verified** — one `-level_22` screenshot owed. Branch `land/d176a-sky-perspective-scroll` exists (forgejo remote) — audit + port to main. | +| D75 | Front-end logos: Nintendo logo degenerate (tiny orbiting fragment); Rareware filtering wrong | **M-195 progress (2026-09-21):** emission + transform both proven correct (D63/D75V probes; zero unknown-opcode warnings; GDLs byte-faithful). Leading hypothesis: all `G_VTX` batches encode v0=0 → multi-batch nodes overwrite shared vertex slots 0..n−1, only the last batch survives. Next: cross-reference one node's G_TRI4 index ranges against per-batch counts (ROM dump) to confirm; fix is port-layer fast3d slot management if so. | +| D290 | Watch in-game "controller" section shows no control-pad graphic | Not investigated (front-end). | +| D174/D172 | Blood: decals never interactively verified (D120 needs sidecar regen); spray color fixed but owed an eyeball | BUNKER1 firefight with regenerated sidecars (`d43 && d69 && d88 --regen`). | +| D240/D241 | Gunshot SFX cadence drifts; PP7/AK47 goes silent under heavy fire near looping sounds | D241 high-confidence = D207 reproduced (check D207 entry status first — index row is stale/ambiguous). Fold into the D207 voice-cap family. | +| D322 | Long-session audio degradation (issue #87, v0.3.0 full campaign): from Silo onward audio worsens; by Caverns/Cradle OST inaudible + SFX "come and go"; restart cures → session-accumulating state | OPEN — static triage done (teardown audit clean, mixer stateless, D202 leak class covered only for ownerless `count==-1` loops and only validated single-level; D305 already records a pool/list desync). Ranked: voice-pool exhaustion/counter drift > queue starvation > evtq saturation. `GE_D322` pool-telemetry probe shipped 2026-09-21; needs a campaign capture with `GE_D322=1 GE_D204=1`. | +| D311 (residual) | Upstream anim-poison source still open (freeze class guarded) | `oldspeed=-1.75e18` at transition start; `/ unkb0` and `/ timespeed` denominators at model.c:3436/:3477. Known issue in v0.3.0 notes. | +| D258 | PAL/JP asset conversion broken at the source-data level | Repair path verified, not applied. Region fidelity — NTSC-only users unaffected, but it blocks "faithful in every region" and any JP/PAL ROM use. | +| D160 (residual) | Cutscene reliability PARTIAL (D243 family mostly fixed via M-189/M-190) | Residual = whatever the live GE_D160/GE_D243 campaign pass shows. | + +### Bucket B — Stability (crashes/freezes/hangs; not N64-parity per se) + +| ID | Item | State / notes | +|----|------|---------------| +| D289 | Dam computer-room crash (Deck, one occurrence, never repro'd) | Needs a human re-test on a current build (D255+). If it never recurs → close as untracked. | +| D287 | Windows: real, non-self-recovering freeze after ~15–20 min idle + click-back | One confirmed occurrence; `gfxFrameMsgQ` full is a lead. Consider crash-dump wiring on Windows for the next hit. | +| D286 | Deck: ~8 s self-recovering frame freeze on Caverns | One confirmed occurrence, no repro trigger. | +| D175 | Brief stutter/hang (door-open on Runway/Surface) | Matches known transient-hang classes; reproduce under `tools_pc/debug.ps1` idle-box before believing it's new. | +| D285 (residual) | Audio-thread race fix was PARTIAL | Re-check the thread-lock state vs D305's NULL guard coverage. | +| D281 | AllUnlocked breaks audio + RMB aim when enabled with zero saves written | User-facing mitigation shipped; proper fix = make the feature robust or gate it harder (see Phase 3 decision). | +| — | getenv caching in hot paths (post-release cleanup, HANDOFF M-192) | D302 fixed one instance; sweep for stragglers. Cheap perf/stability hygiene. | +| D117 | Frame nondeterminism (GE_DETERM attempted, not achieved) | Parked as a research item; do not block the release on it. | + +### Bucket C — Improvements / QoL (outside OG game; after fidelity) + +| ID | Item | Notes | +|----|------|-------| +| Widescreen | Currently **stretched 4:3**, not native — README discloses this | The big one. `WIDESCREEN-FOV-PLAN.md` Option B / CenterHUD path; needs the G-class sign-off decision (CenterHUD touches game code). | +| D237 | F10 overlay: mouse-wheel scroll, more settings, category grouping | Pure port-layer; wheel event already reaches the port. | +| D314/D315 | F10 flicker (user-deprioritized) + main-vs-in-game menu scaling | D315 deferred from v0.3.0; bigger design question — lands naturally with the overlay work. | +| D238 | Mouse sensitivity rework (master sens, RMB aim sens, Y-gain parity) | D304 already merged hipfire+F10 into one control; remainder is feel tuning in `input.c`. | +| D239 | Click-to-lock parity: delete always-grab mode 0 + config key | Small; closes D192 by deletion. | +| D226 | Player-adjustable HUD scale (ammo counter, pickup text, dialogue) | One funnel (`textRenderOutlined`); scale-about-anchor, menus excluded. | +| Rumble (D224) | Wire `osMotor*` → `SDL_GameControllerRumble` (PD precedent exists) | Deprioritized M-87; pick up if gamepad support is in scope for v0.4.0 — user call. | +| Per-pad tuning / hot-plug | PD incremental hot-plug + remembered seats; deadzone/scale/rumble per pad | Medium; real-controller users. | +| Window polish | HiDpi, center window, maximize/default-fullscreen | Small P-class wins. | +| Unlocked FPS | Plan parked; premise changed (D248/D250 fixed — default is now a true 60) | Phase 0 re-measurement before any work; motion interpolation stays out. | + +### Bucket D — Infra / housekeeping + +- **D244** self-hosted CI runner link failure — fix before the release tag so + CI can build win+linux bundles (or confirm GitHub runners suffice). +- Post-release v0.3.0 cleanup (HANDOFF): remove GE_OBJT probes + (`chraction.c` chrSet/UnsetStageFlags, `propobj.c` GAS line); M-183/M-185 + clamp removal pending full-cutscene re-verification; D309 probe decision + (keep for v0.4.0 debugging or remove). +- Working-tree archaeology: ~~uncommitted D236 second-pass state~~ **RESOLVED + before this plan was written — `532092c7`/`6807555c` (Sep 15) already landed + the D266 IA4/texedge decode + D271 portal-culling fixes on main and dropped + the D267–D280 probes.** Consequence: Phase 1 item 9 (D249) can proceed with + the D271 fix in-tree; the D236 tree-wall work continues from D276's oml/fmt=3 + lead on top of the landed decode fixes. + +## Phases + +### Phase 0 — Hygiene (½–1 session; do before any fidelity work) +1. Branch `release/v0.4.0` off `main`. +2. ~~Resolve the uncommitted D236/D271 tree state~~ already landed (`532092c7`). +3. Remove GE_OBJT probes + playtest-folder `.bat`; decide D309 probe fate; + getenv-cache sweep. +4. Fix/confirm CI runner (D244) so release tooling works end-to-end. +5. Carry-over verifications from the v0.3.0 handoff that were owed: + Runway AllUnlocked toggle re-test, menu-click spot check (D316/D317 both + closed — just confirm no regression on the new tree). + +### Release gate (independent of the phases below) + +**D322 (long-session audio degradation, issue #87)** is a campaign-breaking +defect in shipped v0.3.0 and does not wait for the phase ladder: the +`GE_D322` probe is already built and smoke-tested — request the campaign +capture (`GE_D322=1 GE_D204=1`) from the reporter now, and run its decision +rules as soon as the log lands. If the capture implicates a port-side leak, +the fix slots into Phase 2; if it's a rule-2 behavioral difference, it gets +its own sign-off item. + +### Phase 1 — Fidelity wave (the release's core) +Ordered by (crash risk → visibility → effort); each item ends with its own +verification (headless where possible, human eyeball/ear as merge gate): + +1. **D320 live verification + watchdog generalization** — the only open + item that can hard-lock progression on 8 levels; probes already exist. +2. **D289 re-test** (crash class; one human pass, then close or chase). +3. **Batch "one-off geometry/texture anomalies": D288 + D294 + D291** — + all are single-location, bounded, visually documented; likely share a + fast3d import/culling root cause. One investigation thread. +4. ~~**D252 rainbow particles second cause**~~ — **retired (M-188):** the + user's symptom closed as a duplicate of the D219 fix (live retest clean); + decode + dimensions proven correct (M-141/M-156). Re-open only on a + fireball-rainbow re-report. +5. **D245 water seam** — candidate fix exists; A/B against N64 reference, + then flip default (A1-class fidelity call). +6. **D303 + D306/D308 z-fighting family + D307 camera flip** — small visual + parity items; batch per commit cadence. +7. **D236 tree wall** — commit/shelve the in-tree decode fixes first, then + continue from D276's oml/fmt=3 lead. Longest pole; consider dispatching as + a subagent investigation while 4–6 land. +8. ~~**D235 texture reload leak**~~ — **done (M-193):** port-side + `TextureCacheMap` now cleared on every stage transition via + `videoResetTextureCache()` in boss.c; 21/21 sweep pixel-identical; live + death/restart confirm is a playtest item. +9. **D249 culling** — *after* the D271 overlap check; live screenshot+location + first, BFS instrumentation second. +10. **Audio parity: D322 long-session degradation first** (issue #87 — the + only audio report that breaks a full campaign; `GE_D322` probe already + shipped, get the campaign capture, then apply the decision rules in the + finding), **then D240/D241** (fold into D207 family) + verify D230's bass + fix by ear on the elevator track. +11. **Front-end fidelity batch: D75 logos, D290 watch pad graphic, D182(2)/ + D176(b) pitch-shear defect, D176(a) sky Defect 2** (verify the patch + visually first — it's been unverified for weeks), D195 Control alpha, + D197 face wrap. +12. **D174/D172 blood verification** (regen sidecars, BUNKER1 firefight). +13. **D258 PAL/JP asset conversion repair** — apply the verified repair path; + re-run the region sweep. Decide scope: ship JP/PAL-accurate or document + NTSC-only for v0.4.0 (user call). +14. **D311 upstream anim-poison source** — close out the last open thread of + the freeze class so the known-issue bullet can be dropped. + +Exit criteria: every README "Known issues" bullet either fixed or explicitly +re-disclosed with a v0.5.0 pointer; no new fidelity regressions (21-level +sweep after each landing). + +### Phase 2 — Stability wave +1. **D287/D286 freeze investigation** — wire Windows crash dumps (or an + in-process fault log) so the next occurrence is diagnosable; pattern-match + against `gfxFrameMsgQ` lead and the D309 teardown-race class. +2. **D175 stutter** — idle-box repro under `tools_pc/debug.ps1`; likely a + known transient-hang class, confirm and close or chase. +3. **D285 residual** — re-audit audio thread-locking vs D305's guard. +4. **D281 AllUnlocked no-save path** — make it robust (root-cause the + sndHandleEvent/aim interaction) or gate the toggle until a save exists. + User call on which. +5. Long-idle soak test (both platforms) as the stability acceptance bar. + +### Phase 3 — Improvements / QoL (only after Phases 1–2 are green) +Order by user-visible value: +1. **Native widescreen** (letterbox/center instead of stretch) — the biggest + remaining "feels wrong" item; decide the CenterHUD G-class sign-off first. +2. **F10 overlay wave: D237 (wheel + categories + more settings) + D314/D315.** +3. **Input feel: D238 sensitivity rework, D239 delete always-grab, window + HiDpi/center; rumble + per-pad tuning if gamepad is in scope (user call).** +4. **D226 HUD scale** (F10 slider candidate alongside FovScale). +5. Unlocked FPS: re-measure Phase 0 against the post-D248/D250 baseline and + decide whether v0.4.0 or v0.5.0. + +### Phase 4 — Release ritual +1. `./build-pc.sh ntsc-final` clean; `/linkcheck`; full 21-level + `tools_pc/verify.sh sweep --json`. +2. Full campaign playtest sign-off (user), incl. the D320-probe levels and a + water level + Surface + Silo (the Phase 1 visual fixes). +3. Refresh README Known Issues, `.github/release-notes.md`, findings index; + regenerate `agentic-development.md` stats from git (still owed since + v0.3.0 prep). +4. Push `release/v0.4.0` → tag `v0.4.0` → CI draft bundles → validate both + artifacts → fast-forward main. + +## Explicitly out of scope for v0.4.0 +- macOS/ARM, LAN multiplayer, modding features (post-1.0). +- Motion interpolation / sim-rate changes (UNLOCKED-FPS non-goals). +- D117 frame determinism (research-parked). + +## Session log (agent-driven, 2026-09-20 evening) + +**Phase 0 — done except user-side items:** +- `release/v0.4.0` cut off `main` (which already carried the D266/D271 fixes, + `532092c7` — the "uncommitted tree state" item was stale; plan updated). +- D322 probe work committed (`7bb43260`); GE_OBJT probes removed (D321 closed, + M-192 item 7, `56ac2ab8`); D309 probe **kept** (inert, cheap, recurrence + value for the D309/D310 freeze class). +- getenv hot-path sweep (D302 follow-up): function-level scan of all GE_* + sites found no frame/triangle-rate stragglers in fast3d; cached four + per-frame/per-hit guards in `src/game/bg.c` (GE_D104 room pass, GE_D63 + primary+secondary render logs, GE_D154 inner GDL walk) — all `#ifdef PORT`, + mechanical. +- D244 (self-hosted CI runner): needs `pacman -Syu` on the box itself — + **user-side action**, not locally fixable; fallback (`#ifdef PORT` thin + wrapper for the `#pragma weak` alias) only if the toolchain update fails. +- 21-level sweep gate: running on the new tree (see `scratchpad/sweeps/`). +- Carry-over D316/D317 + Runway AllUnlocked re-tests are interactive → folded + into the big playtest brief below. + +**Phase 1 — in flight:** +- Item 1 (D320): generic pin-signature detector added to `d318TimelineTick` + (`GE_D318T=1` now covers any chr: ACT_ATTACK + live-fire attacktype + + byte-stable animframe for 10 s → one `D320T: PIN?` line per chr, repeating + every 10 s while pinned). Detection only — the recovery watchdog stays + hardcoded to ai_22 per D320's own instruction until a second list freezes. + Live verification of Facility ai_19 / Control ai_9 / Depot ai_12 beats = + playtest work (see brief). +- Item 3 (D288/D294/D291 batch): D288 probe refined per M-155 follow-up + (any_behind_camera==0 only — the w<0 bbox math was a false lead; oml word + now logged for asset ID). D294: `GE_D104` room-visibility trace confirmed + sufficient (curRoom/roomsDrawn/budget + per-room load state every 10 s); + needs live Statue repro at FovScale≈130 + max draw distance. D291: still + needs live Dam truck details — lowest value of the three. +- Item 13 (D258 PAL/JP): **deferred pending user scope call** (ship + multi-region or document NTSC-only for v0.4.0) — no PAL/JP ROMs available + here to verify a blind CSV rename against. +- Item 4 (D235 wrong textures after death/restart): **mechanism found + fix + applied (M-193).** M-108's refutation of the game-side CI-cache theory + stands, but the *port* has its own `TextureCacheMap` (source-address keyed, + no content check) that was never invalidated on stage transitions — + `videoResetTextureCache()` existed with zero callers. Now wired into the + per-stage reset block in boss.c (`#ifdef PORT`, after `memaReset`). + Pixel-identical re-uploads; golden sweep running to confirm. Live + death/restart confirmation + a `GE_D235` >0 capture are playtest items. +- D311 upstream poison source (M-194): static pass done — all + `sub_GAME_7F06FE90` callers pass arg2=16.0f (denominator safe); the + old→new lerp only circulates values; `bheadAdjustAnimation` is the one + path where a live player-velocity corruption reaches `model->speed`. Both + speed-write choke points (`modelSetAnimSpeed`, `modelSetAnimation2`) now + log `D311: … ANOMALY` on |v|>1e4/NaN — next Caverns occurrence is a + one-line diagnosis. No env var (D156-guard pattern). +- Item 4 (D252 rainbow particles): **effectively closed — no agent work + left.** Re-read the finding this session: M-141 refuted the width/height + suspect (line=4 → correct 16×14, cross-confirmed by the GE_TEXDUMP + is_fire_shape filter), M-156 proved the ROM bytes decode to a clean + white-hot→ember progression, and **M-188 closed the user's actual symptom + (lingering residue sprites) as a duplicate of the D219 fix** — user + retested live: "seems fine now." Only a *fireball* rainbow re-report would + re-open it. Plan item 4 retired. +- Item 10 (D207 alarm klaxon): **blocked on user repro info, not agent- + workable.** M-77b implemented the designed last-resort LOOPED-preemption + pass + `[D207-DROP]`/`[D207-YIELD]` counters, BUNKER1 forced-alarm soak + showed zero drops / zero yields (pass 1 always finds a victim), and the + change was reverted. The finding now asks for: which level, which + weapon/situation, and a `GE_AUDIOTRACE=1` capture (or clip) of the failing + alarm — then decide between heavy-level 8/8 starvation (re-apply the + reverted pass), an alarm-stop-path leak, or pure perception (klaxon mix + volume vs N64). Added to the playtest brief as a low-effort ask. +- Full 21-level golden sweep: **21/21 PASS** on the final tree (`bb508e5c`), + confirming D235 fix + D311 probe + all Phase 0 changes are pixel-identical. +- **D75 (Nintendo logo) investigation — M-195, no root cause yet but two + suspects eliminated.** (a) Fresh `GE_D63` run: all 23 logo Primary GDLs + emitted every frame, zero unknown-opcode warnings → emission + DL + consumption fine; PC GDLs byte-faithful to N64 source. (b) New `GE_D75V` + per-batch vertex probe: transformed coords match the wordmark geometry + exactly (MP translation matches the lookat) → basematrix / f32→s32 / + matrix-list suspects eliminated. **Leading hypothesis:** every `G_VTX` + batch encodes v0=0, so multi-batch nodes overwrite shared vertex slots + 0..n−1 (only the last batch survives; higher-indexed triangles read stale + slots) — consistent with the single tiny orbiting fragment observed. Next: + ROM-dump one node's GDL stream and cross-reference `G_TRI4` index ranges + against per-batch counts; fix would be port-layer fast3d slot management. + Probe code (`gfx_pc.cpp`, `videoGetFrameCount()` in video.c/h) uncommitted + at end of session — commit with the doc updates. + +### Big playtest brief (for the user, when the tree is final) + +Build: `./build-pc.sh ntsc-final`. Set **`GE_D322=1 GE_D204=1`** for the whole +campaign (D322 pool telemetry — the release gate). For the three D320 beats, +add **`GE_D318T=1`** on: Facility (the captive-scientists monologue/execution +beat), Control (the ai_9 guard beat), Depot (the execution beat) — watch for +`D320T: PIN?` lines; a frozen run keeps printing every 10 s. + +Checklist beyond the normal play: +1. **D322**: full campaign, share `ge007.log` after (decision rules in the + finding). +2. **D316/D317 regression confirm**: click menu rows at a few window sizes, + esp. low rows (crop overscan bars) with SafeAreaCrop on/off; toggle + Game.AllUnlocked back and forth in-game. +3. **D289**: Dam computer room — interact with the terminals (was a one-off + crash, likely D255-class, already fixed — confirm it stays gone). +4. **D294**: Statue, set FovScale ≈130 + max DrawDistance/LodDistance, walk + past the CCCP monument at ground level; if the black-ground window hits, + note the time (a `GE_D104=1` run there is the follow-up capture). +5. **D291**: Dam — watch for texture glitches as the truck drives past; + screenshot + which surface. +6. **D175**: door-open on Runway/Surface — note any stutter/hang. +7. **D287**: leave a level idle+unfocused 15–20 min, click back (the + non-self-recovering freeze; one prior occurrence). +8. **D320 beats** as above with `GE_D318T=1`. +9. Audio by-ear: elevator track bass (D230 verify), PP7/AK47 under heavy fire + near looping sounds (D240/D241). +10. **D235**: on any level, die and restart (or reload a save) in the same + session, then look around — textures should be correct (no swapped/wrong + stage textures). Run once with `GE_D235=1` and share the log if anything + looks off (a `>0` count means a stale-cache hit slipped through). +11. **D288 (Silo)**: play Silo normally; if you see the wrong-color target / + geometry anomaly, set `GE_D288=1 GE_PCDUMP=1` for a 30–60 s run around it + and share log + captures (the probe logs the offending oml word for asset + ID). +12. **D311 (Caverns)**: play Caverns ~2 min of normal combat; if the anim- + speed freeze/poison recurs, the log will now carry a one-line + `D311: … ANOMALY` naming the corrupting call site — share it. +13. **D207 (alarm klaxon)**: if gunfire goes quiet during an alarm, note the + level + weapon + situation; ideally re-run that spot with + `GE_AUDIOTRACE=1` and share the log (or a short clip). +14. **D75 (front-end logos)**: screenshot the Nintendo logo screen (still + expected-broken: only a tiny fragment renders — M-195 suspects vertex-slot + overwrite in fast3d) and the Rareware logo — confirms whether the v0.4.0 + tree changed anything there. + +## Conventions reminder +- One findings entry per investigation; next labels after **D322**. +- Fidelity fixes: port-layer or documented A1/ABI exception only; genuine + behavioral differences need the rule-2 sign-off (`docs/dev-process.md`). +- Every subagent reads `docs/porting-notes.md` first and appends to it. diff --git a/docs/index.md b/docs/index.md index f920a944..1fbb8b20 100644 --- a/docs/index.md +++ b/docs/index.md @@ -19,7 +19,7 @@ as the [Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark), the same Rare "Indy" engine family, one hardware generation apart. **Status: v0.3.0.** The full single-player campaign runs at a steady 60 fps -and is completable end to end (all 21 missions playtested); all 21 missions +and is completable end to end (all 20 missions playtested); all 20 missions load and run clean on Windows, Linux and Steam Deck, and audio (music + SFX) plays throughout. The known rough edges — mostly cosmetic rendering defects, stretched-not-native widescreen, and missing features — are listed plainly diff --git a/docs/security-and-fidelity-status.md b/docs/security-and-fidelity-status.md index 560ccca3..47e61657 100644 --- a/docs/security-and-fidelity-status.md +++ b/docs/security-and-fidelity-status.md @@ -82,7 +82,8 @@ port of the N64's PRNG, but wasn't — a shift-operation helper didn't match the real MIPS64 instruction semantics it was meant to mirror. This was independently confirmed by hand-tracing the assembly against the C port, tracked as finding D284, and fixed before the release (verified clean -across a full 21-level sweep, no crashes). It affected loot placement, AI +across a full level sweep — all 20 missions plus the ending sequence — +no crashes). It affected loot placement, AI behavior variance, and replay-state determinism from the very first random draw, in every release before v0.3.0. Because of the fix, RNG-derived output — including the save-file CRC — changed, which meant existing save