docs: M-20 — BUNKER1 regression disproven (re-verified PASS); fresh Qwen static-audit tasks

- LEVEL-STATUS: -level_09 boot crash from M-19 did not reproduce on ef1ec523
  in 3 runs (1800 frames crash-free). Was sweep flakiness / D117 nondeterminism
  under machine load, not a real regression.
- HANDOFF-LOCAL-AGENT: replaced the 2 completed M-19 tasks with 3 fresh
  static-only audits (osVirtualToPhysical D131 corollary site sweep, in-place
  relayout D130 corollary sweep, glyph-index OOB audit).
This commit is contained in:
James Dansereau committed 2026-08-29 22:26:52 -04:00
1 parent ef1ec52366
commit 106323aeaa
2 files changed
+94 -52

No files matched your search

+93 -51
View File
@@ -1,74 +1,116 @@
# Local-agent handoff tasks (Qwen 27B)
# Local-agent handoff tasks (Qwen 27B) — M-20
Two self-contained, low-risk tasks that are **disjoint from the active Jungle
`-level_37` G_MTX investigation** (that work is in `port/fast3d/gfx_pc.cpp`
around `gfx_sp_matrix` / `seg_addr` / `gfx_run_dl` — do NOT touch that file).
The two M-19 tasks (D63 scaffolding removal in `libultra.c`; PORT-LEARNINGS
§E entries) are **done and committed** (`1fc3cff6`). Below are three fresh
tasks.
Source: `docs/BACKLOG.md` "Technical cleanup" section.
**All three are pure static analysis** — read code, produce a table, write
a doc section. **No builds. No running the game. No `.c` edits.** Deliverable
is a markdown write-up appended to `docs/PCPortResearch.md` §F (add the new
label to the §F index at the top of the file) plus, where noted, one line in
`docs/PORT-LEARNINGS.md`.
Disjoint from the active session work (intro-render investigation in
`port/fast3d/`, propDef converter audit in `tools_pc/d88_propdefs.py`). **Do
NOT touch `port/fast3d/*`, `tools_pc/d88*`, or any `.c`/`.cpp` file.**
READ FIRST for all tasks: `docs/PORT-LEARNINGS.md` (whole file — it is one
screen), then the specific §F entries named in each task (jump via the §F
index; do NOT linear-read `PCPortResearch.md`).
---
## Task A — doc only, zero code risk (do this first)
## Task A — `osVirtualToPhysical()` latent-truncation site audit (D131 corollary)
**Goal:** add two entries to `docs/PORT-LEARNINGS.md`.
**Background:** `docs/PORT-LEARNINGS.md` §A "D131 corollary". The port shim
`osVirtualToPhysical(va)` returns `(u32)(uintptr_t)va`, which silently drops
the high 32 bits of a **compiled module symbol** pointer (`.bss` / `.rodata`
address, image-based at `0x140000000`). D131 fixed the one live instance
(`explosionRenderPropSmoke`) centrally in `seg_addr()` in
`port/fast3d/gfx_pc.cpp`, which now restores the module high word for a
fallthrough w1 in `[0x40000000, 0x70000000)`.
1. New bug class **"D24-implications — host-scheduling nondeterminism / fake
priority semantics"**: the pthread kernel does not enforce N64's 0–31
thread priorities (`osYieldThread` == `Sleep(0)`), so thread interleavings
impossible on real hardware can occur, and frame timing carries host
jitter. **How to apply:** when a flaky timing bug appears (especially
Phase 3 audio underruns), reach first for host thread priorities
(`SetThreadPriority`: scheduler thread time-critical, tick thread normal)
and the deferred `GE_DETERM` fixed-tick mode (§F D117) — NOT for kernel
changes. Link `[[d117]]`-style to the D117 finding.
2. Watch item under the same class: **`osYieldThread` == `Sleep(0)`** is the
one place the port fakes cooperative scheduling. If a level-sweep hot loop
misbehaves under host load, inspect this shim first. Keep as-is until then.
**Task:** grep every call site of `osVirtualToPhysical(` across `src/`
(`grep -rn 'osVirtualToPhysical(' src/`). For each, produce a table row:
Put both in section **E. Process / method notes** (or a new subsection if
that reads better). Match the file's existing terse style. No code changes.
| file:line | argument expression | arg is: runtime-DRAM ptr / compiled symbol / segmented / unknown | reaches a GBI w1 (`gSPMatrix`/`gSPVertex`/`gSPDisplayList`/`gDma*`)? | covered by D131 `seg_addr` fix? | residual risk |
**Verify:** file still renders as markdown; `git diff` is docs-only.
Classify "compiled symbol" when the argument is `&someGlobal`, a `.bss`/
`.rodata` array/struct address, or a function-local `static`. Classify
"runtime-DRAM ptr" when it is the result of a heap/bank allocation
(`mempAlloc*`, `malloc`, a `->` deref of loaded data). Note which are armed
only when a specific effect first draws (explosion / glass / blood /
bondview2 — the §A note lists these).
**On expiry:** commit whatever is written; partial is fine.
**Deliverable:** the table + a short "residual risk" summary (are there sites
that reach fast3d NOT through `seg_addr`, e.g. a raw `memcpy` or a
non-w1 use?) → `docs/PCPortResearch.md` §F, new subsection
**"D131 corollary — osVirtualToPhysical site audit (M-20)"**, label added to
the §F index.
**On expiry:** commit the partial table.
---
## Task B — mechanical dead-code removal, single file
## Task B — in-place ROM-struct relayout aliasing audit (D130 corollary)
**Goal:** remove the closed-out **D63** debug scaffolding from
**`port/src/libultra.c` ONLY** (leave `port/fast3d/gfx_pc.cpp`'s D63 code
alone — that file is in use by the Jungle work; a separate cleanup later).
**Background:** `docs/PORT-LEARNINGS.md` §A "D130 corollary". `romdataFixupFont`
(`port/src/romdata.c`) re-lays-out a ROM struct array (`fontchar` 24→32B) *in
place*: `dst = base + PCstride*i`, `src = base + N64stride*i`, and for small
`i` the two overlap by less than the per-element read span, so a
field-by-field copy loop clobbers a not-yet-read source field. D130 fixed
that one loop by staging all fields into locals first.
**FILES YOU MAY TOUCH:** `port/src/libultra.c` only.
**Task:** find every other in-place N64→PC struct-array relayout. Search:
`grep -rn 'romdataFixup\|Fixup\|relayout\|in.place\|24.*32\|->32B' port/src/`
and read `port/src/romdata.c` fully (it is the main offender file). For each
loop that (a) reads struct fields from a source offset and writes to a
different-stride destination **in the same buffer**, tabulate:
D63 is a closed finding; this code is dead weight in the hottest function in
the port. Remove, in `port/src/libultra.c`:
| file:line (fn) | struct | N64 stride | PC stride | loop direction | dst/src overlap for low i? | reads all fields before writing? | verdict (SAFE / ALIASING BUG / needs staging) |
- the helper block around lines ~490–610: `d63WatchGunbarrelSlot`,
`d63CheckSlot` (the "log only when the slot value changes" fn), the
`D63Act` struct + `s_d63act` ring buffer + `D63_ACT_N`, `d63On`, `d63Tid`,
`d63Act`, the watchdog thread fn + `d63WatchdogStart`, and the
`D63 clobber-watch` block.
- every call site marked `/* TEMP D63 */`: `d63WatchdogStart()` (~261),
`d63Act("send")` + `d63WatchGunbarrelSlot()` (~617–618),
`d63Act("recv")` + `d63WatchGunbarrelSlot()` (~658–659),
`d63Act(...)` (~1110), and the two `getenv("GE_D63")` gfx-task logging
blocks (~1117–1147).
**Deliverable:** the table → `docs/PCPortResearch.md` §F, new subsection
**"D130 corollary — in-place relayout audit (M-20)"**, label in the §F index.
If you find a concrete ALIASING BUG, describe the fix (stage fields into
locals, as D130 did) in prose in the write-up — **do not edit the `.c`
file**; flag it for the integrator.
Grep `D63` and `d63` in the file afterwards — should be zero hits.
**On expiry:** commit the partial table.
**CONSTRAINTS:** no behavior change; deletion only; do not touch any other
file; do not remove non-D63 code even if it looks unused.
---
**BUDGET:** <= 3 build cycles. `export PATH="/c/msys64/mingw64/bin:$PATH" &&
./build-pc.sh ntsc-final` must stay green (240/240 link).
## Task C — negative / OOB glyph-index audit (PORT-LEARNINGS §A last bullet)
**Verify:** build green; `grep -in d63 port/src/libultra.c` empty;
`./build-pc/ge007.x86_64.exe -level_09` still boots to frames (no crash in
first ~15 s).
**Background:** `docs/PORT-LEARNINGS.md` §A final bullet: `chars[*text - 0x21]`
with a control byte (`*text < 0x21`) indexes before `chars[0]`. Benign on
N64 (hits the adjacent 4-byte kerning table → garbage-but-valid glyph);
**fatal on PC** — the widened `fontchar` has an 8-byte `pixeldata` at a
higher offset, so a negative index reads a wild pointer → fast3d AV. No
level is known to feed a control byte to HUD text yet, so this is latent.
**On expiry:** `git checkout port/src/libultra.c` (revert) and write up which
symbols were still entangled.
**Task:** in `src/game/textrelated.c` (and any other file that indexes a
`fontchar`/`chars` array — grep `chars[` and `- 0x21` / `- 33` across
`src/game/`), enumerate every glyph-index expression on the `textRender*` /
`textMeasure*` ASCII paths. For each, tabulate:
**REPORT:** list of removed symbols + line count delta + build result.
| file:line (fn) | index expression | can the byte be `< 0x21` or `>= last glyph`? (what feeds it — dialogue? HUD? menu? filename?) | guarded already? | consequence on PC if OOB |
**Deliverable:** the table + a recommendation: where exactly a
`GLYPH_IDX` clamp macro (`clamp to [0, nglyphs-1]`, or skip the glyph) would
go, expressed as a prose description of the one-line `#ifdef PORT` guard per
site — **do not edit `.c`**. → `docs/PCPortResearch.md` §F, new subsection
**"Glyph-index OOB audit (M-20)"**, label in the §F index. Add one terse
line to `docs/PORT-LEARNINGS.md` §A noting the audit is done and where the
clamp sites are.
**On expiry:** commit the partial table.
---
## Verify (all tasks)
`git diff --stat` shows **only** `docs/PCPortResearch.md` and (Task C)
`docs/PORT-LEARNINGS.md` changed. No other files. Markdown still renders.
`git status` shows no deleted files. Commit message per task, e.g.
`docs: M-20 Qwen — D131 corollary osVirtualToPhysical site audit`.
**No `Co-Authored-By` / `Claude-Session` trailers** (repo policy).
+1 -1
View File
@@ -12,7 +12,7 @@ Build = `f2beae4b` + `tools_pc/d88_propdefs.py` (D123) + `port/src/gimgfixup.c`
| Level | # | Status | Crash site | Class |
|---|---|---|---|---|
| Bunker1 | 09 | **CRASH (regressed since M-18)** | boot crash `frames=0`, PC `0x1400066fc`, fault `0x00a2fc68` (stack ptr, top nibble masked). Reproduces on clean master `0a4b3bae` → pre-existing, not D131. Bisect D125→HEAD. | **new** |
| Bunker1 | 09 | **PASS** (M-20: re-verified — 1800 frames crash-free, no `ge007.crash.log`, direct `-level_09` boot at ~90us/frame). The M-19 "boot crash `frames=0` PC `0x1400066fc`" did **not** reproduce on `1fc3cff6` in three separate runs → it was sweep flakiness / D117 nondeterminism under machine load, not a real regression. | — |
| Silo | 20 | **PASS** 91.7% | — | — |
| Archives | 24 | **PASS** 91.1% | — | — |
| Train | 25 | **PASS** 87.0% | — | — |