diff --git a/docs/dev/findings-index.csv b/docs/dev/findings-index.csv index 088379a0..77c554d3 100644 --- a/docs/dev/findings-index.csv +++ b/docs/dev/findings-index.csv @@ -139,7 +139,7 @@ D239,?,"QoL ask (M-106, user QA):",CLOSED — executed in the v0.2.0 prep pass ( D240,OPEN,"Player gunshot SFX timing/cadence reportedly does not match the N64 original's rate (M-106, user QA report).","OPEN — not root-caused; static call-site tracing only, no runtime verification possible in this environment." D241,OPEN,Player gunshot SFX goes silent under some conditions —,"OPEN — not newly root-caused; high confidence this is D207 reproduced, not an independent bug." D242,?,Player-death sequence UX regression vs N64 original:,NOT A PORT-LOGIC BUG as far as static analysis can tell. -D243,OPEN,"Dam end-of-level cutscene (the abseil/bungee sequence, D148/D160's subject):",OPEN — M-143: mechanism named. +D243,OPEN,"Dam end-of-level cutscene (the abseil/bungee sequence, D148/D160's subject):","OPEN — M-144: CONFIRMED PC-only (user, direct N64 comparison) —" D245,OPEN,IsWater water: two competing patterns with a visible seam that moves as the player looks around (mouse/aim) —,"OPEN — REOPENED, M-142 headless probe found the tc-shift k measurably flips during ordinary view rotation (new root-cause evidence); an opt-in GE_D245_FIXEDSHIFT candidate is build-verified but needs…" D246,OPEN,"Tiny pixel strips at the left and right edges of the screen, ""like overscan"" —","OPEN — one candidate ruled out (M-116 follow-up), root cause not found." D247,RESOLVED,Black bars top and bottom of screen —,"NOT A BUG — confirmed faithful, unmodified N64 decomp behaviour, no code change made." diff --git a/docs/dev/findings.md b/docs/dev/findings.md index 0a30ec58..a2795251 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -546,7 +546,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121). | D240 | **Player gunshot SFX timing/cadence reportedly does not match the N64 original's rate (M-106, user QA report).** — full `## D240` entry at file tail | **OPEN — not root-caused; static call-site tracing only, no runtime verification possible in this environment.** Confidence LOW-MEDIUM that this is a *new* bug distinct from the D155/D186/D193/D204/D209 timing-keystone family (all of which gate the identical `deltaFrames→speedgraphframes→g_ClockTimer→g_GlobalTimer` chain this SFX trigger consumes).… | | D241 | **Player gunshot SFX goes silent under some conditions — reported on Bunker with the alarm sounding, "or some other factor" — but only for PP7 and AK47, Klobb…** — full `## D241` entry at file tail | **OPEN — not newly root-caused; high confidence this is D207 reproduced, not an independent bug.** Recommend folding this repro into D207 (or closing D241 as a duplicate once D207 is reopened) rather than tracking separately.… | | D242 | **Player-death sequence UX regression vs N64 original: PC requires an LMB click to proceed to the mission-failed/file-select screen; user recalls N64 auto-plays…** — full `## D242` entry at file tail | **NOT A PORT-LOGIC BUG as far as static analysis can tell.** Confidence HIGH that the LMB-click skip path is faithful original behavior (Z_TRIG-mapped, exists unmodified in `bondview2.c`), not a defect to remove.… | -| D243 | **Dam end-of-level cutscene (the abseil/bungee sequence, D148/D160's subject): the camera violently shakes/"spazzes" during each of the scripted camera-angle…** — full `## D243` entry at file tail | OPEN — M-143: mechanism named. The `gBondViewCutscene` look-at branch reads `field_3C4/8/C`, a leaky-integrator low-pass filter of Bond's real position that isn't reset when the scripted cutscene warps him — the filter needs ~1s to catch up, producing the shake. The filter's own update is `g_ClockTimer`-scaled (looks decomp-faithful); open question is whether real N64 hardware shows the same transient, which would make this not a port bug at all. D146 still fully decoupled (zero hits, 3rd run running). | +| D243 | **Dam end-of-level cutscene (the abseil/bungee sequence, D148/D160's subject): the camera violently shakes/"spazzes" during each of the scripted camera-angle…** — full `## D243` entry at file tail | OPEN — M-144: CONFIRMED PC-only (user, direct N64 comparison) — real N64 does not show this shake. Mechanism (M-143): the `gBondViewCutscene` look-at branch reads `field_3C4/8/C`, a leaky-integrator low-pass filter of Bond's real position that isn't reset when the scripted cutscene warps him, producing a ~1s look-at snap. Filter math is decomp-exact and `g_ClockTimer`-scaled, so the bug must be upstream: either the position warp itself is wrong/bigger on PC, or a call-ordering desync around the `CAMERAMODE_INTRO` transition. Next: probe raw `field_488.pos`/`field_3B8` around the warp tick. D146 still fully decoupled (zero hits, 3 runs). | | D245 | **IsWater water: two competing patterns with a visible seam that moves as the player looks around (mouse/aim) — "looks almost exactly like skybox" (M-116, user…** — full `## D245` entry at file tail | OPEN — REOPENED, M-142 headless probe found the tc-shift `k` measurably flips during ordinary view rotation (new root-cause evidence); an opt-in `GE_D245_FIXEDSHIFT` candidate is build-verified but needs a live A/B, not shipped as default.… | | D246 | **Tiny pixel strips at the left and right edges of the screen, "like overscan" — look like raw pixels, not 3D graphics (M-116, user QA report).** — full `## D246` entry at file tail | **OPEN — one candidate ruled out (M-116 follow-up), root cause not found.** Step (1) from the original plan is done… | | D247 | **Black bars top and bottom of screen — possible aspect-ratio defect (M-116, user QA report).** — full `## D247` entry at file tail | **NOT A BUG — confirmed faithful, unmodified N64 decomp behaviour, no code change made.** `GE_PCDUMP` captures (both against the pre-existing save and a fresh-EEPROM run, to rule out a stale `Screen` option from earlier test sessions) show the exact same inset on Frigate… | @@ -10699,7 +10699,9 @@ crash class C2 (Facility `-level_34`, Runway `-level_35`): `import_texture_i8` A **M-142 update: live playthrough with both probes on, real signal, still not root-caused.** User played Dam to the abseil cutscene twice this session with `GE_D243=1 GE_D160=1` set (first run), then again with a new `GE_D243CAM` probe added. **Key new fact: the visible "violent shake" symptom reproduced on BOTH runs, but the `D146` stale-memory burst fired on NEITHER run** (log captured well past the historical 1600-3900-frame window both times, zero `D146:` lines) — this decouples the two symptoms M-107/M-109 had been treating as related. The shake is real, reproduces every time, and has nothing observable to do with the D146 mechanism; whatever drives it must be a silent bad-value computation (camera position/angle math), not a logged error. **Camera code path narrowed (partially):** `bondviewFrozenCameraTick`'s `CAMERAMODE_POSEND` branch (`bondview2.c:1537+`) has three sub-paths — `g_CameraLookAtBondPad` look-at, a `gBondViewCutscene`-struct spherical-angle path, and a pad-orbit fallback (`flt_CODE_bss_80079A00` angle accumulated by `g_GlobalTimerDelta` each tick). Added a `GE_D243CAM` probe (`#ifdef PORT`) to the orbit-fallback branch to check whether `g_GlobalTimerDelta` jitter there explains the shake — **it fired zero times**, meaning the Dam abseil cutscene does NOT use that branch; the real driver is one of the two earlier `return`-before-my-probe branches (`g_CameraLookAtBondPad` or `gBondViewCutscene`), not yet instrumented. Next session: add the same style of probe to those two branches (log `pos`/`pos2`/`gBondViewCutscene->theta,verta` every call) and re-capture — same repro (Dam, Agent, to the abseil cutscene, `GE_D160=1` to confirm mode(7) still fires 3x) works reliably and takes only a few minutes end to end. -**M-143: live capture with the two new probes names the mechanism — a leaky-integrator position filter not reset across a scripted position warp; likely decomp-faithful, open question is whether it's a real port bug at all.** User replayed the same Dam-abseil repro with `GE_D243=1 GE_D160=1 GE_D243CAM=1` (probes from the M-142 next-step now added to both previously-uninstrumented `CAMERAMODE_POSEND` sub-paths: `g_CameraLookAtBondPad` look-at and the `gBondViewCutscene` spherical-angle branch). **The `gBondViewCutscene` branch fires** (confirmed live — the pad-orbit branch stays at zero hits, third confirmation). Within it, `pos` (the eye) stays exactly fixed for the whole cutscene segment while `pos2` (the look-at target) is the thing moving — and tracing which of the branch's two `pos2` assignments actually ran (the `dword_CODE_bss_80079A18 == CAMERAMODE_INTRO` case reads `g_CurrentPlayer->field_3C4/3C8/3CC` directly; the `else` case derives `pos2` from `pos` + a `theta`/`verta` trig offset) rules out the trig path by arithmetic: with `theta`/`verta` observed constant across a stretch of frames, the trig formula only allows `pos2` to vary by a fraction of a unit, but the log shows `pos2.y` sweeping from **-22832 to +691 over roughly the first 60 frames** of the branch, then settling into a small ~110-unit 4-frame-period wobble — only the raw-field-read (`CAMERAMODE_INTRO`) path is consistent with a swing that large. **`dword_CODE_bss_80079A18` is scripted, not a mode flag Claude findings mislabeled** — it's set only from `ai->LOOK_AT_BOND_FLAG` in `chrai.c:4007`, i.e. the Dam level's own AI/cutscene script explicitly requests "look at Bond" framing for this segment; this is by design, not a bug in the flag itself. **`field_3C4/3C8/3CC` is not a raw position — it's a leaky-integrator low-pass filter of Bond's real collision position:** `bondviewUpdatePlayerCollisionPositionFields()` (`bondview2.c:4702`, called from three sites including `bondviewFrozenMoveBond` — the puppet/cutscene-movement driver used while Bond is "frozen" for a scripted sequence) runs `field_3B8 = FACTOR_1*field_3B8 + field_488.pos` **`g_ClockTimer` times per call** (already delta-scaled, one of porting-notes' documented `g_ClockTimer`-iteration sites — this specific update looks decomp-faithful, not a naive per-frame-not-per-tick bug), then `field_3C4/8/C = field_3B8 * FACTOR_2` where `FACTOR_1`/`FACTOR_2` are complementary constants (`0.9`/`0.100000024` non-EU, `0.8812`/`0.1188` EU) chosen so the filter's steady state converges back to the real `field_488.pos` — i.e. `field_3C4/8/C` is a **lagged, smoothed shadow of Bond's actual position**, not his position itself. **The mechanism this explains:** the instant the abseil sequence's scripted camera engages `LOOK_AT_BOND_FLAG`, Bond's actual `field_488.pos` (driven by `bondviewFrozenMoveBond`'s animation/offset-based puppet movement) jumps to wherever the cutscene's puppet animation starts — but the `field_3B8` accumulator was still converged on wherever Bond had been standing/walking a moment before (a very different location, hence the ~20,000-unit initial gap), and it takes on the order of a couple dozen ticks of the geometric decay to catch up — visually, a fixed eye with a look-at target that starts wildly displaced and snaps toward the puppet over about a second, i.e. exactly the reported "violent shake." **Open question, not yet answerable from this repo alone: is this also what real N64 hardware shows?** The filter's own update is `g_ClockTimer`-scaled (frame-rate-correct by the same standard porting-notes.md already applies to other delta-scaled code), so nothing found this session points at a PC-specific timing divergence in *this* filter — if the N64 original also snaps Bond's `field_488.pos` for this scripted segment without resetting `field_3B8` (it's only ever zero-initialized once, at player creation in `player.c:271-273`, never re-seeded on a cutscene-mode entry anywhere in `src/game`), the same transient would play out identically on real hardware, which would make this **not a port bug at all** — an original-game quirk that happens to be more noticeable now, or previously undocumented on N64 itself. Confirms (third run in a row): **zero `D146:` hits** — the shake and the D146 stale-memory burst remain fully decoupled; treat them as two separate, unrelated findings going forward, not two symptoms of one cause. **Next, concrete:** (1) the decisive test is an N64 emulator/hardware capture of the identical Dam-abseil moment to see if the same look-at snap is visible there — if yes, close this as "faithful to original, not a port defect" and move D148/D173 (the broader cutscene-bug umbrella) up instead; (2) if no N64 access is available, the next-best port-side check is logging `field_488.pos` and `field_3B8` (not just the already-smoothed `field_3C4/8/C`) at the exact tick `dword_CODE_bss_80079A18` flips to `CAMERAMODE_INTRO`, to confirm the pre-cutscene/post-cutscene position gap is really as large as inferred rather than something else entirely coincidentally producing the same swing shape. +**M-143: live capture with the two new probes names the mechanism — a leaky-integrator position filter not reset across a scripted position warp; likely decomp-faithful, open question is whether it's a real port bug at all.** User replayed the same Dam-abseil repro with `GE_D243=1 GE_D160=1 GE_D243CAM=1` (probes from the M-142 next-step now added to both previously-uninstrumented `CAMERAMODE_POSEND` sub-paths: `g_CameraLookAtBondPad` look-at and the `gBondViewCutscene` spherical-angle branch). **The `gBondViewCutscene` branch fires** (confirmed live — the pad-orbit branch stays at zero hits, third confirmation). Within it, `pos` (the eye) stays exactly fixed for the whole cutscene segment while `pos2` (the look-at target) is the thing moving — and tracing which of the branch's two `pos2` assignments actually ran (the `dword_CODE_bss_80079A18 == CAMERAMODE_INTRO` case reads `g_CurrentPlayer->field_3C4/3C8/3CC` directly; the `else` case derives `pos2` from `pos` + a `theta`/`verta` trig offset) rules out the trig path by arithmetic: with `theta`/`verta` observed constant across a stretch of frames, the trig formula only allows `pos2` to vary by a fraction of a unit, but the log shows `pos2.y` sweeping from **-22832 to +691 over roughly the first 60 frames** of the branch, then settling into a small ~110-unit 4-frame-period wobble — only the raw-field-read (`CAMERAMODE_INTRO`) path is consistent with a swing that large. **`dword_CODE_bss_80079A18` is scripted, not a mode flag Claude findings mislabeled** — it's set only from `ai->LOOK_AT_BOND_FLAG` in `chrai.c:4007`, i.e. the Dam level's own AI/cutscene script explicitly requests "look at Bond" framing for this segment; this is by design, not a bug in the flag itself. **`field_3C4/3C8/3CC` is not a raw position — it's a leaky-integrator low-pass filter of Bond's real collision position:** `bondviewUpdatePlayerCollisionPositionFields()` (`bondview2.c:4702`, called from three sites including `bondviewFrozenMoveBond` — the puppet/cutscene-movement driver used while Bond is "frozen" for a scripted sequence) runs `field_3B8 = FACTOR_1*field_3B8 + field_488.pos` **`g_ClockTimer` times per call** (already delta-scaled, one of porting-notes' documented `g_ClockTimer`-iteration sites — this specific update looks decomp-faithful, not a naive per-frame-not-per-tick bug), then `field_3C4/8/C = field_3B8 * FACTOR_2` where `FACTOR_1`/`FACTOR_2` are complementary constants (`0.9`/`0.100000024` non-EU, `0.8812`/`0.1188` EU) chosen so the filter's steady state converges back to the real `field_488.pos` — i.e. `field_3C4/8/C` is a **lagged, smoothed shadow of Bond's actual position**, not his position itself. **The mechanism this explains:** the instant the abseil sequence's scripted camera engages `LOOK_AT_BOND_FLAG`, Bond's actual `field_488.pos` (driven by `bondviewFrozenMoveBond`'s animation/offset-based puppet movement) jumps to wherever the cutscene's puppet animation starts — but the `field_3B8` accumulator was still converged on wherever Bond had been standing/walking a moment before (a very different location, hence the ~20,000-unit initial gap), and it takes on the order of a couple dozen ticks of the geometric decay to catch up — visually, a fixed eye with a look-at target that starts wildly displaced and snaps toward the puppet over about a second, i.e. exactly the reported "violent shake." **Open question, not yet answerable from this repo alone: is this also what real N64 hardware shows?** The filter's own update is `g_ClockTimer`-scaled (frame-rate-correct by the same standard porting-notes.md already applies to other delta-scaled code), so nothing found this session points at a PC-specific timing divergence in *this* filter — if the N64 original also snaps Bond's `field_488.pos` for this scripted segment without resetting `field_3B8` (it's only ever zero-initialized once, at player creation in `player.c:271-273`, never re-seeded on a cutscene-mode entry anywhere in `src/game`), the same transient would play out identically on real hardware, which would make this **not a port bug at all** — an original-game quirk that happens to be more noticeable now, or previously undocumented on N64 itself. Confirms (third run in a row): **zero `D146:` hits** — the shake and the D146 stale-memory burst remain fully decoupled; treat them as two separate, unrelated findings going forward, not two symptoms of one cause. **Next, concrete (superseded by M-144 below — kept for the reasoning trail):** (1) the decisive test is an N64 emulator/hardware capture of the identical Dam-abseil moment to see if the same look-at snap is visible there — if yes, close this as "faithful to original, not a port defect" and move D148/D173 (the broader cutscene-bug umbrella) up instead; (2) if no N64 access is available, the next-best port-side check is logging `field_488.pos` and `field_3B8` (not just the already-smoothed `field_3C4/8/C`) at the exact tick `dword_CODE_bss_80079A18` flips to `CAMERAMODE_INTRO`, to confirm the pre-cutscene/post-cutscene position gap is really as large as inferred rather than something else entirely coincidentally producing the same swing shape. + +**M-144: CONFIRMED — real N64 does NOT show this shake (user, direct comparison).** This settles the open question M-143 ended on: the abseil cutscene's look-at snap is a genuine PC-only divergence, not an original-game quirk. Since the filter math itself (`bondviewUpdatePlayerCollisionPositionFields`) is decompiled/byte-exact and its update loop is already `g_ClockTimer`-scaled, the bug is not "the filter is unreset" in isolation — that property is presumably just as true in the original binary, since nothing in `src/game` differs from what N64 would execute at this call site. **Reframed root-cause question:** something upstream of the filter must differ between N64 and PC — either (a) the actual position jump the filter is asked to absorb is larger/different on PC than on N64 (i.e. `field_488.pos` itself warps to a wrong or differently-timed value at cutscene entry — a genuine bug in the warp, with the filter just faithfully rendering visible whatever bad delta it's fed), or (b) something about call *ordering/frequency* around the `CAMERAMODE_INTRO` transition differs — e.g. `bondviewUpdatePlayerCollisionPositionFields()` (three call sites: two in normal/frozen movement ticks, one in the `DEATH_CAM_SP` branch) running an extra or missing time relative to when `g_CameraMode`/`dword_CODE_bss_80079A18` actually flips, which would desync the filter's internal state from what N64's single deterministic tick loop produces even though the per-call math matches. **Next, concrete (single next step, supersedes the N64-comparison item above since that question is now closed):** add one more `#ifdef PORT` probe logging `g_CurrentPlayer->field_488.pos` (the raw, pre-filter position) and `g_CurrentPlayer->field_3B8` (the filter's raw accumulator, pre-`FACTOR_2` scale) every tick for a few seconds either side of the moment `dword_CODE_bss_80079A18` becomes `CAMERAMODE_INTRO` — this directly shows (i) how large the real position jump is at the exact warp tick (confirms or refutes candidate (a)) and (ii) whether `field_3B8` is already desynced from `field_488.pos` *before* the warp even happens, which would point at candidate (b) instead. Do not touch `src/game/*.c` behavior yet (rule #2) — this is still diagnosis; if the eventual root cause is call-ordering in the port's scheduler (`port/src/gesched.c`) rather than game logic, that's a legitimate port-layer fix with no `#ifdef PORT` needed in `src/game` at all. **Status (from §F table):** **OPEN — M-109 re-analysis of the same session's raw logs corrects the timing/pattern claims above; the D134/pendingGfx race hypothesis is likely wrong.** Confidence MEDIUM on the correction, LOW-MEDIUM on the new lead. Re-reading `data/playtest_d160.log`/`_run2.log` at the `g_framesRendered` level (not just grepping for `D146`) shows the D146 burst fires **~1600-3900 frames (tens of real seconds) *after*** `bossReturnTitleStage`/the `camera_switch(7)` calls, not during them, in **both** runs — "right in the camera-cut window" and "run 1 only" are both wrong as stated above. This also weakens the D134/`pendingGfx` citation: `osSpTaskStartGo` runs `gfx_run()` synchronously and inline (`port/src/libultra.c:1232-1258`), so nothing from the cutscene's own DL submission is still in flight by the time any teardown code runs — the port doesn't have the async-RSP race the hypothesis above assumes. **New lead:** whatever screen renders in that multi-thousand-frame gap after mission-complete is the more likely site — probably `MENU_MISSION_COMPLETE` (`front.c:7267`, `constructor_menu0D_missioncomplete`) or an adjacent briefing/file-select screen in that chain, same general class as D75 (front-end model absence) / D141 (menu bad-pointer bug), not a cutscene-render race. Of the 4 repeating fault addresses, 3 read as literal zero words and only 1 matches the `0xfafbfbfc…` pattern, arguing against a deliberate poison-fill (none found anywhere in `port/`) and for either genuinely-unwritten memory or a decode landing inside unrelated valid data. Next: an env-gated `front.c` menu-transition trace (`MENU_*` id + `g_framesRendered` on every transition after `bossReturnTitleStage`) plus a `GE_PCDUMP` window over frames ~4500-8000 (not the camera-cut window) to name the exact screen/segment. Cross-ref D160 (this supersedes its stale "cutscene skipped" framing with a "cutscene renders corrupted" one, now further corrected to "corruption isn't in the cutscene render at all") and D173 (Cradle's Bond-floating/spinning cutscene bug — same subsystem family, unconfirmed shared root cause). **M-120: the `GE_D243` trace above was BUILT (statically, i.e. written) on branch `investigate/d243-cutscene-race` (`764a1f26`, pushed, not merged) — `src/game/front.c` only, `#ifdef PORT`, logs the target `MENU_*` name + a local per-tick counter on every `menu_init()` state transition. NOT build-verified: two independent sessions (the dispatched subagent, then this session re-verifying in a fresh worktree) both hit the same reproducible failure — `cmake`'s C-compiler ABI check fails with "Cannot create temporary file in C:\Windows\: Permission denied" when gcc is invoked *through* CMake/ninja, even though a bare `gcc -c` invocation from the same shell, same session, succeeds and correctly resolves its temp dir to `%TEMP%`. This is a genuine, reproducible environment issue distinct from the diff's content (static review of the diff found nothing wrong: enum cases all verified to exist in `bondconstants.h`, brace/`#ifdef` balance checked, follows the existing `GE_D160`/`GE_D178` env-gated trace idiom used elsewhere in the same file) — worth a session with a working toolchain investigating the CMake/ninja-vs-bare-gcc environment discrepancy itself as its own item, separate from D243. Next: build `investigate/d243-cutscene-race` on a session where `./build-pc.sh` actually completes, then run the `-level_33` Dam repro with `GE_D243=1` (and the existing `GE_D160`/`GE_PCDUMP` mechanisms) to correlate the trace against the D146 burst's frame range. **M-141: the M-120 toolchain blocker is EXPLAINED and worked around, GE_D243 is now build-verified.** The "Cannot create temporary file in C:\Windows\" failure isn't specific to CMake/ninja vs. bare `gcc -c` — it's this Claude Code session's `Bash` tool shell (Git-for-Windows Bash, not a real MSYS2 MINGW64 window) not exposing a usable `TMP`/`TEMP` to child processes the way an interactive MSYS2 shell does; a bare `gcc -c` from the same shell happened to not hit the temp-file path M-120 tested, which is why it looked clean while the full build wasn't. Fix: explicitly `export TMP=... TEMP=...` (Windows-style path) alongside the already-known `PATH=/c/msys64/mingw64/bin:/c/msys64/usr/bin:$PATH` fix, both before invoking `./build-pc.sh`/`ninja`/`cmake` — now also recorded in `porting-notes.md` §E as a general session-start gotcha, not just a D243-specific note. Cherry-picked the `GE_D243` trace commit (`764a1f26`) cleanly onto `release/v0.3.0` (branch `investigate/d243-fresh`), fixed one thing the original diff got wrong per this project's own D250 rule (`menu_init()` runs ~once/frame during front-end states — the diff's three `getenv("GE_D243")` calls were uncached; now a single cached `static int s_d243` check), and confirmed it builds clean. **Smoke-tested, not fully exercised:** a bare `-level_33` boot runs 1100+ frames with zero crashes and (correctly) zero `D243:` log lines — bare `-level_XX` skips the front end entirely (per this doc's own M-24-era note), so `menu_init()` never runs; this only proves the probe doesn't regress normal boot, not that it captures anything useful yet. **Still blocked on the same thing M-107/M-109/M-120 all were: an actual interactive playthrough** (main menu → Dam → abseil cutscene → mission-complete → whatever screen the D146 burst fires on, ~1600-3900 frames later) with both `GE_D243=1` and `GE_D160=1` set, which needs a human with input, not available in this session. **Possible connection to D173 worth checking in that same playthrough** (per user, M-141): D173 (floating/spinning Bond puppet in cutscenes, e.g. Cradle/Trevelyan) and D243 (stale-memory DL read some seconds after a cutscene-driven `bossReturnTitleStage`) both sit in the scripted-cutscene/level-transition neighborhood and both ultimately touch "Bond's (or a puppet's) in-world model" — no code-level link found this session (D173's own M-106 pass already ruled out the two most likely struct-aliasing sites, and D243's mechanism looks like a stale/freed buffer read in a *different* subsystem, front-end/menu memory rather than a chr/puppet transform), so treat this as an unconfirmed hypothesis to keep in mind while capturing the next live trace, not an established shared root cause. **Steam Deck playtest confirmation, same M-141 session** — user independently reported "cutscene at end of dam level is badly glitched" without prompting, matching this row's own "camera violently shakes" symptom exactly. Second independent confirmation this is real and reproducible, not a one-off; still needs the interactive `GE_D243=1`+`GE_D160=1` capture this row already calls for.