From 5ac7b9527fc3654272ee6f248ec992cdc1113df3 Mon Sep 17 00:00:00 2001 From: "Claude (auto)" Date: Thu, 27 Aug 2026 18:07:42 +0000 Subject: [PATCH] re: the AA_/AV_ selection is BLOCKED for static RE, with the mechanism Route 3 (call-graph bound): sub_821A6CF0 and sub_821AB650 each read 196/200/204 off THREE different base registers -- three unrelated objects, not the block. Route 4 (data-flow bound): the definition object lives in the global at 0x828F358C; 18 functions touch it, 9 also touch block offsets. The two best are refuted -- sub_8230D1F8 is the rank/score loader storing CraftScore_Adjustment, FFPenalty_Zessel_Maximum and RankScore_S/A/B at exactly 256/320/324/328/332, and sub_82398CC0 uses r19 as a float-constant pool. So the offset region is shared by two unrelated objects and a constant pool: offset-based discrimination is contaminated by construction, which is why it has now failed three times. Catching the selection needs a runtime watch. Side finding, unowned by the corpus: sub_8230D1F8 is the rank/score loader. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE --- docs/re/BACKLOG.md | 48 +++++++++++++++++++++ docs/re/INDEX.md | 2 +- docs/re/structures/unit-datasheet-static.md | 40 +++++++++++++---- 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 45e01b54..274b9e54 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -4476,3 +4476,51 @@ that is the next handle. **"Anti-air vs anti-vessel" stays a reading**, exactly nameβ†’offset mapping when a scripted `addi`β†’`stfs` pairing (which I then wrote anyway) gave the same 20 lines. Script the extraction first; never eyeball a 4.5 KB function. + +--- + +## πŸ”΄ 2026-08-27 β€” the `AA_`/`AV_` selection is BLOCKED for static RE + +Continues the entry above. Two more routes tried, both refuted with their cause +shown; per the standing rule, when every route has a control and they all read +zero, the item is blocked β€” writing it down and moving on. + +**Route 3 β€” call-graph bound.** The only two functions reachable from the +loader's owner, `sub_821A6CF0` and `sub_821AB650`, each read `196`/`200`/`204` +in three consecutive instructions off **three different base registers** +(`r25`/`r24`/`r11` and `r30`/`r29`/`r11`). That is three unrelated objects +contributing one float each β€” not the AA/AV block. Refuted. + +**Route 4 β€” data-flow bound.** The definition object lives in a global: the +loader is fed by `lwz r3, 13708(r26)` with `r26 = 0x828F0000`, i.e. +`[0x828F358C]`. **18** functions touch that global and **9** of them also touch +block offsets β€” a far better bound than the 39 from offset shape alone. The two +best candidates are both refuted: + +* `sub_8230D1F8` is a **different loader**. Resolving its field names the same + `addi`β†’`stfs` way gives `+256 CraftScore_Adjustment`, + `+320 FFPenalty_Zessel_Maximum`, `+324 RankScore_S`, `+328 RankScore_A`, + `+332 RankScore_B` β€” it *stores* at exactly the offsets the unit definition + uses for `AA_Roll_Min` and the four `AxisMode` fields. +* `sub_82398CC0` uses `r19` as a **float-constant pool** (`320(r19)` next to + `272(r19)` and `-656(r19)`), not as a definition pointer. + +πŸ”‘ **This explains the whole pattern of failure.** The offset region is shared by +at least two unrelated objects *and* by a constant-pool base, so every +offset-based discriminator is contaminated **by construction** β€” that is the +third time the offset route has failed on this corpus, and now with a mechanism +rather than just a count. + +πŸ”΄ **BLOCKED.** Catching the selection needs a runtime watch on the definition +object's `+196`…`+332` during flight β€” emulator work, NEEDS-HUMAN, not a disc or +image read. The layout finding stands; "anti-air vs anti-vessel" stays a reading. + +❔ **Side finding, unowned:** `sub_8230D1F8` is the **rank/score table loader** β€” +`RankScore_S`/`_A`/`_B`, `FFPenalty_Zessel_Maximum`, `CraftScore_Adjustment`. +Grep confirms nothing in `docs/re/` mentions any of those names. A cheap item for +a future iteration. + +**Method slip, second time in two iterations:** I dumped ~400 instructions of +`sub_82398CC0` by eye before writing the six-line name-resolution script that +settled both candidates. **Write the script first** β€” it is in the standing rules +and I broke it again. diff --git a/docs/re/INDEX.md b/docs/re/INDEX.md index 57694b92..f83035a1 100644 --- a/docs/re/INDEX.md +++ b/docs/re/INDEX.md @@ -107,7 +107,7 @@ files, which is how the same ground got covered twice. | [`structures/hangar-loadout-system.md`](structures/hangar-loadout-system.md) | The Hangar loadout system β€” loadout β†’ per-slot allow-list β†’ arsenal item | βœ… CONFIRMED β€” 60/60 slot refs, 70/88 item refs (18 = the `No_Equipment` sentinel) | | [`structures/arsenal-item-weapon-chain.md`](structures/arsenal-item-weapon-chain.md) | The 59-of-131 arsenal question β€” an item names a hardpoint slot, not a weapon | βœ…βœ… CONFIRMED β€” 0/59 `PlayerWeapon` are a `Weapon.ID`, 59/59 are a `Turret_NNN` slot | | [`structures/unit-substructure-records.md`](structures/unit-substructure-records.md) | The destructible-subsystem model β€” a unit's `Turret`/`Bridge`/`Hatch`/`ShieldGenerator`/`Thruster` sub-records | βœ… CONFIRMED β€” 835 turrets, 835/835 `WeaponID` resolve, `StructureCount` control 667/684 | -| [`structures/unit-datasheet-static.md`](structures/unit-datasheet-static.md) | The static unit datasheet and AI flight model β€” `Generic`, `Maneuver`, `Effect` | βœ… CONFIRMED β€” 394 Generic + 114 Maneuver + 114 Effect records read; AA_/AV_ are one interleaved block (AV at X, AA at X+8), selection still unfound | +| [`structures/unit-datasheet-static.md`](structures/unit-datasheet-static.md) | The static unit datasheet and AI flight model β€” `Generic`, `Maneuver`, `Effect` | βœ… CONFIRMED β€” 394 Generic + 114 Maneuver + 114 Effect records read; AA_/AV_ are one interleaved block (AV at X, AA at X+8), selection πŸ”΄ BLOCKED for static RE (4 routes, all controlled) | | [`structures/weapon-datasheet-static.md`](structures/weapon-datasheet-static.md) | The static weapon datasheet β€” `Weapon`, `Shell`, `AssortMissileParam` | βœ… CONFIRMED β€” 131 Weapon + 131 Shell + 9 AssortMissileParam records read | | [`structures/isl-timers.md`](structures/isl-timers.md) | A ScriptPhase owns 32 stopwatches, and they count seconds | βœ… CONFIRMED β€” the advance is read from `sub_822710D0`, the unit from | | [`structures/isl-message-dialogue-link.md`](structures/isl-message-dialogue-link.md) | Mission scripts as dialogue β€” built-in 64 -> message id -> caption text | βœ… CONFIRMED total, 2 683/2 683 call sites across all 28 stages resolve, no residue | diff --git a/docs/re/structures/unit-datasheet-static.md b/docs/re/structures/unit-datasheet-static.md index 386ab1ea..975969fb 100644 --- a/docs/re/structures/unit-datasheet-static.md +++ b/docs/re/structures/unit-datasheet-static.md @@ -143,15 +143,39 @@ description, not a rule. `0x8209F674…`. The loader uses the second block; **the first 20 are referenced by nothing**. -### πŸ”΄ The selection is still not found +### πŸ”΄ The selection is BLOCKED for static RE β€” four routes, all with controls -Looking for the consumer by offset does not work here: functions loading two or -more of `+196`/`+204`/`+320`/`+328` number **39** across the image, and those -offsets are far too common to identify anything β€” the same trap the corpus has -paid for before. Only two of the 39 are call-graph-reachable from the loader's -owner (`sub_821A6CF0` itself, and `sub_821AB650`); that is the next handle, and -it was not followed this iteration. **So "anti-air vs anti-vessel" remains a -reading.** +| route | result | +|---|---| +| 1. string xref on the field names | βœ… **only** `sub_822F9498` references them β€” this gave the layout above, and nothing else in the image touches an `AA_`/`AV_` string | +| 2. unbounded offset intersection (`+196`/`+204`/`+320`/`+328`) | πŸ”΄ **39** functions image-wide; pure coincidence | +| 3. call-graph bound β€” the loader's owner `sub_821A6CF0`, and `sub_821AB650` | πŸ”΄ both read `196`/`200`/`204` off **three different base registers** in three consecutive instructions: three unrelated objects contributing one float each, not the block | +| 4. data-flow bound β€” the definition object lives in the global at `[0x828F358C]` (`lwz r3, 13708(r26)` feeds the loader); 18 functions touch it, 9 also touch block offsets | πŸ”΄ the two best are both refuted, below | + +**Why route 4's best candidates fail, and it is instructive:** + +* `sub_8230D1F8` is a **different loader entirely** β€” a scoring table. Resolving + its field names the same way gives `+256 CraftScore_Adjustment`, + `+320 FFPenalty_Zessel_Maximum`, `+324 RankScore_S`, `+328 RankScore_A`, + `+332 RankScore_B`. It *stores* at the very offsets the definition object uses + for `AA_Roll_Min` and the four `AxisMode` fields. +* `sub_82398CC0` uses `r19` as a **float-constant pool** (`lfs f0, 320(r19)` + alongside `272(r19)` and `-656(r19)`), not as a definition pointer. + +So the offset region is shared by at least two unrelated objects **and** by a +constant pool. That is *why* every offset-based discriminator has failed here: +the contamination is structural, not bad luck. + +πŸ”΄ **Marking this blocked for static RE.** The selection would have to be caught +at runtime β€” a watch on the definition object's `+196`…`+332` during flight β€” +which is emulator work, not a disc or image read. **"Anti-air vs anti-vessel" +stays a reading**, as `unit-datasheet-static.md` has always had it; what is new +is the layout, and that the selector must be a `+0`/`+8` offset. + +*Side finding, unowned by the corpus:* `sub_8230D1F8` is the **rank/score +table loader** β€” `RankScore_S`/`_A`/`_B`, `FFPenalty_Zessel_Maximum`, +`CraftScore_Adjustment`. Nothing in `docs/re/` mentions those names. Not pursued +here. ## `Effect`