docs: D243 M-154 — user confirmed double Bond (one frozen copy per shot); corrected log reading; census probe documented

- findings.md ## D243: M-154 entry. User symptom sharpened (one new
  frozen Bond per camera shot; old copies persist, never animate).
  Corrects M-153: the POSENT window has three phases and in phase 3
  prop->pos ITSELF cycles period-4 through three z-lanes while y falls
  smoothly — the rendered model tracks it (per-lane pose offsets), so
  it teleports every frame rather than freezing. H1 vs H2 named;
  probe design + smoke results recorded. §F table cell updated.
- GE-ENV-PROBES.md: GE_D243M row updated (chrdraw census, new tick
  fields, dedupe note).

HANDOFF.md (gitignored) got the matching LATEST block with the
re-capture command.
This commit is contained in:
James Dansereau committed 2026-09-16 16:47:31 -04:00
1 parent 1b3476a401
commit ce8427cff2
2 files changed
+4 -2

No files matched your search

+3 -1
View File
@@ -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-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. M-153: live `GE_D243M` capture (full Dam → abseil; `scratch/d243/m153_dam_abseil_capture.log`) REFUTES the double-instance hypothesis (single model, one draw/frame, no remove/recreate window) and shows the real divergence: the model's rendered position (`field_488.pos` = render readback) freezes on dam-surface points then locks into a strict period-4 cycle through four fixed world points, while `prop->pos` executes the smooth scripted void sweep — the lagged filter (`field_3C4`) chasing that cycle is exactly the observed shake. Next: code dive into `chrTick`→`render_pos` for what produces the four fixed points; D173/D292 are the same family. D146 still fully decoupled (zero hits, 4 runs). |
| 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. M-153: live `GE_D243M` capture (full Dam → abseil; `scratch/d243/m153_dam_abseil_capture.log`) REFUTES the double-instance hypothesis (single model, one draw/frame, no remove/recreate window) and shows the real divergence: the model's rendered position (`field_488.pos` = render readback) freezes on dam-surface points then locks into a strict period-4 cycle through four fixed world points, while `prop->pos` executes the smooth scripted void sweep — the lagged filter (`field_3C4`) chasing that cycle is exactly the observed shake. Next: code dive into `chrTick`→`render_pos` for what produces the four fixed points; D173/D292 are the same family. D146 still fully decoupled (zero hits, 4 runs). M-154: user sharpened the symptom (one new frozen Bond per shot; old copies persist); log re-read corrects M-153 — in phase 3 `prop->pos` itself cycles A,A,B,C through three z-lanes while y falls smoothly, and the rendered model tracks it (per-lane pose offsets), so it teleports every frame rather than freezing; H1 (multiple Model instances) vs H2 (framebuffer accumulation / subcam ghosts) now discriminated by a new `D243M: chrdraw` per-frame model-draw census in `drawjointlist` + extended tick fields (propptr/chrptr/rp/raw); probe smoke-tested, awaiting re-capture. |
| 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… |
@@ -10715,6 +10715,8 @@ crash class C2 (Facility `-level_34`, Runway `-level_35`): `import_texture_i8` A
**M-153 (2026-09-16): the live `GE_D243M` capture (full Dam playthrough → abseil; 351 KB log, 2,991 probe lines, preserved at `scratch/d243/m153_dam_abseil_capture.log`) discriminates M-145's three questions — the double-instance hypothesis is REFUTED, and the model's rendered position turns out to be a period-4 cycle through four fixed world points that diverges from the scripted `prop` sweep; the camera shake is now fully explained mechanically.** **(1) There is no second Bond model.** Exactly one (idx, model-pointer) pair for the entire capture — idx=0, single `bodyModel`, exactly one `draw` line per frame. No REMOVE/CREATE window around the abseil: the model is created at tick 4818 **directly at the post-teleport position** (12.6, −23744, −1330) with `cam=7` POSEND + subcam=1 (INTRO) already set (the D160 `bondviewSetCameraMode(7)` line immediately precedes CREATE), and it persists to the last tick — no REMOVE is logged even through mission-complete/title return (the stage-unload path evidently doesn't route idx 0's body through `bondviewRemovePlayerBody`, or removal happens after the final `playerTick`; minor). M-145's double-image candidates — "two live Bond models" and "stale draw of a removed model via a bodyModel==0 re-seed window" — are both refuted on PC. **(2) Two divergent position streams.** (a) `prop->pos` executes the smooth scripted bungee sweep through the void: y −23859 → +175 (tick ~5000) → −10724 (tick 5910, mission end). (b) The model's *actual rendered position* — `field_488.pos`, which under POSEND+bodyModel≠NULL is written **only** by the on-screen render readback (`bondview2.c:10452`; the `pos ← collision_position` copy at ~4773 is skipped in POSEND, and the other filter re-seed site at 8912 is `mp_respawn_handler`, not this path) — behaves as: tick 4819 = true void position (== prop); ticks 4820–4880 frozen at (y=729.7, z≈−3111); ticks 4881–5041 frozen at (y=229.1, z≈−3106); ticks 5042–5045 a transition burst containing one frame that matches `prop` exactly (y=−12874.7); tick 5046→end: a strict **period-4 cycle through four fixed world points** P1(228.7, −3111) P2(229.2, −3107) P3(79.2, −2512) P4(−1214.8, −2221). The model transform is decoupled from the script in all three axes (by tick 5910 `prop.z`=−1797 while the cycle's z-range is −3111…−2221); it is not terrain-following (the same four values repeat exactly for ~800 ticks while x/z drift). **(3) The camera shake closes mechanically.** `field_3C4/8/C` (= 0.1 × leaky integral of `field_488.pos`) starts at ≈ −22832 — the *exact* `pos2.y` start M-143 observed live — sweeps to +229 over ~180 ticks as the filter converges onto the frozen surface point, then tracks the period-4 cycle. The "violent shake/spazz" = a fixed-eye camera whose look-at anchor (i) starts ~20k units displaced and (ii) teleports between four points at 15 Hz. D146 remains fully decoupled (zero hits, fourth consecutive run). **(4) "Two Bonds" — not present as two instances in this capture.** If the user still saw a double image on this run, the leading candidate is stale `render_pos` submissions lingering in the draw queue while the model teleports between the four cycle points (D75 family): P4 sits ~1,400 units below the dam surface ("floating in the air"), P1/P2 are on it ("standing on the dam"), and each copy would be a frozen snapshot → "neither animates correctly." Not verifiable from this log (the draw probe counts submissions — one per frame — not on-screen images). **Open question for the user: did two Bonds appear in *this* run?** **(5) Cross-ref:** D173 (level-start floating, Cradle spin) and D292 (death sinking) are the same "third-person world model transform" family — the period-4 fixed-point cycle is now a concrete shared-mechanism candidate for all three. **Next:** code dive into where the model's render transform gets its translation during POSENT (`chrTick` → `render_pos`, chraction.c/objecthandler): what state produces the four fixed points (a 4-keyframe anim attached to Bond's model on PC only? a pad table?), and why the smooth `prop` sweep never reaches the model transform after spawn. If the double image is a stale-queue artifact, that is a port/render-layer fix (fast3d draw list) — no game-logic change needed.
**M-154 (2026-09-16): user symptom sharpened to "one new frozen Bond per camera shot"; the M-153 log reading is corrected (the rendered model is NOT frozen in phase 3 — `prop->pos` itself cycles); a per-frame model-draw census probe (`D243M: chrdraw`) is implemented and smoke-tested to discriminate the two remaining hypotheses.** **(1) User observation (reproducible every time so far):** during the abseil, one *new frozen* Bond appears with each camera shot — shot 1 standing, shot 2 mid-jump, shot 3 rappelling; the old copies persist and never animate; the camera glitches when the second Bond appears. **(2) Corrected log reading (supersedes M-153's "period-4 cycle through four fixed points").** The POSENT window (frames 4819–5910) has three phases: **P1** (4820–4880): `prop.y` rises −19791→+175 while `f488` stays frozen at (−4.4, 729.7, −3111.6) — the rendered model is decoupled from prop during the ascent; **P2** (4881–5041): both frozen (prop (−4.3, 175.9, −3107.6), f488 (−4.4, 229.1, −3106.7)); **P3** (5042→end): **`prop->pos` itself cycles period-4 through three z-lanes** — A(≈−31xx), A, B(≈−25xx), C(≈−22xx) — while y falls smoothly at ~30 units/frame. `f488` tracks the *same* cycle exactly with per-lane y offsets (A: +229, B: +79, C: −1215 = per-pad model pose), so in P3 the rendered model is **not frozen** — it teleports between three fixed world points every frame, following prop. M-153's "four fixed points" was lane A (two near-identical samples) + B + C. Structural tell: y stays perfectly continuous across lane boundaries while x/z rotate → either one prop whose x/z come from a cycling source (AI-script GOTO loop setting position to different pads one command per frame — cf. the teleport fall-through at chrai.c:4064 where a failed `chrAdjustPosForSpawn` drops into the next command; or keyframe sampling without interpolation), or `pp->prop` rotating among three PropRecords with synchronized y. **(3) Hypotheses for the visible double/triple image:** **H1** multiple Model instances — each shot spawns a frozen Bond, all drawn every frame (the M-145 family, but spawned via a path invisible to the playerTick probe); **H2** single model + framebuffer accumulation — `subcam=1` snapshot buffer never cleared, so the per-frame teleporting model leaves a trail of frozen ghosts at all three lanes; "old copies persist and never animate" fits H2 naturally (ghosts are frozen by construction). M-153's stale-draw-queue candidate is subsumed by H2. **(4) Probe (implemented, smoke-tested).** `D243M: tick` extended with `propptr=`/`chrptr=` (a changing pointer proves prop rotation; constant → cycling x/z source), `rp=` (the render_pos pointer — a change between phases = matrix-buffer reassignment/aliasing), `raw=` (render_pos[0] translation BEFORE the view transform — distinguishes model-matrix cycling from view-matrix cycling). New `D243M: chrdraw` census in `drawjointlist` (both region variants, objecthandler.c): one line per CHR render submission while a scripted camera mode is active (POSEND/INTRO/SWIRL/FADESWIRL), logging Model* + raw root translation. All CHR draws funnel through it (`chrRenderProp`; player path bondview2.c:10883, generic chrprop.c:443). H1 = extra lines with *distinct* model pointers at the same frame; note the same model is drawn twice per frame (two passes) — dedupe by (frame, model). Accessors `d243mProbeActive()`/`d243mGetFrameCounter()` live in bondview2.c (the camera gate is folded into `active()` so objecthandler.c needs no bondview.h include); D250 cached-getenv kept. Smoke: 45 s bare `-level_33` boot → 4,053 chrdraw + 1,066 tick lines, formats verified, silent in FPS play (cam=FP/NONE gate). **(5) Next:** user re-runs Dam→abseil with `GE_D243M=1` (`cmd /c` capture — see HANDOFF); analysis: (a) distinct-Model* count per frame during POSENT → H1 vs H2; (b) propptr/chrptr stability → prop rotation vs cycling source; (c) raw vs f488pos → model-matrix vs view-matrix origin of the cycle.
**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) zerLine truncated
## D244 — Self-hosted CI runner (`corpyvt6agent01`) link failure: `undefined reference to 'objectiveGetStatus_WEAK'` (2026-09-12, first-ever build attempt on the…