17 Commits

Author SHA1 Message Date
sylph-decoder
4dd6a3f325 re: a bank's wave 1 is not a filtered copy of wave 0 -- and my own discriminator cannot finish the job
Coherence on BGM_103, the menu's bank, with controls run first: a real linear
filter of wave 0 reads 0.93-0.94 in every band, a different bank reads 0.001, and
wave 0 misaligned by 1 s reads 0.004-0.057. The measurement reads 0.027 at 1-4 kHz,
so the 'wave 1 is wave 0 filtered' model is refuted.

The frequency structure is inverted relative to any mic-pair or reverb model:
coherence rises with frequency (0.169 -> 0.827) while energy falls (71 % -> 0.2 %),
and a rear pair decorrelates fastest at HF. In the midrange the two waves are 13x
further apart than the two channels of one wave.

But the L-R control is what limits the tool and it is recorded as such: within one
wave, genuinely one performance in two channels, coherence is only 0.221-0.497. So
'same performance' does not imply high coherence here, my positive control was the
wrong model of the rear-pair reading, and the 🟡 is NOT settled. The tool tests for
linear filtering and neither surviving reading requires it.

Also corrects MISSION's Q10 row, which still carried the refuted three-sub-wave
premise and had directed work at a dead question for days. Its gate is in fact met.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 20:17:23 +00:00
sylph-decoder
2ea7b7eb3d re: my own MISSION correction was wrong on all three clauses
Two iterations ago I corrected MISSION.md's stale "🔴 Emulator-side questions are
blocked" banner and wrote, in its place, that the two items it named were
"unblocked, not answered ... both need a running menu, both now have one, and
neither has been attempted". I wrote that without reading either page.

Reading them:

  8AX vs ptbase was RESOLVED on 2026-08-29. Its status line says so -- both its
  questions closed, page kept for the evidence.

  The gamma control was attempted and half-answered, and its page records that
  the run "needed the emulator only to BOOT, not to reach a menu ... parked behind
  the title-screen blocker for no reason".

  So neither item ever needed a running menu, and the section's premise was wrong
  independently of whether the menu was reachable.

All three clauses false. The failure is specific and worth naming precisely:
replacing a stale status with an UNCHECKED one, in the same edit that criticised
the document for carrying unchecked status. sylpheed-port wrote a dead instruction
inside the commit fixing dead instructions; this is that shape, one document over.

METHOD: a correction is a new claim and needs the same check as the claim it
replaces. The urge to correct supplies confidence the correction has not earned --
check a replacement as hard as the thing it replaces, and hardest when the edit is
about checking.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 19:29:17 +00:00
sylph-decoder
123cfc8561 re: MISSION.md carried three stale headings -- the document nobody audits
I have been reading MISSION.md every iteration as instructed and never once
audited it, while auditing headings, instructions, env vars and fallbacks
everywhere else. It carried three false section headings, each superseded in
HANDOFF.md and nowhere else:

  "🔴 Emulator-side questions are blocked -- the title is not reachable here"
      False. Twelve emulator runs on 2026-08-30 reached the settled title, gated
      on the plate pulse, and drove it into the menu, EXTRAS and out of the
      archive. The two items the section named -- the gamma control and
      separating 8AX from ptbase -- are UNBLOCKED, not answered, and neither has
      been attempted. That distinction is kept.

  "🟡 Needs one more run -- a Japanese-locale capture", describing "one capture we
      cannot take". Taken twice, both committed, via jp_title_session.sh. And both
      questions it blocked are closed, one of them confirmed against that very
      capture. ⚠️ I noticed this section was stale several iterations ago, said so
      in a message, and did not fix it.

  "🔵 Needs a human decision -- rotation". Decided and implemented the day it was
      raised: HANDOFF records "OPTION A IS DONE. The reference renderer rotates",
      and ui_layout.rs carries the rotated blit with a control test pinning 0° and
      360° byte-identical to the unrotated path. The field is now confirmed from
      the ORACLE too -- +30/-45 predicting AABB heights of 1135.3 and 1301.1
      against 1134 and 1303 measured, both under 0.2 %.

