# Session log — 2026-08-11 (autonomous run)

What changed today, in the order a reviewer would want it, with the one item
that needs **your decision** called out first.

## Needs a decision from you

**Editing save slot 01.** Save files can now be written back
([savegame_edit.py](../../tools/re-capture/savegame_edit.py) re-wraps a real save
**byte-identically**), and hand-written saves load. That unblocked several
questions by probing throwaway slots. But the **title-menu screens read the
auto-save (slot 01)**, so the remaining save-field questions (the difficulty
enum, `SHAB.b`) need slot 01 itself edited — the only save with real progress.
Not done. Recoverable (full content backup + slot 01's bytes archived), but it is
your call. Everything else below was done in throwaway slots.

## Findings, by area

### Save format
- **The develop differential**: buying one Arsenal weapon moves exactly three
  fields — Points `+24` (which **separates it from `+28`**), clear ratio `+8`
  (so the ratio counts *collection*, not stages), and two entries of the 54-byte
  blob. Blob alphabet: `0` locked / `2` developable / `4` owned; only the `4`s
  are stored, `2` is re-derived at load.
- **The blob's index space is solved** — it follows `strings.tbl`'s item order,
  **cut items included**, pinned by four probe saves and closing exactly at 53.
- **`SHAB` is the per-stage record table**: record 0 = Stage 01, and `c` is its
  best clear time in ms (`324773` = the `05:24.77` MISSION SELECT shows).
- **Refuted**: every GHAD scalar as stage/difficulty (16 elements probed), and
  "stage = filled `SHAB` count + 1".

### Formats
- **T8aD 96 % → 100 %** of the disc: a surface is a list of **sub-rectangles**
  (`dst X, dst Y, w, h` per rectangle), not a 256 grid. The "~15 % variants" were
  a wrong model.
- **LSTA**: the count was never unreliable — it counts **sprites *and* `PRMD`
  primitives** (64/64 exact).
- **RATC**: "one level deep" is not a limitation; nested records are **leaves
  that reference siblings by name** (10 144/10 148 resolve).
- **UI screens are fully reconstructible from their bundle** — element list +
  order (declaration table, with a **parent index**) and placement/animation
  (keyframe region). **Validated against the running game to ±2 px.**
- **Movie ↔ subtitle ↔ voice link solved statically** (101 movies) — `INDEX` had
  it filed as needing the running game.
- **XPR2 channel order confirmed** against the game (hue 23.3° vs 9.3°).

### Meshes — the user-reported viewer bug
- Root-caused, **after one wrong turn I corrected in place**: the giant slab on
  `e106` is not a stray volume but an **XBG7 mis-decode** — the same resource is a
  49×23×42 turret in 11 containers and 1600×2100×4800 in 3.
- **New detector**: a resource shared across containers must decode to the same
  bounds. **125 of 681** shared resources fail that check — a measured lower
  bound on *silent* mis-decodes (distinct from the 814 honest declines).

## Two disc defects found
`SUBTITLE_S12B.tbl` (referenced by the movie table, present in **no** language)
and `pmbase.t32` (placed by `pmbase.rat`, present **nowhere**). A reimplementation
should skip a missing asset rather than treat it as a decode failure.

## Process notes worth keeping
- Several "the data is inconsistent" comments meant **our model was incomplete**
  (T8aD variants, the LSTA count). Re-test such notes rather than routing around
  them.
- A test that walks the *oracle's* items and looks each up in our output **can
  only fail one way** — it never sees extras. That shape hid the ship bug and,
  earlier, `include_external`.
- When a diagnosis has eliminated every hypothesis and the last step is *a
  visual*, do the visual first. Three iterations went by before a 30-second
  render showed it.
