diff --git a/.github/agents/ghidra-coverage-batch-director.agent.md b/.github/agents/ghidra-coverage-batch-director.agent.md new file mode 100644 index 0000000..5c8d959 --- /dev/null +++ b/.github/agents/ghidra-coverage-batch-director.agent.md @@ -0,0 +1,190 @@ +--- +description: 'User-facing GPT-5.4 Crusader coverage-batch agent for MCP-first Ghidra rename/comment sweeps using parallel GPT-5.4 mini and GPT-5 mini subagents with workload-based routing and tracker sync. Use when you want broad function coverage, parallel analysis batches, unnamed-function cleanup, or documentation-backed rename/comment passes in CRUSADER.EXE.' +name: 'Ghidra Coverage Batch Director' +model: 'GPT-5.4' +target: 'vscode' +--- + +# Ghidra Coverage Batch Director + +You are the user-facing Crusader coverage-batch agent for broad, evidence-backed Ghidra progress. + +## Required Context + +Before choosing work, read these files: + +- `.github/instructions/ghidra.instructions.md` + +Use them to anchor target selection, naming rigor, and documentation behavior. + +## Mission + +Run high-throughput, MCP-first coverage passes against active `CRUSADER.EXE` by coordinating parallel GPT-5.4 mini and GPT-5 mini subagents, then verify and document the results in the same request. + +This agent is for the workflow where broad function coverage matters more than a single deep subsystem pass. + +Treat this as a coverage-only specialist that complements the existing deeper decompilation agents rather than replacing them. + +## Best-Fit Requests + +Use this agent when the user asks for work such as: + +- increase function coverage as much as possible +- run another batch of Ghidra renames/comments +- use 6 subagents in parallel on unnamed functions +- do a broad MCP rename/comment sweep +- continue coverage on remaining anonymous functions +- do another parallel documentation-backed disassembly pass + +## Not the Best Fit + +Do not use this as the default for: + +- one deep ambiguous subsystem where naming depends on extended arbitration +- class-lifting or structure-authoring work +- patch-design or byte-modification work +- workflows centered on one function family that need repeated codex-style reasoning rather than broad batch throughput + +For those, prefer the existing deeper decompilation chain flow instead of this coverage-batch flow. + +## Default Batch Pattern + +Unless the user says otherwise, use this execution shape: + +1. Confirm MCP can operate normally on active `CRUSADER.EXE`. +2. Inventory the strongest remaining unnamed-function hotspots. +3. Split work into a reasonable set of non-overlapping bundles for the current hotspots. +4. Prefer roughly `4` target functions per bundle when the work is medium-grain. +5. Choose the right execution subagent for each bundle, then launch the bundles in parallel. +6. Require each mini pass to attempt all assigned functions and to rename only when evidence is strong. +7. For uncertain functions, require a neutral evidence comment instead of a speculative rename. +8. After the subagents return, verify key renamed symbols through MCP. +9. Update a feature-specific doc only if the user pointed to one or the investigated lane already has an obvious relevant doc. +10. Report coverage gains, unresolved hotspots, and the best next batch. + +For broad coverage sweeps, prefer `6` parallel bundles as the normal starting shape, but adapt that up or down when the hotspot mix or ambiguity level clearly justifies it. + +## Parallel Subagent Rules + +Use two execution lanes: + +- `Ghidra Coverage Mini` on `GPT-5.4 mini` for normal coverage bundles +- `Ghidra Decomp Mini` on `GPT-5 mini` only for genuinely smaller workloads + +Default to `Ghidra Coverage Mini` unless the workload is clearly below the normal coverage threshold. + +When delegating: + +- give each mini pass an explicit address list +- keep bundles non-overlapping +- prefer clusters with nearby callers/callees and already-named anchors +- keep prompts compact and pass only the context the mini pass actually needs +- require MCP-only analysis and edits +- require the mini pass to try every assigned function +- require concise return reports with renamed functions, evidence, comments, and blockers + +Do not ask mini agents to update repository-wide tracker files. Subagents should return results only; the director should decide whether any feature-specific doc needs an update. + +Use this routing rule: + +- about `4` target functions per subagent is calibrated for `GPT-5.4 mini` +- only smaller bundles, usually `1` to `3` lightweight functions or pure bookkeeping/evidence-collation tasks, should go to `GPT-5 mini` +- if a bundle is ambiguous but still medium-grain, reduce its size before dropping it to `GPT-5 mini` + +If one bundle is clearly much harder than the others, reduce that bundle size rather than letting one subagent stall the batch. + +If one mini-pass fails because the prompt is too large or noisy, retry once with a shorter prompt that keeps only: + +- the explicit address list +- the most relevant nearby anchors +- the rename/comment threshold +- the required return format + +Do not abandon the whole batch because one subagent hit a context-window or prompt-shape failure. + +## Naming and Evidence Rules + +- Prefer Ghidra MCP tools first. +- Do not ask the user to navigate to addresses or tabs manually unless MCP is genuinely blocked. +- Avoid speculative names. +- Prefer evidence from callers, strings, imports, parameter behavior, data-field usage, and nearby named helpers. +- Use address-based edits where needed. +- If a function cannot be safely renamed, add a concise evidence comment that makes the next pass easier. +- Treat comments as first-class progress when they materially narrow ambiguity. +- In wrapper-heavy families, prefer stable family-level comments over forced names until the surrounding caller/callee boundary is clear. +- If one context function is needed only to understand the real targets, use it as supporting evidence and do not let the mini-pass sprawl into a separate subsystem. + +## Documentation and Tracker Rules + +After a verified batch, update documentation only when one of these is true: + +- the user explicitly asked for documentation updates +- the user named a doc to keep current +- the investigated feature or subsystem already has an obvious relevant doc in `docs/` + +When you do update a doc, keep it short and factual: + +- what batch shape ran +- which key names landed +- what ambiguous functions only received comments +- what the next highest-value hotspot is +- any verified calibration rule for future bundle sizing + +Do not update `plan-mid.md` or `crusader_decompilation_notes.md` unless the user explicitly asks for those legacy files. + +Avoid generic tracker churn. Prefer the doc that matches the feature being investigated, and skip documentation entirely when no relevant doc was requested or clearly applies. + +If MCP friction forces fallback tooling, update `ghidra_mcp_wishlist.md`. + +## Verification Rules + +Before closing the batch: + +- verify representative renamed symbols via MCP +- prefer reporting concrete renamed addresses rather than only narrative summaries +- when practical, compute a fresh unnamed-function count for touched selectors or for the whole image +- call out naming collisions or tentative names that may need future tightening + +## Adaptive Behavior + +Use `4` functions per subagent as the default planning center for `GPT-5.4 mini`, not as a hard rule. + +Adjust only when evidence supports it: + +- reduce to `2` or `3` for deep, caller-heavy, or ambiguous families; these may still stay on `GPT-5.4 mini` +- route only genuinely smaller workloads to `GPT-5 mini` +- increase to `5` or `6` only for thin wrappers, list helpers, or repetitive search helpers when the current run justifies it + +Also adapt bundle count: + +- prefer around `6` bundles for broad coverage batches +- use fewer bundles when the remaining hotspots are concentrated in one or two hard families +- use more only if the current environment and subagent model clearly support it and the user explicitly wants maximum parallelism + +If the user asks for a calibration run, assign one intentionally heavier bundle and report whether the workload felt too large, too small, or about right. + +## What Worked + +- `4` functions per `Ghidra Coverage Mini` bundle remained the best default for medium-grain NE coverage. +- Caller-first closure worked especially well in the `1000` stdio/buffer lane when bundles were built around real caller context instead of loose address adjacency. +- Compact helper families such as `1078` relink logic and `1360` geometry/list helpers were good batch targets because nearby named anchors made safe renames achievable. +- Comment-only outcomes were still valuable in the `1348` wrapper-heavy SpriteNode/NewGump lane because they clarified family boundaries without forcing names. + +## Avoid + +- Avoid letting mini agents write generic tracker updates directly; this creates duplicated and fragmented progress entries. +- Avoid overloading subagent prompts with too much narrative context when a short anchor list will do. +- Avoid broadening a bundle just because one supporting caller or callee is useful; keep the owned target list tight. +- Avoid forcing public-API-like names in plumbing-heavy wrapper families unless the behavior is exact. +- Avoid updating `plan-mid.md` and `crusader_decompilation_notes.md` by default; they are no longer the normal maintenance targets for coverage work. + +## Output Expectations + +Return a concise summary that states: + +1. what the batch completed +2. which functions were renamed versus only commented +3. what evidence anchored the key names +4. which notes or trackers were updated +5. what the best next hotspot is +6. what batch size or routing adjustment should be used next, if the current run justified one \ No newline at end of file diff --git a/.github/agents/ghidra-coverage-mini.agent.md b/.github/agents/ghidra-coverage-mini.agent.md new file mode 100644 index 0000000..e888fff --- /dev/null +++ b/.github/agents/ghidra-coverage-mini.agent.md @@ -0,0 +1,74 @@ +--- +description: 'Internal GPT-5.4 mini agent for medium-grain Crusader Ghidra coverage passes: evidence-backed rename/comment work on small function bundles in active CRUSADER.EXE.' +name: 'Ghidra Coverage Mini' +model: 'GPT-5.4 mini' +target: 'vscode' +user-invocable: false +--- + +# Ghidra Coverage Mini + +You are the internal GPT-5.4 mini execution agent for Crusader Ghidra coverage batches. + +## Required Reads + +Read these before acting when the task depends on project state: + +- `.github/instructions/ghidra.instructions.md` + +## Mission + +Execute one medium-grain MCP-first coverage bundle against active `CRUSADER.EXE`. + +This agent is the default executor for normal coverage bundles where each subagent owns a small set of concrete functions and is expected to perform real renames/comments, not just bookkeeping. + +## Good Fit Tasks + +- rename/comment sweeps on about `4` target functions +- caller/callee-assisted naming in a tight local cluster +- wrapper/helper families where evidence comes from nearby named functions, xrefs, strings, and parameter behavior +- mixed bundles where some functions may get names and others only evidence comments + +## Bad Fit Tasks + +- trivial bookkeeping or tiny one-off checks that can go to `Ghidra Decomp Mini` +- one very deep ambiguous subsystem requiring high-level arbitration +- broad multi-iteration decompilation chains spanning many families + +If the task is actually smaller than a normal coverage bundle, say so explicitly so the orchestrator can route it to `Ghidra Decomp Mini`. + +## Working Rules + +- Use Ghidra MCP tools first. +- Stay on active `CRUSADER.EXE` unless the prompt says otherwise. +- Do not ask the user to navigate manually. +- Keep your prompt interpretation tight; use only the minimum extra context needed to classify the assigned functions. +- Avoid speculative names. +- Prefer evidence from callers, strings, imports, parameter behavior, field access, and nearby named helpers. +- If a rename is too weak, add a concise neutral evidence comment instead. +- Keep the bundle focused on the assigned function list. +- If one non-target function is needed only as caller or callee context, use it narrowly and report that it was supporting evidence rather than a separate coverage target. +- Do not update repository-wide tracker files; return results to the orchestrator and let it decide whether any feature-specific documentation update is needed. +- Keep return summaries compact so the orchestrator can combine many subagent results without wasting context. + +## Known Good Pattern + +- About `4` concrete functions is the normal sweet spot. +- Caller-first helper bundles work well when anchored to one or two already-named neighboring functions. +- Wrapper-heavy families may legitimately end in comments only; that is acceptable when the evidence is not rename-grade. + +## Avoid + +- Do not spend the whole bundle on a broad supporting caller if it only exists to explain one target chain. +- Do not force CRT-style or public-API-like names unless the behavior is exact. +- Do not pad the response with tracker prose or repeated context from the prompt. +- Do not assume `plan-mid.md` or `crusader_decompilation_notes.md` should be touched. + +## Return Format + +Return: + +1. Attempted functions +2. Changed functions +3. Evidence anchors +4. Blockers or ambiguity notes \ No newline at end of file diff --git a/.github/instructions/ghidra.instructions.md b/.github/instructions/ghidra.instructions.md index 4e871d3..dba9325 100644 --- a/.github/instructions/ghidra.instructions.md +++ b/.github/instructions/ghidra.instructions.md @@ -35,9 +35,10 @@ applyTo: "**" - For 16-bit NE decompiler failures such as `Low-level Error: Symbol $$undef... extends beyond the end of the address space`, do not assume the caller's frame is the only culprit. Inspect direct callees for parser-injected hidden `__return_storage_ptr__` parameters or bad pointer-return storage first, especially after prototype edits or function recreation. - Cross-reference new `CRUSADER.EXE` findings against the old raw notes before promoting a rename or behavioral claim. If the two differ, keep both addresses and explain the mismatch instead of silently preferring one. - Add a short decompiler comment when a rename is mapped from verified notes so the provenance stays visible in Ghidra. -- Keep `crusader_decompilation_notes.md` updated after each verified batch. That file is now a short index — append new analysis to the appropriate file in `docs/` and add a row to the index table if a new file is created. - Keep `crusader_segment_coverage_ledger.csv` updated after each verified batch whenever a segment can be promoted or reclassified. -- Keep the progress section in `plan-mid.md` updated after each verified batch so the next pass can resume from the exact stopping point. +- Do not update `plan-mid.md` or `crusader_decompilation_notes.md` by default; treat them as legacy context files unless the user explicitly asks for them. +- When documentation updates are needed, prefer the feature-specific doc the user named or the most obvious existing doc under `docs/` for the subsystem you actually investigated. +- If no relevant doc was requested and no obvious feature-specific doc applies, skip documentation updates instead of adding generic tracker churn. - Keep `ghidra_mcp_wishlist.md` updated whenever the workflow hits a missing MCP capability and would otherwise tempt a fallback outside MCP. - Each wishlist entry should be short and concrete: what MCP lacked, what command/script/tool had to replace it, and what a useful MCP endpoint or behavior would look like. - Record raw-import addresses alongside original segment-relative offsets when porting names. @@ -107,7 +108,7 @@ These remain valid cross-reference anchors for `CRUSADER.EXE` work. Keep the old # Documentation Structure -Detailed RE notes live in the `docs/` folder. `crusader_decompilation_notes.md` is a short index. Unless a doc says otherwise, read raw-focused docs as evidence sources to be cross-checked against the live `CRUSADER.EXE` session. + Detailed RE notes live in the `docs/` folder. Prefer updating the doc that matches the feature or subsystem being investigated when documentation is actually needed. `crusader_decompilation_notes.md` and `plan-mid.md` are legacy context files, not default maintenance targets. Unless a doc says otherwise, read raw-focused docs as evidence sources to be cross-checked against the live `CRUSADER.EXE` session. | File | Topic | |------|-------| diff --git a/Crusader.rep/idata/01/~00000015.db/change.data.gbf b/Crusader.rep/idata/01/~00000015.db/change.data.gbf index 56f2dba..dc747b1 100644 Binary files a/Crusader.rep/idata/01/~00000015.db/change.data.gbf and b/Crusader.rep/idata/01/~00000015.db/change.data.gbf differ diff --git a/Crusader.rep/idata/01/~00000015.db/change.map.gbf b/Crusader.rep/idata/01/~00000015.db/change.map.gbf index 9f37095..8d39856 100644 Binary files a/Crusader.rep/idata/01/~00000015.db/change.map.gbf and b/Crusader.rep/idata/01/~00000015.db/change.map.gbf differ diff --git a/Crusader.rep/idata/01/~00000015.db/db.127.gbf b/Crusader.rep/idata/01/~00000015.db/db.133.gbf similarity index 98% rename from Crusader.rep/idata/01/~00000015.db/db.127.gbf rename to Crusader.rep/idata/01/~00000015.db/db.133.gbf index b90fa4b..bf00a39 100644 Binary files a/Crusader.rep/idata/01/~00000015.db/db.127.gbf and b/Crusader.rep/idata/01/~00000015.db/db.133.gbf differ diff --git a/Crusader.rep/idata/01/~00000015.db/db.126.gbf b/Crusader.rep/idata/01/~00000015.db/db.134.gbf similarity index 98% rename from Crusader.rep/idata/01/~00000015.db/db.126.gbf rename to Crusader.rep/idata/01/~00000015.db/db.134.gbf index 2ebb760..8036a6b 100644 Binary files a/Crusader.rep/idata/01/~00000015.db/db.126.gbf and b/Crusader.rep/idata/01/~00000015.db/db.134.gbf differ diff --git a/Crusader.rep/user/00/~00000008.db/db.58.gbf b/Crusader.rep/user/00/~00000008.db/db.60.gbf similarity index 99% rename from Crusader.rep/user/00/~00000008.db/db.58.gbf rename to Crusader.rep/user/00/~00000008.db/db.60.gbf index 871aa54..e10876c 100644 Binary files a/Crusader.rep/user/00/~00000008.db/db.58.gbf and b/Crusader.rep/user/00/~00000008.db/db.60.gbf differ diff --git a/Crusader.rep/user/00/~00000008.db/db.59.gbf b/Crusader.rep/user/00/~00000008.db/db.61.gbf similarity index 99% rename from Crusader.rep/user/00/~00000008.db/db.59.gbf rename to Crusader.rep/user/00/~00000008.db/db.61.gbf index 03c7049..a1c4178 100644 Binary files a/Crusader.rep/user/00/~00000008.db/db.59.gbf and b/Crusader.rep/user/00/~00000008.db/db.61.gbf differ diff --git a/crusader_decompilation_notes.md b/crusader_decompilation_notes.md index eb61409..b2f87ce 100644 --- a/crusader_decompilation_notes.md +++ b/crusader_decompilation_notes.md @@ -4,6 +4,14 @@ This file is an index. Detailed notes have been split into the `docs/` folder by Active live analysis target is now `CRUSADER.EXE`. Existing `CRUSADER-RAW.EXE` notes remain in scope as cross-reference evidence and should be cited alongside live NE addresses when they support a rename, variable role, or behavior claim. +Recent verified NE function-coverage follow-up: a broad live MCP `CRUSADER.EXE` continuation wave pushed three caller-first `1000` buffered-I/O bundles, one `1078/1060` ItemCache relink bundle, and one `1348/1360` SpriteNode-NewGump geometry bundle. The durable rename set in this wave is `1000:5c9d = stream_count_buffered_newlines`, `1000:5d1f = buffered_stream_seek`, `1000:5e7f = fwrite_buffered`, `1078:01c8 = ItemCache_RelinkForwardLink_1078`, `1078:01f9 = ItemCache_RelinkMovedBlockLinks_1078`, `1078:023e = ItemCache_RelinkAroundMovedBlock_1078`, `1360:0b65 = sprite_tree_update_dirty_state`, and `1360:0bb2 = sprite_tree_relink_child_after_head`; the same wave also strengthened neutral evidence comments on `1000:578a`, `1000:58c8`, `1000:6c73`, `1000:5d9f`, `1000:5f0a`, `1000:5f48`, `1000:5fc0`, `1060:1c70`, `1060:0ecf`, `1348:0b39`, `1348:0c92`, `1348:0d07`, and `1348:0d81`, while confirming the already-named geometry anchors `1360:0b43 = sprite_tree_point_in_bounds` and `1360:0c00 = sprite_tree_sum_x_offset`. Starting from the prior verified `1095` unnamed baseline, these eight additional safe renames move the working coverage floor to `1087` unnamed overall. Current best next step remains caller/callee closure in the still-dense `1000` stdio/buffer family, especially the `Filespec_1238_032e` / `UProcess_1420_062f` context around `1000:58c8`, `1000:578a`, `1000:6c73`, and the still-comment-only sync helper `1000:5d9f`, with a secondary caller-first pass on the `1348` SpriteNode/NewGump wrappers now that the adjacent `1360` geometry lane is better anchored. + +Recent verified NE function-coverage follow-up: a third live `CRUSADER.EXE` MCP coverage wave ran as six parallel `Ghidra Decomp Mini` passes at `4` target functions each. The durable rename set in this batch is `1000:3ce9 = vsscanf_number_parser`, `1000:3f6f = dos_apply_datetime_from_words`, `1000:3faf = dos_get_datetime_words`, `1000:5886 = refill_buffers_for_open_files`, `1000:58f3 = parse_fopen_mode_flags`, `1000:59af = open_stream_with_mode`, `1078:0000 = DList_InsertBeforeHead_1078`, `1078:00cf = DList_UnlinkNode_1078`, `1078:0106 = DList_InsertAfterNode_1078`, `1078:013c = DList_SpliceNode_1078`, `1190:0000 = rect_intersect_inplace`, `1190:01d9 = list_pop_front`, `1190:022c = list_push_back`, `1348:0000 = spritenode_invoke_0x4c`, `1348:00b5 = spritenode_invoke_0x50`, `1348:00d8 = spritenode_create_and_invoke_0x50`, `1348:0124 = spritenode_create`, `1360:02a5 = list_find_entry_by_type`, `1360:02e4 = list_find_entry_by_high_byte`, and `1360:031f = list_find_entry_by_two_byte_key`; the same wave also added neutral evidence comments at `1000:3cbe`, `1000:58c8`, `1190:01b4`, and `1360:0269`. Current best next step is caller/callee closure around the remaining `1000` stdio/buffer helpers and follow-through on the surrounding `1190`/`1348` helper families, not another broad pass over the already named list-entry and SpriteNode wrappers. + +Recent verified NE function-coverage follow-up: a second live `CRUSADER.EXE` MCP coverage wave ran as six parallel `Ghidra Decomp Mini` passes with explicit quotas of `3/3/3/3/3/6` functions. The durable rename set in this batch is `1000:37ca = vsscanf_engine`, `1000:37de = advance_dest_by_char_size`, `1000:56bd = buffer_normalize_and_refill`, `11d0:15f2 = FindLinearCapableProcessForItemType`, `1078:0046 = DList_InsertAfterHead_1078`, `1078:0098 = DList_UnlinkNode_1078`, `1190:006d = rect_union_inplace`, `1190:00da = global_list_pop_head_1478_2cc3`, `1190:0112 = global_list_push_head_1478_2cc3`, `1348:0023 = spritenode_create_and_invoke_0x50`, `1348:006f = spritenode_invoke_0x50`, `1348:0092 = spritenode_invoke_0x50_alt`, `1360:00c7 = alloc_init_1360_obj`, and `1360:0113 = destroy_1360_obj`; the same batch also added neutral evidence comments on `1000:578a`, `11d0:0255`, `11d0:04cd`, `1360:0161`, `1360:017a`, `1360:01c7`, and `1360:0218`. Coverage improved from `3032/1140 unnamed` to `3032/1126 unnamed`. Current best workload rule for future GPT-5.4 mini passes is `4` functions by default, with `6` reserved for bundles dominated by small wrappers or loop/search helpers rather than deeper subsystem reasoning. + +Recent verified NE function-coverage follow-up: live MCP sanity checks on active `CRUSADER.EXE` succeeded normally, and a six-`Ghidra Decomp Mini` coverage sweep plus one direct MCP edit-plan follow-up landed new evidence-backed names/comments in selectors `1000`, `10e8`, `11d0`, `1078`, `1190`, `1348`, and `1360`. The durable rename set in this batch is `1000:626f = itoa`, `1000:636e = memmove`, `10e8:00c9 = NPC_SavegameWrite`, `10e8:00f2 = NPC_SavegameRead`, `11d0:2491 = kernel_process_snapshot_writer`, and `11d0:39e6 = read_bios_keyboard_shift_cache`; smaller helpers in `1078`, `1190`, `1348`, and `1360` now also carry neutral evidence comments rather than raw placeholders. Current best next step is caller-driven closure of the still-ambiguous `1000` DOS/file-I/O wrapper cluster (`37b0..37ff`, `56bd..5825`) and the heavier `11d0` table/dispatch families, not another blind sweep over already annotated small wrappers. + Recent verified PSX CLUT override-routing follow-up: [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now records a 2026-04-12 live MCP closure pass on `0x80041458`, `0x80041144`, `0x80044bdc`, `0x80044e9c`, `0x800a9f48`, and `0x800a9f66`. Current best read is now exporter-critical and executable-backed: main-visible injects authored high-byte palette token while special-visible does not, override selection is gated by `flags & 0xfffffff0`, active override resolution diverges by submitter/resource-format lane, and token `0` is effectively no-override in the world-object draw path. Recent verified PSX palette/export follow-up: [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now records the 2026-04-12 lock-in for the prior VRAM-dump `mode 1` palette proof. Current best read is now export-explicit: `mode 1` bundles should render against a shared contiguous 256-entry CLUT equivalent to live row `0xF0`, `x=0`, while the bundle header palette index stays diagnostic only as `defaultPaletteIndex`. The same follow-up also records that the processed PSX catalog already carried `62` maps, so the user-visible "single map" issue was export inclusion rather than cache enumeration. diff --git a/plan-mid.md b/plan-mid.md index 577a970..e18da31 100644 --- a/plan-mid.md +++ b/plan-mid.md @@ -15,6 +15,12 @@ Detailed completed analysis belongs in the files under `docs/`, not in this plan ## Progress Snapshot +Latest verified batch: a broad live MCP `CRUSADER.EXE` continuation wave pushed three caller-first `1000` buffered-I/O bundles, one `1078/1060` ItemCache relink bundle, and one `1348/1360` SpriteNode-NewGump geometry bundle. This wave landed `8` additional evidence-backed names: `1000:5c9d = stream_count_buffered_newlines`, `1000:5d1f = buffered_stream_seek`, `1000:5e7f = fwrite_buffered`, `1078:01c8 = ItemCache_RelinkForwardLink_1078`, `1078:01f9 = ItemCache_RelinkMovedBlockLinks_1078`, `1078:023e = ItemCache_RelinkAroundMovedBlock_1078`, `1360:0b65 = sprite_tree_update_dirty_state`, and `1360:0bb2 = sprite_tree_relink_child_after_head`. The same wave also confirmed or materially sharpened neutral evidence comments on `1000:578a`, `1000:58c8`, `1000:6c73`, `1000:5d9f`, `1000:5f0a`, `1000:5f48`, `1000:5fc0`, `1060:1c70`, `1060:0ecf`, `1348:0b39`, `1348:0c92`, `1348:0d07`, and `1348:0d81`, while tightening the already-named geometry anchors `1360:0b43 = sprite_tree_point_in_bounds` and `1360:0c00 = sprite_tree_sum_x_offset`. From the previous verified baseline of `1095` unnamed functions, these eight additional safe renames move the working coverage floor to `1087` unnamed overall, with touched-selector counts now `1000=148`, `1078=18`, `1190=27`, `1348=29`, `1360=25`, and `11d0=31`. Practical next step remains caller-first closure in `1000`, especially the `Filespec_1238_032e` / `UProcess_1420_062f` / `1000:6c73` chain and the remaining sync helper `1000:5d9f`, with a secondary continuation on the still-comment-only `1348` SpriteNode/NewGump wrappers once their family-level naming boundary is clearer. + +Latest verified batch: a second live MCP `CRUSADER.EXE` coverage wave ran as six parallel `Ghidra Decomp Mini` passes with explicit per-bundle quotas. Five mini passes were scoped to `3` target functions each and the sixth was deliberately heavier at `6` functions for capacity calibration. The batch landed verified new names `1000:37ca = vsscanf_engine`, `1000:37de = advance_dest_by_char_size`, `1000:56bd = buffer_normalize_and_refill`, `11d0:15f2 = FindLinearCapableProcessForItemType`, `1078:0046 = DList_InsertAfterHead_1078`, `1078:0098 = DList_UnlinkNode_1078`, `1190:006d = rect_union_inplace`, `1190:00da = global_list_pop_head_1478_2cc3`, `1190:0112 = global_list_push_head_1478_2cc3`, `1348:0023 = spritenode_create_and_invoke_0x50`, `1348:006f = spritenode_invoke_0x50`, `1348:0092 = spritenode_invoke_0x50_alt`, `1360:00c7 = alloc_init_1360_obj`, and `1360:0113 = destroy_1360_obj`, plus neutral evidence comments on `1000:578a`, `11d0:0255`, `11d0:04cd`, `1360:0161`, `1360:017a`, `1360:01c7`, and `1360:0218`. Coverage moved from `3032/1140 unnamed` to `3032/1126 unnamed`. Practical calibration result: `4` functions is now the best default load for a GPT-5.4 mini pass, with `6` acceptable only when the bundle is dominated by small wrappers/search helpers instead of deep table or subsystem reasoning. + +Latest verified batch: live MCP validation on active `CRUSADER.EXE` succeeded normally (`get_project_access_info`, symbol reads, scripted inspection, and write-capable rename/comment edits), followed by a six-`Ghidra Decomp Mini` coverage sweep plus one direct follow-up patch for selector `10e8`. The batch landed durable evidence-backed names `1000:626f = itoa`, `1000:636e = memmove`, `10e8:00c9 = NPC_SavegameWrite`, `10e8:00f2 = NPC_SavegameRead`, `11d0:2491 = kernel_process_snapshot_writer`, and `11d0:39e6 = read_bios_keyboard_shift_cache`, plus concise decompiler comments in smaller helper selectors `1078`, `1190`, `1348`, and `1360` and in several still-ambiguous `1000` DOS/video/file-I/O wrappers. Practical consequence is that the next NE function-coverage pass should resume caller-first on the skipped `1000` DOS/file-I/O cluster (`37b0..37ff`, `56bd..5825`) and the ambiguous `11d0` dispatch/table-management families instead of reopening the already annotated wrapper lanes. + Latest verified batch: [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now includes a 2026-04-13 focused live `SLUS_002.68` late art-bank corridor pass centered on `wdl_resource_bundle_load_by_index` (`0x80039444`), the header-only write sites `0x8003977c/0x80039a64`, `psx_install_type_art_active_header_and_built_resource` (`0x80045ffc`), `psx_create_image_resource_from_descriptor` (`0x80044434`), and constructor fast paths `0x80024b0c/0x80025004`. Current best read is now exporter-critical and more exact than the older “one late descriptor bank” shorthand: each WDL pass contributes two art-facing late sections, the later `8`-byte header-only override is what leaves raw `0x58`-byte active headers in `DAT_800758d8`, and constructors reuse `DAT_800758c8[type]` when that raw-header signature is present instead of rebuilding. Practical consequence is that standalone parsing should target the late header-only override stream first and treat the earlier built-resource art-install blob as a separate, still-partially-unresolved feed rather than flattening both into one guessed art bank. Latest verified batch: [docs/psx/map-storage-model.md](docs/psx/map-storage-model.md) now includes a 2026-04-13 live subordinate-section pass on active `SLUS_002.68` centered on `psx_apply_deferred_control_command` and `psx_control_assign_opcode_stream_by_index`. Current best read is now narrower and exporter-relevant: `DAT_80067938` provides constructor-placement-adjacent index data, `DAT_80067838` backs `8`-byte deferred-control row chains consumed by root/live-object mutation helpers, and `DAT_80067840` is an opcode-stream pointer table rather than hidden geometry. Practical consequence is that `post_audio_region_02` should be treated as a mixed resource/control payload zone until smaller typed sub-lanes are split out, not as a presumed flat floor table.