re: the interpolator is not found, and four routes are excluded

Question 1's behavioural half is answered elsewhere and measured. This is
the other half -- which function -- and it is not found. Recorded as a
bounded negative so the next attempt does not repeat four searches.

Excluded, all by exhaustive scans of the image:

  integer lerp shape (divw with mullw and subf within 10 instructions):
    28 sites image-wide, NONE in the UI region 0x82200000-0x823FFFFF
  mulli by 40, the keyframe record stride: 31 sites, NONE in the UI region
  addi rX,rX,40 in the UI region: 43 sites; the screen/bundle ones at
    0x823CCA6C and 0x823CCA94 disassemble to a 40-byte container COPY loop
    (CTR=10, ten-word copy), a vector reallocation, not an evaluator
  fmadd-family in the UI region: 811 sites over 142 pages -- too diffuse to
    select on, so float is neither excluded nor narrowed

The first two together say the evaluator does not compute its fraction with
integer multiply-and-divide and does not index records by multiplication.
With the measured steps landing on exact integers, the likeliest remaining
shape is a float lerp with a per-segment reciprocal, converted to a byte --
stated as a hypothesis, not a finding.

Names the route I would take next and did not have budget for: trace DOWN
from the quad emitter. sub_823C2AC0 has exactly 6 callers, four of them
sibling emitters, and sub_822380B0 reads its colour from this+0x04..0x10.
Whoever writes those fields is one step from the interpolator.

Reach stated: the two opcode negatives are exhaustive over the whole image
rather than sampled, but they do not exclude the interpolator living
outside the UI region, which is an assumption inherited from
ui-quad-class-foothold.md and not independently checked.

Not blocking the port: it needs whether to lerp and how, which is answered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
This commit is contained in:
sylph-decoder
2026-09-02 15:42:25 +00:00
parent eff9039083
commit 3895f3d686

View File

@@ -0,0 +1,66 @@
# ❔ The keyframe interpolator is not found — but four routes are now excluded
**Status: ❔ undecodable so far, with reach.** 2026-09-02. Instrument: ⟨image⟩ —
mechanical scans of `/image/sylpheed.pe`, no database rows.
Question 1 of [`../agents/PLAYTEST-2026-09-02.md`](../agents/PLAYTEST-2026-09-02.md)
has two halves. **The behavioural half is answered** — the game interpolates
piecewise-linearly, every frame, and the declared keyframes predict the measured
per-frame steps
([`splash-interpolates-every-frame.md`](splash-interpolates-every-frame.md)).
**This page is the other half: *which function*, and it is not found.**
Recorded because a bounded negative stops the next attempt repeating four
searches that cost nothing to state and an hour to redo.
---
## What was excluded, and how
The UI region throughout is `0x82200000 … 0x823FFFFF`, which is where the corpus
places the screen/bundle subsystem and the quad-emitter chain
([`ui-quad-class-foothold.md`](ui-quad-class-foothold.md)).
| route | search | result |
|---|---|---|
| **integer lerp** | a `divw`/`divwu` with both a `mullw` and a `subf` in the preceding 10 instructions — the shape of `v0 + (v1v0)·(tt0)/(t1t0)` | **28 sites image-wide, NONE in the UI region.** The evaluator is not integer multiply-divide there |
| **indexed record access** | `mulli rD,rA,40` — the keyframe record stride is 40 bytes ⟨disc⟩ | **31 sites, NONE in the UI region.** Records are not addressed by multiply |
| **pointer walk by stride** | `addi rX,rX,40` inside the UI region | 43 sites. The ones in the screen/bundle subsystem — `0x823CCA6C`, `0x823CCA94` — disassemble to a **40-byte container copy loop** (`mtspr CTR,10` then a 10-word copy), i.e. a `vector<40-byte>` reallocation. **Not an evaluator** |
| **float lerp** | `fmadd`-family ops in the UI region | **811 sites over 142 pages** — far too diffuse to select on. Not excluded; **not narrowed either** |
📌 **The useful part is the first two.** Together they say the evaluator does not
compute a fraction with integer multiply-and-divide, and does not index its
records by multiplication. Combined with the measured behaviour — steps that land
on exact integers like 3 and 14 — the likeliest remaining shape is a **float
lerp with a reciprocal computed once per segment**, then converted to a byte. That
is a hypothesis, and the `fmadd` scan shows it cannot be found by opcode shape
alone.
## What would find it, in cost order
1. **Trace down from the quad emitter.** `sub_823C2AC0` — the accessor that hands
out the vertex pointer — has exactly **6 callers**, four of them sibling quad
emitters (`sub_821D6A40`, `sub_822380B0`, `sub_82234610`, `sub_821BC718`).
`sub_822380B0` calls it and then reads its colour from fields of `this`
(`+0x04`, `+0x08`, `+0x0C`, `+0x10`). **Whoever writes those fields is one step
from the interpolator**, and the caller set is small enough to enumerate. This
is the route I would take next and did not have budget for.
2. **Watch it from the guest instead of reading for it.** The alpha is in a vertex
buffer at a known address each frame; a watchpoint on the byte that becomes
`k_8_8_8_8` alpha would name the writer directly. `/canary` is read-write and
already carries four RE logger patches.
## Why this is not blocking the port
**It is not.** The port needs to know *whether to lerp and how*, and that is
answered and measured. Naming the function would let the answer generalise from
the splashes to every screen without further captures — worth having, not worth
holding the port for.
## Reach
⟨image⟩, exhaustive over the whole 9.2 MB for the two excluded opcode shapes, so
those negatives are complete rather than sampled — the instruction forms searched
genuinely do not occur in that address range. **They do not exclude the
interpolator living outside `0x82200000…0x823FFFFF`**, which is an assumption
inherited from `ui-quad-class-foothold.md` and not independently checked here.