re: F3 sting half closed -- no sting, measured with a working positive control
Some checks failed
CI / Native — linux (pull_request) Failing after 34m43s
CI / WASM — Web (pull_request) Successful in 31m12s
CI / Formatting (pull_request) Failing after 1m11s

Continues the static lead from two iterations ago
(f3-title-sting-mechanism-found-not-value.md) with the dynamic half it
named as the next step. Booted with --xma_param_probe=true (the same
census menu-audio-cues.md used for the menu's SE cues), no pad input,
recording continuously from window-open: a glyph time series (not a
threshold trigger) and every newly-seen XMA-PARAM stream, stamped on
arrival since Xenia's own log carries no timestamps.

Positive control, and a real one: the probe caught the title's two BGM
stems starting at t=147.6s, matching f3-title-plays-bgm-102-and-103.md's
already-established finding exactly -- the instrument finds a real stream
before being asked to find nothing.

From the plate's first visible activity through 68 seconds of build-in
plus fully-settled pulsing (killed at t=220.1s), zero new XMA streams
appeared beyond the two BGM stems and three unidentified early ones (boot
splash, not this question). No SE-range stream, no second BGM, nothing --
measured, not the prior static reach limit.

Refutation attempt this iteration, recorded either way: my first read of
the fine-grained glyph series said BGM and the plate's build-in start at
"essentially the same moment". Checking the raw per-sample data instead of
a coarse table refutes that -- first non-zero glyph reading is ~0.67s after
BGM onset, and immediately noisy rather than a clean climb. Corrected in
the doc rather than left as an overclaim for someone chasing frame-accurate
sync later.

Reference data: docs/re/data/f3-sting-{glyph-timeseries,xma-param-arrivals}.tsv
-- derived numeric/log-line data, not a capture of rendered game content.
This commit is contained in:
sylph-decoder
2026-09-12 12:40:34 +00:00
parent e61937f7a1
commit 3d7138892c
5 changed files with 1593 additions and 0 deletions

View File

@@ -6663,3 +6663,24 @@ the closest thing to that oracle available in a container with no physical
pad. One run only; the corpus's two-run minimum isn't met, and the pad. One run only; the corpus's two-run minimum isn't met, and the
3-vs-4-frame split in the interval is itself worth a second look. Good 3-vs-4-frame split in the interval is itself worth a second look. Good
enough to stop authoring `-1.0` against, not yet good enough to call final. enough to stop authoring `-1.0` against, not yet good enough to call final.
## ✅ F3's sting half closed — no sting, measured, not inferred
[`docs/re/f3-sting-measured-no-new-stream.md`](../re/f3-sting-measured-no-new-stream.md).
The BGM half was already yours (cues 1102/1103); this is the "does the
Ⓐ-plate play a one-shot sound when it appears" half.
**No, and it's a controlled negative, not silence from a broken
instrument.** Booted with the same `--xma_param_probe` census
`menu-audio-cues.md` used for the menu's SE cues, no pad input at all,
watched continuously from window-open. The probe's own positive control
landed for free: it caught the title's two BGM stems starting exactly when
`f3-title-plays-bgm-102-and-103.md` already says they should, proving the
instrument finds real streams before it's asked to find nothing. From the
plate's first visible activity through **68 seconds** of build-in plus
fully-settled pulsing, **zero new audio streams appeared** — no SE, no
second BGM, nothing.
**For the port:** no automatic sound on the plate appearing. If something
still feels like it's missing there, it's the same "author the mix"
situation F2 already handed you, not a hidden cue.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
# t_s line
9.07 w> 01000014 XMA-PARAM ctx=0 buf=0 ptr=0x13544000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=632 byte_size=1294336 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
9.07 w> 01000014 XMA-PARAM ctx=1 buf=0 ptr=0x13682000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=546 byte_size=1118208 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
9.07 w> 01000014 XMA-PARAM ctx=2 buf=0 ptr=0x13795000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=572 byte_size=1171456 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
147.58 w> 01000014 XMA-PARAM ctx=0 buf=0 ptr=0x13544000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=562 byte_size=1150976 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=eea5129f23100850080bc576b79c758974d9ffcca9615260a24be18daef20908a481041104f41552d6140844424032ff
147.58 w> 01000014 XMA-PARAM ctx=1 buf=0 ptr=0x1365f000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=620 byte_size=1269760 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=7816dbaeb9bf43712000b033c2b62d5b356090922211020ccc80672c18605914ac3a0900f8319c70f50ced6a1724a039
1 # t_s line
2 9.07 w> 01000014 XMA-PARAM ctx=0 buf=0 ptr=0x13544000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=632 byte_size=1294336 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
3 9.07 w> 01000014 XMA-PARAM ctx=1 buf=0 ptr=0x13682000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=546 byte_size=1118208 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
4 9.07 w> 01000014 XMA-PARAM ctx=2 buf=0 ptr=0x13795000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=572 byte_size=1171456 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004081023007dfc001020408c01f7f0004
5 147.58 w> 01000014 XMA-PARAM ctx=0 buf=0 ptr=0x13544000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=562 byte_size=1150976 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=eea5129f23100850080bc576b79c758974d9ffcca9615260a24be18daef20908a481041104f41552d6140844424032ff
6 147.58 w> 01000014 XMA-PARAM ctx=1 buf=0 ptr=0x1365f000 read_off=32 stereo=1 channels=2 rate_id=3 rate=48000 packets=620 byte_size=1269760 sig_off=1024 head=080000000095fc01c001020408c01f7f0004081023007dfc001020408c01f7f0 sig=7816dbaeb9bf43712000b033c2b62d5b356090922211020ccc80672c18605914ac3a0900f8319c70f50ced6a1724a039

View File

@@ -0,0 +1,94 @@
# F3, the sting half, closed — no sting: zero new XMA streams across build-in and 68 s of settled pulsing
**Status:** ✅ measured (⟨capture⟩). Answers the dynamic half
[`f3-title-sting-mechanism-found-not-value.md`](f3-title-sting-mechanism-found-not-value.md)
left open, using exactly the instrument and method that page named.
2026-09-12. Instrument:
[`tools/re-capture/f3_sting_probe.py`](../../tools/re-capture/f3_sting_probe.py).
## Method
Booted with `--xma_param_probe=true` (the same cvar `menu-audio-cues.md`
used for the menu's SE census) and **no pad input at all** — the question
is what plays automatically, not what a press triggers. Two things recorded
continuously from the moment Canary's window exists, not from a threshold
trigger: a glyph (green-pixel) count every ~0.5 s over the whole run, and
every *newly-seen* `XMA-PARAM` log line (Xenia dedupes these itself, one per
distinct stream, keyed on ptr+packet-count) stamped with wall-clock arrival
time — the same "stamp on arrival" technique
[`xma_readoff_trace.py`](../../tools/re-capture/xma_readoff_trace.py)
already uses for a log with no timestamps of its own.
**Positive control (R4), and it's a real one, not a synthetic one:** the
probe found three streams at `t≈9.1 s`, sharing one head but distinct
packet counts and signatures — unidentified, and not this question's
concern; not asserting what they are without checking — and, at
`t≈147.6 s`, **exactly two stereo streams**
starting together — matching `f3-title-plays-bgm-102-and-103.md` and
`bgm-two-stems.md`'s already-established finding that the title's BGM is
two XMA stems played in sync. A probe that reproduces an already-known
positive from a live run is doing its job, not merely configured correctly.
## The plate's timeline, from the glyph series (not assumed)
[`data/f3-sting-glyph-timeseries.tsv`](data/f3-sting-glyph-timeseries.tsv):
| t (s) | glyph | reading |
|---|---|---|
| 0 147.9 | 0 | attract movie, no plate |
| 148.4 151.4 | 17 154 | **build-in**: rising, not yet at the pulse plateau |
| 151.8 onward | 712 1518, cycling | **settled**, pulsing at its established ~2 s period |
**Refutation attempt, recorded either way:** my first read of this was "BGM
and build-in start at essentially the same moment." Checking the raw
per-sample series instead of the coarse table above refutes that: the first
non-zero glyph reading is `148.25 s`**~0.67 s after** BGM onset
(`147.58 s`), not simultaneous, and the values immediately after are noisy
(`107, 40, 0, 0, 0, 17…`) rather than a clean climb, so even "build-in
starts at 148.25 s" is a looser statement than "the plate is visible from
about 148.4 s onward." Both clocks are anchored to the same
title-appearance event, but they are not one event — worth stating
precisely since a later reader chasing frame-accurate sync between title
BGM and title art would otherwise inherit an overclaim.
## The result
[`data/f3-sting-xma-param-arrivals.tsv`](data/f3-sting-xma-param-arrivals.tsv) —
**five distinct streams for the whole 220 s run, and none after `t=147.6 s`.**
From the plate's first visible rise (`148.4 s`) through **68 seconds** of
build-in plus fully-settled pulsing (killed at `220.1 s`), the probe — which
just finished proving it can catch a new stream the instant one starts —
caught **nothing new**. No SE-range stream, no additional BGM-range one,
nothing.
**No sting plays when the plate appears, and none plays for over a minute
of it sitting there pulsing.** This is the measured answer to the half of
F3 the BGM census couldn't reach: not "SE goes through a different call" (a
scope limit) and not "the mechanism exists but its value is unreachable"
(the static finding), but a direct negative from watching the actual
sound-decode path with the game doing nothing else.
## What this does not cover
* **Only the boot title**, no input, one run. Whether Ⓐ itself plays a
confirm sting is already answered elsewhere
(`menu-audio-cues.md`: the `0x5d6c0` wave on the title→menu transition).
This page is specifically the *unprompted* plate-appearance question.
* The static mechanism found last iteration — a dispatch-table call chain
from `GamePart_Title` into the generic play primitive with a non-literal
cue id — is not contradicted by this. The likeliest reading, unchanged:
that slot's cue value is the `-1` "don't play" sentinel for this
GamePart, or the emitter it configures is never triggered on this
particular event. Either way, nothing plays, which is what both pages
now agree on from different instruments (⟨canary-source⟩ then ⟨capture⟩).
* One run, ⟨capture⟩. A second boot repeating the null would be the
standard reproducibility bar this corpus otherwise holds to; not run here
given the length of this single window (68 s past first appearance) and
the working positive control already in the same run.
## Reach
⟨capture⟩, one boot, no input. Covers the plate's entire build-in and 68 s
of settled state. Does not cover the attract-loop title (a different,
harder-to-reach state per this corpus's own capture-harness history) or any
input-triggered event other than the already-decoded confirm cue.

View File

@@ -0,0 +1,151 @@
#!/usr/bin/env python3
"""F3, the sting half -- watch for a NEW XMA stream during the title's
build-in, with NO input, aligned against a continuous glyph time series so
"when did the plate reach full alpha" is measured, not assumed from a
threshold crossing.
Why continuous, not a threshold trigger: this container's own boot gate
(nav_repeat_and_b.py, f1_hold_capture.py) waits for the glyph count to HOLD
in [500,2500] for 12 samples before calling it "TITLE" -- which could
already be past the build-in's interesting part. This script starts
recording both streams (glyph count, XMA-PARAM arrivals) from the moment
Canary's window exists, so the whole rise from 0 can be read back, not just
the plateau.
Positive control, per R4: BGM cues 1102/1103 are already known to play on
the title (f3-title-plays-bgm-102-and-103.md) via this exact probe
mechanism (menu-audio-cues.md). If this run logs zero XMA-PARAM lines at
all, the probe found nothing INCLUDING the thing it's supposed to find, and
the run is void -- not a negative about a sting.
f3_sting_probe.py OUTDIR [duration_s]
"""
import os
import re
import subprocess
import sys
import time
import numpy as np
OUT = sys.argv[1]
DURATION = float(sys.argv[2]) if len(sys.argv) > 2 else 200.0
os.makedirs(OUT, exist_ok=True)
W, H = 1280, 720
env = dict(os.environ)
env["HOME"] = "/sylph-home/re"
env["SDL_AUDIODRIVER"] = "dummy"
env["DISPLAY"] = ":98"
env["XENIA_PAD_FILE"] = os.path.join(OUT, "pad.txt")
def glyph(a):
r, g, b = a[:, :, 0], a[:, :, 1], a[:, :, 2]
return int(((g > 130) & (g - r > 45) & (g - b > 45)).sum())
def _open():
return subprocess.Popen(
["ffmpeg", "-loglevel", "error", "-f", "x11grab", "-draw_mouse", "0",
"-video_size", f"{W}x{H}", "-i", ":98", "-r", "6",
"-f", "rawvideo", "-pix_fmt", "rgb24", "-"],
stdout=subprocess.PIPE, bufsize=W * H * 3 * 4)
def grab(p, n):
buf = p.stdout.read(n)
if len(buf) < n:
return None
return np.frombuffer(buf, np.uint8).reshape(H, W, 3).astype(float)
def main():
with open(env["XENIA_PAD_FILE"], "w"):
pass
subprocess.run(["xsetroot", "-solid", "black"], env=env, check=False)
xuid = os.environ.get("SYLPH_XUID", "")
if not xuid:
content = "/sylph-home/re/.local/share/Xenia/content"
entries = os.listdir(content) if os.path.isdir(content) else []
xuid = entries[0] if entries else ""
if not xuid:
print("FATAL: no profile signed in -- run: run-canary "
"--create_profile_if_none=Tag, wait ~5s, kill it", flush=True)
return
canary_log_path = os.path.join(OUT, "canary.stdout")
canary_log = open(canary_log_path, "w")
proc = subprocess.Popen(
["run-canary", f"--logged_profile_slot_0_xuid={xuid}",
"--xma_param_probe=true", "--log_level=2"],
cwd=OUT, env=env, stdout=canary_log, stderr=subprocess.STDOUT)
print(f"canary pid={proc.pid}, xma_param_probe=true, waiting for window",
flush=True)
T0 = time.time()
while not subprocess.run(
["xdotool", "search", "--name", "Xenia-canary"],
capture_output=True, text=True).stdout.strip():
if time.time() - T0 > 60:
print("FATAL: no window after 60s", flush=True)
return
time.sleep(1)
print(f"[{time.time()-T0:6.1f}s] window exists, recording", flush=True)
glyph_out = open(os.path.join(OUT, "glyph-timeseries.tsv"), "w")
glyph_out.write("# t_s\tglyph\n")
xma_seen = set()
xma_out = open(os.path.join(OUT, "xma-param-arrivals.tsv"), "w")
xma_out.write("# t_s\tline\n")
XMA_RE = re.compile(rb"XMA-PARAM.*")
p, n = _open(), W * H * 3
seg = time.time()
log_pos = 0
while time.time() - T0 < DURATION:
el = time.time() - T0
if time.time() - seg > 30:
p.kill(); p = _open(); seg = time.time()
a = grab(p, n)
if a is not None:
g = glyph(a)
glyph_out.write(f"{el:.2f}\t{g}\n")
glyph_out.flush()
else:
p.kill(); p = _open(); seg = time.time()
# Drain any new XMA-PARAM lines that arrived since last check --
# stamped on ARRIVAL (Xenia's own log lines carry no timestamp),
# same technique xma_readoff_trace.py already uses.
try:
with open(canary_log_path, "rb") as f:
f.seek(log_pos)
chunk = f.read()
log_pos = f.tell()
except FileNotFoundError:
chunk = b""
for line in chunk.splitlines():
if XMA_RE.search(line):
key = line
if key not in xma_seen:
xma_seen.add(key)
xma_out.write(f"{el:.2f}\t{line.decode('utf-8','replace')}\n")
xma_out.flush()
print(f"[{el:7.1f}s] NEW {line.decode('utf-8','replace')}",
flush=True)
p.kill()
glyph_out.close()
xma_out.close()
print(f"[{time.time()-T0:7.1f}s] killing emulator, "
f"{len(xma_seen)} distinct XMA-PARAM lines seen", flush=True)
proc.terminate()
try:
proc.wait(timeout=10)
except subprocess.TimeoutExpired:
proc.kill()
canary_log.close()
if __name__ == "__main__":
main()