re: the 0x1883 record carries entry points -- every phase exit is now reachable

data/isl-phase-guards-all.txt goes from 5 of 177 unreachable exits to 0.

The cheap first step failed, usefully.  An unreached routine's entry offset does NOT
appear as a word anywhere in the file, in any encoding: phase-relative 6.6% against an
11.5% control on reached offsets, absolute 1.6% vs 3.3%, and the /4 forms 0-1.6% vs
6.6-8.2%.  Every variant is at or below its control, which rules out the whole family
of "some instruction operand points at them".  It also rules out dead code: Stage 02's
3069 unreached instructions contain 485 calls, including start_coroutine x75,
squadron_attack x59, set_group_speed x42 and objective_marker x13.

The answer is the mission-level stream that isl-bytecode.md already partly read.  Each
0x1883 record is

    0x1883, base_delta, size, 0, entry_a, entry_b     ; entries PHASE-RELATIVE

Measured over all 28 stages, 82 of those 88 values land on a valid instruction --
93.2%, against a 38.6% chance rate for a random 4-aligned offset.  In Stage 02
entry_b is the phase's force-end handler: 0x1482C, 0x249F0 and 0x34A10, two of which
were exactly the unreachable exits, and the third being already reachable is the
consistency check.

Seeding them: exits unreachable 5 -> 0.  Those exits now report 0 necessary
conditions, which is what an engine-entered abort handler should look like.

Recorded because it is the same mistake twice: the first seeding attempt moved NOTHING
(reach 85.0% -> 85.0%, exits 5 -> 5).  dominating_conditions() builds its own entry set
and did not use the one I had patched -- fix-the-instance-not-the-class again, caught
only because an unchanged count is by now a standing signal.

Not settled and stated: reach went only 85.0% -> 85.2%, so what starts the other ~15%
of code is still unknown, and the negative above says it is not an operand in the file;
entry_a is unidentified; 6 of the 88 values do not land on an instruction.
This commit is contained in:
Sylpheed RE agent
2026-08-27 06:51:16 +00:00
parent da6eb236ef
commit 5c4ae3ad7b
6 changed files with 168 additions and 127 deletions

View File

