Commit Graph
414 Commits
Author SHA1 Message Date
James Dansereau 7b405abc63 fix(D299): Game.SkipIntro crash selecting most save slots
fileValidateSaves() -- the only place saves[] is populated from EEPROM
-- is called exclusively from the legal screen's init, which
Game.SkipIntro's boot-to-file-select shortcut skips entirely. saves[]
was left all-zero, so fileGetSaveForFoldernum() returned NULL for
every folder except whichever one a zeroed save_data happened to
decode to, crashing file-select's unguarded fileGetIsCheatUnlocked()
for the rest. Call fileValidateSaves() from the shortcut too
(port-layer completeness fix, zero game-logic change).

Live-verified by user: all 4 save slots now selectable with
SkipIntro=1, intro still correctly skipped.
2026-09-17 09:43:44 -04:00
James Dansereau f70284b5be D219/D252 M-158: fix §F table status cells (index CSV is generator-derived — update the source row, not the CSV) 2026-09-17 08:50:33 -04:00
James Dansereau 30dcbea085 D219/D252 M-158: rainbow bug not reproducible in 6 identical dev-box runs; classified flaky/environment-dependent; probes left live for next occurrence 2026-09-16 23:15:45 -04:00
James Dansereau 145d3f46ac D219 M-157 correction: measured G_LIGHTING for glass2.c sparks, theory doesn't hold up
Went back and actually tested the G_LIGHTING hypothesis from the
previous commit instead of leaving it as an untested code-reading
inference. Two things prompted this: (1) noticed a code comment near
the existing GE_D172 probe documenting a live result never written up
in findings.md -- "G_LIGHTING is ruled out (5000/5000 samples off)" for
explosion.c's particles specifically, meaning the sibling case this
session's theory leaned on was already empirically disproven, not
merely unconfirmed; (2) that's exactly the kind of unchecked assumption
this session's own rule-2 taxonomy work was written to prevent.

Added GE_D157 (gfx_pc.cpp, gfx_sp_vertex, env-gated, cached getenv):
logs geometry_mode/LIGHTING + resulting shaded RGB whenever a vertex's
raw color bytes match one of glass2.c's g_BulletSparkColors[] entries.
Re-ran the identical Bunker1 repro that produced the magenta/green/cyan
screenshots -- only 2 hits, both LIGHTING=off, both unaffected white,
no hit at all for the pale-yellow value the door-spark path should
produce. Reading: G_LIGHTING likely isn't the mechanism here either
(consistent with the sibling case), though the probe may simply not be
catching the real spark vertices yet (exact-byte-match is fragile).

Corrected the D219 finding to flag the "cross-validates M-110" framing
from the previous commit as superseded, not delete it -- the reasoning
trail (including the mistake) stays visible so a future session doesn't
repeat it. Root cause of the visually-confirmed rainbow bug remains
open; next steps revised to a texture-identity-keyed probe variant.

Added GE_D157 to GE-ENV-PROBES.md. No src/game changes. findings-index
regen was a no-op.
2026-09-16 22:25:39 -04:00
James Dansereau c58797c2da D219 M-157: first visual capture of the rainbow-particle bug, cross-validates M-110's G_LIGHTING lead
Chasing D252 further, got the first-ever screenshot proof of this bug
family: a plain bullet-impact spark on a Bunker1 door cycling magenta ->
purple -> green -> teal -> purple across consecutive shots, captured
headlessly via GE_INPUTSCRIPT (Z fire pulses) + GE_PCDUMP together, then
reading the resulting PPMs directly (PIL) instead of only grepping a
probe log.

Traced the call chain (glass2.c's bullet_spark_render, a different code
path from both D219's explosion.c particles and D252's IMAGE_FIRE_N
system) and ruled out three mechanisms with actual code evidence before
finding one that fits:
- Not D252's fire-tile system (GE_D252 got zero hits on this repro).
- Not a struct-layout/ABI bug (sImageTableEntry is 12 bytes on both
  32- and 64-bit, no pointer members -- checked before assuming, per
  this session's own rule-2 bucket-(a) discipline).
- Not the primitive color (g_BulletSparkColors[1], a hardcoded literal
  for world-prop hits -- always pale yellow).
- The texture itself (explosion_smokeimages, IA8, verified via the
  asset table) has no color channels and decodes correctly.

That leaves M-110's G_LIGHTING-not-cleared mechanism (already proposed,
unconfirmed, for explosion.c) as the one that fits: bullet_spark_render
never clears G_LIGHTING either (only ORs in G_CULL_BACK), so if lighting
is on, fast3d reinterprets the vertex color bytes as a lighting normal
and computes a scene-light SHADE color instead -- independently
converging on the same mechanism at a second call site, for a visually
distinct symptom (bullet sparks vs explosions). Flagged honestly as
unresolved bucket (b) vs (c): bullet_spark_render's missing lighting
clear is decomp-verified N64 ground truth, so a src/game fix needs the
port-layer alternative ruled out first, per docs/dev-process.md's own
new taxonomy -- not assumed just because the mechanism fits.

