Resuming happens on the other machine, so anything that lived only in this workspace either comes into the repo or gets named as something to carry. **The launchers come in.** `run-canary-safe.sh` (Wine) and `run-canary-native-safe.sh` (native) are the ONLY sanctioned way to start Canary from the editor — they force software Vulkan and refuse to launch while a hardware Vulkan device is visible, because Canary on the AMD GPU takes VS Code with it. They sat in the workspace root, outside git, hardcoding one machine's absolute paths, which is exactly why they could not be checked in. They now derive the workspace from their own location and honour `$SYLPHEED_ISO` and `$CANARY_BIN`, so the layout is a default rather than a requirement. Same for `run-canary-native.sh` (interactive, hardware Vulkan — not from the IDE), `diagnose-freeze.sh`, `live-guest-state.sh`, `heaptrack-wrap.sh` and the `asound-null.conf` the native launcher needs beside it. Both safe launchers were run from `tools/` before this commit: the native one reached content in 20 s (`VERDICT: HEALTHY`, title + 25,398 XMA lines, no faults), the Wine one ran 25 s and logged 4 `ADV.wmv` hits. **`docs/agents/HANDOFF-2026-09-18.md`** records what changed since 2026-09-16, what is on the server, what cannot travel through git, and the traps this machine paid for — chiefly that the guest-PC branch probe exists only on the fork's snapshot branch, so a rebuild from `sylpheed-re` silently loses it. **`HANDOFF-2026-09-06.md`** gets a correction note rather than an edit: a plain clone works again now that the 545 MB branch is gone, and its baselines are two baselines old. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
98 lines
4.9 KiB
Bash
Executable File
98 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SAFE launcher for the NATIVE Linux Xenia-Canary build on THIS box.
|
|
#
|
|
# Same safety contract as run-canary-safe.sh (the Wine/Windows variant): the AMD
|
|
# GPU + GPU-accelerated VS Code means a hardware-Vulkan render CRASHES VS Code.
|
|
# This wrapper forces software Vulkan (lavapipe/llvmpipe) IN THE SAME process and
|
|
# HARD-REFUSES to launch if any hardware Vulkan device is still visible.
|
|
#
|
|
# Difference vs run-canary-safe.sh: runs the native ELF directly (NO wine).
|
|
#
|
|
# Usage: tools/run-canary-native-safe.sh [seconds]
|
|
# env: CANARY_BIN override binary (default = worktree Release build)
|
|
# CANARY_EXTRA_ARGS space-separated extra cvars (values w/o spaces)
|
|
# Output: /tmp/canary_native.stdout (+ xenia.log in the binary dir). Prints rc + ADV.wmv hits.
|
|
set -u
|
|
|
|
# --- force software Vulkan, belt-and-suspenders across loader/driver variants ---
|
|
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.json
|
|
export VK_DRIVER_FILES=/usr/share/vulkan/icd.d/lvp_icd.json
|
|
export MESA_VK_DEVICE_SELECT=llvmpipe
|
|
export LIBGL_ALWAYS_SOFTWARE=1
|
|
# --- keep background runs SILENT *without* killing the audio system ---
|
|
# DO NOT use --apu=nop: with no audio system the guest's XAudio render client is
|
|
# NULL and Project Sylpheed derefs null+0x3C at PC 0x824D7C40 -> a FALSE boot
|
|
# crash that never happens in interactive runs. Instead keep the ALSA apu ALIVE
|
|
# and route PCM "default" to the null device (see asound-null.conf): silent, but
|
|
# snd_pcm_open succeeds so the guest is happy. --mute does NOT silence ALSA.
|
|
export SDL_AUDIODRIVER=dummy
|
|
export ALSA_CONFIG_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/asound-null.conf"
|
|
[ -f "$ALSA_CONFIG_PATH" ] || { echo "ABORT: asound-null.conf missing next to script"; exit 4; }
|
|
|
|
# Paths derive from where this script sits — see the note in run-canary-safe.sh.
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
WORKSPACE="$(cd "$HERE/../.." && pwd)"
|
|
BIN_DEFAULT="$WORKSPACE/xenia-canary-native/build/bin/Linux/Release/xenia_canary"
|
|
BIN_EXE="${CANARY_BIN:-$BIN_DEFAULT}"
|
|
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; }
|
|
SECS="${1:-95}"
|
|
|
|
[ -x "$BIN_EXE" ] || { echo "ABORT: native binary not found/executable: $BIN_EXE"; exit 4; }
|
|
|
|
# --- HARD PRE-FLIGHT GATE: only proceed if Vulkan exposes software devices ONLY ---
|
|
devs="$(vulkaninfo --summary 2>/dev/null | grep -i deviceName || true)"
|
|
if echo "$devs" | grep -qiE 'radv|amd|radeon|nvidia|geforce|intel\b'; then
|
|
echo "ABORT(pre-flight): a HARDWARE Vulkan device is still visible -> refusing (would crash VS Code):"
|
|
echo "$devs"
|
|
exit 3
|
|
fi
|
|
if ! echo "$devs" | grep -qiE 'llvmpipe'; then
|
|
echo "ABORT(pre-flight): llvmpipe not visible; lavapipe ICD missing? devs=[$devs]"
|
|
exit 3
|
|
fi
|
|
echo "pre-flight OK: software-only Vulkan -> $devs"
|
|
|
|
# --- clean slate ---
|
|
pkill -x xenia_canary 2>/dev/null; pkill -x Xvfb 2>/dev/null; sleep 1
|
|
|
|
Xvfb :99 -screen 0 1280x720x24 -nolisten tcp >/tmp/xvfb.log 2>&1 &
|
|
XVFB=$!
|
|
sleep 2
|
|
export DISPLAY=:99
|
|
cd "$(dirname "$BIN_EXE")" || { echo "ABORT: bin dir missing"; kill "$XVFB" 2>/dev/null; exit 4; }
|
|
rm -f xenia.log
|
|
|
|
# Real ALSA apu (routed to null sink via ALSA_CONFIG_PATH) so the guest gets a
|
|
# valid render client; --mute belt-and-suspenders. NEVER add --apu=nop here.
|
|
args=(--log_level=3 --mute=true)
|
|
if [ -n "${CANARY_EXTRA_ARGS:-}" ]; then
|
|
read -ra EXTRA <<< "$CANARY_EXTRA_ARGS"
|
|
args+=("${EXTRA[@]}")
|
|
fi
|
|
echo "launch (native, sw-vulkan, SILENT null-ALSA, ${SECS}s): $(basename "$BIN_EXE") ${args[*]}"
|
|
# -k 5: xenia catches SIGTERM and can hang on shutdown; force-KILL 5s later.
|
|
timeout -k 5 "$SECS" "$BIN_EXE" "$ISO" "${args[@]}" >/tmp/canary_native.stdout 2>&1
|
|
rc=$?
|
|
|
|
pkill -x xenia_canary 2>/dev/null; kill "$XVFB" 2>/dev/null; pkill -x Xvfb 2>/dev/null
|
|
|
|
# --- trustworthy boot-health verdict (NOT log-line-count, NOT rc) ---
|
|
# A healthy boot reaches actual content: title loaded + XMA audio decoding + NO
|
|
# host-exception fault loop. rc=137 is EXPECTED (timeout -k kill), not a failure.
|
|
faults=$(grep -ac 'Access Violation' /tmp/canary_native.stdout 2>/dev/null)
|
|
gthrow=$(grep -ac 'GUEST-THROW' xenia.log 2>/dev/null)
|
|
title=$(grep -ac 'Title name: PROJECT SYLPHEED' xenia.log 2>/dev/null)
|
|
xma=$(grep -acE 'XmaContext|Processing context' xenia.log 2>/dev/null)
|
|
echo "rc=$rc logsize=$(wc -c < xenia.log 2>/dev/null)"
|
|
echo "boot-health: title=$title xma=$xma faults=$faults guest_throw=$gthrow"
|
|
if [ "$title" -ge 1 ] && [ "$xma" -ge 100 ] && [ "$faults" -eq 0 ] && [ "$gthrow" -eq 0 ]; then
|
|
echo "VERDICT: HEALTHY (reached content, no crash)"
|
|
elif [ "$gthrow" -ge 1 ]; then
|
|
echo "VERDICT: GUEST-THROW CRASH (the real bug) -- see GUEST-THROW lines in xenia.log"
|
|
elif [ "$faults" -ge 1 ]; then
|
|
echo "VERDICT: FAULT (host access-violation loop) -- crash PC:"
|
|
grep -aoE 'PC: 0x[0-9A-Fa-f]+' /tmp/canary_native.stdout | sort | uniq -c | head -3
|
|
else
|
|
echo "VERDICT: INCOMPLETE (did not reach content in ${SECS}s -- raise timeout?)"
|
|
fi |