All three corrected leading with the correction, originals quoted and demoted
beneath. Only FACTS were changed; the questions and their gates are untouched,
since keeping the document true is maintenance and changing what it asks would be
overstepping.

METHOD: audit the document that defines the objective, because it is the one
nobody audits. A document read only for instructions is never read for review, and
the more central it is the more often it is consulted and the less often checked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 19:15:40 +00:00
Sylpheed RE agent
590fc5bbff agent: tag the decoder states the port pins, and stop leaking credential config
Two fixes to push-work and the policy that goes with them.

**Tags.** The port's exporter depends on sylpheed-formats BY REVISION, so a
commit of ours is part of its build -- and the commit it pinned lived on one
auto/* branch and nowhere else. Deleting that branch orphans it; squash-merging
it is worse, because squash creates NEW commits, so main appears to contain the
work while the pinned sha becomes unreachable and the port stops building for a
fresh checkout. Silently, at their build, long after the breakage.

push-work now pushes with --follow-tags, which publishes annotated tags
reachable from the pushed commits, and MISSION.md says to tag whatever the port
needs. formats-pin-2026-08-29 at 76653ca is the first, created after the fact.

**Credentials.** This script set credential.helper as --local config, which
PERSISTS in the repository. The repo is a bind mount the host also uses, so the
host's git inherited a path that exists only inside the container and every host
push failed with "unable to get credential storage lock". Now applied with -c to
the single push. Same fix already landed on the port side; this copy still had
the bug and would have re-leaked on the next push.

Committed with a pathspec so the agent's in-flight work is untouched.
2026-08-29 10:59:14 +02:00
Sylpheed RE agent
0fd8e6953e re(ui): answer four of the port's five asks -- splash, fade-out, focus, gamma
1 SPLASH ADDRESSING (was blocking P3). No content predicate exists: design size
fails (every extra composable bundle sampled is 1280x720, like every screen) and
element count fails (fragments run 2..15, the splash halves are 3 and 7). But
GP_TITLE needs none -- `--all` adds exactly four bundles there and all four are
real screens, with the --all index equal to the pak entry index 1:1. And there
are TWO splash screens: 11/14 are the developer logos, 10/13 are the SQUARE ENIX
publisher wordmark, which the port did not have and which the boot shows first.

2 FADE-OUT (was blocking P3). It is (a), and it is bigger than the fade quad.
Every element ends on exactly ONE untimed keyframe, which rules out (b); that
block is where the screen plays out -- quad to a=255, buttons/labels/glows to
a=0, frames hold. (c) is refuted by a null test that discriminates: a black quad
alone holds the button/background brightness ratio constant, and through the
fade it falls 6.50 -> 1.94, 3.4x monotonic.

3 FOCUS (saves P5 rework). Over-vs-instead is unobservable -- the focused sprite
covers the base at 100.0% of base-visible pixels on three pairs once aligned
(true offset (7,7); the centre alignment reads a misleading 78-84%), and
compositing both ways differs by RMSE 1.1 inside the button rect. The real defect
is the focus record's SECOND element: ptbtn0Nf.rat declares ptbtneff01.t32 (a
42x46 glowing ring, focus only) plus the bright label, where the base declares
one sprite. That ring is the marker the port draws nowhere.

5 GAMMA. The capture is not neutral: capture ~ 255*(render/255)^g, g ~ 1.34-1.49,
and the chain says it is a ramp the GAME installed, not a capture artefact. So
RMSE against captures has a floor. Reach stated: the flat patches are all dark
(render ~0-60), so midtones and highlights are unconstrained.

4 ROTATION is a human's call and is recorded in MISSION, not acted on -- the port
rotating while the reference renderer does not would make verify-screen report a
large diff meaning "the port is right". The RE half is answered: rotation is
about the declared pivot, measured against a GPU capture.

The focus record's +20 element-count word is marked 🟡 not  -- read on GP_TITLE's
ten button records only; the disc-wide check is written and still running.
2026-08-29 08:19:23 +00:00
Sylpheed RE agent
9c16fa7860 re: a title negative that survives its own cross-check
Three earlier "the title never appears" claims came from instruments
later found broken -- a stale pixel oracle, a 41 s sampling interval, a
freezing stream. This one carries its own evidence.

title_probe_xchecked.py restarts its capture stream every 30 s AND prints
its reading beside an independent `import` grab every 60 s:

  1851 frames in 560.2 s = 3.30 fps
  cross-checks 9, disagreements 1
  max glyph 0

  t= 62s stream   6.05 | import   0.07  disagree (a fade, logos mid-transition)
  t=123s stream   7.40 | import   7.49  agree
  t=183s stream   8.18 | import   8.29  agree
  t=243s stream   0.23 | import   0.10  agree
  t=311s stream  89.68 | import  89.51  agree
  t=371s stream  80.97 | import  81.58  agree
  t=426s stream 117.43 | import 117.72  agree
  t=487s stream  77.71 | import  76.25  agree
  t=546s stream  70.43 | import  70.55  agree

Eight of nine agree within 2%, fps held at 3.30 with no collapse to 1.60,
and the surface moved through dark and bright phases. So the frames were
live: over 560 continuous seconds from launch, sampled 3.3 times a
second, the interactive title's green (A) plate never appears while the
game renders throughout. The final frame correlates 0.0145 / -0.0047 /
0.0102 with our title / main menu / EXTRAS renders -- attract-movie
content, not a UI screen.

Why remains unknown. live-title-press-a.png with its 753 glyph pixels
proves the title was reachable from this container on 2026-08-28, and
clearing the shader cache fixed the black surface but not this.

The two emulator-side questions (gamma control, 8AX vs ptbase) are
therefore blocked on a characterised failure rather than a suspicion.
Neither blocks the five menu screens, so I am returning to static work;
the probe is committed for whoever picks it up.

METHOD: a probe that cross-checks itself turns "no result" into a result.
2026-08-29 02:14:21 +00:00
Sylpheed RE agent
e492cee8b9 re: build the fast probe -- and it refutes the diagnosis that motivated it
Last iteration I blamed four failed runs on the probe sampling every
~41 s, slower than the title screen lasts, and withdrew three earlier
conclusions on that basis. Building the fix tested the claim and killed
it.

The speedup is real and control-verified. One long-lived ffmpeg x11grab
stream, raw RGB, glyph counted in numpy -- no per-sample process startup,
no PNG encode, no convert -crop:

  wrapper `screenshot`            3.98 s per sample (emulator running)
  import -window root -> PPM      1.20 s
  long-lived x11grab stream       0.29 s          13.7x

The counter is byte-identical to is_title.py: 753 on the committed title
capture, 327 on the main menu.

Pointed at a running game it says the opposite of what I expected:

  332 frames in  85.3 s = 3.89 fps; max glyph 0
  1674 frames in 420.0 s = 3.99 fps; max glyph 0

1674 consecutive samples over seven unbroken minutes, four per second,
zero green-(A) pixels. Sampling rate was a real defect that happened not
to be the cause.

So "neither locale reaches the interactive title without a pad press" --
withdrawn last iteration for want of evidence -- is reinstated, now as a
dense measurement, with its reach stated: a MID-RUN window only, silent
about the boot title.

Leading hypothesis, unconfirmed: the PRESS (A) plate appears only in the
boot title window and the attract loop's title carries none, which is
exactly what title_states_capture.sh was written to test. The experiment
is to start the fast probe from t=0 rather than attach to a run already
in progress.

METHOD: fixing the instrument is how you test the explanation that blamed
it -- a plausible mechanism is a hypothesis, and the fix is its
experiment, not its proof.
2026-08-29 01:34:40 +00:00
Sylpheed RE agent
924d4953d5 re: the boot harness was blinking slower than the title -- diagnosed
Four consecutive runs failed to reach the interactive title, across two
locales, two launch paths and two display-gamma settings. I attributed it
in turn to a stale oracle, to the locale, and to the attract loop. It was
none of those.

  one `screenshot` call, emulator running:  10.8 s
  one `screenshot` call, emulator killed:    0.117 s

92x, measured at a 1-minute load average of 1.80 -- so it is contention
with the emulator through the X server, not background load.
skip_intro.sh takes two grabs per iteration plus a numpy import, giving a
median sampling interval of 41 s in the last run (38/82/41/20/30/30/35/
47/46/45/44/43/21/19). The title lasts "a few seconds" before the attract
loop reclaims it -- wait_title.sh's own header says so. The harness was
sampling slower than the event it was waiting for. That also explains why
runs at 16:43-18:05 the same day succeeded.

Withdrawn as CAUSES, though the observations stand: "the JP run never
reaches the interactive title", "neither locale reaches it without a pad
press", and "the game sat in the attract loop for 604 s". The English
control did control for locale -- it just shared the same defect.

Also recorded: I set kernel_display_gamma_type = 0 for the gamma control
run, which brightens the frame (mid-attract mean 122.8 vs 52.5/82.8 at
type 2) -- and skip_intro classifies movie-vs-static on an ABSOLUTE rmse
threshold, so the gamma change biased the very classifier the run
depended on. Changing a display setting and a capture behaviour in one
run confounds both. Config restored to type 2.

The fix is not applied: make the probe cheap enough to outpace the title
window (small region, no convert round trip, one long-lived process).
Every remaining emulator-side question is waiting on that.
2026-08-29 01:18:05 +00:00
Sylpheed RE agent
2624008c93 re: the title capture is not reachable here either; stopping this line
Run 3 used the proven path rather than my own probe: launched exactly as
boot_menu.sh does (DISPLAY=:98, --apu=sdl, /dev/shm/xenia_* cleared, the
existing profile signed in) and drove skip_intro.sh, the detector that is
documented to work and that is stricter than mine (glyph >= 800 AND a
static frame).

It classified every one of 20 samples over 604 s as "movie", waited them
all out, and timed out. A direct check at 604 s says it was right: zero
green-glyph pixels, screen_id = other, warm mean (69,53,40), correlation
0.09 with build 7. The game really was playing attract movies for ten
minutes.

Three runs, two locales, two launch paths, ~35 minutes of emulator time,
no interactive title. Either the attract loop is far longer than the
600-780 s windows tried, or something regressed since
live-title-press-a.png was captured -- that one came from a pad-driven
boot (e21a9ab, "booting to the main menu and walking it").

Also settled a discrepancy I had flagged without checking: there is no
contradiction with title_states_capture.sh. It waits on screen_id.py, a
LOOSER oracle than is_title.py, and was written precisely to test whether
the interactive title draws ptbtn00 and the attract one does not. It
never claimed to reach the interactive title.

Stopping this line. The capture blocks none of the five menu screens and
has now cost five iterations. The locale mechanism, the fixed oracle and
the launch recipe are all committed, so what remains is patience with the
attract loop, not tooling. METHOD line on knowing when to stop paying for
a non-blocking answer.

Emulator stopped, lock cleared, locale English.
2026-08-29 00:49:49 +00:00
Sylpheed RE agent
105ed4d3e2 re: the English control removes the locale from the title-capture problem
Two iterations framed the JP title capture as possibly locale-specific.
It is not. Same flags, same oracle, English locale: 75 samples over 734 s,
every one glyph = 0. The English boot does not present the interactive
title either. Canary was alive throughout, polling
XamInputGetKeystrokeEx (1801 calls); the frame at 734 s has content but
correlates 0.15 with build 4's render and 0.05 with the main menu -- an
attract-movie frame, not title art.

So neither locale reaches the interactive title in ~12 minutes without a
pad press. What is actually untested is the pad: pad.py and
nav_to_flight.sh exist, and title_states_capture.sh reaches title states
with a flag set this probe did not replicate (--log_ui_draws
--ui_draw_capture_frames, plus xdotool window focus). It is a capture
problem, not a locale one. MISSION.md updated.

Also resolved a caveat I had given the port agent without checking it:
"rotation is decoded but not rendered" does NOT affect their five screens
at rest. Title, main menu, EXTRAS and both splash halves have ZERO
top-level elements with a non-zero rotation. The only rotations on any of
them are the title's two nested ptloop records (r = 30 and -45), and at
rest those sit at x = 1521 and x = -839 -- a 399-wide sprite entirely off
both edges of a 1280 screen. The caveat now applies only to animating the
title build-in, where the sweeps cross the screen rotated.

Two METHOD lines: run the control before theorising about the difference,
and log every sample so a failure is a measurement rather than a silence.

Emulator stopped, lock cleared, locale English.
2026-08-29 00:35:49 +00:00
Sylpheed RE agent
23f12a3710 re: fix wait_title.sh's stale oracle; the JP title still is not reached
Last iteration's "never reached the title in 787 s" was a broken tool
reporting on the world. wait_title.sh was still sampling the single pixel
(625,618) that is_title.py had already been written to replace -- its
docstring says why: a 1280x720 coordinate sampled against the 1279x675
game surface, so it always reads the copyright line. The replacement sat
in the same directory. wait_title.sh now delegates to it.

is_title.py passes its own controls before being trusted here: 753
green-glyph pixels on the committed English title capture, 327 on the
main menu, threshold 400.

Re-ran with the working oracle and the profile flag the English captures
use. The game STILL did not present the interactive title -- but that is
now a measurement rather than an artefact: not one frame showed a single
green-(A) glyph pixel, and content correlation against either build-7
render never exceeded 0.22. Canary was alive and polling
XamInputGetKeystrokeEx (601 calls), sitting in the attract movie.

So the open question narrowed again, and is written into MISSION.md:
whether the attract loop returns to the INTERACTIVE title without a pad
press. title_states_capture.sh claims it does on the English boot with no
pad input; if that holds, the difference is the locale.

Nothing decided about the keyframe-time association or the rest() rule.
Emulator stopped, lock cleared, locale restored to English.
2026-08-29 00:21:44 +00:00
Sylpheed RE agent
948273883f re: the JP-locale capture is not blocked -- I stopped one grep too early
Last iteration I wrote into MISSION.md that a Japanese-locale capture is
impossible here, because user_language is DECLARE_int32 at four call
sites with no DEFINE and no entry in xenia-canary.config.toml. That is
true, and it was not the question. The language is PERSISTED:
kernel_state.cc builds XConfig over <storage_root>/xconfig.settings,
SetDefaults() only supplies a value when the file has none, and the file
is writable. Checking where a setting is stored rather than where it is
configured turned "blocked, needs a human decision" into a two-line edit.
Withdrawn from MISSION.md; METHOD and REFUTED lines added.

The field is located from struct landmarks rather than a hard-coded
offset, and the check re-runs on every invocation so it fails loudly if
the layout moves:

  music_volume 0.7f at User+449  -> BE float at 2727 -> User base 0x8e6
  language          at User+44   -> reads 1 (kEnglish) at 0x912
  country           at User+64   -> reads 103 (US) at 0x926

XLanguage::kJapanese = 2 (xbox.h:307). set_console_language.py wraps it
with a backup and a --restore.

The capture itself is still NOT taken, for a smaller reason than I
claimed. A run with the locale set to Japanese booted fine but never
reached the title in 787 s: wait_title.sh's green-(A) oracle never fired
and burst-sampling found no frame correlating above 0.18 with either
build-7 render -- the run sat in the attract loop. So it needs a longer
or pad-driven run, not a rebuilt emulator. Emulator stopped, lock
cleared, locale restored to English.

Nothing is decided about the keyframe-time association or the rest()
rule; this only changes what standing between us and deciding them.
2026-08-29 00:05:58 +00:00
Sylpheed RE agent
00b6259e9a re(ui): finish the top-level rotation census; record the JP-capture blocker
Two threads had converged on needing one capture this container cannot
take, so this iteration records that and finishes something reachable.

BLOCKED, written into MISSION.md rather than worked around: Q1's keyframe
time association and the rest() rule for plateau-less elements both now
hinge on a running capture of GP_TITLE build 7, the Japanese title. The
console language is not settable here -- user_language appears only as
DECLARE_int32 at four call sites with no DEFINE anywhere in the tree, and
it is absent from the registered cvars in xenia-canary.config.toml. There
is no flag to pass, and guessing one is specifically unsafe: run-canary's
own header records that xenia calls ShowSimpleMessageBox from
ParseLaunchArguments before logging starts, so a bad flag blocks forever
with an empty log. Rebuilding canary to add the cvar would be improvising
around the blocker; it needs a human decision. Neither question blocks
the five menu screens.

FINISHED: the disc-wide top-level rotation count, left running four
iterations ago as a shell loop over `screen info --geometry` that never
completed (it decodes every texture per build). Walking the placement
region directly takes seconds.

  top-level elements with a keyframe group   15 493
  carrying a non-zero rotation                2 152  (13.89 %)

Both controls pass: GP_TITLE build 4 reports 0 (its rotations are the
nested ptloop records) and GP_DIALOG build 0 reports the expected two.

The control earned its place -- the first version indexed the pak with a
`screen list` BUILD number and got 0 for a screen that has two, because
GP_DIALOG build 0 is entry 2. GP_TITLE maps 1:1, which is how the
assumption survived. METHOD line added.

Two free corroborations of the rotation decode. The rotated population is
dominated by tactical-map ship icons -- pbb_destroyer 444, pbr_destroyer
402, pbr_fighter 276 -- i.e. markers rotated to heading, the single
largest use of the field on the disc. And GP_TITLE entry 7's Japanese
wordmark pieces settle from ALTERNATING tilts:

  ptlogo3a  r = 0, -14, -4, -1, 0, ...
  ptlogo3b  r = 0, +14, +4, +1, 0, ...
  ptlogo3c  r = 0, -14, -4, -1, 0, ...

Same magnitudes, opposite signs, all decaying to upright. A misread field
does not produce that.
2026-08-28 23:46:54 +00:00
Sylpheed RE agent
4820865835 re: S1 -- the Ready Room probe is a no-go, and not for the reason the
question expected

One iteration, as the mission gates it, and no Ready Room work started.

The two criteria it named both pass. It is NOT 3D: the corpus already
holds a capture of the running screen and it is a flat six-item menu in
the same visual language as the title. And unrecoverable paths do not
mean unrenderable screens -- content enumeration finds 60 builds in the
1106 entries.

What kills it is something the question did not ask. GP_READY_ROOM.pak
does not appear to hold the Ready Room's own menu at all. Two signals
agree: the four largest builds composite to briefing panels -- a planet
readout, unit markers, direction arrows -- and, much harder, the 902
bundles declare 317 distinct element names of which NONE matches any of
the six labels on the screen (takeoff, brief, hangar, pilot, option,
mission, ready all return nothing). The pak is the briefing /
tactical-map content behind the BRIEFINGS item. If this is ever picked
up, the first job is finding where the menu lives -- GP_BUNK.pak is the
obvious place -- not naming this pak's keys.

The probe also reaches back into something already delivered: kind ==
0x3002 finds ZERO buttons across all 902 bundles here, while GP_TITLE has
16. 0x3002 is one member of a 0x3000 family with sub-bits, and this pak
uses 0x3000/0x3004/0x300c/0x3008. Nothing in the milestone changes --
every screen in scope is GP_TITLE -- but the handoff now says not to ship
that equality as a general button test.
2026-08-28 18:24:48 +00:00
Sylpheed RE agent
8e58077962 port: add Q10 -- what a music bank's sub-waves actually are
BGM_001.slb is three sub-waves (10 KB, 4.47 MB, 4.67 MB) and the decoder
concatenates them into one 347 s track. That is a default nobody chose, not a
decision: two near-equal halves could be intro + loop, two variations, or two
halves of one piece, and a menu that loops its music needs to know which.

Found while wiring the Audio Library up to the shared banks. Recorded in
HANDOFF.md as a trap too, so the port does not build looping on top of the
concatenated track before the question is answered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 17:43:25 +02:00
Sylpheed RE agent
880e6ebe83 port: the container agent answers the questions, it does not build the port
Corrects the split I got wrong in 965c3f7. The container is for reverse
engineering, now focused on the menu port; a SEPARATE agent builds the port from
its investigation results. My previous version had the container agent writing
the exporter and the Godot project, which is not the intent.

This lands on the research/engineering line that was already in the estimate:
the container agent takes the research half, the port agent the engineering half.

docs/port/MISSION.md is now a list of open QUESTIONS (Q1-Q9) rather than build
milestones, ordered by what blocks the port earliest -- the keyframe time unit,
which build is which screen state, paint order for the six screens, button ->
GamePart, navigation semantics, the boot sequence driver, transitions, menu
audio bindings, and video binding. Each is done when a written result with
evidence exists, not when something compiles. S1, the Ready Room probe, stays
gated at one iteration and a go/no-go.

Most of these are BEHAVIOUR questions -- timing, transitions, what a d-pad press
does at the end of a list -- so the mission and the loop prompt both push hard
on measuring the oracle rather than reasoning from the file.

docs/port/FORMAT.md is deleted. The export schema is the port agent's design and
was not mine to specify. It is replaced by docs/port/HANDOFF.md, the single page
the port agent reads: a status table, what is already settled and can be relied
on today, and the facts that will trip the port up (the WMV3/WMA Pro intro, the
Static.slb size over-declaration, the voice-vs-music downmix, JNGL_001).

The derived/authored idea survives as the thing it always was -- a finding, not
a design. Every answer must be classified DECODED, MEASURED or UNDECODABLE-with-
reach, and never a fourth thing, because measured and undecodable both mean the
port agent is authoring that value and has to know it. Labelling a guess as a
decode would put it into the port wearing the badge of a measurement.

Reverts the Godot install from the RE container, its AGENT.md section, and the
export/ gitignore entry -- none of that belongs on this side of the wall.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 17:16:47 +02:00
Sylpheed RE agent
965c3f70fd port: make the Godot menu shell the agent's primary objective
Sets a new mission: boot the real disc through developer splash -> intro video
-> title -> main menu -> submenus in Godot 4, interactively, with no gameplay,
no 3D and no emulator.

docs/port/MISSION.md defines it -- eight gated milestones, each finished by an
ARTIFACT rather than by compiling, plus the Ready Room as an explicitly gated
stretch goal with a one-iteration probe that decides go/no-go. GP_READY_ROOM is
1106 entries with 6 recoverable names and is ISL-scripted, so it is either a
week or a quarter, and the agent must not start it on its own authority.

Architecture, per the user's decision: the Godot project is INDEPENDENT of the
Rust viewer and never reads a disc format. An offline Rust exporter converts the
disc into open formats; Godot reads only those. No GDExtension, no Rust in the
Godot project, and sylpheed-viewer is off limits -- it stays the human's
verification tool with its static-data rule intact.

docs/port/FORMAT.md specifies the open format, versioned, because modding is the
port's second goal and that makes the layout a deliverable rather than a temp
directory: JSON over XML (Godot parses JSON natively; its XMLParser is SAX),
names never hashes, provenance in every generated file, and unknowns listed
rather than guessed.

The discipline the whole thing rests on is the derived/authored split. `export/`
is regenerated wholesale and never hand-edited; `authored/` is hand-written and
survives a re-export. Three things this milestone needs are NOT on the disc in
any decoded form -- which button does what, paint order, and menu sound cues --
so they live in `authored/` with a stated `why`. Deleting an authored entry
because the exporter can now emit it IS the measure of progress.

`export/` is gitignored: it is generated from the user's own disc and this stays
a clean-room repo.

Container: adds a pinned Godot 4 (windowed under Xvfb for screenshots, plus a
headless wrapper). ffmpeg already carries libtheora, which is the video target --
Godot 4 plays only Ogg Theora natively and the disc's ADV.wmv is WMV3/WMA Pro.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 17:11:35 +02:00