# ✅ How a built-in's result reaches a condition — the operand chain The previous iteration named the branches and stated plainly that this was still missing: *"naming the branch does not by itself give the clear condition — that needs the operand chain feeding each compare."* It is read now, and it closes. ## ⚠️ First: the corpus already had half of it, and I had written the stale file [`isl-bytecode.md`](isl-bytecode.md) — which **owns** the opcode table — already named ops 21–24 (`push.i` / `push.f` / `pop.i` / `pop.f`) and ops 13–18 as the six branches. My own [`isl-branches.md`](isl-branches.md), written one iteration earlier, said `op23` and `op21` were unread. **The stale file was mine.** Verified rather than assumed, from the thunks and handlers: | op | moves | verified by | |---|---|---| | 21 `push.i` | `[phase+168]` → deque at `phase+44` | thunk: `addi r4,r30,168` / `addi r3,r30,44` | | 22 `push.f` | `[phase+184]` → deque at `phase+64` | thunk: `addi r4,r30,184` / `addi r3,r30,64` | | 23 `pop.i` | → `[phase+168]` | handler `0x82271C30`, only r3-offset touched is **168** | | 24 `pop.f` | → `[phase+184]` | handler `0x82271CB8`, only r3-offset touched is **184** | With `isl-bytecode.md`'s operand-kind table (`special[0] = [phase+164]`, `special[1] = [phase+168]`), `pop.i` lands in **`special[1]`**. ## ✅ The built-in table is a thin dispatch layer over a vtable Each of the 147 entries is a **stub**, not an implementation. The stub resolves the `local[]` argument base and tail-calls a fixed slot of the `ScriptPhase` vtable at `[phase+0]`: ``` 82272DFC addi r3, r31, 20 ; local[] base 82272E00 bl 0x82454A40 ; resolve 82272E04 lwz r11, 0(r31) ; the vptr 82272E10 lwz r11, 184(r11) ; <- fixed slot, one per built-in 82272E14 b 0x822724F0 ; mtspr CTR / bcctrl, then return 0 ``` Measured over all 147: | | count | |---|---| | dispatched through a `ScriptPhase` vtable slot | **112** | | write `[phase+164]` (`special[0]`) inline in the stub | 17 | | write `[phase+184]` inline | 0 | **Every named predicate is in the vtable group** — `unit_state` 184, `unit_alive` 188, `hp_pct_test` 64, `dist_lt` 56, `unit_hp_pct` 256, `is_engaged` 252, `group_ratio_pct` 196, `timer_elapsed` 372, `player_gauge0/1_test` 396/400 — which is the control: the split is not arbitrary, it separates engine queries from script-local bookkeeping. ## ✅ The vtable is at `0x820A84BC`, derived self-checkingly Not guessed from a stride — the trap this corpus already paid for. Derived from a **known implementation**: 1. `isl-bytecode.md` documents built-in **39** `MARK_LAST_PHASE` as `[phase+300] = 2`. 2. The function `0x8226B498` is exactly `addi r11,r0,2 ; stw r11,300(r3) ; blr`. 3. It appears as a data word at exactly **one** address: `0x820A8570`. 4. Built-in 39's stub uses slot **180** → base = `0x820A8570 − 180` = **`0x820A84BC`**. **The check, which was not used in the derivation:** built-in **40** `mark_not_last` (`[phase+300] = 1`) uses slot **176**, so the base predicts `0x820A84A8`… and slot 176 holds `0x8226B4A8`, which is `addi r11,r0,1 ; stw r11,300(r3) ; blr` — the `= 1` stub sitting immediately after the `= 2` one. Predicted and confirmed. **Third, independent:** the database's own `vptr_writes` lists `0x820A84BC` as a vtable, written at `0x82261B80`. ## ✅ And the result lands in `special[0]` `unit_state` is slot 184 → **`0x8226ADF0`**. It indexes `[phase+324]` — the unit array `isl-builtins.md` already documents — by `local[4]`, reads the record, and writes its answer to **`[phase+164]` = `special[0]`** at both its normal exit (`0x8226AEC4`) and its early exit (`0x8226AF48`). That completes the chain, and the phase-3 poll loop now reads end to end: ``` call unit_state(ADT308) ; result -> special[0] pop.i ; special[1] <- the pushed comparand cmp.i special[0], special[1] beq -> 0xFEB4 ; loop back while they are equal ``` **A built-in's return value is `special[0]`; the comparand is popped into `special[1]`; the compare and branch do the rest.** That is the shape of every clear condition in the corpus. ## 🟡 Not settled * **The other 111 vtable slots are not read.** The base is now known, so each is a lookup rather than a search — but knowing where `hp_pct_test` lives is not the same as having read it. * **Which comparand each site pushes.** The loop above compares against whatever `push.i` put on the deque; recovering that per site needs the push tracked through the decode, which `isl.py` does not do. * **The 35 non-vtable built-ins**, and `op21`/`op22`'s generic deque helpers (`0x82175C20`, `0x82274BA0`), were not read — only their arguments. * **The vtable's length.** `0x820A84BC` is the base and slot 404 is in use, so it is at least 102 entries; I did not establish where it ends.