docs: define the status markers, and fix six mislabelled or superseded entries

An audit of BACKLOG.md turned up a class of error with a single root cause: the
README defines only the CONFIRMED/PROBABLE/HYPOTHESIS confidence scale, while
the pages actually use a second vocabulary -- and 🔴 appears 98 times without
ever being defined.  It gets used for two different things, "refuted" and
"blocked", and three entries slid from one into the other.

README now defines /🟡//🔴//🚧 and states the rule the corpus was missing:
🔴 never means "we have not run it yet".  That is  or 🚧.  Its blocked sense is
only for a real limit of the box -- no push credentials, no hardware Vulkan, a
decision only the user can make -- and since the box can run the emulator,
script input, screenshot and read guest memory, "needs a run" is never blocked.
I made exactly this mistake on the world-unit item earlier today, which is what
prompted looking for others.

Fixed in BACKLOG.md:

  * the elimination test, marked 🔴 UNRUN and in fact run and refuted nine
    lines further down;
  * the frozen capture, marked 🔴 STILL UNRUN and in fact taken eleven lines
    down -- 🔴 wrong twice, since "the freeze did not happen this run" is a
    scheduling outcome and not a refutation;
  * a 🚧 STILL UNRUN item whose stated blocker (the boot-nav bug) is fixed;
  * the objective-counter heading, which asserts 0xbdb59668 as the answer while
    its own first body line refutes that address -- retitled to say what is
    actually solved, the method;
  * the paint-order "third measured permutation" question, answered inside its
    own entry by a third, fourth and fifth screen;
  * the UTF-16 endianness question -- resolved, and it is not a stale comment:
    localization.rs both documents LE and decodes with u16::from_le_bytes, so
    it is a code bug worth filing.

Also fixes the corpus's only dangling link (INDEX.md pointed at
structures/idxd-unnamed-keys.md, never written).
This commit is contained in:
Sylpheed RE agent
2026-08-26 10:29:15 +00:00
parent 76a998eed4
commit b712972d09
3 changed files with 35 additions and 8 deletions

View File

@@ -157,7 +157,7 @@ where translucent sprites overlap.
A separate earlier slip on the same page counted the six *language* copies of
`GP_MAIN_GAME_2D` as six paks. Same shape each time: a statistic computed over
an unverified sampling frame.
* ❔ A third measured permutation, to promote "holds on two" to a rule. The
* ~~❔ A third measured permutation, to promote "holds on two" to a rule.~~ **Answered inside this same entry** — a third, fourth and fifth screen were measured, the last from `GP_SAVE_LOAD`, i.e. outside `GP_TITLE.pak`. The
cheapest is a screen whose object is resident at the same time as the title's.
* ❔ 341 builds now composite in an order no capture has checked.
@@ -600,7 +600,7 @@ search cannot find a *schedule*.
longer covers those (it still covers t=170/210/240; the run was cut at 240 s by
the turn timeout, not the planned 330 s). 🟡 **Sharper hypothesis:** the
squadron ended at **2, never 0** — no squadron has ever been eliminated in any
run, so the trigger may be *elimination*, not damage. 🔴 **Elimination test UNRUN (2026-08-24)**: the hunting
run, so the trigger may be *elimination*, not damage. **Elimination test unrun (2026-08-24)***superseded below by the `SYLPH_KEEPOUT=1400` run that refuted it; and 🔴 was the wrong marker, an unfinished run is ❔, not blocked*: the hunting
pilot died at t=83 s with the squadron at 14. ✅ But the player's own record hit
`2→0` — first `n→0` ever seen, so the signal does register elimination (no
arrival followed; weak, it was the player not an enemy squadron). ✅ **KEY:
@@ -799,8 +799,11 @@ search cannot find a *schedule*.
`0xbdb59668` is phase-1 progress** and is the right signal to watch, not
`deployed`. Closes a loop to the first session. 🔴 **Method lesson: the crate
already knew this** — several iterations reconstructed it the hard way;
`grep -rl TextIndex crates/` would have saved the detour. Minor: `ixud.rs`
says UTF-16BE, `localization.rs` says LE — one comment is wrong.
`grep -rl TextIndex crates/` would have saved the detour. Minor, resolved 2026-08-26:
strings are **UTF-16BE** ([`idxd-container`](structures/idxd-container.md),
1 104/1 104 objects), so `ixud.rs` is right and **`localization.rs` is the wrong
one** — its header says UTF-16LE *and* it decodes with `u16::from_le_bytes`, so
it is a code bug, not a stale comment.
* ✅🔴 **(2026-08-24) REMAINING OB hunt: method works, run unfinished**
([`remaining-ob-hunt.md`](remaining-ob-hunt.md)). Correlate heap words against
*named* kill events instead of scanning for a value: **one `e010` event cut ~8 M
@@ -987,7 +990,7 @@ search cannot find a *schedule*.
groups sharing a handle. 🟡 `%ebp` is **not** a usable count — `WaitMultiple`
reuses it at `8fc158` — so the array is bounded by reading until an entry stops
resolving. What survives: the object types and the self-validating read.
* 🔴 **(2026-08-25) The frozen capture is STILL unrun — the freeze did not happen.**
* **(2026-08-25) The frozen capture was unrun — the freeze did not happen that run.** *Superseded: it was taken (see `FROZEN CAPTURE TAKEN` below). 🔴 was wrong twice — the capture was not blocked, and "it did not happen this run" is a scheduling outcome, not a refutation.*
Two captures in one run (200 s and 367 s of mission), and `screen_id` reads
**`flight`** at both, plus at ~470 s with a drifting frame mean. So the labelled
`healthy -> frozen` diff is **two healthy captures**, and its `20 -> 18` is three
@@ -1382,7 +1385,7 @@ premise was wrong.**
long-lived Python process computing both signals — then re-run. Second: check
whether the fast 2026-08-25 run had a warm shader cache that this one, started
after `rm -f /dev/shm/xenia_*`, did not.
* 🚧 **(2026-08-25) STILL UNRUN — the live test of the `reset_phase_threads`
* 🚧 **(2026-08-25) Still unrun — the live test of the `reset_phase_threads`
rename.** Built-in 100 clears the trigger container and frees every thread but
the caller, so at a phase terminator **both** `[phase+272+20]` (triggers
queued) and `[phase+216+8]` (coroutines alive) should collapse; if they climb
@@ -1509,7 +1512,9 @@ shared checkout (202 files, no submodule churn), profile bootstrapped with the
meant to, the profile + save + `bin/` copies want a home inside a repo or a
named volume; that is a call for the user, not for an agent.
## ✅ SOLVED (2026-08-23) — the mission objective counter is at `0xbdb59668`, and the hunt is automated
## ✅🔴 SOLVED (2026-08-23) — the *method* for finding the mission objective counter is automated; the **address is run-dependent**
*(Retitled 2026-08-26: the old heading asserted `0xbdb59668` as the answer while its own first line refutes that address. The method is the result.)*
🔴 **`0xbdb59668` is refuted as a durable address** (2026-08-23): 0 in two
independent Stage 02 runs while the HUD read `004`/`008`/`012`, on an allocated

