v0.04 loaded job-specific sprites, and with one particular party it looked almost right — 3 of 4 heroes correct. Reordering the party scrambled which hero got which sprite. Sprites tracked party position, not hero identity.
The numeral test showed each slot receiving a block number matching its seat, not its character. A "works for one formation, breaks on shuffle" bug is a classic signature of confusing two index spaces — here, slot (seat 0–3 in the party lineup) versus charID (Bartz=0, Lenna=1, Galuf=2, Faris=3, Krile=4).
The v0.04 hook lives at C1:2517, inside the battle sprite loader. v0.04 assumed the X register there encoded the party slot (slot = ((X−8)>>3)&3) and then read hero identity from RAM. Reading the surrounding code in the Bank C1 disassembly showed both assumptions were wrong:
C1/24EB Y = 0 ; loop over party slots
C1/24EE LDA $CFC6,Y ; A = CHARACTER ID for slot Y ($FF = empty)
C1/2505 ASL ×3 / TAX ; X = charID × 8 ← row into pointer matrix
C1/250B LDA $C124A3,X → $70 ; walk-sprite base for this HERO
C1/2517 LDA $C124A7,X → $76 ; ★ KO-sprite pointer ← our hook site
C1/2526 LDA $CFCA,Y ; job (0-21); × $600 selects the job's art
C1/259A PLY / INY / CPY #4 / loop