EC-002: probe_art.py decode-strategy harness

Paired WP: WP-002 Purpose: Ordered enumeration of decode strategies to try against TGIFILE.ART entry 0, with stop conditions so the WP doesn’t sink into infinite codec-guessing.

This checklist applies whether or not WP-001’s Ghidra trace succeeded. If it did, run only the strategies the trace points at. If it didn’t, work the list top-to-bottom; each strategy has a time-box.


Pre-flight

Phase A — Extract first (no decoding yet, time-box: 30 min)

If sanity checks fail, stop and recheck the entry-table walker — the bug is upstream of any decode strategy.

Phase B — Strategies, in order. Stop at the first one that produces a recognizable image.

B1. Raw 8-bit palette-indexed at common resolutions (time-box: 30 min)

If WP-003 found a palette, this is the highest-probability first try.

Stop condition: a recognizable image appears, OR all four resolutions look like pure noise → move to B2.

B2. Raw 16-bit RGB565 / RGB555 at common resolutions (time-box: 20 min)

DirectX 7 truecolor surfaces are 16-bit; if the engine kept assets in that format, raw 16-bit is possible.

Stop condition: recognizable image, OR uniform color noise → move to B3.

B3. F0-opcode RLE — interpretation 1 (time-box: 1 hour)

Hypothesis: F0 NN = “literal run of NN bytes follows,” F0 00 or 0xFF = end-of-row, other bytes = palette indices.

Stop condition: recognizable image, OR decoder runs but output is jumbled → move to B4.

B4. F0-opcode RLE — interpretation 2 (time-box: 1 hour)

Hypothesis: 0xFn is an opcode family where the low nibble carries an operand (run-length, distance, or offset). F0 0C → “opcode 0, operand 12”; F0 08 → “opcode 0, operand 8.”

Stop condition: recognizable image, OR all variants produce noise → move to B5.

B5. Standard LZ77 / LZSS (time-box: 1 hour)

If F0 is a flag byte for the LZSS literal/match distinction (high bit set = literal, etc.):

Stop condition: recognizable image, OR noise → move to B6.

B6. Stop and reassess (HARD STOP after this point)

If B1–B5 all fail:

Do not continue past B6 inventing new strategies blind. Past this point the cost-effective move is Ghidra, not Python.

Phase C — Capture findings (time-box: 30 min after success)

Phase D — Cross-title spot check (stretch, time-box: 30 min)

Definition of done