View File

@@ -12,7 +12,7 @@ Promote to a prose `structures/…md` file when a format needs behavioural notes
|--------|-------|-----------------------|-------|
| IPFB `.pak` archive | ✅ | `sylpheed-formats/src/pak.rs` + `tests/pak_idxd_disc.rs` | header + 12-byte TOC, Z1/zlib payloads |
| name-hash (TOC keys) | ✅ | `sylpheed-formats/src/hash.rs` | Barrett-reduction hash; recovers original paths |
| IDXD object/table | ✅ | `sylpheed-formats/src/idxd.rs` + `tests/idxd_records_disc.rs` ([container](structures/idxd-container.md)) | **The binary record/index region in front of the string pool is DECODED** (2026-08-25), closing the parser's long-standing "not yet decoded" note. Uniform 16-byte records `{name_hash, name_off, field_begin, field_end}` sorted by hash and binary-searched, then a field count, 12-byte fields `{key, name_off, value_off}` sorted by key, a pool size, and the string pool; the trailing `pool_size == file_len - pool_base` identity makes the layout self-checking. Verified over the **whole disc** with **zero** failures: 7 750/7 750 objects, 190 782/190 782 records reproducing their stored `tag_hash`, 1 271 462/1 271 462 named fields reproducing their key — and `IXUD` is the same container with `ixud_hash`, UTF-16BE and all offsets in **chars** (1 104/1 104 objects, 628 165/628 165 fields). **Field names are stored on disc** — a field's middle word points at its own name — so nothing needs preimage search except the **504** field entries disc-wide that are hash-keyed with no name — which are only **42 distinct keys**, each in 12 places (see [idxd-unnamed-keys.md](structures/idxd-unnamed-keys.md)), and are provably unrecoverable from the hash alone; the other 1 485 073 nameless fields are *positional*, keyed by a literal integer (line slots, movie ids). ⚠️ **Two long-held beliefs WITHDRAWN**: the word at `0x08` is **not a schema hash**, it is record 0's `name_hash` (7 750/7 750) — the header has no type field at all, so an object's kind is known only from the caller that loads it; and the field's middle word is **not** an always-`0xFFFFFFFF` flags word. The first was caught by a test asserting that every movie id names a real record: `1005 -> STAGE10_PHASE01` failed because `tag_hash("STAGE10_PHASE01")` **is** `0x067025B9`, that table's supposed schema id. 🟡 the legacy value-before-key string-pool reader is now known to be an *approximation* of the real table, and every number derived from it is re-checkable but not yet re-checked |
| IDXD object/table | ✅ | `sylpheed-formats/src/idxd.rs` + `tests/idxd_records_disc.rs` ([container](structures/idxd-container.md)) | **The binary record/index region in front of the string pool is DECODED** (2026-08-25), closing the parser's long-standing "not yet decoded" note. Uniform 16-byte records `{name_hash, name_off, field_begin, field_end}` sorted by hash and binary-searched, then a field count, 12-byte fields `{key, name_off, value_off}` sorted by key, a pool size, and the string pool; the trailing `pool_size == file_len - pool_base` identity makes the layout self-checking. Verified over the **whole disc** with **zero** failures: 7 750/7 750 objects, 190 782/190 782 records reproducing their stored `tag_hash`, 1 271 462/1 271 462 named fields reproducing their key — and `IXUD` is the same container with `ixud_hash`, UTF-16BE and all offsets in **chars** (1 104/1 104 objects, 628 165/628 165 fields). **Field names are stored on disc** — a field's middle word points at its own name — so nothing needs preimage search except the **504** field entries disc-wide that are hash-keyed with no name — which are only **42 distinct keys**, each in 12 places (the page for these was never written — the finding is in this row), and are provably unrecoverable from the hash alone; the other 1 485 073 nameless fields are *positional*, keyed by a literal integer (line slots, movie ids). ⚠️ **Two long-held beliefs WITHDRAWN**: the word at `0x08` is **not a schema hash**, it is record 0's `name_hash` (7 750/7 750) — the header has no type field at all, so an object's kind is known only from the caller that loads it; and the field's middle word is **not** an always-`0xFFFFFFFF` flags word. The first was caught by a test asserting that every movie id names a real record: `1005 -> STAGE10_PHASE01` failed because `tag_hash("STAGE10_PHASE01")` **is** `0x067025B9`, that table's supposed schema id. 🟡 the legacy value-before-key string-pool reader is now known to be an *approximation* of the real table, and every number derived from it is re-checkable but not yet re-checked |
| XPR2 texture + cubemap | 🟡/✅ | `sylpheed-formats/src/texture.rs` + [colour check](xpr2-colour-check.md) | de-tile + A8R8G8B8 and DXT1. **Channel order ✅ confirmed against the running game**: the Delta Saber's decoded atlas is orange-dominant (median saturated hue 23.3°, *zero* cool pixels) and the game renders the same hull at 9.3° — a red↔blue swap would sit at ≈200°. Exact fidelity (gamma/sRGB curve, premultiplied alpha, per-channel scale) is 🟡 untested, since a hue comparison cannot see it; cubemap face ordering ❔ |
| T8aD 2D texture | ✅ | `sylpheed-formats/src/t8ad.rs` | **100 % of the disc decodes** (19 216/19 216, measured). The "~15 % deferred variants" were a wrong model, not a variant: a surface is a list of **arbitrary sub-rectangles**, each with a 16-byte header of `dst X, dst Y, width, height`, not a 256×256 grid — `0x1c` is the **rectangle count**. Uncovered area stays transparent. **Colours ✅ CONFIRMED** ([k8888](structures/texture-color-k8888.md)) |
| RATC bundle | ✅ | `sylpheed-formats/src/ratc.rs` | child listing confirmed. **"One level deep" is not a limitation — there is nothing deeper**: 2 859 bundles hold 18 002 children at depth 1 and **0 at depth 2**, with no parse failures. Nested RATC blobs are **leaf records that reference siblings by name** (`opt `, the sprite name): 3 311 leaves, all embedding sibling names, **10 144 of 10 148 references resolve**. The 4 that do not are one dangling asset — `pmbase.rat``pmbase.t32` in `GP_STAGE_CLEAR.pak`'s four language builds, and `pmbase.t32` is **on the disc nowhere** |

