1ca90bfbd688abdfbd4df6895aaa951ce7497279
14 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a84eb14900 |
port: close their XPR lead, and find their class in the lane I called clean
They flagged five XPR_* texture toggles as relevant since I consume textures, and my off-edge splash residual -- non-tonal, ~0.5 RMSE above quantisation, no candidate -- has the shape a subtle decode difference would produce. Closed: the toggles live in texture.rs::decode_surface, shared by from_xpr2 and cube_faces_from_xpr2, and my exporter calls neither -- sprites come from t8ad::parse. t8ad.rs reads no environment variables in its 202 lines, so the sprite path has no hidden freedom either. The candidate is eliminated with no replacement. Enumerating what my exporter reaches turned up SYLPHEED_KF_TIME_SHIFT, which they reported as absent from crates/. True on their branch, false on mine: my ui_layout.rs is the stale era and the knob is live at line 497. The pinned tag has 0 occurrences (2 of LEGACY) so export/ cannot be perturbed, but verify-screen builds its reference from the workspace, which can. Tested both directions: with the knob the reference reports rest t=12, the corrected reading, and the era guard passes; without it, t=70 and the guard refuses. So the knob is the working remedy that makes a workspace-built reference usable, and it appeared in no tool, help text or instruction in my tree -- their exact class, in the lane I had just told them was clean. The refusal message now carries the remedy. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
66f0adce02 |
port: sweep instructions above descriptions -- the silent class is clean, two loud hits
Their sharpening: a stale instruction manufactures a false confirmation, strictly worse than a stale description that merely misleads. Applied to my instruction surface, the documented invocations in tool and script headers. All fifteen distinct flags across those examples are parsed, so nothing in my headers can produce their failure mode by being inert. But 'parsed' is a proxy and its gap is known -- --shots parses and does nothing on the --boot path -- so I ran two documented examples end to end rather than trusting the grep, and both produce a 1280x720 frame. Two hits, both loud rather than silent: 11 references to tools/verify-capture and tools/verify-screen, paths that do not exist since the tools are under tools/port/ (fixed in 4 files); and check-all claiming eleven tools where there are fourteen (now states both so the sentence dates itself). The distinction worth recording: mine fail loudly, theirs failed silently. A wrong path announces itself; an inert environment variable returns a clean wrong result. Both are stale instructions and only one manufactures evidence. Honest limit: I tested the flag surface plus two examples end to end, not all thirteen documented invocations -- the --boot ones take 156 s each. That is a judgement about cost, not a claim of coverage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
d725f8e2f8 |
port: the dead-rule grep found two more, and the cause is my correction habit
Their generalisation of my 'untimed' marker -- search for the vocabulary the dead rule needed -- is the cheap version and it works. Swept for the nouns of every rule refuted this session. Two real hits: verify-screen:57 still asserting 'all four are COMPOSITED rather than standalone', the reading withdrawn after they tested it disc-wide at 7.9%; and boot.gd:197 opening with the pre-fix 'no time slot' claim before retracting it. Third and fourth instance after spin_period_units and exit_ramp_units, and in all four the correction sits below the false claim in the same block, with both written by me. The diagnosis is a habit: my corrections are ADDITIVE. I append a CORRECTION block and leave the original standing, which is right for a record and wrong for a statement -- a reader takes the first assertion and the retraction three lines later has already lost. The habit that creates these is the same one I adopted to make corrections honest. Fix: keep quoting the original but demote it grammatically, leading with 'what this used to say'. Both rewritten. Verified comment-only by artifact rather than by reading -- the main_menu render is byte-identical before and after. Also records agreement with their caution: the failed gap+clear rule was rejected, not narrowed to menu transitions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
d8488640a8 |
port: my backdrop predicate is exact in GP_TITLE and its reading was wrong
I offered 'a declared opaque-black backdrop distinguishes standalone from composited' and asked for it to be tested against archives I do not have. It was. The split reproduces exactly: derived independently from the disc, GP_TITLE gives 12 with and 4 without, the four being entries 0-3 -- my build_00, build_01, press_start, press_start_jp -- with element names matching. Two genuinely different paths, my export against their disc reader. The reading does not survive. Disc-wide the predicate is rare, 76 of 965 builds at 7.9%, with GP_HANGAR_ARSENAL 0 of 390, GP_OPTIONS 0/14, GP_PAUSE_MENU 0/6. Read as 'composited' it makes 92% of the game composited, which the archives do not support. What survives is narrower: it separates screens that BEGIN FROM BLACK from everything else, and their sharpening is the part I would not have reached -- the negative class is heterogeneous, so a two-way rule cannot express it. My caveat named the exact test that refuted the reading, but I still put the refuted interpretation into verify-screen's header as a stated fact while the hedge lived in DECISIONS.md. Corrected, with the 7.9% figure and an explicit do not carry this into the four unexported archives. Hedging in the write-up does not protect the claim shipped in the tool -- the same delivery gap as the capture-phase term, repeated four iterations after fixing it once. Within GP_TITLE the rule is exact and --black for those twelve is justified from the file rather than assumed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
c6735f55a6 |
port: audit the --black premise -- declared on 12 screens, assumed on 4, all composited
Their finding that screen render --black's premise is declared on the splash builds is checkable across my whole export, and verify-screen passes --black to all sixteen screens on that premise. Audited by asking whether a screen declares a full-screen untextured primitive at t=0 with fade_argb 0xff000000. Twelve do -- pteff00 on both titles, both menus and both extras, palogo_eff0 on all four splashes, pgloading_eff00 on build_12/15. Four do not: press_start, press_start_jp, build_00, build_01. All four exceptions are composited rather than standalone. press_start is one element, the plate, whose own name_why records it is composited over the title. build_00/build_01 carry the pgloading_* set without the pgloading_eff00 backdrop that build_12/15 declare. Harmless where used: verify-screen gives --black to both renderers so the assumption cancels in a consistency check, and verify-capture already scores the plate over the title rather than on black. The exposure was real and the tooling had already routed around it, which could only be established by looking. The rule that falls out: a declared opaque-black backdrop distinguishes a standalone screen from a composited one, derivable from the file rather than from a name. Recorded as a rule with its evidence -- sufficient as observed, not proven necessary, on four exceptions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
dbbf28e22f |
port: my branch IS the stale era, and verify-screen's reference was never its own build
Told the Decoder their diagnosis was wrong. They were right. ui_layout.rs is md5 b6c19d08 in my working tree, at HEAD, on my pushed branch and on origin/main -- one file, stale marker present, tree clean. What misled me is the same trap a third time: CARGO_TARGET_DIR is a shared /sylph-home/port/target-container, so two source trees write one binary and cargo fingerprints per source path -- each build reports Finished while the binary on disk belongs to whichever tree wrote last. A CLI built from my workspace is 3a39fce (stale, rest t=70), identical to one built from origin/main; the binary verify-screen actually used was 8e0aa76 (fixed, rest t=12), from a tree nobody had named. It happened to be the right era, which is worse than wrong -- it agreed with the pin by luck and one rebuild would have flipped it silently, and title_jp differs by 74507 px between eras. verify-screen now reads the reference CLI's pteff00 rest instant and compares it against the export the port reads, refusing to score if they disagree. Controlled both ways: passes with the matching binary, refuses the stale one built from my own workspace. And the pin is load-bearing, not an annoyance to revert: the workspace crate is stale, so the pin is the only reason the export is correct. Consequence worth stating -- my published branch carries the stale crate, so anyone building sylpheed-cli from it gets the stale decoder. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
a43dee3ab0 |
port: the loading screens are no longer black -- it was the paint order
verify-screen's header has said since P1 that build_12/build_15 render pure black in both renderers, with an open question whether that was the port's bug or the decoders' reading of rest. Measured today: max 214.5 on both sides, mean 1.949 port against 1.918 reference. Not blank, and they agree. It was the paint order. My own earlier measurement had already answered it and I had not connected them: removing the forced-backdrop pass makes the first element pgloading_loop5 and the black screen returns. pgloading_eff00 carries layer: null, layer_source: none -- the only elements in the export with neither a read nor an implied key -- so its position rests entirely on the occlusion constraint. The guard stays, with the stale paragraph kept as history. It was right when written, and a guard that stops firing is the kind that rots out of a tool. Refutation attempt on the Decoder's census scope: my six transient ptlogo_back2eff* on title are also GP_TITLE, so if they were fallback fires their count of four would be wrong. Their claim survives -- all six reach rest by the plateau path, alpha 255->255 with identical pos and scale, so the fallback never runs. The two censuses differ in scope, not in fact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
835acf930e |
port: WITHDRAW the claim that the port drifted away from the game -- wrong frame
The previous entry scored verify-screen's title_jp frame against the oracle and concluded the port had moved away from the game. That frame is posed --pose=rest, which the port does not ship. Posed as it runs, the disputed block scores +0.9994 against the reference's +0.8727, and the whole surface +0.9652 against +0.9200 -- holding under gamma compensation and on the English control (+0.9946 vs +0.9560). The port is closer to the game than the reference on both title screens. Mechanism: ptlogo_back2eff1 is (0,0)(98,0)(100,255)(102,255)(104,0) -- a 4-unit sparkle whose rest.t is the peak of its own flash. Six of them stagger across the logo, so --pose=rest fires every sparkle at once. The 25.6% excess light was real and was in a frame nobody sees. verify-screen is not at fault: it poses rest deliberately, so that both renderers read one decoder and the run is a consistency check. I used a consistency-check frame for a correctness question. Its header now says its frames must never be scored against a capture. A second claim in that entry was also wrong -- both screens draw those layers under pose=rest; I had compared a --menu timeline log against a verify-screen rest log and read a mode difference as a screen difference. verify-capture takes a fifth per-row field, a capture crop, because this capture is a full display frame with the surface at +0+45 while the others are pre-cropped. With it title_jp reads RMSE 20.91 / 1.04%, beside title's 14.16 / 0.21%. The row prints 'no capture' until their branch merges. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
8ae0ec2287 |
port: verify-screen was nondeterministic; pin the pulse phase in the harness
Running the full set after the plate fix, press_start returned over3 5021, 8919, 5021 on three identical runs. The plate's looping focus record takes its phase from time_units, which free-runs, so the captured frame lands wherever the grab fell -- while the reference renderer cannot pulse at all. The port is not the thing that is wrong: the pulse is measured and a thing that pulses does not stop because the screen arrived. ScreenView.loop_phase_units pins it, negative means free-running and stays the default everywhere, and only the harness passes --loop-phase=0. Controlled: pinned, 3 runs identical; free-running, 3 of 4 identical and one different. That 3-of-4 is why it survived -- it looks deterministic most of the time, and without the negative control a no-op flag would have been indistinguishable from a fix. With the phase pinned press_start reads max 1 / over3 0 OK -- the recorded baseline exactly. Fifteen of sixteen rows now match. The sixteenth, title_jp, has genuinely drifted: 155/20498 -> 233/61208, deterministic, on the Godot side, localized to one 350x396 block at (405,74). There is no capture of the Japanese title, so I can say the renderers moved apart but not which moved. Recorded as an ask, not resolved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
71243bcc60 |
port: confirm no screen of mine carries a .tbm, and guard verify-screen anyway
The Decoder found that sylpheed-cli screen render silently omits the background of any .tbm-bearing build, and stated that none of my screens has one. That is a claim about my tree and it decides whether my regression baseline is sound, so I tested it: zero .tbm across all 16 builds in my manifest -- wider than the five they said. Both controls fired (GP_TUTORIAL build 0 -> pubase.tbm; GP_TITLE build 5 -> none); my first attempt's control printed nothing and I nearly read that as agreement. verify-screen now names the omission on any .tbm-bearing row. It cannot fire on a screen I ship -- which is how a guard goes dead -- so its expression is controlled directly in both directions. No verdict or bar changes. Regression unchanged: title max 6 / over3 790, main_menu max 4 / over3 0. Their identification (reading TUTORIAL off the framebuffer) and my edge correlation (run before their message, blind to the text) agree on GP_TUTORIAL build 0 from no shared assumption. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
fd6d9b6d47 |
port: add check-all; verify-screen ignored its own statistic; 'six expected DIFFERS' was wrong
Eleven tools and nothing ran them together -- the ninth instance of correct, documented and unexercised, one level up. check-all runs the four that assert, reports the oracle table, and gives verify-screen an allowance that EXPIRES when the pin lands rather than standing forever. All eleven exercised first; none had rotted. verify-screen computed over3 because 'a single max cannot tell 2 pixels from 25 444' and then decided the verdict on max alone: main_menu (max 4, over3 0) read DIFFERS while extras (max 3, over3 0) read OK. The bar is unchanged; a frame with no pixel over it now gets its own ROUNDING verdict. And corrects a claim I have given the Decoder more than once. The real count was ten, now eight: six forced-backdrop, two rounding, and TWO UNEXPLAINED -- title at 790 px and title_jp at 20498, neither carrying a forced element. My leaf hypothesis is refuted: emptying draw_leaf_for changes the numbers not at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
bb9626defe |
port: the game decodes all three voice streams at once, and two baseline rows were comparing blank frames
TWO FINDINGS, one mine and one handed to me, and the second retires a premise I built on twice. THE P1 BASELINE HAD ROWS THAT PROVED NOTHING. `build_12` and `build_15` render pure black in BOTH renderers -- mean 0, max 0 -- so the difference is zero and `verify-screen` scored them `max 0 over3 0 OK`, the strongest verdict it has. Two of sixteen rows were comparing nothing against nothing. Worse than a missing test, because a missing test is visible in the count. Cause isolated by a control, not by reading: `build_00`/`build_01` are the same loading screen minus three elements and render fine (mean 1.913, max 214.5). The dressed variants add `pgloading_eff00`, a 1280x720 primitive resting OPAQUE BLACK at t=38 inside its own opening black hold, with no layer key so paint order puts it last. The rule I was about to write -- "rest.t before the last timed keyframe is the pathology" -- was killed by running the census first: 152 of 212 elements in this export have rest.t earlier than their last timed keyframe. It is the norm. What is actually unusual is the CONTENT, and its reach is one: `pgloading_eff00` is the only element in the export whose resting pose is a fully opaque full-frame quad. One instance is not a rule, so the renderer is unchanged and the HARNESS is fixed: a blank pair now reports BLANK -- both renderers drew nothing; this row proves nothing. `status` is untouched, so an unrelated DIFFERS still fails. THE VOICE EXPORT IS KNOWN INCOMPLETE. The Decoder booted Canary with --xma_param_probe and the game decodes ALL THREE streams CONCURRENTLY, in three XMA contexts whose byte sizes match the disc payloads exactly. So "three presentations of one take, pick one" is refuted by the running game and the question I had been arguing -- WHICH presentation -- has no answer. This one no census could have caught. Every measurement was right: the streams are equal-duration, one is silence, one is 0.60x another with the residual 26.8 dB down. The frame around them was wrong, and the file says ChannelMask 0x0002 on all three. It took the running game -- which is the mission's own sentence arriving in practice. BEHAVIOUR HELD DELIBERATELY. An equal-gain 1/n sum of channel pairs is not a downmix either -- MISSION section 6 pins an explicit matrix for exactly that reason -- and summing cost S00A 6.02 dB when one stream was silence. Swapping one guess for another on a message is what produced this entry twice. What changed is that the wrongness is now LOUD, because this failure sounds like success: one stream is clean audible dialogue. A top-level manifest warning per movie, the console line, and the authored entry all say `1 of 3 streams`. "They are 5.1" is recorded as the Decoder's HYPOTHESIS with its own counter-evidence attached, and nothing builds on it. What settles it is asked: a recording of the game's own output over ADV through the null sink, which turns channel roles into a fit against an oracle. Refutation attempt, survived: the Decoder's loading-screen variant map. Entries 0/1 carry 7 elements and 12/15 carry those seven plus baseeff, eff00 and loop5 -- exact in count and identity, and it is what made build_00 a control. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF |
||
|
|
cdea236713 |
port: the P1 regression harness could not have run since the monorepo merge
verify-screen resolves its reference binary to a path build-reference-cli
stopped being able to produce: that script greps Cargo.toml for a
`Syplheed-Reborn.git", rev = "..."` pin, and
|
||
|
|
65cefa74c3 |
monorepo: one repository for the decoders, the port and the corpus
Some checks failed
Merges the Godot port into the reverse-engineering repository, preserving both
histories -- 1019 commits of corpus plus the port's 31, brought in by subtree
merge and then moved into place so git can follow each file across the rename.
The reason is not tidiness. The two-repo split forced the exporter to depend on
the decoders by pinned revision, and that created a whole class of failure that
now disappears: a sha reachable only from a topic branch, orphaned by a
squash-merge, breaking a fresh checkout silently at build time. It also forced a
live read-only mount of one agent's working tree into another's container, which
is why a contract file could move mid-iteration. With a path dependency, a
decoder change and the exporter change it requires land in the same commit or
not at all.
Canary stays separate: it is a fork tracking upstream.
New structure for the long term:
docs/game/ how the game is NAVIGATED -- menus, modals, prompts, alerts,
and in-game flight. Written so nobody rediscovers it. Mostly
open questions on purpose; the in-game tutorials are the
resource for the flight half.
docs/port/MODDING.md
modding as a constraint on the exporter TODAY, not a later
feature: one logical asset in one file (the disc splits nearly
everything, and resolving that is the exporter's job), names a
person recognises, PNG/OGG/OGV/JSON only, base-and-overrides so
re-exporting is always safe, provenance in every file.
data/base + data/mods
generated tree and drop-in overrides, both gitignored
exchange/ transient inter-agent files, deliberately outside history
docs/agents/ the team protocol
Both the README and the navigation doc lead with the correction that cost the
most: the oracle is the real game under Xenia Canary. Reborn's renderer is a
hypothesis under test, it has been wrong, and treating it as ground truth
propagated into three documents and both agents before a human caught it.
Scripted modding stays possible without being built: no screen name is hardcoded
in GDScript and there is no native code in port/, which is what Godot Mod Loader
needs to be able to substitute behaviour later.
|