diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 0ddb172..5a9f3bd 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -450,6 +450,34 @@ unknown, what evidence exists, and what the first step would be. Move an item in System 15, MainGame 17, PauseMenu 19, StageClear 20, MissionLog 21, GameOver 22, Debriefing 23, Dialog 24, Tutorial 25, ChallengeMission 26, Leaderboard 27. +* βœ…πŸ”΄ **(2026-08-27) THE `(16,32]` GATE IS READ β€” it is `!= 16 && <= 32`, a + VALIDITY CHECK on a load-time parameter, and my own GamePart-id lead is killed + by its control. [structures/isl-condition-builtins](structures/isl-condition-builtins.md).** + πŸ”΄ **The corpus's own notation was wrong.** `(16, 32]` implies a lower bound; + there is none β€” everything **below 16 passes**. The test is + `kind != 16 && kind <= 32`. + βœ… **`X+12` is a constructor argument, not engine state.** `sub_8225EC78(X, + kind, …)` β€” the function carrying `"script load cancel"` β€” does + `stw r4, 12(r30)` and then applies **those same two tests to `r4`**, bailing + out of the load. Every later site re-tests the field it just stored, so the + gate is the object's **invariant**, not a selector between behaviours. Control: + **42 sites image-wide** have this exact `cmpi 16` β†’ `cmpi 32` shape, **34 in one + region** (`sub_821A9DC8`, `sub_821AA1B0`, `sub_821AB570`, `sub_821AB650`) plus 3 + in `sub_8225EC78` β€” one object, guarded everywhere it is touched. + βœ… **The object chain is read.** `X` is installed at `0x821A78EC` + (`stw r25, 104(r30)`), the previous instance torn down first via + `sub_8225EB60` β€” so **`X = [GamePart+104]` is the game part's CURRENT SCRIPT + INSTANCE**. `X+4` β†’ `Y`; `Y+4` β†’ the **ScriptPhase**; `Y+72` = the answer, and + `[ScriptPhase+10152]` gets the same value. `X+12` arrives as `[r21+8]`, `r21` + being `sub_821A6CF0`'s second argument. + πŸ”΄ **REFUTED, my own lead, in the same pass.** GamePart ids run 0…27 and **16 is + not among them**, which made "`X+12` is a GamePart id, 16 being the unregistered + one" very inviting. Its control kills it: **1, 2 and 18 are also missing** from + the `RegisterToFactory` list, so 16 is one of *four* gaps, not a unique one. + Not adopted. + 🟑 Not settled: what the kind **means**. The gate is read; the value's domain is + not, and chasing it needs another hop up (`sub_821A6CF0`'s caller). + ## βœ…βœ… SOLVED β€” the mission freeze was a modal sign-in dialog (2026-08-26) `XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the diff --git a/docs/re/structures/isl-condition-builtins.md b/docs/re/structures/isl-condition-builtins.md index cb7ba4f..a56b0b9 100644 --- a/docs/re/structures/isl-condition-builtins.md +++ b/docs/re/structures/isl-condition-builtins.md @@ -134,6 +134,49 @@ left unnamed rather than named off an unverified premise. and exactly one reference in the image β€” a tail `b` from `0x821AC064` β€” so the string recipe finds nothing there. +## πŸ”΄βœ… (2026-08-27) The gate is `!= 16 && <= 32` β€” and it is a VALIDITY CHECK, not a selector + +πŸ”΄ **First, a correction to this page's own notation.** Written as `(16, 32]` it +implies a lower bound. There is none: + +``` +8225EC90 cmpi cr6, 0, r4, 16 +8225EC94 stw r4, 12(r30) ; <- the field IS the argument +8225EC98 bc 12, eq, ; == 16 -> bail +8225EC9C cmpi cr6, 0, r4, 32 +8225ECA0 bc 12, gt, ; > 32 -> bail +``` + +Everything **below** 16 passes. The condition is `kind != 16 && kind <= 32`. + +βœ… **`X+12` is a constructor parameter, not engine state.** `sub_8225EC78(X, +kind, …)` β€” the function carrying the string `"script load cancel\n"` β€” stores +its second argument into `+12` and applies the identical pair of tests to it +immediately, bailing out of the load. Every later occurrence re-tests the field +it just stored. So the gate is that object's **invariant**, re-checked wherever +it is touched, not a switch selecting between behaviours. + +βœ… **Where it is checked**: 42 sites image-wide with this exact `cmpi 16` β†’ +`cmpi 32` shape, **34 of them in one code region** β€” `sub_821A9DC8`, +`sub_821AA1B0`, `sub_821AB570`, `sub_821AB650` β€” plus 3 in `sub_8225EC78`. One +object, guarded everywhere. + +βœ… **And the object chain is now read.** `X` is installed at `0x821A78EC` +(`stw r25, 104(r30)`), the previous one torn down first through `sub_8225EB60`; +so `X = [GamePart+104]` is **the game part's current script instance**. From +there `X+4` β†’ `Y`, and `Y+4` β†’ the **ScriptPhase**, `Y+72` = the answer, with +`[ScriptPhase+10152]` receiving the same value. `X+12`'s value arrives as +`[r21+8]`, `r21` being `sub_821A6CF0`'s own second argument. + +πŸ”΄ **A tempting reading, killed by its control.** GamePart ids (from the +`RegisterToFactory` strings) run 0…27, and **16 is not among them** β€” which +makes "`X+12` is a GamePart id and 16 is the unregistered one" very inviting. +It fails: **1, 2 and 18 are also absent** from that list, so 16 is one of *four* +gaps, not a unique one. Nothing distinguishes it. The reading is not adopted. + +🟑 So what the kind **means** is still open β€” the gate is now read, but the +value's domain is not. + 🟑 Its neighbours belong to the same cluster: `builtin103` reads `[phase+10156]` and `[phase+10152]` (9 and 7 writers), and a sibling vtable stub clears `[phase+10152]`. The shape is an engineβ†’script status trio, but that is a