Compare commits
12 Commits
fix/export
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bfe590c6bc | |||
|
|
7907c8d286 | ||
| c03e5c9bd0 | |||
|
|
43f0a905a0 | ||
| f732b5ac1a | |||
|
|
1fdbb5f197 | ||
| 9414830ed7 | |||
| 884a2c3944 | |||
| 8108958a77 | |||
| b9d009b7a2 | |||
| b0906f3ed6 | |||
| 46ee0d7f78 |
@@ -10,11 +10,22 @@
|
|||||||
# AVAILABLE MEMORY as well as core count — a full-parallel build of this tree
|
# AVAILABLE MEMORY as well as core count — a full-parallel build of this tree
|
||||||
# has OOM-killed the host outright.
|
# has OOM-killed the host outright.
|
||||||
#
|
#
|
||||||
# build-canary [Release|Debug] [extra cmake --build args]
|
# `Checked` is the default, and should stay it: it is what the host builds and
|
||||||
|
# what `run-canary` picks first, so the two agree by construction. Building
|
||||||
|
# `Release` here instead leaves a second binary that `run-canary` will not use
|
||||||
|
# -- hours of CPU for something nothing runs. `Checked` is optimised, with
|
||||||
|
# assertions left in.
|
||||||
|
#
|
||||||
|
# build-canary [Checked|Release|Debug] [extra cmake --build args]
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
CONFIG="${1:-Release}"; shift || true
|
CONFIG="${1:-Checked}"; shift || true
|
||||||
SRC="${PROJECT_DIR:-/work}/xenia-canary"
|
# $XENIA_SRC FIRST. In this container the Canary source is bind-mounted at
|
||||||
|
# `/canary`, and `$PROJECT_DIR/xenia-canary` does not exist -- so the old default
|
||||||
|
# made this script unusable here, and the documented workaround was to symlink
|
||||||
|
# `/canary` into the repository and remember to delete it again (CONTAINER-NOTES
|
||||||
|
# §"The toolchain is real"). The launcher already exports the right path; read it.
|
||||||
|
SRC="${XENIA_SRC:-${PROJECT_DIR:-/work}/xenia-canary}"
|
||||||
BUILD="${XENIA_BUILD_DIR:-/sylph-home/re/canary-build}"
|
BUILD="${XENIA_BUILD_DIR:-/sylph-home/re/canary-build}"
|
||||||
JOBS="${SYLPH_JOBS:-2}"
|
JOBS="${SYLPH_JOBS:-2}"
|
||||||
|
|
||||||
|
|||||||
@@ -48,15 +48,26 @@ fi
|
|||||||
PROJECT_DIR="${PROJECT_DIR:-/work}"
|
PROJECT_DIR="${PROJECT_DIR:-/work}"
|
||||||
|
|
||||||
# ── Binary ───────────────────────────────────────────────────────────────────
|
# ── Binary ───────────────────────────────────────────────────────────────────
|
||||||
|
# `Checked` FIRST. All three configurations can be built, but `Checked` is the
|
||||||
|
# one this project actually builds, so it is the one carrying our
|
||||||
|
# instrumentation; the `Release/` and `Debug/` binaries beside it are months-old
|
||||||
|
# leftovers that still run and still boot the game, which is exactly what makes
|
||||||
|
# them dangerous -- a probe run against one reports zero hits and reads as a
|
||||||
|
# finding about the game. Measured on this box 2026-09-21: `Checked` has
|
||||||
|
# `audit_61_branch_probe_pcs`, `Release` (Aug 28) and `Debug` (Jul 19) do not.
|
||||||
pick_bin() {
|
pick_bin() {
|
||||||
[ -n "${XENIA_BIN:-}" ] && { echo "$XENIA_BIN"; return; }
|
[ -n "${XENIA_BIN:-}" ] && { echo "$XENIA_BIN"; return; }
|
||||||
|
# Configuration is the OUTER loop, location the inner one: a `Checked` build
|
||||||
|
# anywhere beats a `Release` build anywhere. The other order picks a stale
|
||||||
|
# container `Release` over a fresh instrumented repo `Checked`, which is the
|
||||||
|
# exact mistake this is here to stop.
|
||||||
|
for cfg in Checked Release Debug; do
|
||||||
for c in \
|
for c in \
|
||||||
"${XENIA_BUILD_DIR:-/sylph-home/re/canary-build}/bin/Linux/Release/xenia_canary" \
|
"${XENIA_BUILD_DIR:-/sylph-home/re/canary-build}/bin/Linux/$cfg/xenia_canary" \
|
||||||
"${XENIA_BUILD_DIR:-/sylph-home/re/canary-build}/bin/Linux/Debug/xenia_canary" \
|
"$PROJECT_DIR/xenia-canary/build/bin/Linux/$cfg/xenia_canary"; do
|
||||||
"$PROJECT_DIR/xenia-canary/build/bin/Linux/Release/xenia_canary" \
|
|
||||||
"$PROJECT_DIR/xenia-canary/build/bin/Linux/Debug/xenia_canary"; do
|
|
||||||
[ -x "$c" ] && { echo "$c"; return; }
|
[ -x "$c" ] && { echo "$c"; return; }
|
||||||
done
|
done
|
||||||
|
done
|
||||||
}
|
}
|
||||||
BIN="$(pick_bin)"
|
BIN="$(pick_bin)"
|
||||||
if [ -z "${BIN:-}" ]; then
|
if [ -z "${BIN:-}" ]; then
|
||||||
@@ -64,6 +75,13 @@ if [ -z "${BIN:-}" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Say what is in the binary before the run, not after reading an empty log.
|
||||||
|
# A missing probe is a build that predates it, never a quiet game.
|
||||||
|
for sym in audit_61_branch_probe_pcs RE-DRAW; do
|
||||||
|
grep -aqm1 -- "$sym" "$BIN" \
|
||||||
|
|| echo "run-canary: ⚠ $BIN has NO '$sym' -- it predates that instrumentation. Rebuild with: build-canary" >&2
|
||||||
|
done
|
||||||
|
|
||||||
# ── ISO ──────────────────────────────────────────────────────────────────────
|
# ── ISO ──────────────────────────────────────────────────────────────────────
|
||||||
ISO="${SYLPH_ISO:-}"
|
ISO="${SYLPH_ISO:-}"
|
||||||
if [ -z "$ISO" ]; then
|
if [ -z "$ISO" ]; then
|
||||||
|
|||||||
@@ -122,11 +122,28 @@ docker_args() {
|
|||||||
# (file offset = VA - 0x82000000), which removes the need to boot the
|
# (file offset = VA - 0x82000000), which removes the need to boot the
|
||||||
# emulator and scrape /dev/shm to get at it. An earlier belief that this
|
# emulator and scrape /dev/shm to get at it. An earlier belief that this
|
||||||
# file was STALE was tested and refuted -- it is current.
|
# file was STALE was tested and refuted -- it is current.
|
||||||
-v "${SYLPH_XENIA_RS:-$PROJECT/xenia-rs}:/xenia-rs:ro"
|
|
||||||
-v "${SYLPH_PE:-$PROJECT/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).pe}:/image/sylpheed.pe:ro"
|
-v "${SYLPH_PE:-$PROJECT/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).pe}:/image/sylpheed.pe:ro"
|
||||||
-e "SYLPHEED_DB=/xenia-rs/sylpheed.db"
|
# 🔴 THE DISASSEMBLY DATABASE. This used to be read from the xenia-rs clone
|
||||||
|
# (`SYLPHEED_DB=/xenia-rs/sylpheed.db`). That repo is retired, its directory
|
||||||
|
# is gone, and the mount that served it was removed -- so the variable named
|
||||||
|
# a path that did not exist and `zq.py` had nothing to open. The database now
|
||||||
|
# lives beside the repo as a build artefact; mounted at the container's repo
|
||||||
|
# root, which is where `zq.py` looks when `$SYLPHEED_DB` is unset.
|
||||||
|
#
|
||||||
|
# Read-only on purpose: the host owns it, DuckDB takes an exclusive lock to
|
||||||
|
# write, and two agents plus the human sharing one file would corrupt it.
|
||||||
|
# Regenerating means writing elsewhere and pointing `$SYLPHEED_DB` at it.
|
||||||
-e "SYLPHEED_PE=/image/sylpheed.pe"
|
-e "SYLPHEED_PE=/image/sylpheed.pe"
|
||||||
-e "SYLPHEED_IMAGE_BASE=0x82000000"
|
-e "SYLPHEED_IMAGE_BASE=0x82000000"
|
||||||
|
# 🔴 EVIDENCE IS SHARED, NOT COMMITTED (issue #49). Each agent works in its
|
||||||
|
# OWN clone, so a gitignored capture written in one container is invisible to
|
||||||
|
# the other and to the human -- git used to be the transport and no longer is.
|
||||||
|
# One host directory, bind-mounted into both agents, is: all three see the
|
||||||
|
# same files live, every `docs/re/captures/...` citation resolves everywhere,
|
||||||
|
# and nothing can reach git history. Read-write on purpose -- showing each
|
||||||
|
# other a screenshot is the point.
|
||||||
|
-v "${SYLPH_CAPTURES:-$PROJECT/Sylpheed/docs/re/captures}:/work/docs/re/captures"
|
||||||
|
|
||||||
# The shared exchange: transient files with provenance, outside git history.
|
# The shared exchange: transient files with provenance, outside git history.
|
||||||
-v "sylpheed-exchange:/exchange"
|
-v "sylpheed-exchange:/exchange"
|
||||||
-e "PROJECT_DIR=/work"
|
-e "PROJECT_DIR=/work"
|
||||||
@@ -268,6 +285,20 @@ docker_args() {
|
|||||||
echo "==> NOTE: no ISO at $_iso -- Canary has nothing to boot." >&2
|
echo "==> NOTE: no ISO at $_iso -- Canary has nothing to boot." >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# The disassembly database. `zq.py` looks at the repo root when $SYLPHEED_DB
|
||||||
|
# is unset, so mounting it there needs no environment variable at all -- which
|
||||||
|
# is what the dead `/xenia-rs/sylpheed.db` variable taught: a path in an env
|
||||||
|
# var and a path in a mount drift apart silently.
|
||||||
|
_db="${SYLPH_DB:-$PROJECT/Sylpheed/sylpheed.db}"
|
||||||
|
if [ -f "$_db" ]; then
|
||||||
|
_out+=(-v "$_db:/work/sylpheed.db:ro")
|
||||||
|
else
|
||||||
|
echo "==> NOTE: no sylpheed.db at $_db -- /sylph-dis and zq.py cannot run." >&2
|
||||||
|
echo " build one: cargo run --release -p sylpheed-xexdb --bin sylph-xexdb -- \\" >&2
|
||||||
|
echo " dis \"\$SYLPH_ISO\" --db sylpheed.db --analyze sql --quiet" >&2
|
||||||
|
echo " then re-apply the RE names with tools/apply_re_symbols.sql" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
# ── GPU ──
|
# ── GPU ──
|
||||||
# Three distinct cases, and conflating them is how you end up believing you
|
# Three distinct cases, and conflating them is how you end up believing you
|
||||||
# have hardware Vulkan while actually running llvmpipe:
|
# have hardware Vulkan while actually running llvmpipe:
|
||||||
|
|||||||
@@ -67,6 +67,14 @@ docker_args() {
|
|||||||
-v "sylpheed-port-claude:/sylph-home/port/.claude"
|
-v "sylpheed-port-claude:/sylph-home/port/.claude"
|
||||||
-v "${SYLPH_CLAUDE_HOME:-$HOME/.claude}:/sylph-home/port/.claude.seed:ro"
|
-v "${SYLPH_CLAUDE_HOME:-$HOME/.claude}:/sylph-home/port/.claude.seed:ro"
|
||||||
-v "${SYLPH_CLAUDE_JSON:-$HOME/.claude.json}:/sylph-home/port/.claude.host.json:ro"
|
-v "${SYLPH_CLAUDE_JSON:-$HOME/.claude.json}:/sylph-home/port/.claude.host.json:ro"
|
||||||
|
# 🔴 EVIDENCE IS SHARED, NOT COMMITTED (issue #49). Each agent works in its
|
||||||
|
# OWN clone, so a gitignored capture written in one container is invisible to
|
||||||
|
# the other and to the human -- git used to be the transport and no longer is.
|
||||||
|
# One host directory, bind-mounted into both agents, is: all three see the
|
||||||
|
# same files live, every `docs/re/captures/...` citation resolves everywhere,
|
||||||
|
# and nothing can reach git history. Read-write on purpose -- showing each
|
||||||
|
# other a screenshot is the point.
|
||||||
|
-v "${SYLPH_CAPTURES:-$WORKSPACE/Sylpheed/docs/re/captures}:/work/docs/re/captures"
|
||||||
-v "sylpheed-exchange:/exchange"
|
-v "sylpheed-exchange:/exchange"
|
||||||
-e "PROJECT_DIR=/work"
|
-e "PROJECT_DIR=/work"
|
||||||
# Same guardrail as the decoder, added the same day and for its reason: the
|
# Same guardrail as the decoder, added the same day and for its reason: the
|
||||||
|
|||||||
@@ -1,3 +1,27 @@
|
|||||||
|
# ✅ CLOSED 2026-09-20 — every phase done, and the two human decisions taken
|
||||||
|
|
||||||
|
Nothing on this page is outstanding. It is kept as the record of how the two-repo
|
||||||
|
layout was reached; **where it describes the repository's present state it is
|
||||||
|
now out of date on purpose**, and the notes below say how.
|
||||||
|
|
||||||
|
| the page says | what is true now |
|
||||||
|
|---|---|
|
||||||
|
| "**Still open, for the human**: the history fork" | **Taken: full purge.** `git filter-repo` stripped 182 assets from every commit; force-pushed 2026-09-19. `main` `2a93be99` → `e16556dc`, `.git` **217 MB → 114 MB**, **0** assets anywhere in history, verified from an independent fresh clone. Backups + runbook: `~/sylph-repo-backup-2026-09-19/` |
|
||||||
|
| "`docs/re/captures/` is 118 MB of game screenshots inside a public repository" | **Decided (#49): no game assets in the repos.** Captures live on disk, gitignored, shared between the host and both agents by bind mount; derived measurements (csv/tsv/txt/log/json/npy) stay tracked. PR #59 |
|
||||||
|
| "all six repos are `private=False`" | Still true, and now deliberate — there is nothing game-derived in them |
|
||||||
|
| "`ai-agent-*.md`, `scratch/`, `_voice_span.rs` — keep or drop" | `scratch/` and `_voice_span.rs` dropped in the 2026-09-18 cleanup; the `ai-agent-*.md` files are the human's and stay |
|
||||||
|
| the four archived repos | unchanged: `Sylpheed-Godot`, `xenia-rs`, `xex2tractor` archived read-only, `Syplheed-Reborn` deleted. ⚠️ Their local clones are **gone from this machine** too, and `sylph-decoder` no longer mounts `xenia-rs` |
|
||||||
|
|
||||||
|
🔴 **The one thing this page got right and nobody acted on.** It named
|
||||||
|
`crates/sylpheed-export`'s dependency on **this repository by tag** as the hard
|
||||||
|
blocker for a rewrite. It was not re-checked before the purge, the locked rev
|
||||||
|
vanished, and the build broke for every clean checkout while still working on the
|
||||||
|
machine that did the rewrite — its `~/.cargo/git` still held the old object.
|
||||||
|
Fixed in PR #60 (re-lock) and PR #61 (path dependency, which removes the class).
|
||||||
|
**Before any future history rewrite, grep for a dependency on the repo's own URL.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Consolidating six repositories into two
|
# Consolidating six repositories into two
|
||||||
|
|
||||||
**Set by the human, 2026-09-13.** The end state is **two** repositories:
|
**Set by the human, 2026-09-13.** The end state is **two** repositories:
|
||||||
|
|||||||
@@ -12,13 +12,20 @@ already went wrong once.
|
|||||||
* **The toolchain is real.** `tools/re-capture/rebuild_canary.sh` exists because
|
* **The toolchain is real.** `tools/re-capture/rebuild_canary.sh` exists because
|
||||||
the old box had no cmake/ninja/clang and only runtime sonames, so it hand-
|
the old box had no cmake/ninja/clang and only runtime sonames, so it hand-
|
||||||
relinked object files. **Do not use it here.** Use `build-canary`.
|
relinked object files. **Do not use it here.** Use `build-canary`.
|
||||||
🔴 **But `build-canary` does not work in this container as it stands
|
✅ **FIXED 2026-09-21 — `build-canary` now reads `$XENIA_SRC` first**, which the
|
||||||
|
launcher already sets to `/canary`, so there is no symlink to make and none to
|
||||||
|
forget. The two paragraphs below are kept because they are how the defect was
|
||||||
|
found and refuted, but **neither describes the script any more.**
|
||||||
|
|
||||||
|
🔴 ~~**`build-canary` does not work in this container as it stands
|
||||||
(2026-08-29).** It builds `${PROJECT_DIR:-/work}/xenia-canary`, which **does
|
(2026-08-29).** It builds `${PROJECT_DIR:-/work}/xenia-canary`, which **does
|
||||||
not exist here** — the Canary source is at **`/canary`** (`$XENIA_SRC`). The
|
not exist here** — the Canary source is at **`/canary`** (`$XENIA_SRC`). The
|
||||||
warm 235 MB tree at `/sylph-home/re/canary-build` is configured with
|
warm 235 MB tree at `/sylph-home/re/canary-build` is configured with
|
||||||
`CMAKE_HOME_DIRECTORY=/work/xenia-canary`, also missing, and its
|
`CMAKE_HOME_DIRECTORY=/work/xenia-canary`, also missing, and its
|
||||||
`build-Release.ninja` carries **no per-file rules** — it wants to re-run CMake
|
`build-Release.ninja` carries **no per-file rules** — it wants to re-run CMake
|
||||||
first, which would fail on the absent source root.
|
first, which would fail on the absent source root.~~ The warm tree is gone too:
|
||||||
|
every `sylph-*` volume was removed in the 2026-09-18 cleanup, so the next build
|
||||||
|
configures from scratch against `/canary` and caches the right source root.
|
||||||
|
|
||||||
✅ **The conclusion drawn from all that is REFUTED (2026-08-31).** The note went
|
✅ **The conclusion drawn from all that is REFUTED (2026-08-31).** The note went
|
||||||
on to say *"any Canary change is a full reconfigure against `/canary` plus a full
|
on to say *"any Canary change is a full reconfigure against `/canary` plus a full
|
||||||
@@ -38,9 +45,10 @@ already went wrong once.
|
|||||||
warm 235 MB tree is otherwise intact and the ninja re-run resolves its rules
|
warm 235 MB tree is otherwise intact and the ninja re-run resolves its rules
|
||||||
from the symlink.
|
from the symlink.
|
||||||
|
|
||||||
⚠️ **Remove the symlink when you are done.** `/work` is the repository, and
|
⚠️ ~~**Remove the symlink when you are done.**~~ No longer needed — but if you
|
||||||
`xenia-canary` is not in `.gitignore`, so it shows up as untracked and can be
|
ever make one by hand, note that `/work` is the repository and `xenia-canary`
|
||||||
swept into a `git add -A`.
|
is not in `.gitignore`, so it shows up as untracked and can be swept into a
|
||||||
|
`git add -A`.
|
||||||
* **numpy and Pillow are installed.** `entities2.py`, `flight_probe.py` and the
|
* **numpy and Pillow are installed.** `entities2.py`, `flight_probe.py` and the
|
||||||
image oracles work. Their absence used to look like a logic bug.
|
image oracles work. Their absence used to look like a logic bug.
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,42 @@ sylph-agent-canary-build the warm 235 MB Canary build tr
|
|||||||
sylpheed-exchange agent -> agent files, read-only in
|
sylpheed-exchange agent -> agent files, read-only in
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Plus one bind mount, which is not a volume on purpose** — the host's
|
||||||
|
`Sylpheed/docs/re/captures/`, mounted read-write into both agents at
|
||||||
|
`/work/docs/re/captures`:
|
||||||
|
|
||||||
|
```
|
||||||
|
-v "${SYLPH_CAPTURES:-<workspace>/Sylpheed/docs/re/captures}:/work/docs/re/captures"
|
||||||
|
```
|
||||||
|
|
||||||
|
🔴 **Why it has to exist.** Each agent works in its OWN clone, so before issue
|
||||||
|
#49 the transport for evidence was *git*: commit the screenshot, the other agent
|
||||||
|
pulls it. #49 removed that — captures are gitignored now — and without a
|
||||||
|
replacement a capture written in one container is invisible to the other agent,
|
||||||
|
to the human, and to `check-capture-citations`, which would call every citation
|
||||||
|
dangling. One host directory shared by all three restores it: the same file is
|
||||||
|
live everywhere, every `docs/re/captures/...` citation resolves, and nothing can
|
||||||
|
reach git history. Read-write on both, because showing each other a screenshot
|
||||||
|
is the point.
|
||||||
|
|
||||||
|
Verified rather than assumed: container A wrote a `.png` there, a **separate**
|
||||||
|
container B read it back, the host saw it, and `git status` reported **0**
|
||||||
|
changes.
|
||||||
|
|
||||||
|
⚠️ **Evidence that must cross MACHINES still cannot go this way** — a bare clone
|
||||||
|
on the other desktop has no captures at all. Attach it to the issue or PR; that
|
||||||
|
is the only channel that travels.
|
||||||
|
|
||||||
|
⚠️ **The agent volumes were all deleted in the 2026-09-18 cleanup** and Docker
|
||||||
|
recreates them empty on next launch. Nothing was lost — both agent clones were
|
||||||
|
verified clean with nothing unpushed, and the exchange held only spent artefacts.
|
||||||
|
One side effect is welcome: the empty `*-claude` volumes mean the next launch
|
||||||
|
starts a **fresh** session, which is the documented workaround for the
|
||||||
|
"resumes the old brief" defect below.
|
||||||
|
|
||||||
|
⚠️ **`sylph-decoder` used to mount `xenia-rs` read-only. That repo is retired and
|
||||||
|
the directory is gone**, so the mount pointed at nothing; removed.
|
||||||
|
|
||||||
**Credentials** — three files on the host, `chmod 600`, mounted read-only:
|
**Credentials** — three files on the host, `chmod 600`, mounted read-only:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -129,10 +129,18 @@ exchange volume carries the working artefacts.
|
|||||||
| kind | where | why |
|
| kind | where | why |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| code, decoded knowledge | **git** | history, review, permanence |
|
| code, decoded knowledge | **git** | history, review, permanence |
|
||||||
| evidence cited by a finding | **git** | it is the proof |
|
| evidence cited by a finding — a screenshot, a frame, a savegame | **`docs/re/captures/`, present but NEVER committed** | it is the proof, but it is game content. The directory is gitignored and shared between the host and both agents, so all three see the same file; `tools/re/check-capture-citations` fails if a citation has no file, and fails again if an asset is tracked |
|
||||||
|
| a measurement you derived — csv, tsv, txt, log, json | **git** | our own numbers, not game content, and most findings rest on them |
|
||||||
|
| evidence that must cross machines | **attached to the issue or PR** | captures are local-only now, so a bare clone has none of them. Attaching is the only channel that reaches the other desktop or a reviewer |
|
||||||
| **evidence a human must look at** — the screenshot or film behind a `state/needs-human` item | **attached to that issue** | it travels *with* the item, a person sees it in a browser, and it cannot be orphaned from the claim it supports |
|
| **evidence a human must look at** — the screenshot or film behind a `state/needs-human` item | **attached to that issue** | it travels *with* the item, a person sees it in a browser, and it cannot be orphaned from the claim it supports |
|
||||||
| exploratory captures, work in progress, "look at this" | **`share`** → `/exchange` | no history; would bloat the repo forever |
|
| exploratory captures, work in progress, "look at this" | **`share`** → `/exchange` | no history; would bloat the repo forever |
|
||||||
|
|
||||||
|
⚠️ **This table's first row used to say "git", and that is how 76 MB of
|
||||||
|
screenshots accumulated** — directly above the rule forbidding exactly that. The
|
||||||
|
two contradicted each other for months and the table won, because it was the one
|
||||||
|
that told you what to *do*. Issue #49 settled it and the history was rewritten;
|
||||||
|
if you find yourself reaching for `git add -f` on a capture, the answer is no.
|
||||||
|
|
||||||
🔴 **Never commit game content.** Not sprites, not audio, not transcoded video,
|
🔴 **Never commit game content.** Not sprites, not audio, not transcoded video,
|
||||||
not a capture of the running game — under *any* directory name. On 2026-09-04
|
not a capture of the running game — under *any* directory name. On 2026-09-04
|
||||||
this rule was live, and freshly tightened, while **545 MB of extracted disc
|
this rule was live, and freshly tightened, while **545 MB of extracted disc
|
||||||
|
|||||||
@@ -56,11 +56,28 @@ rather than left in a document you might not reach.
|
|||||||
| path | what | env |
|
| path | what | env |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `/image/sylpheed.pe` | the decompressed executable image | `SYLPHEED_PE` |
|
| `/image/sylpheed.pe` | the decompressed executable image | `SYLPHEED_PE` |
|
||||||
| `/xenia-rs/sylpheed.db` | a disassembly database, 586 MB | `SYLPHEED_DB` |
|
| `sylpheed.db` at the repo root | the disassembly database, 337 MB | — (`zq.py` finds it; `$SYLPHEED_DB` only to override) |
|
||||||
|
| `/canary/build/bin/Linux/Checked/xenia_canary` | the built oracle, inside the `/canary` mount | — |
|
||||||
| `/disc` | the extracted disc | `SYLPHEED_DISC` |
|
| `/disc` | the extracted disc | `SYLPHEED_DISC` |
|
||||||
| `/iso/game.iso` | the retail ISO Canary boots | `SYLPH_ISO` |
|
| `/iso/game.iso` | the retail ISO Canary boots | `SYLPH_ISO` |
|
||||||
| `/canary` | the Canary source, read-write | `XENIA_SRC` |
|
| `/canary` | the Canary source, read-write | `XENIA_SRC` |
|
||||||
|
|
||||||
|
⚠️ **The database is read-only and is NOT in git** — it is a build artefact, and
|
||||||
|
`docs/re/captures/` is the same (issue #49). If either is missing the launcher
|
||||||
|
says so and prints the command that builds it. Query the database with
|
||||||
|
`python3 tools/zq.py …`, never by reading a disassembly dump.
|
||||||
|
|
||||||
|
⚠️ **Take the oracle from `Checked/`, not `Release/`.** `Checked` is what this
|
||||||
|
tree actually builds (optimised, with assertions); the `Release/` binary beside
|
||||||
|
it is a stale August build with no `audit_61` probe in it. `strings` on the two
|
||||||
|
is how that was found, and is how to check any binary before quoting a run from
|
||||||
|
it.
|
||||||
|
|
||||||
|
The `Checked` build carries all three instrumentations — `RE-INPUT`, `RE-DRAW`
|
||||||
|
and the `audit_61` guest-PC branch probe (fork PR #2 brought the probe onto
|
||||||
|
`sylpheed-re`; before it, the probe lived only on `phase-a-tracing`). Verified
|
||||||
|
by `strings` on the binary, not assumed.
|
||||||
|
|
||||||
**The `.pe` is a flat VA dump**: file offset = `VA - 0x82000000`. Reading
|
**The `.pe` is a flat VA dump**: file offset = `VA - 0x82000000`. Reading
|
||||||
`0x820A1630` is `seek(0xA1630)`. No XEX decrypt, no LZX, **no booted emulator** —
|
`0x820A1630` is `seek(0xA1630)`. No XEX decrypt, no LZX, **no booted emulator** —
|
||||||
dumping guest memory works but makes the whole static corpus depend on a running
|
dumping guest memory works but makes the whole static corpus depend on a running
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ The instrumented branch stops at the Stage 02 briefing under a storm of
|
|||||||
behind `upstream/canary_experimental` (`a5a18f5c7`); our branch carries 50 of its
|
behind `upstream/canary_experimental` (`a5a18f5c7`); our branch carries 50 of its
|
||||||
own.
|
own.
|
||||||
|
|
||||||
* **`version.h` is never generated.** The build fails on
|
* ~~**`version.h` is never generated.**~~ ✅ **FIXED — `CMakeLists.txt` now
|
||||||
`trace_writer.cc:17: fatal error: 'version.h' file not found`. Upstream's
|
generates it at configure time**, calling `xenia-build.py`'s
|
||||||
`xenia-build.py` writes it from git HEAD; the container's `build-canary`
|
`generate_version_h()` and falling back to a stub if that fails, so a
|
||||||
wrapper does not invoke it, and our tree only builds because a stale copy from
|
CMake-direct build no longer depends on a stale copy in the build directory.
|
||||||
an old `sylpheed-re` build sits in the build directory. Regenerated by hand in
|
It used to fail on `trace_writer.cc:17: fatal error: 'version.h' file not
|
||||||
exactly the format that script emits.
|
found`, and the fix had to exist before the 2026-09-18 cleanup deleted the
|
||||||
|
build volume that was carrying that stale copy.
|
||||||
* **`build-canary` reports success on a failed build.** The harness recorded
|
* **`build-canary` reports success on a failed build.** The harness recorded
|
||||||
"completed (exit code 0)" while ninja had stopped with `1 error generated`.
|
"completed (exit code 0)" while ninja had stopped with `1 error generated`.
|
||||||
Only the missing binary gave it away.
|
Only the missing binary gave it away.
|
||||||
|
|||||||
@@ -36,7 +36,60 @@ CITE = re.compile(
|
|||||||
r"`?((?:docs|crates|port|tools|authored|export)/[\w./-]+"
|
r"`?((?:docs|crates|port|tools|authored|export)/[\w./-]+"
|
||||||
r"\.(?:md|rs|gd|json|txt|py|tsv|csv))`?"
|
r"\.(?:md|rs|gd|json|txt|py|tsv|csv))`?"
|
||||||
)
|
)
|
||||||
PEER_REFS = ("origin/auto/frame-blend-draw-path", "origin/main")
|
# ⚠️ `origin/auto/frame-blend-draw-path` used to head this list and NO LONGER
|
||||||
|
# EXISTS -- the consolidation merged it and the branch was removed. The class is
|
||||||
|
# kept because it is about the workflow, not about that one branch: the next
|
||||||
|
# topic branch that lands a finding recreates the condition exactly. What must
|
||||||
|
# not happen again is the selftest asserting the class against a fixture path
|
||||||
|
# that has since become an ordinary local file, which is how it came to print
|
||||||
|
# 🔴 BROKEN on a correct checkout. It now finds its own fixture, or says the
|
||||||
|
# condition does not exist here.
|
||||||
|
PEER_REFS = ("origin/main",)
|
||||||
|
|
||||||
|
|
||||||
|
def a_peer_only_path() -> str | None:
|
||||||
|
"""A path carried by a PEER_REF but absent from this working tree.
|
||||||
|
|
||||||
|
The selftest needs a REAL one: a hardcoded fixture silently stops testing
|
||||||
|
the moment that file lands locally, and then reports the scanner broken
|
||||||
|
instead of itself. On a clean, up-to-date checkout there is usually no such
|
||||||
|
path at all -- which is not a failure, it is the class being empty here.
|
||||||
|
"""
|
||||||
|
for ref in PEER_REFS:
|
||||||
|
out = subprocess.run(["git", "ls-tree", "-r", "--name-only", ref],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
for f in out.stdout.splitlines():
|
||||||
|
if f.endswith((".md", ".rs", ".gd", ".json", ".txt", ".py",
|
||||||
|
".tsv", ".csv")) and not os.path.exists(f):
|
||||||
|
return f
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def gitignored(path: str) -> bool:
|
||||||
|
"""Is this path deliberately untracked? Pattern match -- existence not needed."""
|
||||||
|
return subprocess.run(["git", "check-ignore", "-q", path],
|
||||||
|
capture_output=True).returncode == 0
|
||||||
|
|
||||||
|
|
||||||
|
def unbuilt(path: str) -> bool:
|
||||||
|
"""A citation of GENERATED output whose tree has not been built here.
|
||||||
|
|
||||||
|
🔴 THE THIRD ABSENCE, AND IT IS NOT AN ERROR. `export/` is the exporter's
|
||||||
|
output and is gitignored (`.gitignore` `/export*/`). A checkout where nobody
|
||||||
|
has run the exporter has no `export/` at all, so the four `DECISIONS.md` and
|
||||||
|
`BLOCKED.md` citations of `export/manifest.json` and `export/screens/...`
|
||||||
|
were counted as "resolve NOWHERE" and this check was red on a clean tree --
|
||||||
|
for a state no edit can fix, which is precisely the shape its own docstring
|
||||||
|
says it exists to avoid.
|
||||||
|
|
||||||
|
`check-capture-citations` already learned this for `docs/re/captures/`.
|
||||||
|
Same rule here: absent BECAUSE UNBUILT is reported; absent while the tree
|
||||||
|
IS built is a real broken citation and still fails.
|
||||||
|
"""
|
||||||
|
if not gitignored(path):
|
||||||
|
return False
|
||||||
|
root = path.split("/")[0]
|
||||||
|
return not os.path.exists(root)
|
||||||
|
|
||||||
|
|
||||||
def on_a_ref(path: str) -> str | None:
|
def on_a_ref(path: str) -> str | None:
|
||||||
@@ -49,7 +102,7 @@ def on_a_ref(path: str) -> str | None:
|
|||||||
|
|
||||||
|
|
||||||
def scan(files):
|
def scan(files):
|
||||||
resolves, peer, nowhere = 0, {}, {}
|
resolves, peer, nowhere, ungenerated = 0, {}, {}, {}
|
||||||
for p in files:
|
for p in files:
|
||||||
try:
|
try:
|
||||||
text = open(p, encoding="utf-8").read()
|
text = open(p, encoding="utf-8").read()
|
||||||
@@ -58,11 +111,13 @@ def scan(files):
|
|||||||
for m in sorted(set(CITE.findall(text))):
|
for m in sorted(set(CITE.findall(text))):
|
||||||
if os.path.exists(m):
|
if os.path.exists(m):
|
||||||
resolves += 1
|
resolves += 1
|
||||||
|
elif unbuilt(m):
|
||||||
|
ungenerated.setdefault(m, p)
|
||||||
elif (ref := on_a_ref(m)):
|
elif (ref := on_a_ref(m)):
|
||||||
peer.setdefault(m, (p, ref))
|
peer.setdefault(m, (p, ref))
|
||||||
else:
|
else:
|
||||||
nowhere.setdefault(m, p)
|
nowhere.setdefault(m, p)
|
||||||
return resolves, peer, nowhere
|
return resolves, peer, nowhere, ungenerated
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
@@ -82,28 +137,51 @@ def main() -> int:
|
|||||||
# exists) and does not resolve here (the reader still gets nothing), and
|
# exists) and does not resolve here (the reader still gets nothing), and
|
||||||
# a scanner that collapsed it into either would make the flag meaningless
|
# a scanner that collapsed it into either would make the flag meaningless
|
||||||
# while still passing the two checks above.
|
# while still passing the two checks above.
|
||||||
|
peer_probe = a_peer_only_path()
|
||||||
peerfile = os.path.join(tmp, "peer.md")
|
peerfile = os.path.join(tmp, "peer.md")
|
||||||
open(peerfile, "w").write("see `docs/re/f5-a-press-snaps-the-plate.md`\n")
|
open(peerfile, "w").write("see `%s`\n" % (peer_probe or "docs/port/PORT-MISSION.md"))
|
||||||
rp, pp, np_ = scan([peerfile])
|
# The FOURTH class: generated output whose tree is not built here.
|
||||||
|
# It has to be told apart from "resolves nowhere", which is the whole
|
||||||
|
# point -- a scanner that lumped them together is what made this check
|
||||||
|
# red on a clean checkout.
|
||||||
|
genfile = os.path.join(tmp, "gen.md")
|
||||||
|
open(genfile, "w").write("see `export/screens/title/main_menu.json`\n")
|
||||||
|
|
||||||
_, _, nb = scan([bad])
|
rp, pp, np_, gp = scan([peerfile])
|
||||||
r, _, ng = scan([good])
|
|
||||||
|
_, _, nb, _ = scan([bad])
|
||||||
|
r, _, ng, _ = scan([good])
|
||||||
|
rg, pg, ng2, gg = scan([genfile])
|
||||||
caught = len(nb) == 1
|
caught = len(nb) == 1
|
||||||
passed = len(ng) == 0 and r == 1
|
passed = len(ng) == 0 and r == 1
|
||||||
peer_ok = len(pp) == 1 and rp == 0 and len(np_) == 0
|
# None == the class is empty in this checkout, not that it is broken.
|
||||||
ok = caught and passed and peer_ok
|
peer_ok = (len(pp) == 1 and rp == 0 and len(np_) == 0 and len(gp) == 0) \
|
||||||
|
if peer_probe else None
|
||||||
|
# Only meaningful while `export/` is absent; if someone ran the exporter
|
||||||
|
# in this checkout the citation legitimately resolves instead.
|
||||||
|
gen_ok = (len(gg) == 1 and len(ng2) == 0 and len(pg) == 0) \
|
||||||
|
if not os.path.exists("export") else (rg == 1)
|
||||||
|
ok = caught and passed and gen_ok and peer_ok is not False
|
||||||
print("selftest: planted dangling caught=%s, real citation passed=%s, "
|
print("selftest: planted dangling caught=%s, real citation passed=%s, "
|
||||||
"peer-branch classed separately=%s -> %s"
|
"peer-branch classed separately=%s, unbuilt-generated classed "
|
||||||
% (caught, passed, peer_ok, "ok" if ok else "🔴 BROKEN"))
|
"separately=%s -> %s"
|
||||||
if not peer_ok:
|
% (caught, passed,
|
||||||
|
"n/a (no peer-only path exists here)" if peer_ok is None
|
||||||
|
else peer_ok,
|
||||||
|
gen_ok, "ok" if ok else "🔴 BROKEN"))
|
||||||
|
if not gen_ok:
|
||||||
|
print(" 🔴 a citation of unbuilt generated output must NOT be "
|
||||||
|
"dangling; got resolves=%d peer=%d nowhere=%d ungenerated=%d"
|
||||||
|
% (rg, len(pg), len(ng2), len(gg)))
|
||||||
|
if peer_ok is False:
|
||||||
print(" 🔴 --for-merge cannot mean anything if the peer class is "
|
print(" 🔴 --for-merge cannot mean anything if the peer class is "
|
||||||
"not distinguished; got resolves=%d peer=%d nowhere=%d"
|
"not distinguished; got resolves=%d peer=%d nowhere=%d"
|
||||||
% (rp, len(pp), len(np_)))
|
% (rp, len(pp), len(np_)))
|
||||||
return 0 if ok else 2
|
return 0 if ok else 2
|
||||||
|
|
||||||
files = sorted(glob.glob("docs/port/*.md"))
|
files = sorted(glob.glob("docs/port/*.md"))
|
||||||
resolves, peer, nowhere = scan(files)
|
resolves, peer, nowhere, ungenerated = scan(files)
|
||||||
total = resolves + len(peer) + len(nowhere)
|
total = resolves + len(peer) + len(nowhere) + len(ungenerated)
|
||||||
print("citations of repo paths in docs/port/*.md: %d" % total)
|
print("citations of repo paths in docs/port/*.md: %d" % total)
|
||||||
print(" resolve here : %d" % resolves)
|
print(" resolve here : %d" % resolves)
|
||||||
# 🔴 --for-merge TURNS THE PEER CLASS INTO A FAILURE.
|
# 🔴 --for-merge TURNS THE PEER CLASS INTO A FAILURE.
|
||||||
@@ -130,6 +208,13 @@ def main() -> int:
|
|||||||
print(" After this merges they resolve NOWHERE -- the reader gets a dead")
|
print(" After this merges they resolve NOWHERE -- the reader gets a dead")
|
||||||
print(" path. Land the finding first and make it a dependency of this PR.")
|
print(" path. Land the finding first and make it a dependency of this PR.")
|
||||||
return 1
|
return 1
|
||||||
|
if ungenerated:
|
||||||
|
print(" not built in this checkout : %d (reported, not failed)"
|
||||||
|
% len(ungenerated))
|
||||||
|
for m, src in sorted(ungenerated.items()):
|
||||||
|
print(" %-52s <- %s" % (m, os.path.basename(src)))
|
||||||
|
print(" run the exporter and these resolve; a path still missing")
|
||||||
|
print(" afterwards IS dangling and fails below.")
|
||||||
if nowhere:
|
if nowhere:
|
||||||
print(" 🔴 resolve NOWHERE : %d" % len(nowhere))
|
print(" 🔴 resolve NOWHERE : %d" % len(nowhere))
|
||||||
for m, src in sorted(nowhere.items()):
|
for m, src in sorted(nowhere.items()):
|
||||||
|
|||||||
@@ -82,10 +82,16 @@ def committed() -> tuple[set[str], set[str]]:
|
|||||||
if fn == ".gitignore":
|
if fn == ".gitignore":
|
||||||
continue
|
continue
|
||||||
files.add(os.path.join(dirpath, fn).replace(os.sep, "/"))
|
files.add(os.path.join(dirpath, fn).replace(os.sep, "/"))
|
||||||
|
# 🔴 START AT 3, NOT 4 — 3 is `docs/re/captures` ITSELF. Starting at 4 built
|
||||||
|
# every sub-directory and never the root, so the eight pages that cite the
|
||||||
|
# directory as a whole ("evidence lives in `docs/re/captures/`") each looked
|
||||||
|
# like a citation of a file that does not exist, and the gate was red on a
|
||||||
|
# clean, correct tree. The selftest could not see it either: it took an
|
||||||
|
# arbitrary member of `dirs`, which is always a sub-directory.
|
||||||
dirs = set()
|
dirs = set()
|
||||||
for f in files:
|
for f in files:
|
||||||
parts = f.split("/")
|
parts = f.split("/")
|
||||||
for i in range(4, len(parts)): # docs/re/captures/<dir>/...
|
for i in range(3, len(parts)): # docs/re/captures[/<dir>/...]
|
||||||
dirs.add("/".join(parts[:i]) + "/")
|
dirs.add("/".join(parts[:i]) + "/")
|
||||||
return files, dirs
|
return files, dirs
|
||||||
|
|
||||||
@@ -182,6 +188,9 @@ def selftest() -> int:
|
|||||||
("real file passed", real_file, True),
|
("real file passed", real_file, True),
|
||||||
("directory reference passed", real_dir, True),
|
("directory reference passed", real_dir, True),
|
||||||
("directory without slash passed", real_dir.rstrip("/"), True),
|
("directory without slash passed", real_dir.rstrip("/"), True),
|
||||||
|
# The root is the case the arbitrary `real_dir` above can never be.
|
||||||
|
("captures root itself passed", ROOT, True),
|
||||||
|
("captures root without slash passed", ROOT.rstrip("/"), True),
|
||||||
("sentence punctuation stripped", real_file + ".", True),
|
("sentence punctuation stripped", real_file + ".", True),
|
||||||
]
|
]
|
||||||
# 🔴 THE SELFTEST USED TO PASS WHILE THE SCAN RETURNED NOTHING. It exercised
|
# 🔴 THE SELFTEST USED TO PASS WHILE THE SCAN RETURNED NOTHING. It exercised
|
||||||
@@ -235,6 +244,21 @@ def main() -> int:
|
|||||||
print(" cited by a page or a tool : %d" % (len(files) - len(orphans)))
|
print(" cited by a page or a tool : %d" % (len(files) - len(orphans)))
|
||||||
print(" cited by nothing : %d (reported, not failed —" % len(orphans))
|
print(" cited by nothing : %d (reported, not failed —" % len(orphans))
|
||||||
print(" an orphan may be evidence a page owes)")
|
print(" an orphan may be evidence a page owes)")
|
||||||
|
# 🔴 A BARE CLONE HAS NO CAPTURES AT ALL, and that is not a defect.
|
||||||
|
# Since #49 the assets are never committed, so a fresh clone, a worktree or
|
||||||
|
# a CI checkout legitimately has none — and the naive check calls all 134
|
||||||
|
# citations dangling and exits 1. A gate that is red on every clean checkout
|
||||||
|
# is one people learn to ignore, which is how the last wrong-by-default
|
||||||
|
# check in this file cost a session. Distinguish "none here" from "this one
|
||||||
|
# is missing": with some assets present, a gap is real and still fails.
|
||||||
|
assets_here = sum(1 for f in files if f.lower().endswith(ASSET_SUFFIXES))
|
||||||
|
if assets_here == 0 and dangling:
|
||||||
|
print(" ⓘ no captures on this checkout: %d citations unresolved" % len(dangling))
|
||||||
|
print(" Expected — captures are local-only (#49) and a fresh clone has none.")
|
||||||
|
print(" Copy them in, or read the evidence on the issue it is attached to.")
|
||||||
|
print(" 🔴 game assets TRACKED : %d" % len(stowaways))
|
||||||
|
return 1 if stowaways else 0
|
||||||
|
|
||||||
rc = 0
|
rc = 0
|
||||||
if dangling:
|
if dangling:
|
||||||
print(" 🔴 cited but NOT present : %d" % len(dangling))
|
print(" 🔴 cited but NOT present : %d" % len(dangling))
|
||||||
|
|||||||
@@ -32,7 +32,18 @@ export ALSA_CONFIG_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/asound-nu
|
|||||||
# Paths derive from where this script sits — see the note in run-canary-safe.sh.
|
# Paths derive from where this script sits — see the note in run-canary-safe.sh.
|
||||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
WORKSPACE="$(cd "$HERE/../.." && pwd)"
|
WORKSPACE="$(cd "$HERE/../.." && pwd)"
|
||||||
BIN_DEFAULT="$WORKSPACE/xenia-canary-native/build/bin/Linux/Release/xenia_canary"
|
# 🔴 THE INSTRUMENTED BINARY IS THE `Checked` ONE, and it is the only config this
|
||||||
|
# build tree can produce: `ninja -n bin/Linux/Release/xenia_canary` lists ZERO
|
||||||
|
# steps, so Release is not a target here and its binary still dates from
|
||||||
|
# 2026-08-28, before the audit_61 probe existed. Pointing at Release therefore
|
||||||
|
# runs an oracle with no probe and no way to refresh it.
|
||||||
|
#
|
||||||
|
# The old default named `xenia-canary-native/`, a directory that does not exist
|
||||||
|
# on this workspace at all -- the checkout is `xenia-canary/`.
|
||||||
|
#
|
||||||
|
# `Checked` is optimised WITH assertions, which is what you want from a
|
||||||
|
# behavioural reference: a bad state stops loudly instead of being sampled.
|
||||||
|
BIN_DEFAULT="$WORKSPACE/xenia-canary/build/bin/Linux/Checked/xenia_canary"
|
||||||
BIN_EXE="${CANARY_BIN:-$BIN_DEFAULT}"
|
BIN_EXE="${CANARY_BIN:-$BIN_DEFAULT}"
|
||||||
ISO="${SYLPHEED_ISO:-$WORKSPACE/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso}"
|
ISO="${SYLPHEED_ISO:-$WORKSPACE/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso}"
|
||||||
[ -f "$ISO" ] || { echo "ABORT: no ISO at '$ISO' — set \$SYLPHEED_ISO"; exit 4; }
|
[ -f "$ISO" ] || { echo "ABORT: no ISO at '$ISO' — set \$SYLPHEED_ISO"; exit 4; }
|
||||||
|
|||||||
@@ -24,7 +24,18 @@ set -u
|
|||||||
# Paths derive from where this script sits — see the note in run-canary-safe.sh.
|
# Paths derive from where this script sits — see the note in run-canary-safe.sh.
|
||||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
WORKSPACE="$(cd "$HERE/../.." && pwd)"
|
WORKSPACE="$(cd "$HERE/../.." && pwd)"
|
||||||
BIN_DEFAULT="$WORKSPACE/xenia-canary-native/build/bin/Linux/Release/xenia_canary"
|
# 🔴 THE INSTRUMENTED BINARY IS THE `Checked` ONE, and it is the only config this
|
||||||
|
# build tree can produce: `ninja -n bin/Linux/Release/xenia_canary` lists ZERO
|
||||||
|
# steps, so Release is not a target here and its binary still dates from
|
||||||
|
# 2026-08-28, before the audit_61 probe existed. Pointing at Release therefore
|
||||||
|
# runs an oracle with no probe and no way to refresh it.
|
||||||
|
#
|
||||||
|
# The old default named `xenia-canary-native/`, a directory that does not exist
|
||||||
|
# on this workspace at all -- the checkout is `xenia-canary/`.
|
||||||
|
#
|
||||||
|
# `Checked` is optimised WITH assertions, which is what you want from a
|
||||||
|
# behavioural reference: a bad state stops loudly instead of being sampled.
|
||||||
|
BIN_DEFAULT="$WORKSPACE/xenia-canary/build/bin/Linux/Checked/xenia_canary"
|
||||||
BIN_EXE="${CANARY_BIN:-$BIN_DEFAULT}"
|
BIN_EXE="${CANARY_BIN:-$BIN_DEFAULT}"
|
||||||
ISO="${SYLPHEED_ISO:-$WORKSPACE/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso}"
|
ISO="${SYLPHEED_ISO:-$WORKSPACE/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso}"
|
||||||
[ -f "$ISO" ] || { echo "ABORT: no ISO at '$ISO' — set \$SYLPHEED_ISO"; exit 4; }
|
[ -f "$ISO" ] || { echo "ABORT: no ISO at '$ISO' — set \$SYLPHEED_ISO"; exit 4; }
|
||||||
|
|||||||
@@ -57,7 +57,22 @@ rm -f xenia.log
|
|||||||
|
|
||||||
# Binary is overridable (default keeps the historical _i2d snapshot); extra
|
# Binary is overridable (default keeps the historical _i2d snapshot); extra
|
||||||
# cvars pass through via CANARY_EXTRA_ARGS (space-separated, values w/o spaces).
|
# cvars pass through via CANARY_EXTRA_ARGS (space-separated, values w/o spaces).
|
||||||
|
# ⚠️ THIS WINE BUILD HAS NO INSTRUMENTATION AND CANNOT BE REFRESHED HERE.
|
||||||
|
# Measured 2026-09-20: `xenia_canary_i2d.exe` does not exist at all, and the
|
||||||
|
# `xenia_canary.exe` that does (2026-06-19) has ZERO hits for both
|
||||||
|
# `audit_61_branch_probe_pcs` and `RE-INPUT`/`RE-DRAW`. Rebuilding it needs the
|
||||||
|
# clang-cl + xwin cross toolchain on the `cross-build-wine` branch.
|
||||||
|
#
|
||||||
|
# 🔴 FOR PROBE RUNS USE `run-canary-native-safe.sh` INSTEAD -- same hard Vulkan
|
||||||
|
# gate, same headless behaviour, and it runs the Checked native binary, which
|
||||||
|
# carries audit_61 and the RE-INPUT/RE-DRAW logging.
|
||||||
BIN_EXE="${CANARY_BIN:-xenia_canary_i2d.exe}"
|
BIN_EXE="${CANARY_BIN:-xenia_canary_i2d.exe}"
|
||||||
|
if [ ! -f "$BIN/$BIN_EXE" ]; then
|
||||||
|
echo "ABORT: no Wine binary at $BIN/$BIN_EXE" >&2
|
||||||
|
echo " This build is stale and uninstrumented; use run-canary-native-safe.sh" >&2
|
||||||
|
echo " for anything needing audit_61 or the RE-* logging." >&2
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
args=(--log_level=3 --mute=true)
|
args=(--log_level=3 --mute=true)
|
||||||
[ -n "$PROBES" ] && args+=("--audit_61_branch_probe_pcs=$PROBES")
|
[ -n "$PROBES" ] && args+=("--audit_61_branch_probe_pcs=$PROBES")
|
||||||
if [ -n "${CANARY_EXTRA_ARGS:-}" ]; then
|
if [ -n "${CANARY_EXTRA_ARGS:-}" ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user