View File

@@ -37,6 +37,28 @@ This mirrors the project method — *measure the oracle, never infer; refute bef
| `PROBABLE` | Strong single-source inference. | One clean observation, or an unambiguous static read of the disassembly. |
| `HYPOTHESIS` | Educated guess, not yet tested. | Anything else. Must say what would confirm/refute it. |
### The status markers
The table above is the *confidence* scale. The markers that appear in
`BACKLOG.md` and the `structures/` pages are a separate, and until now undefined,
vocabulary. They mean:
| Marker | Meaning |
|---|---|
| ✅ | Confirmed — verified against ground truth. |
| 🟡 | Partial: true as far as it goes, or true under a stated assumption. |
| ❔ | Open question. Nobody has answered it yet. |
| 🔴 | **Refuted** — shown false — **or blocked by something the container cannot do.** |
| ❌ | A specific claim that was tried and failed. Prefer 🔴. |
| 🚧 | Work started and not finished. |
**🔴 never means "we have not run it yet."** That is ❔ or 🚧. Reserve 🔴's
"blocked" sense for a real limit of the box — no push credentials, no hardware
Vulkan (lavapipe only), or a decision only the user can make. The box *can* run
the emulator, script input, screenshot, read guest memory, and build and test
Rust, so "needs a run" is never a blocker. This paragraph exists because the
marker was undefined for 98 uses and three of them were mislabelled that way.
**Promotion requires new evidence, not re-reading the old evidence.** A `HYPOTHESIS` that
"looks right again" is still a `HYPOTHESIS`. Only an *independent* check promotes it.
If evidence later contradicts an entry, **demote it and record the contradiction** — do