WS4 level sweep driven to completion: 12/21 solo levels PASS
(load + render + no-crash). Full matrix in docs/LEVEL-STATUS.md,
reusable runner tools_pc/level_sweep.sh, WS6 checklist docs/LEVEL-PLAYTEST.md.
Fixes:
- D123 (tools_pc/d88_propdefs.py): crash class C1 on 6 levels
(Dam/Runway/Frigate/Statue/Streets/Cradle). D122 fallout - the widened
Vehichle/AircraftRecord.ailist slot was zeroed instead of carrying its
read-before-write integer AI-list id, so prop.c -> ailistFindById(0) ->
GAILIST_AIM_AT_BOND -> ai() ran a CHR aim list with a NULL chr ->
chrIsNotDeadOrShot(NULL). New OBJ_ID_WORDS arm. 4 levels -> PASS,
Runway falls through to C2. BUNKER1/Silo unregressed.
- D124 (port/src/gimgfixup.c): crash class C2 on Jungle. Compiled
explosion-DL pointer-sync keyed on an IMAGESEG marker that texLoad()
had already erased -> compiled globalDL_0xNNN arrays kept link-time
IMAGESEG words -> 0xABCDxxxx into fast3d on first explosion draw.
Latent on every level. Detect the slot from the compiled array instead.
Diagnosed, NOT fixed (write-ups in PCPortResearch.md SF):
- C2-GDL (D124-Facility addendum): Facility/Runway - model texture-pool
path yields a garbage tex->data; every model file loads at an odd
bank base (mempAllocBytesInBank does no alignment). Suspect
d43_emit.py/pcmodels sidecar texture-blob offsets (N64 8B vs PC 16B Gfx).
- C3/C6 (D125): Aztec/Bunker2/Surface2 - converted propDefs blob in RAM
doesn't match d88_propdefs.py offline output (garbage after record 0);
runtime sizepropdef() walk drifts ~100 records -> wrong door/modelid.
d88_propdefs.py convert_stream + sizepropdef() PORT strides verified
correct; suspect a dest-offset/pd_end bug in d88_emit.py propdefs emit.
Remaining: 9 crashes / 6 classes (C2-GDL, C3/C6, C2m Jungle G_MTX,
C5 Control BG portal, C4 Depot BG tile/room, C7 Surface1 sndSetupSound).
Priority order in docs/LEVEL-STATUS.md.
Also folds in the in-progress docs restructure (HANDOFF/AGENTS/CLAUDE,
PCPortResearch D121/D122 SF/SH entries, PLAN-linear-level-sweep,
HANDOFF-ARCHIVE, BACKLOG).
All ~235 translation units now compile and the target links under MSYS2
GCC 16 + CMake/Ninja (ninja ge007 -k 0: 236/236, zero errors). N64 build
untouched; every src/ change is -DPORT-gated.
Portability fixes (findings D7-D17 in docs/PCPortResearch.md section 11):
- AI X-macro system: SWITCH() call sites activated to the author's
hand-written byte-identical references under PORT; port/shim/
bondaicommands.h + bondconstants.h + CPPLib.h re-emit the IDO paste
tricks (isSubroutine, file-record macros, generated CALL) GCC-clean.
- 64-bit pointer-in-word initializers: monAnim jump targets now go
through an index table resolved by the interpreter (chrai.h/propobj.c);
UsetuplenZ.c credits pointer PORT-gated to 0.
- IDO printf engine compiled for PC (xprintf/xlitob/xldtob) with a
shadow xstdio.h resolving the _Printf prototype clash.
- Host-libc gaps stubbed in port/: bcopy/bzero, __libm_qnan_f,
tlbmanage*, g_ViXScales/YScales; chrObjRandom PRNG ported from .s.
Asset data strategy (D16): single-file assets compiled for real
(animation tables, fonts, textures, rareware logo); obseg per-file .c
excluded (colliding file-local globals the N64 build isolates via
per-ELF linking); 758 ROM-derived table symbols + ramrom_* + segment
markers stubbed in port/src/assetstubs.c / n64stubs.c.
fast3d is a no-op placeholder (port/src/gfxstub.c) until Phase 2 brings
in the real software RSP. Binary not yet runnable end-to-end: ROM
loading in romdata.c is still a TODO.