Also documented the headless-visual-capture technique itself
(GE_INPUTSCRIPT + GE_PCDUMP together, then actually opening the PPMs)
in porting-notes.md as a reusable method -- several other long-open
visual findings (D290/D291/D294) have been stalled purely for lack of
eyes on the pixels, not for lack of a working probe.

No src/game or port/ changes -- diagnosis only, screenshots are
session-local (scratch/, gitignored). findings-index.csv regen was a
no-op.
2026-09-16 22:20:49 -04:00
James Dansereau 1e1041c6ba D252: note GE_D172 re-run on the same repro found nothing (no combiner data) 2026-09-16 18:18:05 -04:00
James Dansereau 46b72b76fa D252 M-156: GE_D252 probe finally fired, decode confirmed correct by hand
Reused the D219/M-90 scripted-fire technique (GE_INPUTSCRIPT Z pulses) on
a bare -level_33 boot to get bullet-impact sparks headlessly -- got 14
distinct fire-stage texture dumps (scratch/d252_raw_*.bin, gitignored).
Hand-decoded all 14 as RGBA5551 big-endian and averaged the opaque
texels per stage: a perfect, smooth white-hot -> yellow -> orange ->
deep-red -> fade-out progression, zero off-hue content anywhere. This
independently reconfirms M-141's width/height/byte-order conclusion and
goes further -- it's the first time this investigation actually looked
at the decoded numeric pixel values rather than reasoning about the
decode formula, and it rules out the source asset data and the decoder
entirely. The bug is confirmed downstream: GL upload, the texture
cache, or the G_CC_INTERFERENCE combiner.

Also checked and refuted M-141's texture-cache-collision lead: all 14
captured stages have distinct texture_addr values, so TextureCacheKey
(gfx_pc.h) can't be colliding between stages the way that theory
required. Recorded a concrete next step (correlate a live GE_PCDUMP
rainbow frame against which of the now-known-correct 14 stages was
bound) for the next session.

No src/game or port/ changes -- diagnosis only. findings-index.csv
regen was a no-op (no new Dxx label).
2026-09-16 18:16:33 -04:00
James Dansereau d5fd08f40c D288: frame-gate the GE_D288 probe, re-run, still inconclusive
Gated GE_D288 to num_dls 550-755 (the reported bug window, same pattern
GE_D236RM already uses) and raised the bbox threshold from 0.15 to 0.5.
Volume dropped 116k -> 28,883, but that's still not the isolated signal
-- traced the remaining noise to a bad assumption in the probe itself:
bbox_frac from a raw x/w divide is meaningless once any_behind_camera=1
(w<0 or near-zero), which is exactly why the surrounding D233 code already
defers to GL's own clipper for that case rather than trusting the divide.
Restricting to any_behind_camera=0 (2,128 hits) still found no match for
the target color (83,62,44); the persistent hits across the window look
like static level geometry, not the transient bug triangle.

Working theory: the bare -level_20 boot's scripted intro camera may not
reach the same state the original visual bug report came from -- the same
"deterministic boot flag != deterministic camera path" pattern this
session's D236 passes independently hit on a different level. Recorded a
revised next-step list in findings.md; a live human repro is now more
promising than further headless probing of this specific approach.

No src/game changes. findings-index.csv regen was a no-op.
2026-09-16 18:10:43 -04:00
James Dansereau 08865bedeb D288 M-155: ran the GE_D288 probe, result inconclusive -- needs frame-gating
Ran the M-152 next-step probe (GE_D288=1 GE_PCDUMP=560-745:5, backgrounded,
25s bare -level_20 boot). Two problems surfaced with the probe itself, not
the underlying bug: it fires 116k times in ~1500-2000 frames (the
bbox_frac>0.15 threshold catches ordinary near-camera geometry throughout
the whole run, not just the reported ~562-741 window), and the target
color signature (83,62,44) never appears in the log. No GE_PCDUMP PPM
output was produced either, so no visual cross-check was available.
Confidence unchanged from M-152; this is a probe-refinement finding, not
a root-cause finding. Recorded the concrete next step (frame-gate GE_D288
on num_dls the way GE_D236RM already does) in the D288 entry.

