D310 (RULE-2-SIGNOFF): size AI_PRINT records at their true 1-byte width in chraiitemsize (#ifdef PORT) — fixes D309 spin + Caverns standing-still guards

This commit is contained in:
James Dansereau committed 2026-09-18 12:55:06 -04:00
1 parent 0f8bd90aaf
commit 0c700852e2
3 files changed
+49 -2

No files matched your search

+2 -1
View File
@@ -186,4 +186,5 @@ D305,FIXED,"Steam Deck SIGSEGV on the v0.3.0 pre-release build (Cavern, early in
D306,OPEN,"Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).","OPEN — reported only, not investigated."
D307,OPEN,"In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g.","OPEN — reported only, not investigated."
D308,OPEN,"Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).","OPEN — reported/confirmed by the user, not investigated."
D309,OPEN,Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen —,OPEN — root cause fully identified and evidenced (mechanism below); no fix made.
D309,FIXED,Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen —,"FIXED via D310 (RULE-2-SIGNOFF, 2026-09-18) —"
D310,FIXED,"RULE-2-SIGNOFF: chraiitemsize() mis-sizes 1-byte AI_PRINT records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT —","FIXED (signed off + implemented 2026-09-18, #ifdef PORT, N64 arm unchanged) —"
1 # GENERATED by tools_pc/gen_findings_index.py -- do not hand-edit.
186 D306
187 D307
188 D308
189 D309
190 D310
+26 -1
View File
@@ -594,7 +594,8 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D306 | **Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).** — full `## D306` entry at file tail | OPEN — reported only, not investigated. Explicitly not for v0.3.0. |
| D307 | **In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g. Bunker (user QA, 2026-09-18) — NOT the player's view camera.** — full `## D307` entry at file tail | OPEN — reported only, not investigated. Explicitly not for v0.3.0. |
| D308 | **Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).** — full `## D308` entry at file tail | OPEN — reported/confirmed by the user, not investigated. Explicitly not for v0.3.0; D306 may be one instance of this. |
| D309 | **Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen — boss thread spins forever in `ai()` on `m_RunToBondPersistent` via a phantom `GotoNext(lblZero)` created by `chraiitemsize`'s `AI_PRINT` NUL-scan mis-sizing a stringless PRINT record (user report + live GDB diagnosis, 2026-09-18).** — full `## D309` entry at file tail | OPEN — root cause fully identified and evidenced (mechanism below); no fix made. Latent original N64 bug exposed by PC teardown ordering; fix bucket undetermined (port-side teardown ordering vs rule-2 sign-off). User decision owed: fix before v0.3.0 tag or log as known issue. |
| D309 | **Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen — boss thread spins forever in `ai()` on `m_RunToBondPersistent` via a phantom `GotoNext(lblZero)` created by `chraiitemsize`'s `AI_PRINT` NUL-scan mis-sizing a stringless PRINT record (user report + live GDB diagnosis, 2026-09-18).** — full `## D309` entry at file tail | FIXED via D310 (RULE-2-SIGNOFF, 2026-09-18) — the mis-sizing landmine is neutralized, so the phantom-`GotoNext(0)` spin path no longer exists; pending user live re-verification in Caverns. The teardown-ordering open question (why PC presents the unreachable-Bond state) remains documented but is now harmless. |
| D310 | **RULE-2-SIGNOFF: `chraiitemsize()` mis-sizes 1-byte `AI_PRINT` records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT — fixes D309's freeze mechanism and the Caverns standing-still guards (`Stop`+`PRINT("wait")` mis-lands on EndList, re-executed every tick; user report 2026-09-18).** — full `## D310` entry at file tail | FIXED (signed off + implemented 2026-09-18, `#ifdef PORT`, N64 arm unchanged) — pending user live re-verification of both symptoms in Caverns. PD precedent: PRINT removed, slot 0xAD reassigned. |
Phase 2 replaced the Phase-1 demo loop with the real `mainproc()` on real OS
threads, compiled GE's real `src/sched.c`, and brought in PD's fast3d software
@@ -11910,3 +11911,27 @@ This confirms the M-160/M-164/M-165 hypothesis (`## D173`'s own consolidated-nex
**Not "fully fixed"** — user is explicit that a small positional-offset residual remains ~1/10 of the time, and that no separate investigation/fix was made for D173/D292's own code path specifically (D243's fix in `bondview2.c`'s cutscene body-model buffer layout was the actual change; D173/D292 improving alongside it is the side-effect being confirmed here, not a targeted fix). Worth noting for a future session: since D173/D292 were never traced to their own exact call site, if the residual offset ever becomes a live complaint again, whoever picks it up should not assume it's the same code path as D243's fix — that fix touched one specific buffer-layout call site (Bond's cutscene body model), and D173's own M-172/M-173 measurements were taken on the *level-start intro puppet*, a different code path (`solo_char_load`/`bondviewSetCameraMode`'s `CAMERAMODE_SWIRL` branch, per D173's own M-175 finding) that was never itself touched by the D243 fix — the improvement is a side effect of shared underlying mechanics, not the same call site being patched twice.
**Status:** MOSTLY FIXED (D173 and D292 both), user-confirmed live, small residual offset remains and is not investigated further. Public docs (release notes, README) should describe this as "the Bond positioning/floating issue is now mostly resolved, small residual placement drift only, no more full floating or spin-glitching" rather than "separate, unconfirmed, still open."
## D310 — RULE-2-SIGNOFF: `chraiitemsize()` mis-sizes 1-byte `AI_PRINT` records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT — fixes D309's freeze mechanism and the Caverns standing-still guards (signed off + implemented, 2026-09-18).
**Status:** **RULE-2-SIGNOFF** / FIXED (pending user live re-verification of both symptoms in Caverns). One-line `src/game` behavior change under `#ifdef PORT`; N64 build untouched.
**The defect.** The `PRINT()` macro (`src/aicommands2.h:4913`) emits exactly **one command byte** into the built AI list — its string argument is discarded at list-build time. But `chraiitemsize()`'s `case AI_PRINT:` (`src/game/chrai.c:682`, original) sized the record by scanning forward to the next NUL byte, so stepping on a PRINT always skips ~20 bytes into whatever records follow and resumes at an arbitrary byte pattern. Only 4 PRINTs exist in all of `src/game/chraidata.c`; two are commented out (`m_DeadAI:74`, `m_StandardGuard:136`) and **both active ones are in `m_RunToBondPersistent`** — so exactly one AI list in the game is affected.
**Two observed symptoms, one landmine (both live-verified 2026-09-18 with `GE_D309` probes, gdb symbol confirmation):**
1. **D309's complete freeze** (Caverns→intro): `PRINT("no go!\n")` @+4 mis-lands at +22 = `00 00` = phantom `AI_GotoNext(0)`; no `Label(0)` exists → `chraiGoToLabel` returns 0 ("causes infinite loop outside of debug", `chrai.c:753`) → PC restarts at 0 → same path → tight spin inside one `ai()` call. (Full mechanism in `## D309`.)
2. **Standing-still guards** (user report, Caverns 00 Agent: one after the first elevator, one after the next door — "fidgeting but staying still", still react to shots): guard completes its 1-second dash window → `Stop()` + `PRINT("wait\n")` @+167 mis-lands at +189, where arg bytes of a later record decode as `Label(88)` then `0x04` = **`AI_EndList`**. `ai()` at EndList `return`s **without saving the offset** (`chrai.c:988`, "same as yield except without pushing offset past it") → the identical path re-executes every tick → `Stop` re-issued forever; the source's intended follow-up (UnsetMyFlags2 / random check / MyTimerStart / sit-rep DO-LOOP / `GotoFirst(lblRun)` resume) is swallowed by the mis-skip. Damage still interrupts because shot/death changes `actiontype` outside the AI list. Live probe lines: `D309: PRINT chr=3/4 list=<m_RunToBondPersistent> off=167 size=22 landcmd=0x02` repeating every tick; `gdb info symbol` confirmed the list pointer is `m_RunToBondPersistent`.
**Sign-off request as stated (per `docs/dev-process.md` §7):**
1. *Change:* `src/game/chrai.c`, `chraiitemsize()`, `case AI_PRINT:` — replace the NUL-scan with `return 1;` (the record's true on-disk size), under `#ifdef PORT`; the `#else` arm is byte-identical to the original decomp.
2. *Proof of divergence:* mechanism verified live (gdb symbol + per-tick probe lines above, exact offsets/sizes/landing bytes). Intended-behavior references: (a) the list source itself — PRINT sits between two real commands and is a no-op by construction; (b) user's direct N64 experience — guards do not stand frozen in Caverns on real hardware (same standard as M-144's user comparison that settled D243). Honest caveat recorded at request time: the ROM *code* would mis-skip on N64 too if reached — this is a latent original defect, and the fix restores the list author's intent rather than provable N64 behavior.
3. *Why not `port/`:* no N64 hardware dependency to shim — the sizer function's own logic operating on game data is the defect; nothing upstream (ABI/layout §A1 suspects, port-layer) is involved. *Why not the ABI exception:* nothing pointer-width-driven; the 32-bit original has identical code and data.
4. *Same-engine precedent:* Perfect Dark removed `PRINT` from the AI language entirely and **reassigned slot 0xAD** to a real command (`aiChrCopyProperties`, `pd_port/src/game/chraicommands.c:8159`) — Rare themselves retired this broken record class in the next title on the same engine.
**Grant (2026-09-18, in-thread):** "I want to proceed with your implementation plan here to fix this bug." (User's reply to the full §7 write-up; asked only whether a fresh session was needed — answered no, granted in this session.)
**Resulting diff:** `src/game/chrai.c` `chraiitemsize()` — `case AI_PRINT:` now `return 1;` under `#ifdef PORT`, original NUL-scan moved to the `#else` arm unchanged (commit following this entry). Verification: full-list decode of `m_RunToBondPersistent` with the fix (`scratch/decode_printfix.c`) walks +0→EndList@223 with every record valid, and the post-`"wait"` sequence matches `chraidata.c:666+` line-for-line (`UnsetMyFlags2(4)`, `IFNewRandomGreaterThan(160)`, `SetMyFlags2(4)`, `MyTimerStart`, sit-rep block, `GotoFirst(lblRun)`); post-`"no go!"` resumes at `Label(27)+Yield` as in source.
**Scope note (§7 drift check):** affects exactly one AI list (the only one with active PRINTs). Both observed symptoms are inside that scope; no other list's behavior changes.
**Cross-refs:** D309 (this fix neutralizes its spin mechanism — the teardown-ordering open question in D309's "why PC and not N64" remains, but reaching that state is now harmless); GE_D309 probes (`chrai.c` `ai()`/`chraiGoToLabel`, `chraction.c` `chrGoToBond`) remain as diagnostic tools.