CONCEDED. I set the falsifier as "at 120 the publisher splash runs 2.125 s against cold boots measuring 4.30/4.60/4.37". 2.125 s is the declared ANIMATION length; 4.3 s is how long the SCREEN is up. The screen holds after the timeline ends, so those are different quantities and the comparison would have found a contradiction at ANY units-per-second. The Decoder also checked the defence I handed them -- that the dwell corpus might be emulator-contaminated -- and declined it. Their capture reproduces those boots (publisher 4.263 s, developer 3.457 s, four runs agreeing). They could have waved my numbers away and did not. 🔴 BUT FOLLOWING IT THROUGH FOUND SOMETHING NOBODY HAD SAID: THE PORT HAS NO HOLD. publisher declared 255 units measured 4.270 s animation at 60 = 4.250 s developer declared 210 units measured 3.527 s animation at 60 = 3.500 s The port's screen time IS its animation time; the residual is +0.02 s, i.e. none. The game, by the Decoder's counts, is on screen 219 presents and animates ~128 of them -- about 42 % hold. So if 120 is right, this port makes TWO ERRORS THAT CANCEL: it animates every splash 2x too slow, and it omits the hold entirely, and the two sum to almost exactly the right total screen time. That is why the dwell check passes, and authored/timing.json cited that agreement as proof -- "So the pacing was right all along and nothing changes in the code." Conditional on 120, that sentence is a coincidence. Corrected in place. ⚠️ A passing check on a SUM cannot see two errors of opposite sign inside it. Fourth member of today's family, after the non-inverting latch check, the unguarded buffer assumption, and the segmentation that nearly produced a convenient answer. 🔴 AND 120 EXPLAINS BOTH OPEN PLAY-TEST FINDINGS. 60 EXPLAINS NEITHER. finding 3, "the plate arrives late": at 60 full at 3.933 s at 120 1.967 s finding 4, "the game's fade is MORE PRONOUNCED": at 60 build-in 0.750 s, then the screen leaves at once at 120 build-in 0.375 s, then the screen HOLDS ~1.7 s At 60 the logo drifts in slowly and leaves; at 120 it snaps in and sits, which is what "more pronounced" describes. Finding 4 is explained twice over by one constant -- the fade is 2x slow AND the hold is missing. Every named cause for both findings has died over the past several iterations; 120 is the first hypothesis that accounts for either, and it accounts for both. This is not a measurement and I am not calling it decisive. It is the one thing the port can contribute that no capture can: what a human watching both reported. STILL HOLDING AT 60. Reach is one boot and they are not asking me to lift it. ⚠️ The hold and the constant are COUPLED. At 60 the port must NOT gain a hold -- the animation already fills the screen time and a hold would overshoot by ~40 %. The missing hold is a defect only if 120 is right. When it moves it is TWO changes: the constant, and a hold measured as (screen presents - animation presents), which must NOT be inferred from the total -- the total is exactly the quantity that cannot distinguish the two errors. Not settled: the constant; the clock origin; the ~1.0-1.2 menu residual. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AHUQvXGyNcKonSEWsgWcX
Sylpheed
A clean-room reverse engineering and port project for Project Sylpheed: Arc of Deception (Xbox 360, 2007).
Three things live here, in one repository so that a change spanning them lands as one commit:
| The decoders | crates/sylpheed-formats — the disc's formats, read and verified disc-wide |
| The port | port/ — a Godot 4 project, plus crates/sylpheed-export which converts a disc into the open asset tree it reads |
| The corpus | docs/re/ — what has been reverse engineered, with its evidence, its retractions and its dead ends |
You need your own copy of the game. No game content is in this repository and none ever will be. The exporter reads the disc you supply.
The oracle is the real game
sylpheed-cliand the Explorer are tools for verifying our decoding. They are hypotheses under test and they have been wrong. When something must be checked against the truth, the truth is the game running in Xenia Canary, captured — not any renderer of ours.
This is stated first because getting it backwards is the most expensive mistake this project has made.
Layout
crates/
sylpheed-formats/ the decoders. Disc-wide verified; the corpus is its spec
sylpheed-cli/ headless tools -- render a screen, dump a table, probe audio
sylpheed-viewer/ the Explorer: a human's window onto the disc. STATIC data only
sylpheed-export/ disc -> the open, moddable asset tree
port/ the Godot 4 project. Reads open formats ONLY
authored/ decisions that are NOT on the disc, each with its reason
data/
base/ generated by the exporter. Gitignored, never hand-edited
mods/ drop-in overrides. Yours
docs/
re/ the corpus: findings, refutations, method traps
game/ how the game is navigated -- menus, modals, flight
port/ the port's mission, its handoff contract, modding rules
-- and RUNNING.md, which is how you actually start it
agents/ how the agent team works together
tools/ capture harnesses, probes, the share tool
exchange/ transient inter-agent files. NOT in git
docker/ the agent containers
Where to start
docs/re/INDEX.md— what is decodeddocs/re/REFUTED.md— what has been tested and dieddocs/re/METHOD.md— traps this project has already paid fordocs/game/navigation.md— how the game is navigateddocs/port/MODDING.md— why the asset tree looks the way it does
Xenia Canary is a separate repository: it is a fork tracking upstream, and it carries our instrumentation.
Conventions
Confidence is per claim, never per document: ✅ CONFIRMED · 🟡 PROBABLE ·
❔ HYPOTHESIS · ❌ REFUTED. A withdrawn result is kept with its reasoning
rather than deleted — that is why the numbers here can be trusted.