Also caught and documented a real tooling gotcha: a backgrounded
ge007.x86_64.exe launch from this Bash tool doesn't reliably die to
`pkill -f` (process shows as bare `ge007.x86_64` in ps, no .exe suffix) --
a stray instance ran ~90s past its intended capture window before being
caught via `taskkill //F //IM ge007.x86_64.exe`. Added to porting-notes.md
so the next session uses taskkill from the start.

findings-index.csv regen was a no-op (no new Dxx label).
2026-09-16 18:07:47 -04:00
James Dansereau 7e81fb5e55 D236 pass 11: GE_INPUTSCRIPT nav attempt, no working path found, one new data point
Tried to keep the -level_36 deterministic boot's camera in the outdoor
room past its scripted indoor transition, to re-run GE_D236RM facing the
tree line directly (the concrete next step pass 10 named). Three
GE_INPUTSCRIPT variants (sustained SDOWN, sustained SUP, a START-skip +
delayed SUP) each changed the pre-transition room (curRoom 7/12/13) but
none held the camera outdoor past the transition, which fires at roughly
the same real time regardless of direction and earlier when START skips
faster -- timer/event-driven, not position-driven.

One new data point: the START-skip run's very first two GE_D236RM
samples hit count=10 then 6 (vs pass 10's flat max of 4) before
collapsing back to 2 then 0 within ~100 draw-list calls. Still far short
of D280's ~720 free-run figure -- best current explanation is that
D280's original number came from a genuinely different, later, closer
vantage than anything reachable in this boot's opening seconds, not a
CPU-side instantiation bug at this specific vantage.

No src/game or port/ file touched (GE_D236RM unmodified from pass 10).
Added the "opening cutscene isn't fully input-inert, but its transition
may still be time-gated not position-gated" quirk to porting-notes.md.
findings-index.csv regen was a no-op (no new Dxx label).
2026-09-16 18:04:08 -04:00
James Dansereau 23da815dda D236 pass 10: refute "nondeterministic instantiation", it's room occlusion
Per the rule-2-clarification pass-10 brief in findings.md, applied the new
three-bucket taxonomy to D280's leading theory that the 0x0c184b50
discrete-tree-card render-mode class instantiates inconsistently across
runs of the deterministic -level_36 boot (~4 tris vs ~720).

Added a small env-gated diagnostic (GE_D236RM, port/fast3d/gfx_pc.cpp
gfx_sp_tri1) counting that class's per-frame triangle count, heartbeat-
logged every 300 frames even at zero. Three independent -level_36
launches (one with sustained GE_INPUTSCRIPT camera rotation) produced
byte-identical per-frame counts, falsifying the "run-to-run dependent"
premise outright. Cross-referencing with the existing GE_D104 room-census
probe in the same run shows the count drops to zero at the exact frame
the player's curRoom transitions from 12 (17-20 rooms drawn, an outdoor
vista) to 18 (1-5 rooms, an enclosed indoor space) via the boot's own
scripted intro camera — ordinary portal/room occlusion, not a bug. None
of buckets (a)/(b)/(c) apply; no src/game or port/ fix made or warranted.

The original "wall not discrete sprites" symptom is untouched by this
pass — narrowed the real next step to getting a camera into room 12
facing the tree line directly, in docs/dev/findings.md.

Added the generalisable "deterministic boot flag != deterministic camera
path" quirk to porting-notes.md §E. findings-index.csv regenerated.
2026-09-16 17:58:01 -04:00
James Dansereau 1c60da6f46 docs: clarify rule #2's diagnostic scope + define rule-2 sign-off process
Widens the written scope of AGENTS.md non-negotiable #2's ABI exception to
match established practice (runtime struct/union misreads, not just
ROM-serialized structs — the D209/D210/D255 pattern), states explicitly
that diagnosis into src/game is never restricted (only the fix is), and
defines a real three-bucket taxonomy + sign-off procedure (dev-process.md
§7) for the rare genuine-behavior-difference case, replacing the
undefined ad hoc "ask the user" gesture that's been referenced without
being defined across ~10 places in the docs.

