agents: the splashes exactly, and stop photographing a moving thing
Some checks failed
CI / Native — macos-latest (push) Has been cancelled
CI / Native — windows-latest (push) Has been cancelled
CI / WASM — Web (push) Has been cancelled
CI / Formatting (push) Has been cancelled
CI / Native — ubuntu-latest (push) Has been cancelled

A human played the port on real hardware for the first time (2026-09-01) and
found four things. Two were port defects, fixed. Two are open and are now both
agents' focus: the PRESS (A) plate arrives late, and the splash fade/blur is
weaker than the game's.

Their verdict on method is the reason this is a brief change and not a ticket:

  "the agents were essentially guessing and trying to copy what one would see,
   but while they did get close it still is not quite right"

Close-but-not-right is the signature of reproducing APPEARANCE instead of
deriving MECHANISM. So the Decoder's focus block asks, in order: is there a
post-process pass at all, what is it, where do its parameters come from -- and
only then what curve. Both routes, dynamic (GPU state, shader constants, render
targets; add logging to Canary, it is theirs read-write) and static (.pe, the
DB, the paks), with each fact labelled by which produced it.

TEMPORAL-VERIFICATION.md is the other half, and it generalises past the
splashes. We have been photographing the game at time t, and t is never the
same twice: emulator speed varies with host load, Canary presents at ~28.1 fps,
the capture path costs a variable 0.1-10.8 s, and a long-lived x11grab stream
degrades and then freezes. The register already carries FOUR refutations of
exactly this shape. The replacement rule: record a film, not a photograph;
align by CONTENT, not by clock, and report the lag as a measurement rather than
minimising it away; prefer ordering, counts, durations and shape over any value
at a wall-clock instant; anchor on an event; report achieved fps against
requested fps.

Also into both briefs: the input set. The port had no joypad binding for (A) or
(B) and nobody noticed for a whole milestone, because --script sends
InputEventAction, which BYPASSES the input map -- so every check asserted the
code below the map and nothing about the map. The Decoder is asked to DECODE
the full set the game reads rather than discover it by pressing buttons; the
Port is told input is verified at the device level or not at all.

And both briefs now point at the R1 register reclassification, because two of
the ten re-opened entries land on this focus: "the declared keyframe timeline
reproduces the captured splash" is 🟡 our-reader, and the rest() pair is open
in BOTH directions -- while the two splashes are the only screens that reach
that fallback.
This commit is contained in:
MechaCat02
2026-09-01 17:59:17 +02:00
parent 1b1a4dfcd3
commit aad3fb382e
4 changed files with 395 additions and 0 deletions

View File

