Merge remote-tracking branch 'origin/main' into auto/frame-blend-draw-path
This commit is contained in:
106
docs/agents/PLAYTEST-2026-09-01.md
Normal file
106
docs/agents/PLAYTEST-2026-09-01.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# Play-test, 2026-09-01 — a human, a real controller, the port
|
||||||
|
|
||||||
|
**The first time a person played this port on real hardware.** It found four
|
||||||
|
things. Two were fixed on the spot by the human; two are open and are the
|
||||||
|
**current focus of both agents**.
|
||||||
|
|
||||||
|
⚠️ This page is a record of observations, not a mission change. `PORT-MISSION.md`
|
||||||
|
and the loop briefs carry the objective.
|
||||||
|
|
||||||
|
## What was found
|
||||||
|
|
||||||
|
| # | finding | status |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | **Ⓐ and Ⓑ did nothing on the pad.** Could not skip the intro, could not open a submenu. | ✅ fixed by the human — `port/scripts/gamepad.gd` |
|
||||||
|
| 2 | **The left stick moved the cursor far too fast.** | ✅ fixed by the human — latched to one step per deflection |
|
||||||
|
| 3 | **The `PRESS Ⓐ` plate appears too late.** | 🔴 **OPEN** |
|
||||||
|
| 4 | **The splash fade/blur is wrong** — the game's is *more pronounced*. | 🔴 **OPEN** |
|
||||||
|
|
||||||
|
## 1 & 2 — why no check caught them, which matters more than the fixes
|
||||||
|
|
||||||
|
> **`--script` sends `InputEventAction`, which BYPASSES the input map.**
|
||||||
|
|
||||||
|
Every check the port had asserted the code *below* the input map and nothing
|
||||||
|
about the map itself. The map turned out to have **no joypad binding for
|
||||||
|
`ui_accept` or `ui_cancel` at all** — measured on Godot 4.7.2, not remembered,
|
||||||
|
because the remembered answer was wrong:
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_accept key:Enter, key:Kp Enter, key:Space <- no joypad button at all
|
||||||
|
ui_cancel key:Escape <- no joypad button at all
|
||||||
|
ui_up key:Up, JOYBTN:11, JOYAXIS:1- <- d-pad AND left stick
|
||||||
|
ui_down key:Down, JOYBTN:12, JOYAXIS:1+
|
||||||
|
```
|
||||||
|
|
||||||
|
Four actions reached the pad and two did not. Ⓐ was dead for the whole of P5
|
||||||
|
while the unattended walk passed on every iteration.
|
||||||
|
|
||||||
|
The **same blind spot** hid finding 2: an `InputEventAction` is not an analog
|
||||||
|
axis, so nothing could observe that a stick held at deflection emits an event
|
||||||
|
per *jitter*, each reporting the action as pressed — one cursor step per jitter.
|
||||||
|
|
||||||
|
Now asserted by `tools/port/verify-input`, with a control that removes each
|
||||||
|
check's own subject. (Its first version inverted all nine assertions when only
|
||||||
|
two depended on the fix, and reported seven correct checks as broken. Three rows
|
||||||
|
now say plainly they are **not controllable** — they assert Godot's own bindings
|
||||||
|
— and one is a **negative carrying a positive control** rather than a faked
|
||||||
|
inversion.)
|
||||||
|
|
||||||
|
### The standing rule that follows
|
||||||
|
|
||||||
|
**Synthetic input is not a test of input.** Anything injected below the input map
|
||||||
|
is evidence about the code above it and nothing else. A test of input must go in
|
||||||
|
at the device level — `InputEventJoypadButton`, `InputEventJoypadMotion`,
|
||||||
|
`InputEventKey` — or must assert the map directly.
|
||||||
|
|
||||||
|
## 3 — the plate is late
|
||||||
|
|
||||||
|
The port raises the plate at `t=236`, **3.93 s** after the shared clock starts,
|
||||||
|
which it derives as `238 − 118 = 120 units = 2.000 s` after the title's build-in
|
||||||
|
ends. A human watching both says it is **late**.
|
||||||
|
|
||||||
|
This lands in a spot the corpus already knows is soft. All of the following are
|
||||||
|
live:
|
||||||
|
|
||||||
|
* `REFUTED.md`: *"a screen has SETTLED at its `rest.t`"* → ❌ — believing `rest.t`
|
||||||
|
had already put a port's plate **3.97 s late** once.
|
||||||
|
* `REFUTED.md`: the 2.13 s figure was *"a wall-clock reading stretched by Canary
|
||||||
|
presenting at ~28.1 fps"*, corrected to 120 units. **So the conversion between
|
||||||
|
units and seconds is load-bearing here and is exactly what
|
||||||
|
[`TEMPORAL-VERIFICATION.md`](TEMPORAL-VERIFICATION.md) says not to trust from a
|
||||||
|
wall clock.**
|
||||||
|
* The keyframe **time-unit shift** is unresolved (`ui-keyframe-time-unit.md`).
|
||||||
|
* 🔴 After the 2026-09-01 R1 pass, *"the declared keyframe timeline reproduces the
|
||||||
|
captured splash"* is **🟡 `⟨our-reader⟩`**, not ❌ — the record-layout fix
|
||||||
|
re-times a group's final pose and the entry was never re-derived under it.
|
||||||
|
|
||||||
|
**Candidate causes, none established:** the unit→seconds constant; the clock
|
||||||
|
origin (do both builds really start together?); `rest.t` again; the record layout.
|
||||||
|
Settle it by **ordering and counts**, not by a stopwatch.
|
||||||
|
|
||||||
|
## 4 — the splash fade/blur
|
||||||
|
|
||||||
|
The port applies **no blur at all**. It draws declared keyframe alphas. So
|
||||||
|
*"more pronounced in the game"* is consistent with a post-process the export does
|
||||||
|
not describe, a different ramp shape, or both — and nothing in the export can
|
||||||
|
distinguish those.
|
||||||
|
|
||||||
|
🔴 **And the two splashes are the ONLY screens that reach `rest()`'s
|
||||||
|
plateau-less fallback** — title, main menu and `EXTRAS` reach it zero times. So
|
||||||
|
finding 4 lands precisely where our resting-pose heuristic is least trustworthy,
|
||||||
|
and the R1 pass just re-opened that question **in both directions** (see the
|
||||||
|
`rest()` pair in `REFUTED.md`). That is not a coincidence to step around.
|
||||||
|
|
||||||
|
## The human's verdict on method
|
||||||
|
|
||||||
|
> *"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."*
|
||||||
|
|
||||||
|
Close-but-not-right is the signature of reproducing **appearance** instead of
|
||||||
|
deriving **mechanism**. A ramp tuned until it looks right is wrong in a way
|
||||||
|
nobody can name and has no reach to the next screen.
|
||||||
|
|
||||||
|
The instruction that follows: for the splashes, **find out what the game is
|
||||||
|
doing** — is there a post-process pass, how many, what shader, what blend, what
|
||||||
|
render targets, and where do its parameters come from — before proposing any
|
||||||
|
curve. See the Decoder's brief.
|
||||||
139
docs/agents/TEMPORAL-VERIFICATION.md
Normal file
139
docs/agents/TEMPORAL-VERIFICATION.md
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
# Verifying things that MOVE
|
||||||
|
|
||||||
|
**Both agents read this.** Set by the human on 2026-09-01, after a play-test
|
||||||
|
found the splash fade and the `PRESS Ⓐ` plate visibly wrong while every check
|
||||||
|
either agent had was green.
|
||||||
|
|
||||||
|
## The diagnosis, in one sentence
|
||||||
|
|
||||||
|
> **We have been trying to photograph the game at time *t*, and *t* is never the
|
||||||
|
> same twice.**
|
||||||
|
|
||||||
|
Every temporal claim in this corpus rests on grabbing a frame at a wall-clock
|
||||||
|
instant and comparing it to something. That instant drifts — emulator speed
|
||||||
|
varies with host load, Canary presents at ~28.1 fps rather than 30, the capture
|
||||||
|
path costs a variable 0.1–10.8 s, and a long-lived `x11grab` stream degrades and
|
||||||
|
then freezes. So the comparison is between *our render at the time we meant* and
|
||||||
|
*the game at some other time*, and the difference between those two things is
|
||||||
|
being read as a difference in the **content**.
|
||||||
|
|
||||||
|
The register already carries four separate refutations of this exact shape:
|
||||||
|
|
||||||
|
* *"a latency read off a classified `x11grab` stream is a duration"* — ❌. At
|
||||||
|
1503 ms per classification against an 8 fps stream the consumer ran at
|
||||||
|
0.64 fps; four "durations" died. A screen transition, a button press and a
|
||||||
|
plate fade all came out at ~20–25 s, which is the tell.
|
||||||
|
* *"2 391 frames over 600 s, max glyph 0, therefore the title never appears"* —
|
||||||
|
withdrawn: **the instrument stalls**, repeating one stale frame, reading
|
||||||
|
surface mean 5.21 where `import` read 125.65 at the same moment.
|
||||||
|
* *"the boot harness fails because its polling loop samples every ~41 s"* —
|
||||||
|
the defect was real and fixing it (13.7×) **did not change the answer**.
|
||||||
|
* *"the in-box capture noise of 0.32 between sessions"* — it was not noise, it
|
||||||
|
was the **trigger**: gating on the plate pulse phase-locks the shutter, so
|
||||||
|
0.32 is a lower bound produced by the instrument. At an arbitrary phase the
|
||||||
|
honest figure is 11.9.
|
||||||
|
|
||||||
|
That last one is the important one, and it cuts both ways: **gating hides
|
||||||
|
variance, and not gating produces it.** Neither is a measurement of the game.
|
||||||
|
|
||||||
|
## What to do instead
|
||||||
|
|
||||||
|
The rule is simple and it removes the whole class:
|
||||||
|
|
||||||
|
> **Never compare at an absolute time. Record a SEQUENCE, and align it by
|
||||||
|
> CONTENT.**
|
||||||
|
|
||||||
|
### 1. Capture a film, not a photograph
|
||||||
|
|
||||||
|
Record a continuous run of frames with an index and a timestamp each, spanning
|
||||||
|
the whole animation with margin at both ends. One frame is a sample of a
|
||||||
|
distribution you have not characterised; a film *is* the distribution.
|
||||||
|
|
||||||
|
**State the achieved rate against the requested rate, every time.** A capture
|
||||||
|
that asked for 4 fps and delivered 1.6 is not a slow capture, it is a
|
||||||
|
**different capture**, and it has already produced two withdrawn findings here.
|
||||||
|
An instrument that cannot report its own completeness may not be trusted (R3).
|
||||||
|
|
||||||
|
### 2. Align by content, then measure
|
||||||
|
|
||||||
|
Find the offset that best matches, rather than assuming offset zero:
|
||||||
|
|
||||||
|
* reduce each frame to a scalar or a small vector — mean of a region, an
|
||||||
|
element's alpha, a per-tile amplitude;
|
||||||
|
* do the same for the prediction;
|
||||||
|
* **search the lag** that maximises agreement, and report *both* the lag and the
|
||||||
|
agreement at it.
|
||||||
|
|
||||||
|
The lag is not an error to be minimised away — **it is a measurement**. A
|
||||||
|
consistent lag across runs is a real offset in our model. A lag that varies
|
||||||
|
run to run is the harness, and says so.
|
||||||
|
|
||||||
|
### 3. Prefer quantities that have no phase
|
||||||
|
|
||||||
|
Ranked by how much they survive a drifting clock:
|
||||||
|
|
||||||
|
| quantity | survives drift? |
|
||||||
|
|---|---|
|
||||||
|
| **ordering** — A finishes before B starts | ✅ completely |
|
||||||
|
| **counts** — 83 frames at full alpha | ✅ (given a known, reported rate) |
|
||||||
|
| **durations and ratios** — ramp is 2× the hold | ✅ |
|
||||||
|
| **shape** — monotone, eased, stepped, its inflections | ✅ |
|
||||||
|
| a value **at a named event** — alpha when the plate first appears | 🟡 needs the event found, not the time |
|
||||||
|
| a value **at wall-clock t** | ❌ this is the thing that has been failing |
|
||||||
|
|
||||||
|
The two strongest existing results in the corpus are both of this kind: the
|
||||||
|
**hold duration** (83 frames of full alpha) is called *calibration-free* in
|
||||||
|
`ui-keyframe-time-unit.md` and decided the question; and the `_eff` glows'
|
||||||
|
**exact steps of 34** are a shape, not a sample.
|
||||||
|
|
||||||
|
### 4. Anchor on an event
|
||||||
|
|
||||||
|
Quote everything relative to a frame you can *find* rather than a time you
|
||||||
|
requested: the first frame an element is non-black, the frame the plate first
|
||||||
|
appears, the last frame of the previous screen. Then a drifting start costs
|
||||||
|
nothing, because every number is a difference.
|
||||||
|
|
||||||
|
### 5. Say what you expected before you look (R2)
|
||||||
|
|
||||||
|
*"This ramp declares 80 units, so at 30 fps I expect ~80 frames and I will
|
||||||
|
accept 74–86."* Written first, it makes a near-miss legible as a near-miss
|
||||||
|
instead of something to rationalise. Written after, any number can be explained.
|
||||||
|
|
||||||
|
### 6. Convert units deliberately
|
||||||
|
|
||||||
|
⚠️ **Canary presents at ~28.1 fps, so a wall-clock duration off this emulator is
|
||||||
|
~6 % long.** A measured interval landing near a round number of keyframe units
|
||||||
|
probably *is* that number of units — that is how `2.13 s` turned out to be
|
||||||
|
`120 units = 2.000 s`. Quote the unit count, then the seconds, then the fps you
|
||||||
|
divided by. Never the seconds alone.
|
||||||
|
|
||||||
|
## The other half: stop reproducing by eye
|
||||||
|
|
||||||
|
The play-test's verdict on the splashes was *"close, but not quite right"*, and
|
||||||
|
that is the signature of **matching appearance instead of deriving mechanism**.
|
||||||
|
A ramp tuned until it looks right will be wrong in a way nobody can name, and
|
||||||
|
"looks right" has no reach — it does not tell you what the next screen will do.
|
||||||
|
|
||||||
|
So for anything visual that is still not exact, the question is not *"what
|
||||||
|
curve fits?"* but **"what is the game actually doing?"**:
|
||||||
|
|
||||||
|
* Is there a **post-process pass at all** — a blur, a bloom, a fade quad, a tone
|
||||||
|
curve? That is a GPU-state question with a yes/no answer.
|
||||||
|
* If yes: how many passes, what render targets, what blend, what shader, and
|
||||||
|
**where do its parameters come from** — immediate constants, a table in a pak,
|
||||||
|
a computed ramp?
|
||||||
|
* Only then, what curve.
|
||||||
|
|
||||||
|
A mechanism found this way is *decoded*, generalises to every screen, and cannot
|
||||||
|
be "close". A curve fitted by eye is none of those things.
|
||||||
|
|
||||||
|
## What this does not license
|
||||||
|
|
||||||
|
Doing more of this is not a reason to stop shipping. A measurement that would
|
||||||
|
take an hour is not blocked on building the perfect harness first — take the
|
||||||
|
cheap phase-invariant version (an ordering, a count) and say what its reach is.
|
||||||
|
|
||||||
|
And **an instrument that cannot pass a control is not a starting point.** A
|
||||||
|
filter that fails its own known-positive is dead, not tuneable; a lag search
|
||||||
|
that cannot recover a synthetic 30-frame offset cannot measure an unknown one.
|
||||||
|
Run the control first, and record it.
|
||||||
@@ -1,6 +1,60 @@
|
|||||||
You are the **Decoder**. Answer the open questions the Godot menu port is
|
You are the **Decoder**. Answer the open questions the Godot menu port is
|
||||||
blocked on, one at a time.
|
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
|
## Your objective
|
||||||
|
|
||||||
`docs/port/MISSION.md` — read it every iteration. It lists the open questions and
|
`docs/port/MISSION.md` — read it every iteration. It lists the open questions and
|
||||||
@@ -19,6 +73,19 @@ an export schema, stop and go back to the question you were answering.
|
|||||||
git -C /work fetch origin && git -C /work merge --no-edit origin/main
|
git -C /work fetch origin && git -C /work merge --no-edit origin/main
|
||||||
```
|
```
|
||||||
|
|
||||||
|
🔴 **On your FIRST iteration after 2026-09-01, also merge the human's branch:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C /work merge --no-edit origin/human/r1-register-reclassification
|
||||||
|
```
|
||||||
|
|
||||||
|
It carries the **R1 reclassification of `REFUTED.md`** (every entry now names its
|
||||||
|
`⟨instrument⟩`; ten moved ❌ → 🟡), R1 as standing text in `PROTOCOL.md`, and
|
||||||
|
`tools/stale-instrument`. It branches from `auto/frame-blend-draw-path`, so if
|
||||||
|
you are on that line it is a fast-forward. **Two of the ten re-opened entries
|
||||||
|
land on this iteration's focus** — do not start the splashes without reading
|
||||||
|
them.
|
||||||
|
|
||||||
You work on a topic branch, and you read the protocol, the mission and the
|
You work on a topic branch, and you read the protocol, the mission and the
|
||||||
shared tooling **from your own checkout** — so without this you are following
|
shared tooling **from your own checkout** — so without this you are following
|
||||||
whichever version of the rules existed when your branch started. That is not
|
whichever version of the rules existed when your branch started. That is not
|
||||||
@@ -40,6 +107,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.
|
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
|
8. `docs/agents/CONTAINER-NOTES.md` — the container's tooling, and the reference
|
||||||
assets described below.
|
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
|
## Reference assets you may not know you have
|
||||||
|
|
||||||
@@ -132,6 +217,23 @@ renderer is a claim about our renderer.
|
|||||||
* Verify with an **artifact**, not "it compiles".
|
* Verify with an **artifact**, not "it compiles".
|
||||||
* Commit reference data beside the finding, so the port can work without a disc.
|
* 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
|
## Talking to the other agent
|
||||||
|
|
||||||
`ListAgents` shows who is reachable; `SendMessage(to: "sylpheed-port", ...)` reaches
|
`ListAgents` shows who is reachable; `SendMessage(to: "sylpheed-port", ...)` reaches
|
||||||
|
|||||||
@@ -1,5 +1,58 @@
|
|||||||
You are the **Port**. Build the Godot menu shell, one milestone at a time.
|
You are the **Port**. Build the Godot menu shell, one milestone at a time.
|
||||||
|
|
||||||
|
## 🔴 CURRENT FOCUS, set by the human 2026-09-01: THE LOGO SPLASHES, EXACTLY
|
||||||
|
|
||||||
|
A human played this port on a real controller for the first time. Read
|
||||||
|
[`../agents/PLAYTEST-2026-09-01.md`](../agents/PLAYTEST-2026-09-01.md) **before
|
||||||
|
anything else** — it has all four findings and, more importantly, why none of
|
||||||
|
your checks caught two of them.
|
||||||
|
|
||||||
|
**Two were fixed for you by the human. Do not re-do them; do read them.**
|
||||||
|
|
||||||
|
1. **Ⓐ and Ⓑ were never bound to the pad.** Godot 4.7.2 binds no joypad button to
|
||||||
|
`ui_accept` or `ui_cancel`, while it binds the d-pad *and* the left stick to
|
||||||
|
`ui_up`/`ui_down`. Ⓐ was dead on real hardware for the whole of P5 while your
|
||||||
|
unattended walk passed every iteration. Fixed in `port/scripts/gamepad.gd`;
|
||||||
|
asserted by `tools/port/verify-input`, now in `check-all`.
|
||||||
|
2. **The left stick fired once per jitter.** An axis is not an edge. Latched to
|
||||||
|
one step per deflection, with hysteresis.
|
||||||
|
|
||||||
|
> ### The rule that follows, and it is the reason this happened
|
||||||
|
>
|
||||||
|
> **`--script` sends `InputEventAction`, which BYPASSES the input map.** Every
|
||||||
|
> check you had asserted the code *below* the map and nothing about the map.
|
||||||
|
> Synthetic input is not a test of input.
|
||||||
|
>
|
||||||
|
> **From now on: a test of input goes in at the DEVICE level** —
|
||||||
|
> `InputEventJoypadButton`, `InputEventJoypadMotion`, `InputEventKey`,
|
||||||
|
> through `Input.parse_input_event` — or it asserts the input map directly.
|
||||||
|
> `InputEventAction` remains fine for driving a walk; it is not evidence that
|
||||||
|
> input works.
|
||||||
|
|
||||||
|
**Two are open and are your focus:**
|
||||||
|
|
||||||
|
3. **The `PRESS Ⓐ` plate arrives late.** You raise it at `t=236`, derived as
|
||||||
|
`238 − 118 = 120 units = 2.000 s`. A human watching both says late. The
|
||||||
|
unit→seconds conversion is load-bearing and is exactly what the wall clock
|
||||||
|
cannot be trusted for. **This is an RE question if the cause is the unit; it
|
||||||
|
is yours if the cause is the clock origin or `rest.t`.** Establish which
|
||||||
|
half it is before asking, and say how you established it.
|
||||||
|
4. **The splash fade/blur is not the game's** — the game's is more pronounced.
|
||||||
|
You apply **no blur at all**. Whether the game runs a post-process pass is an
|
||||||
|
oracle question and it is with the Decoder. **Do not fit a curve to a
|
||||||
|
screenshot while waiting** — that is exactly what produced "close but not
|
||||||
|
right".
|
||||||
|
|
||||||
|
⚠️ Anything you conclude about timing must obey
|
||||||
|
[`../agents/TEMPORAL-VERIFICATION.md`](../agents/TEMPORAL-VERIFICATION.md).
|
||||||
|
Record a film and align by content; never compare at an absolute time.
|
||||||
|
|
||||||
|
⚠️ **`REFUTED.md` was reclassified by the human on 2026-09-01 (rule R1).** Ten
|
||||||
|
entries moved ❌ → 🟡 because our own renderer or reader killed them. Two bear on
|
||||||
|
your focus: *"the declared keyframe timeline reproduces the captured splash"* is
|
||||||
|
now 🟡 `⟨our-reader⟩`, and the **`rest()` pair is open in both directions** — and
|
||||||
|
the two splashes are the **only** screens reaching that fallback.
|
||||||
|
|
||||||
## Your objective
|
## Your objective
|
||||||
|
|
||||||
`docs/port/PORT-MISSION.md` — read it every iteration. Milestones P0…P7, each
|
`docs/port/PORT-MISSION.md` — read it every iteration. Milestones P0…P7, each
|
||||||
@@ -15,6 +68,19 @@ guess of yours is indistinguishable from a fact and will be believed later.
|
|||||||
git -C /work fetch origin && git -C /work merge --no-edit origin/main
|
git -C /work fetch origin && git -C /work merge --no-edit origin/main
|
||||||
```
|
```
|
||||||
|
|
||||||
|
🔴 **On your FIRST iteration after 2026-09-01, also merge the human's branch:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C /work merge --no-edit origin/human/r1-retro-tick
|
||||||
|
```
|
||||||
|
|
||||||
|
It carries **the two input fixes made for you** (`port/scripts/gamepad.gd`,
|
||||||
|
`tools/port/verify-input` + its control, wired into `check-all`), the new
|
||||||
|
`BLOCKED.md` rows **H1–H3**, and the retro tick. It branches from
|
||||||
|
`auto/port-p6-audio`, so on that line it is a fast-forward. **Merge it before
|
||||||
|
touching input**, or you will re-derive a fix that is already written and
|
||||||
|
asserted.
|
||||||
|
|
||||||
You work on a topic branch, and you read the protocol, the mission and the
|
You work on a topic branch, and you read the protocol, the mission and the
|
||||||
shared tooling **from your own checkout** — so without this you are following
|
shared tooling **from your own checkout** — so without this you are following
|
||||||
whichever version of the rules existed when your branch started. That is not
|
whichever version of the rules existed when your branch started. That is not
|
||||||
@@ -79,6 +145,14 @@ That is the easiest thing here to get subtly wrong.
|
|||||||
disagree, say which is wrong rather than tuning until they match.
|
disagree, say which is wrong rather than tuning until they match.
|
||||||
* Godot runs headless (`godot-headless`), or windowed under Xvfb with
|
* Godot runs headless (`godot-headless`), or windowed under Xvfb with
|
||||||
`screenshot`.
|
`screenshot`.
|
||||||
|
* **Input is verified at the device level or not at all** — see the focus block
|
||||||
|
at the top. `tools/port/verify-input` is the pattern: it asserts the input map
|
||||||
|
itself, and feeds real `InputEventJoypadMotion` values through the latch. Run
|
||||||
|
it and its `--control` in `check-all`.
|
||||||
|
* **Anything that moves** follows `../agents/TEMPORAL-VERIFICATION.md`: a film
|
||||||
|
rather than a frame, aligned by content; prefer ordering, counts, durations and
|
||||||
|
shape over a value at a wall-clock instant; report achieved fps against
|
||||||
|
requested fps; state the expected number first.
|
||||||
* Audio: `docs/port/AUDIO-VERIFICATION.md` — no sound card is needed to answer
|
* Audio: `docs/port/AUDIO-VERIFICATION.md` — no sound card is needed to answer
|
||||||
any of it. Write to a temp name and rename on completion; another agent
|
any of it. Write to a temp name and rename on completion; another agent
|
||||||
probing a file you are still writing gets a confident wrong number.
|
probing a file you are still writing gets a confident wrong number.
|
||||||
|
|||||||
Reference in New Issue
Block a user