Mirrors the same framing into CONTRIBUTING.md and the PR template for
external contributors. Extends porting-notes.md §A1 with D255 as a third
worked example and a tell-tale-signs checklist, explicitly distinguishing
it from D284 (same epistemic shape, different mechanism, no rule-2
question at all). Appends a ready-to-dispatch pass-10 brief to the D236
entry applying the new taxonomy to its actual next step.

Docs-only; no code/build changes. Per docs/dev/notes/RULE-2-CLARIFICATION-PLAN.md.
2026-09-16 17:45:58 -04:00
James Dansereau deac53f892 docs: D243 M-154 fix 2 (second probe crash + final deref-free tick path) 2026-09-16 17:09:36 -04:00
James Dansereau 2a1f1b2472 findings: D243 M-154 crash-fix note + D298 corrected (full HUD, suspected debug-launch artifact)
- D243: M-154 fix paragraph — probe-side AV at the abseil CREATE
  (render_pos = 0xFF tombstone until instcalcmatrices runs during the
  draw pass); guarded; transition frame now logged.
- D298: user corrected the symptom — the FULL HUD is missing, not just
  the aim-mode crosshair; suspected debug-launch artifact; per explicit
  instruction, do not raise until seen in a regular release-targeted
  build. Entry re-scoped and parked accordingly.