@@ -1,6 +1,60 @@
You are the **Decoder**. Answer the open questions the Godot menu port is
blocked on, one at a time.
## 🔴 CURRENT FOCUS, set by the human 2026-09-01: THE LOGO SPLASHES, EXACTLY
A human played the port on real hardware and reported that the splashes are
**close but not right** — the fade/blur is more pronounced in the game — and that
the `PRESS Ⓐ` plate arrives late. Read
[`PLAYTEST-2026-09-01.md`](PLAYTEST-2026-09-01.md) first; it has the findings and
why none of our checks caught them.
Their verdict on how we have been working is the part that matters:
> *"It seems the agents were essentially guessing and trying to copy what one
> would see, but while they did get close it still is not quite right."*
**So do not fit a curve to a screenshot. Find the mechanism.** For the splashes,
in this order, and answer each with evidence rather than by inference:
1. **Is there a post-process pass at all?** A blur, a bloom, a fade quad, a tone
curve, a resolve-and-resample. Yes/no, from GPU state.
2. **If yes: what is it?** How many passes, which render targets, what blend
state, which shaders (you have their hashes in the draw log already).
3. **Where do its parameters come from?** Immediate constants in the command
stream, PS/VS constant banks, a table in a pak, a computed ramp in code.
4. **Only then, what curve** — and it should fall out of 3, not be fitted.
Use **both** routes and say which produced each fact:
* **Dynamic** — Canary. Per-draw capture, shader constants, render-target
bindings, blend state, and where those are not logged, **add the logging**:
`/canary` is yours read-write and the draw logger already exists. Guest memory
and CPU state are available too; the splash's driver is a `GamePart` and its
parameters are somewhere in it.
* **Static** — the `.pe` image, `sylpheed.db`, the paks. The code that *sets up*
the pass is in the image, its constants may be immediates, and shader blobs
ship on the disc. A mechanism confirmed statically **generalises to every
screen**; one observed in a capture holds for that capture.
A mechanism found this way is *decoded* and cannot be "close". A curve fitted by
eye is neither.
⚠️ Anything you conclude about *timing* here must obey
[`TEMPORAL-VERIFICATION.md`](TEMPORAL-VERIFICATION.md). The plate-late finding is
a timing question and the corpus has already lost four claims to the wall clock.
### Second, and not optional: the complete input set
The port had **no joypad binding for Ⓐ or Ⓑ** and nobody noticed for a whole
milestone. The port has fixed its side. Yours is the other half:
**Decode what the game actually reads.** Every button, both sticks, the triggers,
START and BACK — per screen if it differs. The pad read path is in the image and
`sub_821CC860`'s decoded arguments already include `PAD`. Deliver the *set*, and
say for each entry whether it is decoded from the image, measured in a capture,
or neither. Guessing which buttons exist by pressing them is how we got here.
## Your objective
`docs/port/MISSION.md` — read it every iteration. It lists the open questions and
@@ -40,6 +94,24 @@ If the merge conflicts, resolve it, say so in your reply, and carry on.
side**. Fill it in as you go: you are the one who sees the real screens.
8. `docs/agents/CONTAINER-NOTES.md` — the container's tooling, and the reference
assets described below.
9. `docs/agents/TEMPORAL-VERIFICATION.md` — **how to verify anything that
moves.** Set by the human. Every temporal claim must obey it.
10. `docs/agents/PLAYTEST-2026-09-01.md` — what a human found playing the port.
⚠️ **`REFUTED.md` was reclassified by the human on 2026-09-01 under rule R1.**
Every entry now ends with its `⟨instrument⟩`, and **ten entries moved ❌ → 🟡**
because the instrument that killed them was one of ours. A 🟡 is *not* dead — it
is re-openable, and each says what would settle it. Read the file's own "How to
read this file" section once. When you improve a renderer, a reader or the
capture harness, run `tools/stale-instrument <that instrument>`: it lists exactly
what that instrument killed, so those claims re-open instead of staying dead
because nobody remembered which ones rested on it.
🔴 Two of the ten bear directly on the current focus. *"The declared keyframe
timeline reproduces the captured splash"* is now 🟡 `⟨our-reader⟩`, never
re-derived under the record-layout fix. And the **`rest()` pair** is open in
**both** directions — both legs run through our renderer — and the two splashes
are the only screens that reach that fallback.
## Reference assets you may not know you have
@@ -132,6 +204,23 @@ renderer is a claim about our renderer.
* Verify with an **artifact**, not "it compiles".
* Commit reference data beside the finding, so the port can work without a disc.
### Anything that moves
**Read `docs/agents/TEMPORAL-VERIFICATION.md` and follow it.** The short form:
* **Record a film, not a photograph.** One frame is a sample of a distribution
you have not characterised.
* **Align by CONTENT, not by clock.** Search the lag that best matches and report
the lag *and* the agreement at it. The lag is a measurement, not an error.
* **Prefer quantities that have no phase** — ordering, counts, durations, ratios,
shape. The two strongest timing results in this corpus are both of that kind.
* **Anchor on an event**, then quote differences from it.
* **State the expected number before reading the actual one.**
* **Report achieved fps against requested fps.** A capture that asked 4 and got
1.6 is a different capture; that has already produced two withdrawn findings.
* ⚠️ Canary presents at **~28.1 fps**, so a wall-clock duration off this emulator
is **~6 % long**. Quote unit counts first, then seconds, then the fps used.
## Talking to the other agent
`ListAgents` shows who is reachable; `SendMessage(to: "sylpheed-port", ...)` reaches