Merge pull request 'docs(agents): the gate that cannot see a working tree, and the Phase 5/7 checks re-run' (#36) from docs/consolidation-dirty-tree-finding into main
Some checks failed
CI / Native — linux (push) Has been cancelled
CI / WASM — Web (push) Has been cancelled
CI / Formatting (push) Has been cancelled

Reviewed-on: #36
This commit was merged in pull request #36.
This commit is contained in:
2026-09-15 19:46:37 +00:00

View File

@@ -259,6 +259,160 @@ deleting, or step 3 silently ratifies every omission in step 2.
The two `.jsonl` mission-state dumps alone are 4.3 MB, and one is an orphan. The two `.jsonl` mission-state dumps alone are 4.3 MB, and one is an orphan.
## 🔴 A gate that walks `refs/heads` cannot see a working tree
**Found 2026-09-14, on the other machine, while pulling the repos.** `xenia-rs`
had **468 uncommitted lines plus an untracked 338-line `imports.rs`** sitting in
`crates/xenia-analysis` — the very crate Phase 3 lifted. Written 2026-09-10
21:0121:23; found four days later.
It existed in exactly one place, and that place was not git:
| | `imports.rs` | `import_address` | `zq.py impcalls` |
|---|---|---|---|
| PR #32, the lifted crate | ✗ | ✗ | ✗ |
| `iterate-4A` (committed) | ✗ | ✗ | ✗ |
| **xenia-rs working tree** | **✓** | **✓ (4 files)** | **✓** |
**Phase 0 is titled "Secure the single-copy work" and its gate passed anyway**,
because the gate tests branch *reachability* — it iterates `refs/heads`. A dirty
working tree has no ref. Canary's two dirty files were secured only because a
human already knew they were there; nothing *found* them. Phase 1 then pushed
xenia-rs's four branches and called the archive honest while this sat beside them.
Phase 5 ends with *"delete the local clone"* and Phase 7 drops the emulator, so
this had a deletion scheduled against it.
**The gate needs a second half. Before archiving or deleting anything:**
```bash
for d in Sylpheed sylpheed-reborn xenia-rs xenia-canary; do
n=$(git -C "$d" status --porcelain | wc -l)
[ "$n" = 0 ] || echo "🔴 $d has $n uncommitted path(s)"
done
```
Run 2026-09-14 across all four: only `xenia-canary` is dirty, and both entries
(`build-cross/`, `vkd3d-proton.cache`) are already on Phase 7's drop list.
**Secured**`xenia-rs` branch **`harvest/import-thunk-naming`** @ `b4f19f1`,
pushed. Committed exactly as found, not cleaned up: editing it first would have
destroyed the thing being preserved. `cargo check -p xenia-analysis` = **0**.
**Ported****PR (new)** `feat/xexdb-import-naming`, stacked on #32. The
lift's base is exactly the harvest's parent, so every file merged three-way:
**10 conflicts, all of them caused by the lift's reformatting pass** — 9 are the
harvest's additions landing inside blocks rustfmt had rewrapped (so the content
is kept and re-indented to the lift's style), and **1 is genuinely semantic**:
insertion *order*, because `xdbf_achievements.image_id` is now an FK onto
`xdbf_images(id)`, so the image rows must be inserted first. The conflict there
was the stale copy of the block left at its old position. `cargo test -p sylpheed-xexdb` 10/0, clippy and fmt clean.
📌 Two things it carries, both absent from #32 as lifted: import-thunk
recognition (disassembly says `xboxkrnl.exe::RtlEnterCriticalSection` instead of
`.long 0x01010194`), and **16 schema-wide foreign keys** — with `functions`
deliberately excluded and the golden test now *asserting* zero inbound FKs onto
it, since DuckDB's UPDATE is delete+insert and one inbound FK would make
`functions.name` un-updatable and break `apply_re_symbols.sql`.
### Phase 3 residue found while porting
***`tools/zq.py` hardcoded `/home/fabi/…/xenia-rs/sylpheed.db`** — a default
path *inside the repository Phase 5 archives and Phase 7 drops*, resolving on
exactly one machine and days from becoming a `duckdb` exception with nothing
saying why. **Fixed in PR #35 (`38cc170`):** `$SYLPH_XEXDB``<repo
root>/sylpheed.db` → a refusal naming both, with the repo-root path taken
relative to the *script* rather than the caller's cwd. **No fallback beyond
that, deliberately** — the database is an untracked build artefact of a few
hundred MB, so there is nothing to fall back *to*, and a default that silently
resolves to the wrong database is worse than no default. Same shape as #16.
The stale `xenia-rs dis` regeneration hint is now `sylph-xexdb dis`.
* `SCHEMA.md` is still headed *"`xenia-analysis` schema reference"* and cites
`xenia-rs dis --db` — the retired repo and binary. Not fixed.
* Phase 3's "says SQLite, is DuckDB" correction **was** made where it counts
(README and the binary's module doc both say DuckDB), but two inline comments
at `sylph-xexdb.rs:499` and `:874` still say SQLite.
## ▶️ The Phase 5 and Phase 7 checks, re-run 2026-09-14 on the second machine
This page says *"Do not trust this page's ledger when you get there."* So the
checks were re-run rather than read. **No repository was archived and nothing was
deleted** — both are the human's, and both stay open. What follows is only what
the checks now say.
### Phase 5 · containment — and the check the page asks for is wrong for half its list
| repo | disposition | tips | contained in Sylpheed |
|---|---|---|---|
| `Syplheed-Reborn` | absorbed | 21 | **21 ✅** |
| `Sylpheed-Godot` | absorbed | 2 | **2 ✅** |
🔴 **Phase 5 names four repos, but the containment check only means something for
the two that were *absorbed*.** `xenia-rs` and `xex2tractor` were never absorbed —
their disposition is *harvest, then archive*. Run the check literally against
`xenia-rs` and it reports **42 of 42 refs "NOT PRESENT in Sylpheed"**, every line
true and every line unactionable. That is the failure this page already names once,
about Phase 0's first gate: *a check that goes red for something unactionable*.
**For the two harvest repos the invariant is different** — the harvested artefacts
are in Sylpheed, and the repository is *archived, not deleted*:
| artefact | on `main` | on its PR branch |
|---|---|---|
| `docs/reference/xex2-format.md` | ✗ | ✅ #30 |
| `docs/reference/xbox360-exports.json` | ✗ | ✅ #30 |
| `LICENSE` | ✗ | ✅ #30 |
| `crates/sylpheed-xexdb` (32 files) | ✗ | ✅ #32 |
| `tools/zq.py` | ✅ | ✅ |
⚠️ **So the harvest is real but is not on `main` yet.** Archiving is still safe —
the branches are pushed, and archiving is reversible — but **Phase 5 should follow
the harvest PRs, not precede them**, or `main` alone does not carry what was
harvested.
### Phase 5 · nothing lives outside git — re-verified, still true
| | issues | PRs | releases | wiki |
|---|---|---|---|---|
| the four retiring repos | **0** | **0** | **0** | none |
| `Sylpheed` | 36 | 19 | 0 | none |
📌 `has_wiki: true` is the repository *feature flag*, not content —
`/wiki/pages` returns **404 on all six**, i.e. no wiki was ever initialised. Read
the flag as content and you would report six wikis that do not exist.
📌 All six repos are still **`archived: false`, `private: false`**. The retention
question this page leaves open is therefore unchanged and now has a number beside
it: `docs/re/captures/` is ~87 MB of game screenshots in a **public** repository.
### Phase 7 · most of the drop list is not on this machine
The list was measured on the agent box. Here:
| item | page | this machine |
|---|---|---|
| `agent-backups/` | 687 MB | **absent** |
| `xenia-rs/audit-runs/` | 57 MB | **724 KB** |
| local `pi/clippy`, `pi/clippy-clean`, `pi/reauth3` | 3 branches | **0 — not on this box** |
| `texcompare/`, `ship_render/` | 14 MB + 64 KB | **both absent** |
| root `canary_*.log` / `.stdout` / `.stderr` | ~15 MB | 1 file |
| `stock-oracle/` | 34 MB | 34 MB ✅ |
| `Sylpheed/target/` | 32 GB | **34 GB** ✅ |
**Phase 7's one open question is answered.** It asks to *"confirm no `docs/re/`
page cites"* `texcompare/` or `ship_render/` before dropping them. Four citations
of `ship_render` exist — and **all four name the example *program*, not the output
directory**: `cargo run --example ship_render` in `xbg7-mesh.md`, two in
`BACKLOG.md`, and the tracked `examples/ship_render.rs` itself. `texcompare` is
cited nowhere at all. The directories are droppable; the example is tracked code
and stays. (Same directory-vs-file distinction that made Phase 4's "10 dangling
citations" turn out to be one.)
⚠️ **Disk is tighter than this page records: 90 % used, 96 GB free** (the page says
83 %). `Sylpheed/target/` is 34 GB of that and is the only large item here — but it
is a deletion on the human's disk, and rebuilding it is hours, so it stays until
asked for.
## Phase 5 — Verify the invariant, then archive ⬜ **NOT STARTED** ## Phase 5 — Verify the invariant, then archive ⬜ **NOT STARTED**
For each of `Syplheed-Reborn`, `Sylpheed-Godot`, `xenia-rs`, `xex2tractor`: For each of `Syplheed-Reborn`, `Sylpheed-Godot`, `xenia-rs`, `xex2tractor`:
@@ -281,12 +435,23 @@ blocker:
sylpheed-formats = { git = "…/Sylpheed.git", tag = "formats-pin-2026-09-01" } sylpheed-formats = { git = "…/Sylpheed.git", tag = "formats-pin-2026-09-01" }
``` ```
**The build depends on this repo by tag**, pinned in `Cargo.lock` to `#1cd5b8b1`. **The build depends on this repo by tag**, pinned in `Cargo.lock` to `#1cd5b8b1`
A rewrite invalidates all 8 `formats-pin-*` tags, every commit SHA, PR #23's re-checked 2026-09-14, and the pin is exactly right: `formats-pin-2026-09-01`
`1cd5b8b1`, and the in-container build fetches it over the network for real.
A rewrite invalidates every `formats-pin-*` tag, every commit SHA, PR #23's
merge, both agents' clones, and needs a force-push through branch protection. merge, both agents' clones, and needs a force-push through branch protection.
* **Don't rewrite** (recommended): 118 MB on a host with 154 GB free, where 📌 **The tag count is 7, not 8** — server and local agree, and all 7 tags in
`Sylpheed/target` alone is 32 GB. The cost is not worth the blast radius. `Sylpheed` are `formats-pin-*`. The eighth, `formats-pin-2026-08-29` (no letter
suffix), lives in **`Syplheed-Reborn`**, which a Sylpheed rewrite would not
touch and which Phase 5 archives read-only anyway. It does not change the
decision; it is one fewer thing to re-cut.
* **Don't rewrite** (recommended): 118 MB — and the disk argument has moved.
The host is now at **90 %, 96 GB free** (this page said 83 % / 154 GB), and
`Sylpheed/target` alone is **34 GB**. Reclaiming 118 MB by rewriting history,
while 34 GB of rebuildable build output sits beside it, is still the wrong
lever.
* **Do rewrite:** then it happens **here, in Phase 5** — while tags are being * **Do rewrite:** then it happens **here, in Phase 5** — while tags are being
re-cut and agents re-cloned anyway, so the disruption is paid once instead of re-cut and agents re-cloned anyway, so the disruption is paid once instead of
twice. Re-point the `formats-pin` dependency **first**. twice. Re-point the `formats-pin` dependency **first**.
@@ -335,6 +500,7 @@ been merged** — merging is the human's, and #32 contains #30 and #31.
|---|---|---| |---|---|---|
| **0** secure single-copy work | ✅ done | Canary `8e63a9542`, `sylpheed-re` + `audit-handle-lifecycle-probes` pushed | | **0** secure single-copy work | ✅ done | Canary `8e63a9542`, `sylpheed-re` + `audit-handle-lifecycle-probes` pushed |
| **1** make the archive honest | ✅ done | xenia-rs `iterate-4B/4C/4D/4E` pushed (32/52/56/59 commits) | | **1** make the archive honest | ✅ done | xenia-rs `iterate-4B/4C/4D/4E` pushed (32/52/56/59 commits) |
| **0b** the dirt the gate could not see | ✅ done 2026-09-14 | xenia-rs `harvest/import-thunk-naming` `b4f19f1`, ported in `feat/xexdb-import-naming` |
| **2** harvest xex2tractor | ✅ done | **PR #30** `harvest/xex2tractor-assets` | | **2** harvest xex2tractor | ✅ done | **PR #30** `harvest/xex2tractor-assets` |
| **3** lift the DB tool | ✅ done | **PR #32** `feat/xexdb-tool` | | **3** lift the DB tool | ✅ done | **PR #32** `feat/xexdb-tool` |
| **4** captures + the missing check | ✅ done | **PR #33** `fix/capture-citations` | | **4** captures + the missing check | ✅ done | **PR #33** `fix/capture-citations` |
@@ -343,7 +509,7 @@ been merged** — merging is the human's, and #32 contains #30 and #31.
| **5** archive the four repos | ⬜ **open — needs the human** | | | **5** archive the four repos | ⬜ **open — needs the human** | |
| **7** intended drops | ⬜ **open — partly needs the human** | | | **7** intended drops | ⬜ **open — partly needs the human** | |
## 🔴 Four claims on this page were wrong. Read these before trusting the rest. ## 🔴 Five claims on this page were wrong. Read these before trusting the rest.
1. **"10 dangling citations" was ONE.** Eight were *directory* references, which 1. **"10 dangling citations" was ONE.** Eight were *directory* references, which
resolve and are simply absent from `git ls-tree`; one was a path at the end of resolve and are simply absent from `git ls-tree`; one was a path at the end of
@@ -354,6 +520,9 @@ been merged** — merging is the human's, and #32 contains #30 and #31.
3. **The Phase 0 gate compared branches by SHA** and called seven safe branches 3. **The Phase 0 gate compared branches by SHA** and called seven safe branches
unpushed. It tests reachability now. unpushed. It tests reachability now.
4. **There is no DXC submodule drift.** The ` m` is *nested* submodule dirt. 4. **There is no DXC submodule drift.** The ` m` is *nested* submodule dirt.
5. **Phase 0 did not secure all the single-copy work**, and its gate could not
have: it walks `refs/heads`, and 468 uncommitted lines in `xenia-rs` have no
ref. Secured 2026-09-14 — see the section above Phase 5.
## What the other machine should do next ## What the other machine should do next
@@ -370,14 +539,33 @@ been merged** — merging is the human's, and #32 contains #30 and #31.
⚠️ **#32 is stacked.** Merge #30 and #31 first, or merge #32 and close them — ⚠️ **#32 is stacked.** Merge #30 and #31 first, or merge #32 and close them —
its `build.rs` needs #30's export table, so they cannot be independent. its `build.rs` needs #30's export table, so they cannot be independent.
**One result outstanding:** the workspace `cargo test` count for #32. `check`, **The workspace `cargo test` count for #32 — reported 2026-09-15** (also posted
`clippy`, `fmt` and `wasm` are all 0; the test leg was interrupted twice by on #32). `sylph-ci:local`, rustc 1.98.1 byte-identical to the runner, head `6048829`:
branch switches and never reported cleanly. Run it and post the number:
| | disc | suites | passed | failed | ignored |
|---|---|---|---|---|---|
| `docker/ci/run cargo test --workspace --no-fail-fast` | PRESENT | 45 | **367** | **1** | 14 |
| + #35, disc not mounted (as the runner) | ABSENT | 45 | 377 | 0 | 14 |
The +9 is exactly #35's nine `imports.rs` unit tests. 🔴 **The one failure is `main`'s,
not #32's**: `ui_prm_primitives_disc` has failed since #23 (bisected; see #32's
description). It took three failures to get a number, and each one is now a rule:
```bash ```bash
docker/ci/run cargo test --workspace SYLPH_CI_MEM_GB=14 docker/ci/run cargo test --workspace --no-fail-fast
``` ```
* **`--no-fail-fast`** — without it the run stops at the first failing binary. An
earlier attempt reported "25 suites / 201 passed", which was half the workspace.
* **`SYLPH_CI_MEM_GB`** sized to the host — the default 7 is half of the *agent box*.
On this 31 GB machine, with the disc mounted, `slb_leading_segment_disc` is
SIGKILLed: six threads each load a voice bank. Serial passes 10/10 under the
same 7 GB, so it is concurrency, not one allocation.
* **~36 GB of disk** for a cold `sylph-ci-target` volume. It took this host from
90 % to 95 %; it has been deleted since. And a desktop package update that
upgrades `containerd.io` restarts `dockerd`, killing an in-flight run *and every
other container on the host* — which is what ended the second attempt.
### Phase 5 — archive, and the history fork ### Phase 5 — archive, and the history fork
**Do not trust this page's ledger when you get there.** Re-run the containment **Do not trust this page's ledger when you get there.** Re-run the containment