2026-09-16 16:57:40 -04:00
James Dansereau 90c87fa227 findings: D298 filed — aim-mode crosshair missing (regression, parked per user)
User-reported 2026-09-16 during the M-154 re-run build: the aim-mode
crosshair no longer renders, suspected to come from earlier v0.3.0 work.
Explicitly parked ('don't fix, just for context'). Entry records the
symptom, rules out the probe-only M-154 commits and D295's menu-buffer
widen, points at the crosshair draw path (crosshairimage / bondview.h
show-hide flag / gunfire.c D215 renderdata family) and a bisect plan.
2026-09-16 16:50:59 -04:00
James Dansereau ce8427cff2 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.
2026-09-16 16:47:31 -04:00
James Dansereau 8d42ac5ee2 D287 M-152: correct false evidence citation, static architecture trace
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.
2026-09-16 16:26:39 -04:00
James Dansereau 695ff7ec09 docs: D243 M-153 — live GE_D243M capture analyzed; double-instance refuted, period-4 render cycle named
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.
2026-09-16 16:25:08 -04:00
James Dansereau 190141ff53 docs: D230 status was stale OPEN despite M-121 fix in the same entry
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.
2026-09-16 16:17:53 -04:00
James Dansereau 895118c205 D290 M-152: static investigation, decomp side ruled out
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.
2026-09-16 16:15:30 -04:00
James Dansereau fbc2a533ae D288 M-152: static investigation, add GE_D288 near-plane probe
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.
2026-09-16 16:13:33 -04:00
James Dansereau fd065071cc findings: D243 M-151 probe landed; GE-ENV-PROBES + index updated 2026-09-16 15:58:37 -04:00
James Dansereau 5071185f8c findings: D295 M-148/M-149 + D297 filed/closed (M-150); porting-notes D8/D9
- D295: full M-148 root-cause/repro record (difficultytext overflow ->
  high-bit byte -> langGetJpnCharPixels NULL deref; OOB theory retracted;
  pre-D284 save fingerprint identified), verdict FIXED (M-149).
- D297: new entry — v0.3.0 wipes all pre-fix saves (D284 side effect);
  scope verified (5 slots only, block-0 is a factory seal), FIXED (M-150).
- D284: correct the false 'savegames are unaffected' claim.
- porting-notes: D8 instance (difficultytext[4]); new D9 — changing a
  PRNG/CRC implementation invalidates persisted derived state; sweep
  rewrites data/ge007.eep gotcha in E.
2026-09-16 15:28:44 -04:00
James Dansereau 6f28156956 findings: D243 M-145 - two-Bonds observation confirms third-person model lifecycle bug
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.
2026-09-16 09:38:02 -04:00
James Dansereau 08dbd581e9 findings: D285 live-Deck verification (Archives, dual grenade launchers, rocket-cheat guards, v0.2.2) 2026-09-16 09:37:02 -04:00
James Dansereau 2c19689c62 findings: D243 M-144 — user confirms real N64 does NOT show the abseil shake
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
2026-09-16 00:17:08 -04:00
James Dansereau 91ba14d2e6 findings: D243 M-143 — name the shake mechanism (unreset position-smoothing filter)
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
2026-09-16 00:13:30 -04:00
James Dansereau 24fb22ca80 D243: live playthrough decouples shake from D146; add GE_D243CAM probe
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
2026-09-15 23:44:07 -04:00
James Dansereau 8c28453517 findings: fix D255's stale OPEN status (was FIXED+verified, never updated)
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
2026-09-15 23:25:23 -04:00
James Dansereau e978e526be findings: D249 static review rules out two suspects, narrows to portal BFS
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
2026-09-15 23:20:44 -04:00
James Dansereau 7412a9818d sky.c: D245 headless probe + opt-in fixed-shift A/B candidate
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
2026-09-15 23:06:47 -04:00
James Dansereau e108d6bf2e findings: log D295, campaign-halting Control Center crash (GitHub #87)
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
2026-09-15 22:52:11 -04:00
James Dansereau a3637c40e1 optionsoverlay: add D293 quit-to-desktop row to the F10 overlay
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
2026-09-15 22:49:42 -04:00
James Dansereau 44ea596411 findings: validation fixes — D252 derived status now reflects M-141 (both hypotheses refuted, root cause open); normalize D221/D227 append flags to 'appended 2026-09-15 ctx-opt' 2026-09-15 22:24:48 -04:00
James Dansereau 81cb276ed5 hygiene: untrack docs/dev/notes/ctx-opt/consolidate_ab.py (dir is gitignored; validator finding) 2026-09-15 22:24:48 -04:00
James Dansereau 093e428639 findings.md: has-section dedup, rows 20-27 (D280 D275 D274 D273 D272 D284 D285 D286)
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.
2026-09-15 21:51:22 -04:00
James Dansereau e9bb415488 findings.md: has-section dedup, rows 16-19 (D217 D271 D276 + skips)
- 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.
2026-09-15 21:50:34 -04:00
James Dansereau 2a84927e3f findings.md: finish D227 shrink (status cell was missed in the batch-2 pass)
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.
2026-09-15 21:49:31 -04:00
James Dansereau e85175639c findings.md: has-section dedup, rows 11-15 (D206 D207 D205 D176 D177)
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.
2026-09-15 21:48:28 -04:00
James Dansereau 45427eaf0e findings.md: has-section dedup, rows 1-10 (D159 D161 D186 D200 D221 D227 D229 D228 D204 D202)
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/.
2026-09-15 21:45:46 -04:00
James Dansereau 00a877cc53 findings.md: D70–D121 §H cross-check — shrink covered rows to pointers, migrate D120
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.
2026-09-15 21:41:50 -04:00
James Dansereau 14eb1f8330 findings.md: shrink the 3 multi-label rows with per-sublabel sections to pointers
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.
2026-09-15 21:40:23 -04:00
James Dansereau e2b8ec3432 findings.md: consolidate the (a)/(b) duplicate-label sections (D152+, D233, D234)
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/.
2026-09-15 21:39:38 -04:00
James Dansereau 8687846bee findings.md: header documents the ctx-opt migration + CSV lookup path + 4 known index gaps
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).
2026-09-15 21:39:33 -04:00
James Dansereau 9c9d4a0997 docs(findings): migrate D250/D252/D255 to tail sections (ctx-opt P1, manual)
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.
2026-09-15 21:30:27 -04:00
James Dansereau 9a8f1c9162 docs(findings): migrate D211/D219 to tail sections (ctx-opt P1, structurally-odd follow-up)
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.
2026-09-15 21:29:31 -04:00
James Dansereau 6208276d2b docs(findings): repair pre-existing table formatting in D211/D219/D255 (NOT a content edit)
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).
2026-09-15 21:29:20 -04:00
James Dansereau dd2e95e229 docs(findings): repair D233/D234 disambiguation markers (were inserted before '##')
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.
2026-09-15 21:24:21 -04:00
James Dansereau 1726221030 docs(findings): disambiguate duplicate D233/D234 section headings (a)/(b)
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.
2026-09-15 21:23:47 -04:00
James Dansereau 60b1e4ff61 docs(findings): migrate fat §F rows D271-D294 to tail sections (ctx-opt P1, batch 8/8)
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.
2026-09-15 21:23:27 -04:00