@@ -20,6 +20,24 @@ unknown, what evidence exists, and what the first step would be. Move an item in
what starts the 389 unreachable routines is **still open**. 🟡 A trigger node's
layout and its consumer are unread; built-in 25 stays unnamed.
***(2026-08-27) EVERY PHASE EXIT IS NOW REACHABLE — [isl-stream-entry-points](isl-stream-entry-points.md).**
`data/isl-phase-guards-all.txt`: **5 of 177 unreachable exits → 0.** The cheap
first step FAILED usefully: an unreached routine's entry offset does **not**
appear as a word in the file in any encoding (phase-relative 6.6 % vs an 11.5 %
control; absolute 1.6 % vs 3.3 %; /4 forms 01.6 % vs 6.68.2 %) — all at or
below chance, ruling out "some operand points at them". Nor is it dead code: the
3069 unreached instructions in Stage 02 hold **485 calls** (`start_coroutine` ×75,
`squadron_attack` ×59, `objective_marker` ×13). ✅ The answer is the mission-level
stream: each `0x1883` record is `0x1883, base, size, 0, entry_a, entry_b` with the
entries **phase-relative** — **82 of 88 land on a valid instruction (93.2 %) vs a
38.6 % control** — and `entry_b` is the phase's FORCE_END_PHASE handler (Stage 02:
`0x1482C`, `0x249F0`, `0x34A10`). Those exits now show **0 necessary conditions**,
which is what an engine-entered abort handler should look like.
⚠️ First seeding attempt moved NOTHING (85.0 %→85.0 %, 5→5) because
`dominating_conditions()` builds its own entry set — fix-the-instance again.
🟡 Still open: reach only 85.0 %→**85.2 %**, so what starts the other ~15 % is
unknown; `entry_a` is unidentified; 6 of 88 values do not land on an instruction.
## ✅✅ SOLVED — the mission freeze was a modal sign-in dialog (2026-08-26)
`XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the

View File

@@ -32,9 +32,7 @@ fired by time passing, which is not a property of the graph.
precond 0x002BC4 hp_pct_test(ADT101, 0) != 1
precond 0x0031D8 read_freg(0) < 600
## phase 1 — FORCE_END_PHASE at 0x00E0B4: 2 necessary condition(s)
precond 0x00DFD4 builtin103() == 1
TRIGGER 0x00E034 hp_pct_test(ADS129, 0) != 1
## phase 1 — FORCE_END_PHASE at 0x00E0B4: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x011B10: 2 necessary condition(s)
precond 0x011814 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -57,11 +55,7 @@ fired by time passing, which is not a property of the graph.
precond 0x011B70 read_freg(0) < 70
precond 0x012774 read_freg(0) < 600
## phase 2 — FORCE_END_PHASE at 0x01B828: 4 necessary condition(s)
precond 0x01B4FC builtin103() == 1
precond 0x01B55C hp_pct_test(ADT205, 0) != 1
precond 0x01B5A0 unit_alive(ADT205) != 1
TRIGGER 0x01B6F8 unit_alive(ADT205) != 1
## phase 2 — FORCE_END_PHASE at 0x01B828: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -74,7 +68,7 @@ entry to that `END_PHASE` passes through it, so it is NECESSARY for the
phase to end that way. Reachability alone is the wrong query here —
in a poll loop both successors reach the exit.
CFG reached 15670 of 18739 instructions (83.6%).
CFG reached 15821 of 18739 instructions (84.4%).
`precond` = necessary: the exit cannot happen unless it holds.
`TRIGGER` = also SUFFICIENT: once it holds the exit is unavoidable.
@@ -105,8 +99,7 @@ fired by time passing, which is not a property of the graph.
precond 0x005888 read_freg(0) <= 210
precond 0x006070 read_freg(0) < 1200
## phase 1 — FORCE_END_PHASE at 0x01482C: UNREACHABLE from any static entry
(started from the trigger queue at `phase+272`, by data not code)
## phase 1 — FORCE_END_PHASE at 0x01482C: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x019640: 2 necessary condition(s)
precond 0x0191CC unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -127,9 +120,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x01AA38 global[104] != 0
TRIGGER 0x01AAF8 global[4] == 0
## phase 2 — FORCE_END_PHASE at 0x0249F0: 2 necessary condition(s)
precond 0x0247E4 hp_pct_test(ADN202, 0) != 1
TRIGGER 0x024848 unit_state(TCT206) != 1
## phase 2 — FORCE_END_PHASE at 0x0249F0: 0 necessary condition(s)
## phase 3 — END_PHASE at 0x02B96C: 2 necessary condition(s)
precond 0x02B4F8 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -170,8 +161,7 @@ fired by time passing, which is not a property of the graph.
precond 0x02C240 read_freg(0) <= 300
precond 0x02CFD4 read_freg(0) < 1200
## phase 3 — FORCE_END_PHASE at 0x034A10: UNREACHABLE from any static entry
(started from the trigger queue at `phase+272`, by data not code)
## phase 3 — FORCE_END_PHASE at 0x034A10: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -184,7 +174,7 @@ entry to that `END_PHASE` passes through it, so it is NECESSARY for the
phase to end that way. Reachability alone is the wrong query here —
in a poll loop both successors reach the exit.
CFG reached 8382 of 11105 instructions (75.5%).
CFG reached 8482 of 11105 instructions (76.4%).
`precond` = necessary: the exit cannot happen unless it holds.
`TRIGGER` = also SUFFICIENT: once it holds the exit is unavoidable.
@@ -220,9 +210,7 @@ fired by time passing, which is not a property of the graph.
precond 0x003FC8 read_freg(0) < 210
precond 0x0046E8 read_freg(0) < 600
## phase 1 — FORCE_END_PHASE at 0x009FF4: 2 necessary condition(s)
precond 0x009E60 unit_state(ADT101) == 1
TRIGGER 0x009EC4 unit_state(ADT101) != 1
## phase 1 — FORCE_END_PHASE at 0x009FF4: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x00E1B8: 2 necessary condition(s)
precond 0x00DD44 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -249,8 +237,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00F1E4 <unknown> != 1
TRIGGER 0x00F450 global[60] != 1
## phase 2 — FORCE_END_PHASE at 0x014CF8: UNREACHABLE from any static entry
(started from the trigger queue at `phase+272`, by data not code)
## phase 2 — FORCE_END_PHASE at 0x014CF8: 0 necessary condition(s)
## phase 3 — END_PHASE at 0x019638: 2 necessary condition(s)
precond 0x0191C4 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -286,8 +273,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x01A994 global[44] != 0
TRIGGER 0x01AB10 global[8] == 0
## phase 3 — FORCE_END_PHASE at 0x01F510: 1 necessary condition(s)
TRIGGER 0x01F200 hp_pct_test(ADN301, 0) != 1
## phase 3 — FORCE_END_PHASE at 0x01F510: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -332,8 +318,7 @@ fired by time passing, which is not a property of the graph.
precond 0x003208 hp_pct_test(ADT101, 0) != 1
precond 0x0037FC read_freg(0) < 600
## phase 1 — FORCE_END_PHASE at 0x0052A4: 1 necessary condition(s)
TRIGGER 0x0051E0 hp_pct_test(ADT106, 0) != 1
## phase 1 — FORCE_END_PHASE at 0x0052A4: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x008918: 2 necessary condition(s)
precond 0x008474 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -360,8 +345,7 @@ fired by time passing, which is not a property of the graph.
precond 0x008FA4 global[16] != 1
precond 0x0099A4 read_freg(0) < 600
## phase 2 — FORCE_END_PHASE at 0x00C9CC: 1 necessary condition(s)
TRIGGER 0x00C6BC hp_pct_test(ADN201, 0) != 1
## phase 2 — FORCE_END_PHASE at 0x00C9CC: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -404,8 +388,7 @@ fired by time passing, which is not a property of the graph.
precond 0x003B20 hp_pct_test(ADT110, 0) != 1
precond 0x003B74 hp_pct_test(ADT111, 0) != 1
## phase 1 — FORCE_END_PHASE at 0x007538: 1 necessary condition(s)
TRIGGER 0x0071DC dist_lt(TCN004, TCN001, 20000) == 1
## phase 1 — FORCE_END_PHASE at 0x007538: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x00A088: 4 necessary condition(s)
TRIGGER 0x00964C unit_hp_pct(TCN001, Character_Player_Test) == 0
@@ -423,9 +406,7 @@ fired by time passing, which is not a property of the graph.
precond 0x00A19C hp_pct_test(ADT207, 0) != 1
precond 0x00A1F0 hp_pct_test(ADT208, 0) != 1
## phase 2 — FORCE_END_PHASE at 0x00EEF4: 2 necessary condition(s)
precond 0x00ED64 hp_pct_test(ADS251a, 0) != 1
TRIGGER 0x00EDC4 hp_pct_test(TCN004, 40) != 1
## phase 2 — FORCE_END_PHASE at 0x00EEF4: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -466,9 +447,7 @@ fired by time passing, which is not a property of the graph.
precond 0x00409C global[0] < 9
TRIGGER 0x00422C global[4] != 1
## phase 1 — FORCE_END_PHASE at 0x008EFC: 2 necessary condition(s)
precond 0x008D6C hp_pct_test(ADS151b, 0) != 1
TRIGGER 0x008DCC hp_pct_test(TCN004, 40) != 1
## phase 1 — FORCE_END_PHASE at 0x008EFC: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x00C5D4: 2 necessary condition(s)
precond 0x00C130 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -502,8 +481,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00D618 squad_survival_pct(TCN205, 99.9) == 1
TRIGGER 0x00D72C global[8] == 0
## phase 2 — FORCE_END_PHASE at 0x010E18: 1 necessary condition(s)
TRIGGER 0x010D54 hp_pct_test(TCN215, 0) != 1
## phase 2 — FORCE_END_PHASE at 0x010E18: 0 necessary condition(s)
## phase 3 — END_PHASE at 0x013FCC: 2 necessary condition(s)
precond 0x013B28 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -529,10 +507,7 @@ fired by time passing, which is not a property of the graph.
precond 0x014698 hp_pct_test(ADT301, 0) != 1
precond 0x014F2C read_freg(0) < 1200
## phase 3 — FORCE_END_PHASE at 0x01B31C: 3 necessary condition(s)
precond 0x01B0E8 unit_state(ADN321) != 1
precond 0x01B140 unit_state(TCN001) == 1
TRIGGER 0x01B1B8 dist_lt(ADN321, TCN001, 10000) != 1
## phase 3 — FORCE_END_PHASE at 0x01B31C: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -581,9 +556,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x0037FC read_freg(0, 0) >= 300
TRIGGER 0x0039B8 global[8] != 1
## phase 1 — FORCE_END_PHASE at 0x00976C: 2 necessary condition(s)
precond 0x0095D4 hp_pct_test(ADS151a, 0) != 1
TRIGGER 0x00963C hp_pct_test(TCN012, 40) != 1
## phase 1 — FORCE_END_PHASE at 0x00976C: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x00D168: 2 necessary condition(s)
precond 0x00CD80 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -635,12 +608,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00EF18 squad_survival_pct(TCN004, 99.9) != 0
TRIGGER 0x00F344 global[16] != 1
## phase 2 — FORCE_END_PHASE at 0x017104: 5 necessary condition(s)
precond 0x016A98 hp_pct_test(ADN223, 0) != 1
precond 0x016C00 unit_state(ADN223) != 1
precond 0x016D00 unit_state(ADN232) != 1
precond 0x016E00 unit_state(ADN233) != 1
TRIGGER 0x016F00 unit_state(ADN234) != 1
## phase 2 — FORCE_END_PHASE at 0x017104: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -678,8 +646,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00457C hp_pct_test(ADN102, 0) != 1
TRIGGER 0x004C78 global[4] != 1
## phase 1 — FORCE_END_PHASE at 0x00C980: 1 necessary condition(s)
TRIGGER 0x00C8BC global[0] != 5
## phase 1 — FORCE_END_PHASE at 0x00C980: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x00FB10: 2 necessary condition(s)
TRIGGER 0x00EEB8 unit_hp_pct(TCN001, Character_Player_Test) == 0
@@ -704,8 +671,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x010C38 hp_pct_test(TCN012, 99.9) != 0
TRIGGER 0x010D28 global[28] != 1
## phase 2 — FORCE_END_PHASE at 0x015A80: 1 necessary condition(s)
TRIGGER 0x0159BC hp_pct_test(ADN210, 0) != 1
## phase 2 — FORCE_END_PHASE at 0x015A80: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -755,8 +721,7 @@ fired by time passing, which is not a property of the graph.
precond 0x004234 global[0] != 11
precond 0x004A0C read_freg(0) < 600
## phase 1 — FORCE_END_PHASE at 0x007BF0: 1 necessary condition(s)
TRIGGER 0x007B2C hp_pct_test(TCN109, 0) != 1
## phase 1 — FORCE_END_PHASE at 0x007BF0: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x00AA50: 2 necessary condition(s)
precond 0x00A698 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -781,8 +746,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00B454 unit_state(TCN006) != 1
TRIGGER 0x00B650 global[4] == 0
## phase 2 — FORCE_END_PHASE at 0x00F018: 1 necessary condition(s)
TRIGGER 0x00EF54 hp_pct_test(TCN009, 0) != 1
## phase 2 — FORCE_END_PHASE at 0x00F018: 0 necessary condition(s)
## phase 3 — END_PHASE at 0x012204: 2 necessary condition(s)
precond 0x011E4C unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -826,9 +790,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x013290 unit_state(TCN006) != 1
TRIGGER 0x013534 global[4] == 0
## phase 3 — FORCE_END_PHASE at 0x01CA54: 2 necessary condition(s)
precond 0x01C940 unit_relation(TCN001, ADN320) == 1
TRIGGER 0x01C990 unit_relation(ADN320, TCN001) != 1
## phase 3 — FORCE_END_PHASE at 0x01CA54: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -864,8 +826,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x001918 hp_pct_test(TCN001, 99.9) != 0
TRIGGER 0x001A2C global[4] == 0
## phase 1 — FORCE_END_PHASE at 0x007CF4: 1 necessary condition(s)
TRIGGER 0x007C0C global[0] > 2
## phase 1 — FORCE_END_PHASE at 0x007CF4: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -905,8 +866,7 @@ fired by time passing, which is not a property of the graph.
precond 0x0025A0 read_freg(0) < 600
precond 0x0027E0 global[0] < 10
## phase 1 — FORCE_END_PHASE at 0x00A684: 1 necessary condition(s)
TRIGGER 0x00A588 hp_pct_test(ADS151a, 0) != 1
## phase 1 — FORCE_END_PHASE at 0x00A684: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x00C488: 2 necessary condition(s)
precond 0x00C0A0 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -930,14 +890,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00CFA8 hp_pct_test(TCN004, 99.9) != 0
TRIGGER 0x00D098 global[4] != 1
## phase 2 — FORCE_END_PHASE at 0x014728: 7 necessary condition(s)
precond 0x014044 unit_state(ADS254) != 2
precond 0x0141C4 global[28] != 1
precond 0x014228 unit_state(ADS254) != 1
precond 0x014314 unit_state(ADS255) != 1
precond 0x014400 unit_state(ADS256) != 1
precond 0x0144EC unit_state(ADS257) != 1
TRIGGER 0x0145D8 unit_state(ADS258) != 1
## phase 2 — FORCE_END_PHASE at 0x014728: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -973,9 +926,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00435C hp_pct_test(ADN001, 0) != 1
TRIGGER 0x005214 global[12] != 1
## phase 1 — FORCE_END_PHASE at 0x012824: 2 necessary condition(s)
precond 0x012434 hp_pct_test(ADN045, 0) != 1
TRIGGER 0x0124A0 unit_state(ADN045) != 1
## phase 1 — FORCE_END_PHASE at 0x012824: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1016,9 +967,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00640C global[4] != 0
TRIGGER 0x00681C global[8] != 1
## phase 1 — FORCE_END_PHASE at 0x00EAA0: 2 necessary condition(s)
precond 0x00E910 hp_pct_test(ADS051a, 0) != 1
TRIGGER 0x00E970 hp_pct_test(TCN004, 40) != 1
## phase 1 — FORCE_END_PHASE at 0x00EAA0: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1058,14 +1007,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x002E90 read_freg(0) > 300
TRIGGER 0x003034 global[8] != 1
## phase 1 — FORCE_END_PHASE at 0x0061D4: 7 necessary condition(s)
precond 0x005DE0 hp_pct_test(ADT102, 0) != 1
precond 0x005E58 hp_pct_test(ADT103, 0) != 1
precond 0x005ED0 hp_pct_test(ADT104, 0) != 1
precond 0x005F48 hp_pct_test(ADT105, 0) != 1
precond 0x005FC0 hp_pct_test(ADT108, 0) != 1
precond 0x006038 hp_pct_test(ADT114, 0) != 1
TRIGGER 0x006070 global[0] > 1
## phase 1 — FORCE_END_PHASE at 0x0061D4: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x008324: 1 necessary condition(s)
precond 0x007FC4 unit_hp_pct(TCN201, Character_Player_Test) != 0
@@ -1082,8 +1024,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x008974 hp_pct_test(TCN201, 99.9) != 0
TRIGGER 0x008AA8 global[8] != 1
## phase 2 — FORCE_END_PHASE at 0x00AA94: 1 necessary condition(s)
TRIGGER 0x00A9D0 hp_pct_test(ADT201, 20) != 1
## phase 2 — FORCE_END_PHASE at 0x00AA94: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1115,8 +1056,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x00571C hp_pct_test(ADN101, 0) != 1
TRIGGER 0x00632C global[0] != 1
## phase 1 — FORCE_END_PHASE at 0x00C730: 1 necessary condition(s)
TRIGGER 0x00C618 hp_pct_test(ADN101, 0) != 1
## phase 1 — FORCE_END_PHASE at 0x00C730: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x010FE0: 2 necessary condition(s)
TRIGGER 0x010388 unit_hp_pct(TCN001, Character_Player_Test) == 0
@@ -1136,9 +1076,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x0124D4 squad_survival_pct(TCN207, 99.9) != 0
TRIGGER 0x0125C4 global[8] != 1
## phase 2 — FORCE_END_PHASE at 0x017304: 2 necessary condition(s)
precond 0x017164 hp_pct_test(ADT201, 0) != 1
TRIGGER 0x017240 global[0] != 1
## phase 2 — FORCE_END_PHASE at 0x017304: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1172,10 +1110,7 @@ fired by time passing, which is not a property of the graph.
precond 0x000CF8 player_gauge0_test(0) != 1
TRIGGER 0x000D34 player_gauge1_test(0) != 1
## phase 1 — FORCE_END_PHASE at 0x001584: 3 necessary condition(s)
TRIGGER 0x001404 builtin141(TCN001, 1, 2, 0, 0, 0, 1000, 5, 100, 100) != 1
TRIGGER 0x001524 builtin141(TCN001, 1, 2, 0, -4000, 0, 1000, 5, 100, 100) != 1
TRIGGER 0x001544 global[0] != 1
## phase 1 — FORCE_END_PHASE at 0x001584: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1358,10 +1293,7 @@ fired by time passing, which is not a property of the graph.
precond 0x0076D8 hp_pct_test(TCN004, 0) != 1
precond 0x007D84 read_freg(0) < 1800
## phase 1 — FORCE_END_PHASE at 0x00C114: 3 necessary condition(s)
precond 0x00BB08 unit_state(ADT101) != 1
precond 0x00BDE8 unit_state(ADT108) != 1
TRIGGER 0x00C090 global[80] != 1
## phase 1 — FORCE_END_PHASE at 0x00C114: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1374,7 +1306,7 @@ entry to that `END_PHASE` passes through it, so it is NECESSARY for the
phase to end that way. Reachability alone is the wrong query here —
in a poll loop both successors reach the exit.
CFG reached 9522 of 9936 instructions (95.8%).
CFG reached 9577 of 9936 instructions (96.4%).
`precond` = necessary: the exit cannot happen unless it holds.
`TRIGGER` = also SUFFICIENT: once it holds the exit is unavoidable.
@@ -1396,8 +1328,7 @@ fired by time passing, which is not a property of the graph.
precond 0x017AB0 read_freg(0) < 1200
TRIGGER 0x017BAC global[0] >= 100
## phase 1 — FORCE_END_PHASE at 0x01C28C: UNREACHABLE from any static entry
(started from the trigger queue at `phase+272`, by data not code)
## phase 1 — FORCE_END_PHASE at 0x01C28C: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1438,8 +1369,7 @@ fired by time passing, which is not a property of the graph.
precond 0x00462C read_freg(0) < 900
TRIGGER 0x004828 global[0] != 0
## phase 1 — FORCE_END_PHASE at 0x00FF5C: 1 necessary condition(s)
TRIGGER 0x00FE2C hp_pct_test(TCT019, 50) != 1
## phase 1 — FORCE_END_PHASE at 0x00FF5C: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1497,8 +1427,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x003514 unit_state(TCN005) != 1
TRIGGER 0x003710 hp_pct_test(TCN004, 80) != 1
## phase 1 — FORCE_END_PHASE at 0x0088A0: 1 necessary condition(s)
TRIGGER 0x0087DC hp_pct_test(ADN119, 50) != 1
## phase 1 — FORCE_END_PHASE at 0x0088A0: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1534,8 +1463,7 @@ fired by time passing, which is not a property of the graph.
precond 0x002920 read_freg(0) < 1200
TRIGGER 0x002A4C unit_hp_pct(TCN001, ELLEN) != 0
## phase 1 — FORCE_END_PHASE at 0x006F24: 1 necessary condition(s)
TRIGGER 0x006E60 hp_pct_test(ADT112, 0) != 1
## phase 1 — FORCE_END_PHASE at 0x006F24: 0 necessary condition(s)
------------------------------------------------------------------------
@@ -1548,7 +1476,7 @@ entry to that `END_PHASE` passes through it, so it is NECESSARY for the
phase to end that way. Reachability alone is the wrong query here —
in a poll loop both successors reach the exit.
CFG reached 14755 of 19779 instructions (74.6%).
CFG reached 14840 of 19779 instructions (75.0%).
`precond` = necessary: the exit cannot happen unless it holds.
`TRIGGER` = also SUFFICIENT: once it holds the exit is unavoidable.
@@ -1588,5 +1516,4 @@ fired by time passing, which is not a property of the graph.
precond 0x011534 global[52] < 14
precond 0x011554 global[60] != 1
## phase 1 — FORCE_END_PHASE at 0x038960: UNREACHABLE from any static entry
(started from the trigger queue at `phase+272`, by data not code)
## phase 1 — FORCE_END_PHASE at 0x038960: 0 necessary condition(s)

View File

@@ -993,5 +993,5 @@ block over its ACTUAL predecessors — not from a linear walk.
0x034968 if <unknown: no static entry> == 1 -> 0x34988
0x034988 if global[20] != 7 -> 0x34A00
0x0349E0 if <unknown: no static entry> == 1 -> 0x34A00
0x034A90 if <unknown: no static entry> == <unknown> -> 0x34A30
0x034AA4 if <unknown: no static entry> == <unknown> -> 0x34A5C
0x034A90 if global[116] == 1 -> 0x34A30
0x034AA4 if global[116] == 2 -> 0x34A5C

View File

@@ -7,7 +7,7 @@ entry to that `END_PHASE` passes through it, so it is NECESSARY for the
phase to end that way. Reachability alone is the wrong query here —
in a poll loop both successors reach the exit.
CFG reached 15670 of 18739 instructions (83.6%).
CFG reached 15821 of 18739 instructions (84.4%).
`precond` = necessary: the exit cannot happen unless it holds.
`TRIGGER` = also SUFFICIENT: once it holds the exit is unavoidable.
@@ -38,8 +38,7 @@ fired by time passing, which is not a property of the graph.
precond 0x005888 read_freg(0) <= 210
precond 0x006070 read_freg(0) < 1200
## phase 1 — FORCE_END_PHASE at 0x01482C: UNREACHABLE from any static entry
(started from the trigger queue at `phase+272`, by data not code)
## phase 1 — FORCE_END_PHASE at 0x01482C: 0 necessary condition(s)
## phase 2 — END_PHASE at 0x019640: 2 necessary condition(s)
precond 0x0191CC unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -60,9 +59,7 @@ fired by time passing, which is not a property of the graph.
TRIGGER 0x01AA38 global[104] != 0
TRIGGER 0x01AAF8 global[4] == 0
## phase 2 — FORCE_END_PHASE at 0x0249F0: 2 necessary condition(s)
precond 0x0247E4 hp_pct_test(ADN202, 0) != 1
TRIGGER 0x024848 unit_state(TCT206) != 1
## phase 2 — FORCE_END_PHASE at 0x0249F0: 0 necessary condition(s)
## phase 3 — END_PHASE at 0x02B96C: 2 necessary condition(s)
precond 0x02B4F8 unit_hp_pct(TCN001, Character_Player_Test) != 0
@@ -103,5 +100,4 @@ fired by time passing, which is not a property of the graph.
precond 0x02C240 read_freg(0) <= 300
precond 0x02CFD4 read_freg(0) < 1200
## phase 3 — FORCE_END_PHASE at 0x034A10: UNREACHABLE from any static entry
(started from the trigger queue at `phase+272`, by data not code)
## phase 3 — FORCE_END_PHASE at 0x034A10: 0 necessary condition(s)

View File

@@ -0,0 +1,74 @@
# ✅ The mission-level `0x1883` record carries two ENTRY POINTS — and they were the missing exits
Every phase exit in all 28 stages is now reachable. `data/isl-phase-guards-all.txt`
went from **5 of 177 exits unreachable** to **0**.
## The hunt, including the part that failed
The first step was the cheap one: take each unreached routine's entry offset and
look for it as a word anywhere in the file. **It is not there**, in any encoding:
| entry encoded as | appears as a word | control (reached offsets) |
|---|---|---|
| phase-relative | 6.6 % | **11.5 %** |
| absolute | 1.6 % | 3.3 % |
| phase-relative / 4 | 1.6 % | 6.6 % |
| absolute / 4 | 0.0 % | 8.2 % |
Every variant sits **at or below** the control, so nothing in the bytecode names
these routines. That is a real negative, and it ruled out the whole family of
"some instruction operand points at them".
It also ruled out *dead code*: the 3 069 unreached instructions in Stage 02
contain **485 calls**, including `start_coroutine` ×75, `squadron_attack` ×59,
`set_group_speed` ×42 and `objective_marker` ×13. That is live mission logic.
## ✅ The answer is in the mission-level stream
`isl-bytecode.md` records that the stream at `+0x24` holds three `0x1883` records,
one per phase, whose operand is the phase's code base, and notes they each end
"in a pair of plausible ISL entry offsets". They are exactly that. The record is
```
0x1883, base_delta, size, 0, entry_a, entry_b ; entries PHASE-RELATIVE
```
**Measured over all 28 stages: 82 of 88 of those values land on a valid
instruction — 93.2 %, against a 38.6 % chance rate for a random 4-aligned
offset.**
And for Stage 02 the second entry of each record is the phase's force-end
handler:
```
base 0x0000E4 -> 0x014848, 0x01482C <- 0x1482C was an unreachable exit
base 0x014AA8 -> 0x024A0C, 0x0249F0
base 0x024B4C -> 0x034AC8, 0x034A10 <- 0x34A10 was an unreachable exit
```
Both of Stage 02's unreachable exits are named here, and phase 2's `0x249F0`
already reachable — is the same slot, which is the consistency check.
Seeding these as CFG entries: **exits unreachable 5 → 0** across the disc.
🔑 It also *reads*: those exits now show **0 necessary conditions**, because they
are entry points rather than code reached through tests. A handler the engine can
enter directly, with no preconditions, is what `FORCE_END_PHASE` should look like.
## ⚠️ Seeded in one place, and the count did not move
The first attempt added the entries to `conditions()` and reported reach
**85.0 % → 85.0 %**, exits **5 → 5**. Nothing moved, which is the signal.
`dominating_conditions()` builds its **own** entry set and did not use the one I
had patched — the same fix-the-instance-not-the-class mistake that cost 22× its
own size earlier in this corpus. With both patched: exits **5 → 0**.
## 🟡 Not settled
* **Reach only went 85.0 % → 85.2 %.** These records name a handful of routines,
not the ~15 % of code still unreached. What starts *the rest* is still open —
and the negative above says it is not an operand in the file.
* **`entry_a` is unidentified.** `entry_b` is the force-end handler in the three
Stage-02 records; what the first entry of each pair is has not been checked.
* **6 of 88 values do not land on an instruction.** Not investigated — they may
be absent phases, a different record variant, or a decode edge.

View File

@@ -132,7 +132,8 @@ def dominating_conditions(b):
import collections as _c
E, nxt = edges(b, spawn=True)
offs = isl.linear_offsets(b)
entries = {e for e in set(isl.phase_bases(b)) | set(coroutine_entries(b)) if e in nxt}
entries = {e for e in set(isl.phase_bases(b)) | set(coroutine_entries(b))
| set(stream_entries(b)) if e in nxt}
preds = _c.defaultdict(list)
for a, ss in E.items():
for s in ss: preds[s].append(a)
@@ -174,6 +175,31 @@ def dominating_conditions(b):
return out, len(R), len(offs)
def stream_entries(b):
"""The pair of entry points each mission-level `0x1883` record carries.
Layout, per phase: `0x1883, base_delta, size, 0, entry_a, entry_b`
with both entries PHASE-RELATIVE. Measured over all 28 stages: 82 of 88
land on a valid instruction (93.2 %) against a 38.6 % chance rate for a
random 4-aligned offset.
These are why some routines have no static predecessor at all: nothing in
the bytecode names them. In Stage 02 the SECOND entry of phases 1 and 3 is
exactly the `FORCE_END_PHASE` site that the CFG could not otherwise reach.
"""
code = struct.unpack_from('>I', b, 0x08)[0]
end = struct.unpack_from('>I', b, 0x0C)[0]
out = []
for o in range(0x24, 0x400, 4):
if o + 24 > len(b): break
if struct.unpack_from('>I', b, o)[0] == 0x1883:
base = code + struct.unpack_from('>I', b, o + 4)[0]
for k in (16, 20):
t = base + struct.unpack_from('>I', b, o + k)[0]
if 0 <= t < end: out.append(t)
return out
def coroutine_entries(b):
"""Every `start_coroutine` target, found by a linear pre-pass."""
offs = isl.linear_offsets(b)
@@ -212,7 +238,7 @@ def conditions(b, s1=None, s2=None):
# have no static predecessor. Seed every `start_coroutine` target as well --
# a linear pre-pass finds them because the target is staged into local[0]
# immediately before the call, which no control-flow boundary intervenes in.
entries = list(bases) + coroutine_entries(b)
entries = list(bases) + coroutine_entries(b) + stream_entries(b)
for e in entries:
if e in nxt or e == offs[-1]:
IN[e] = EMPTY; work.append(e)