scratch/d287_freeze_gdb.txt, cited as this finding's freeze-time
evidence, does not contain it -- grepped for every specific number the
write-up quotes (frame 17616, the three heartbeat stall times) and got
zero hits. The file on disk is an unrelated clean normal-exit capture.
No real freeze-time thread state has actually been analyzed for this bug
yet; corrected the entry so a future session doesn't treat it as
narrowed-and-confirmed.
Also traced the consumer/producer architecture statically (mainThread's
only OS_MESG_BLOCK send is rsp.c:271's osSendMesg into the scheduler's
cmdQ; GE_D60 doesn't cover sends), and found portHeartbeatCheck hard-caps
at 3 reports/process -- "heartbeat stopped logging" in the original
write-up is that cap, not new evidence. Both quirks added to
porting-notes.md. No code change -- diagnostic-only pass, needs a real
live capture next.
The user's interactive Dam->abseil run with GE_D243M=1 GE_D160=1 landed
(351 KB log, 2991 probe lines; preserved locally at scratch/d243/).
Findings (## D243 M-153 + §F table cell):
- Single Bond model throughout (one idx/model pair, one draw/frame); no
REMOVE/CREATE window around the abseil — M-145's double-instance and
bodyModel==0 re-seed-window hypotheses are refuted on PC.
- Two divergent position streams: prop->pos runs the smooth scripted
void sweep; the model's rendered position (field_488.pos = render
readback, the only writer under POSEND) freezes on dam-surface points
then locks into a strict period-4 cycle through four fixed world
points. The lagged filter (field_3C4, starting at the exact -22832
M-143 observed) chasing that cycle is the observed camera shake.
- Next: code dive chrTick->render_pos for what produces the four fixed
points; D173/D292 are the same family.
The §F summary table row and the entry's own inline Status line still
said "OPEN -- static-analysis pass done (M-108)" even though the same
paragraph documents the RAW16-wavetable byte-swap fix landed at M-121
(v0.2.0). Left a future session likely to re-investigate an already-fixed
bug. Corrected both to FIXED, noting the still-owed by-ear pass.
Traced the watch controller-graphic render path end to end: page gating,
model/item wiring, ROM resource-table entry, and the generic equip/load
pipeline all check out byte-matched or generic-and-proven-elsewhere.
Rules out src/game/ with high confidence. Best-narrowed hypothesis (not
confirmed): a fast3d translucent-blend edge case for the one-off
PROP_TYPE_PLAYER draw used during the watch's fade-in, matching this
project's recurring one-off-combiner-mode bug class. Falsifier for the
next live session recorded in the finding. No code change.
Read gfx_sp_tri1 against D233/D106/D271's existing guards. D233's
trivial-reject fix is ruled out as a direct cause -- GL clips well-formed
clip-space geometry correctly downstream of it. Found a new, previously
uncatalogued unguarded site: the G_CULL_BOTH backface-cull cross-product
divides raw vertex w with no epsilon guard, which can NaN/Inf near w=0
and silently skip both cull branches. Not yet confirmed against a live
repro. Added GE_D288 (cached-getenv, D250-safe) to catch the culprit
triangle's w/bbox at draw time on the next -level_20 run.
No game-logic change; port/fast3d/ diagnostic only, inert unless
GE_D288 is set.
Static trace confirms user's hypothesis architecturally: the Dam exit
script runs on a model-less BG driver chr, while the visible Bond is the
player's own third-person model teleported via chr_try_teleporting_to_pad
(CHR_BOND_CINEMA). Ties the abseil camera shake (M-143/M-144) and the
double-Bond image to one model-lifecycle mechanism; cross-refs D173/D292.
Closes the open question M-143 ended on: this is a genuine PC-only
divergence, not an original-game quirk. Since bondviewUpdatePlayerCollisionPositionFields's
smoothing-filter math is decomp-exact and already g_ClockTimer-scaled, the
bug must be upstream of the filter -- either the position warp itself is
wrong/larger on PC, or a call-ordering desync around the CAMERAMODE_INTRO
transition. Narrows the next step to a single probe: log raw field_488.pos
and field_3B8 (pre-filter) around the warp tick, instead of the open-ended
"needs N64 hardware" framing M-143 left off on.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
Live Dam-abseil capture with the new lookatpad/gBondViewCutscene GE_D243CAM
probes (added this session) fires the gBondViewCutscene branch. Its pos2
read is g_CurrentPlayer->field_3C4/8/C, a leaky-integrator low-pass filter
of Bond's real position (bondviewUpdatePlayerCollisionPositionFields) that
is never reset when a scripted cutscene warps his position out from under
it -- the filter takes ~1s to catch up, and a fixed eye with a look-at
target sweeping through that catch-up is the reported shake. The filter's
own update is g_ClockTimer-scaled (frame-rate-correct by the project's
usual standard), so this looks decomp-faithful rather than a port-specific
timing bug -- open question is whether real N64 hardware shows the same
transient, which would make this not a port defect at all.
D146 stays fully decoupled (zero hits on a third consecutive live run).
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
Live Dam abseil cutscene captures (2 runs, both diagnostic probes on):
the visible camera shake reproduces every time, but the D146 stale-memory
burst fired on neither run -- the two symptoms M-107/M-109 treated as
related are actually independent. Added an env-gated GE_D243CAM probe to
bondviewFrozenCameraTick's pad-orbit CAMERAMODE_POSEND branch to check for
g_GlobalTimerDelta jitter; zero hits rules out that branch entirely. The
Dam cutscene uses one of the other two CAMERAMODE_POSEND sub-paths
(g_CameraLookAtBondPad or gBondViewCutscene), neither instrumented yet --
next session's concrete next step per docs/HANDOFF.md.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
The M-140 fix writeup existed in two places -- an orphaned paragraph right
after the table row, and the pre-fix narrative in the tail ## D255 section
-- but neither ever updated the table row's own status cell, so
findings-index.csv (generated from the table) reported a real, fixed,
live-verified crash as still OPEN. Consolidated into one writeup in the
tail section (which findings-index.csv derives its verdict from per this
file's own ctx-opt convention) and fixed the row's status cell to match.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
Confirmed correct level IDs (Streets=29, Egyptian=32, not the finding's
original level_20 guess). Source review clears both the unscaled-far-clip
and LOD-distance-multiplier hypotheses (bgfog.c/video.c both already scale
consistently). Narrowed to bg.c's portal/room-visibility BFS as the one
remaining suspect -- could be a real bug or just N64 behavior newly visible
on PC's sharp display; needs a live screenshot + location before touching
this decomp-verbatim system, not more static tracing.
Headless GE_PCDUMP long-sightline attempts on Streets/Statue/Egyptian did
not transfer from the D245 technique -- none of them have a scriptable path
to an open sightline without real level navigation.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
Adds a GE_D245V env-gated probe dumping the water fan's raw S/T span each
call, and a GE_D245_FIXEDSHIFT env var (skyPortForceFanShift) that forces a
constant tc-shift k instead of the per-frame adaptive pick. Both are
diagnostic/opt-in only -- default behavior is unchanged (verify.sh
frigate/"surface 2" PASS with the env vars unset).
Headless GE_INPUTSCRIPT rotation on Frigate found k genuinely flips (kT
4->3) during ordinary view turning, which the original single-frame D227V
trace never caught -- new evidence for why the M-116 allowShift=TRUE fix
didn't hold up live. The fixed-k candidate is NOT the default; it needs a
live A/B (unset vs 3/4/5) to know if it actually looks better, not another
blind ship.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
00 Agent campaign crashes at end of Control Center, then crashes on every
subsequent relaunch — points at corrupted persisted state (save/EEPROM),
not a one-off frame bug. Possibly-related audio degradation reported from
Streets onward, unconfirmed. Not investigated; needs the user's crash log
and save file before further work.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
No discoverable in-UI way to quit (Deck/controller-only setups had only
window-close/Alt+F4). Adds a ROW_ACTION row kind (not config-backed, same
pattern as the existing __Resolution row) that triggers the identical
configSave()+exit(0) path SDL_QUIT already uses. Build-verified on Windows
and Linux; verify.sh dam PASS, no regression.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
Same protocol: topics were compressions of their own §H entries (verified
by probe), statuses (the verdicts) kept verbatim. Skipped as already-thin:
D240-D243, D247 (one-liner + short status each).
§F table region: 226 KB -> 166 KB.
- D217: 7.5 KB status was a digest of the §H M-86→M-97 entries (each
'See full write-up: §H ...'); only the closing verdict was missing —
appended it (PR #47 + PR #49 merged, white residual → D228, M-105
stale-status correction).
- D271/D276: topics were compressions of their own §H entries; statuses
(the verdicts) kept verbatim.
- Skipped as already-thin/substantive: D220, D132 (compact audit summary),
D183, D179, D178, D182, D181.
The earlier edit replaced only D227's topic cell; its 11.9 KB status
survived. That status was a digest of the full write-ups, which exist:
§H '## D227' entries M-94/M-95/M-96/M-98/M-100/M-100b (in findings.md) and
M-99 (full entry in HANDOFF-ARCHIVE.md). Digest wording survives in git
history + snapshot.
Same protocol. Three sections ended before their final disposition — the
newer verdicts were appended verbatim to the section first (flagged):
- D206: M-77c user by-ear A/B = PASS (section still listed it as 'still owed')
- D207: M-77c MONITORING disposition
- D205: M-78 CLOSED (root cause was D206)
D176's defect-(b) summary (grey diagonal static, D183 0/166) has no section
home — kept as the row's substantive topic instead of a bare pointer.
Each cell checked line-by-line against its ## Dxx section(s); cells were
compressed summaries of the sections, so rows shrink to one-liner + pointer
and status keeps its verdict. Two cells carried facts NEWER than their
sections — appended verbatim to the sections first (flagged in-section):
- D221: human mouse-playtest confirmation (section still said 'eyeball owed')
- D227: M-100b human play-test confirmed (section ended 'still owed')
D228's status was the post-split FIX write-up, absent from its pre-fix
M-97 section — appended as a second ## D228 pass-section.
Exact pre-shrink wording survives in git history + notes/snapshot-pre-ctx-opt/.
Semantic coverage check of each §F row labeled D70–D121 against the §H
narrative (done directly, not delegated):
- D85, D86·D87, D88.4, D121: thin rows, fully covered by §H entries —
topic reworded as one-liner + 'see §H' pointer, status kept verbatim
- D117, D118: fat cells whose content (M-52 addenda; M-24 mouse-look
rework incl. D118b/c) is fully in §H — shrunk to one-liner + pointer
- D120: fat cell with NO section and no §H coverage (sole record of the
M-30 PointUsage fix) — pure verbatim move to a new ## D120 tail section,
row becomes a pointer; verified byte-identical vs pre-migration snapshot
- D75: LEFT AS-IS — its status cell holds a v0.2.0-pre playtest result not
present in §H; shrinking would lose data
- D119·D120: left as-is — sole record of D119 (§H mentions it only in passing)
Range rows (D70–D74, D89–D92, …) stay as-is per plan.
D76·D164, D165·D166, D180·D181 each point at existing ## Dxx sections that
fully cover the cell content (verified line-by-line; cells were compressed
summaries of the sections). Status cells kept verbatim. The remaining two
multi-label rows (D86·D87, D119·D120) are thin §H-era summary rows with no
sections — deferred to the D70–D121 §H cross-check.
Each label had a full writeup + a short 'Duplicate row' triage pass.
Keep the full writeup; append the short pass's genuinely-unique content
verbatim under a dated merge note (D233/D234: GRAPHICS-BACKLOG.md logging +
triage hypotheses; D152+: fully subsumed — noted as such). Both §F table
rows stay (cell 1 frozen) and both now point at the single merged section.
Nothing deleted: earlier text in git history + notes/snapshot-pre-ctx-opt/.
Cell 1 of the §F table is frozen, so four rows (D69·D78–D84, RC3·D167,
the D88.x range row, D118d) are invisible to findings-index.csv — LABEL_RE
can't parse their label format. Documented in the file header alongside
the lookup convention and a record of what the 2026-09-15 migration did
(including the one non-verbatim step: D250/D252/D255 derived statuses).
These three rows were fat topic with NO status cell (2-column rows). Topic
moved verbatim to new ## Dxx sections; table rows get a substantive one-liner
+ a status DERIVED from each entry's own verdict text (D250 FIXED / D252 OPEN
known-issue / D255 OPEN pending rule-#2 sign-off) — the derivation is flagged
in-section for auditability. CSV regenerated, label set unchanged (171); all
three topics verbatim-checked against the snapshot.
Pure moves following the 6208276d formatting repair: topic/status cells moved
verbatim to new ## Dxx sections; table rows now carry one-line summary +
pointer. CSV regenerated, label set unchanged (171); both sections
verbatim-checked against the snapshot.
Formatting fixes only — text preserved verbatim, no content added/removed:
- D211: the HUD ammo display '7 | 93' contained a literal unescaped pipe,
splitting its status cell in two; wrapped that token in backticks.
- D219: a call-chain used pipes as separators between separate code spans
(5 cells instead of 3); merged into one continuous code span — same text,
backtick positions moved.
- D255: row lacked the trailing pipe its neighbours have; added it so the
table is well-formed 3-column (status cell empty, as in D250/D252).
These were pre-existing CSV corruption (garbled/truncated status_raw), not
migration artifacts. CSV regenerated; label set unchanged (171).
The previous commit's (a)/(b) insertion landed at the line start, producing
' (a)## D233 — …' lines that no longer parse as headings. Moved the markers to
after the label: '## D233 (a) — …'. 117/117 migrated sections now have valid
headings; CSV check + label set still green.
Two table rows each carry the same label+topic with a status progression
(earlier vs updated pass). Both migrated verbatim in batch 6; heading markers
are formatting only. Flagged for Bucket B consolidation.
12 rows: topic/status cells moved verbatim to new '## Dxx' sections at file
tail; table rows now carry a one-line summary + pointer. CSV regenerated, label
set unchanged (171). Nothing deleted.
20 rows: topic/status cells moved verbatim to new '## Dxx' sections at file
tail; table rows now carry a one-line summary + pointer. CSV regenerated, label
set unchanged (171). Nothing deleted.
21 rows: topic/status cells moved verbatim to new '## Dxx' sections at file
tail; table rows now carry a one-line summary + pointer. CSV regenerated, label
set unchanged (171). Nothing deleted.
10 rows: topic/status cells moved verbatim to new '## Dxx' sections at file
tail; table rows now carry a one-line summary + pointer. CSV regenerated, label
set unchanged (171). Nothing deleted.
Also disambiguates the two '## D152+' headings from batch 2 as (a)/(b)
(formatting only; content untouched — flagged for Bucket B consolidation).
14 rows: topic/status cells moved verbatim to new '## Dxx' sections at file
tail; table rows now carry a one-line summary + pointer. CSV regenerated, label
set unchanged (171). Nothing deleted.
9 rows: topic/status cells moved verbatim to new '## Dxx' sections at file
tail; table rows now carry a one-line summary + pointer. CSV regenerated, label
set unchanged (171). Nothing deleted.
15 rows: topic/status cells moved verbatim to new '## Dxx' sections at file
tail; table rows now carry a one-line summary + pointer. CSV regenerated, label
set unchanged (171). Nothing deleted.
16 rows: topic/status cells moved verbatim to new '## Dxx' sections under a
provenance divider at file tail; table rows now carry a one-line summary +
pointer. CSV regenerated, label set unchanged (171). Nothing deleted.
Companion to the local split of docs/HANDOFF.md (gitignored rolling
working file — that half of the move is working-tree-only, backed up in
the pre-edit snapshot). Appends lines 137-5764 of the pre-split HANDOFF
(### ARCHIVE — M-140 onward, ~444 KB) after the existing M-2/M-3 brief,
with a divider documenting coverage and the newest-first ordering of
the moved block. Content verbatim; CRLF->LF normalised to match this
file and .gitattributes (eol=lf). Verified: live head + moved chunk
rejoin byte-identical to the original (CR-stripped); appended region
cmp-clean against the snapshot.
Archive intro corrected: it claimed 'through session M-11' but held only
M-2/M-3; the M-4-M-11 gap is pre-existing, noted as such.
AGENTS.md findings bullet + HANDOFF-ARCHIVE.md intro pointer now steer
cold-starting agents to docs/dev/findings-index.csv (grep this, then read
the specific ## Dxx entry) instead of linear-reading the ~100k-token §F
table. Base: release/v0.3.0 @ bf24bef8.
User clarified the black-geometry drop-out happened at normal ground
level during normal progression near the statue, not from the
elevated ramp with wide sightlines as the first write-up assumed.
Retracted the "widened FOV frustum from elevation" framing of the
room-visibility hypothesis; kept the underlying room-transition/
streaming-timing guess since it doesn't depend on elevation.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
User report at Video.FovScale~130 + max draw distance/LOD: ground
geometry near an elevated wide-visibility vantage point drops out to
solid black, then recovers 10-30s later on its own. Doesn't cleanly
match D222 (NPC/object culling, FIXED), D249 (default-FOV far
geometry, doesn't self-recover), or D218 (fog/tint boundary, not
missing geometry) -- logged as its own finding with those three as
neighbors, not a confirmed duplicate of any. Leading unconfirmed
guess: a portal/room-visibility BFS not accounting for the widened
FOV frustum.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
User corrections on the playtest batch: D289 (Dam computer-room
crash) is most likely the same computer-terminal SIGSEGV D255 already
fixed this session, not a separate mystery -- needs a re-test on the
post-fix build before treating as new. D292 (Bond sunk into floor on
death) is confirmed the same "Bond's world model positioned wrong"
family as D173/D148, not a separate bug -- cross-referenced both
directions so the split-across-two-files writeup (GRAPHICS-BACKLOG.md
D148 + findings.md D173) is easier to find as one thread covering
level-start floating, cutscene spin, and now death-pose sinking.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
User completed a Dam-through-Runway Steam Deck playtest and reported
9 items. Four corroborate already-open findings (D173 third-person
Bond floating at level start, D246 fullscreen edge strips -- Deck's
own default preset sets MSAA=4, exactly this row's leading suspect,
D219 purple/blue particle colors widened to blood decals, D243 Dam
end-cutscene camera glitch -- second independent confirmation). Five
are new: D289 (Dam computer-room crash, non-reproducing), D290 (watch
controller-page missing pad graphic), D291 (Dam truck texture
glitches), D292 (death-pose Bond sunk into floor, possibly D173-
adjacent), D293 (no way to quit the game from the UI -- confirmed in
code, SDL_QUIT via window-close/Alt+F4 is the only path; a QoL gap on
Deck/controller-only setups).
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
User reported a stray triangle during the Silo missile-shaft camera
pan (previously D171, parked since M-34 as "observed, not
investigated"). Reproduced headlessly, precisely bounded to frames
~562-741 of a bare -level_20 boot: a large, flat-shaded, untextured
brown triangle (uniform RGB(83,62,44)) grows then shrinks across the
pan, consistent with a real world-space triangle mis-transformed near
the camera plane rather than a HUD element or garbage vertex-color
read. Points at the D106/D233 near-plane/w-clip neighborhood in
port/fast3d/gfx_pc.cpp, not yet confirmed at the code level. Evidence
saved to docs/img/bugs/. Also noted: foreground `timeout N ...` launches
of the exe from this session's Bash tool produce zero GE_PCDUMP output;
backgrounding the launch works reliably -- worth remembering next time.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
User reproduced the "stuck standoff" 3-4 times; traced to a hard
timeout in ai_22 (label 0x13, UsetuparkZ.c) that fires the execution
unconditionally after ~2.5 min if no other trigger fires first. User
waited it out and confirmed it resolves normally with dialogue -- not
a freeze, not a new bug. Documented so it isn't re-flagged.
Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi