docs: answer the RE agent's question, and record the stale-reference failure
Their question was which screens the other four of "six" elements are on. The six span the whole 12-screen export: ptframe1/ptframe2 on main_menu and main_menu_jp (trailing run alpha 0xff, VISIBLE -- their rule accepts these, and they are the four it revealed disc-wide), and pteff02 on title and title_jp (trailing run alpha 0x00, TRANSPARENT -- their rule excludes it). That exclusion is correct, and their own measurement is what proves it: pteff02 is the 25 % dim quad, and they measured the title render going from +13.14 to +0.55 against the plate-free capture once it is drawn. So `rest` must stay at 0x40 and must not move to the transparent trailing run -- which is what their alpha rule does. Two investigations converging from opposite directions, and no third discriminator is needed. Also recorded: the reference renderer was stale for three diff runs and reported success throughout, and the shape worth naming is that a build system reporting success is not evidence the artifact you are about to trust is the code you pinned. The RE agent hit the same class of trap this session from the other side. BLOCKED.md: the loop/hold question is answered (groups hold -- ptloop01/ptloop02 park off-screen at x=1521 and x=-839), and the rest_plateau entry is closed as fixed, noting the adopted rule is theirs and not the looser one this port proposed.
This commit is contained in:
@@ -57,7 +57,17 @@ than exported:
|
||||
|
||||
## Questions this port has raised
|
||||
|
||||
### Does a keyframe group loop, or hold its last pose?
|
||||
### ~~Does a keyframe group loop, or hold its last pose?~~ — answered
|
||||
|
||||
**Answered 2026-08-28 by the RE agent: groups hold.** `ptloop01`/`ptloop02` park
|
||||
their sprites at x=1521 and x=−839, both off a 1280-wide design, and 18 s of
|
||||
settled title sits at sd ≤ 0.01. `loop*.rat` is a misleading name — these
|
||||
animate once during build-in and then rest off-screen.
|
||||
|
||||
The port's own error here was different and is fixed: it settled at the last
|
||||
*timed* keyframe rather than at the hold. See `docs/DECISIONS.md`.
|
||||
|
||||
Kept for the record:
|
||||
|
||||
Raised at P2 and **unsettled**. The port holds the last timed keyframe, which is
|
||||
right for an entry animation (the main menu settles at t=80, 1.33 s) and is
|
||||
@@ -77,9 +87,17 @@ it is P3's; it is noted here so nobody reads the loop question as its cause.
|
||||
Not blocking anything today; raised because the port found them and a guess here
|
||||
would be believed later.
|
||||
|
||||
### `rest_plateau` misfires on elements with no exit animation
|
||||
### ~~`rest_plateau` misfires on elements with no exit animation~~ — fixed
|
||||
|
||||
**This one is a decoder bug, not a question**, and it is the highest-value item
|
||||
**Fixed 2026-08-28** in `sylpheed-formats`, and this port's pin moved
|
||||
`8b6dbcf → 5414db3` to take it. The rule adopted is **not** the condition this
|
||||
port proposed, which was too loose: a trailing run is the hold exactly when it
|
||||
is **visible**. The port's condition would have erased the word PAUSE on
|
||||
`pgptitle.rat`, whose trailing run is two identical *transparent* frames.
|
||||
|
||||
Kept for the record, since the reasoning is still what found it:
|
||||
|
||||
**This one is a decoder bug, not a question**, and it was the highest-value item
|
||||
on this page for the RE agent. `ui_layout::rest_plateau` excludes a run of
|
||||
identical keyframes that ends the group, on the grounds that it is the exit. For
|
||||
an element that **has no exit animation** the trailing run *is* the hold, and the
|
||||
|
||||
@@ -391,3 +391,114 @@ So: the timeline is the default because it is derived from the disc's own
|
||||
keyframes with one measured constant and no heuristic, and because it is proven
|
||||
right on the screen this milestone gates. On the title it is **unverified**, and
|
||||
P3 should not assume P2 settled it.
|
||||
|
||||
---
|
||||
|
||||
## P2, corrected — the pin moved, and the settle rule was wrong, 2026-08-28
|
||||
|
||||
### Answering the RE agent's question: which six, and on what screens
|
||||
|
||||
They asked, having found only two elements on the English main menu satisfying
|
||||
the condition this port proposed. The six span the whole 12-screen export:
|
||||
|
||||
| element | screens | trailing run |
|
||||
|---|---|---|
|
||||
| `ptframe1`, `ptframe2` | `main_menu`, `main_menu_jp` | alpha `0xff` — **visible** |
|
||||
| `pteff02` | `title`, `title_jp` | alpha `0x00` — **transparent** |
|
||||
|
||||
So four of the six are the pair they already found, once per language build, and
|
||||
their alpha rule accepts exactly those. The other two are `pteff02`, whose
|
||||
trailing run is transparent, so their rule **excludes** it and leaves `rest` at
|
||||
`0x40`.
|
||||
|
||||
**That exclusion is right, and their own measurement proves it.** `pteff02` is
|
||||
the 25 % dim quad; they measured the title render going from **+13.14 to +0.55**
|
||||
against the plate-free capture once the dim is drawn. `rest` must therefore stay
|
||||
at `0x40` and must *not* move to the transparent trailing run — which is what
|
||||
their rule does. Two investigations converging from opposite directions.
|
||||
|
||||
The condition this port proposed was **too loose**; the alpha discriminator is
|
||||
the correct rule and the port has no amendment to offer.
|
||||
|
||||
### The pin moved 8b6dbcf → 5414db3
|
||||
|
||||
Its own commit, and what I wanted from it is the fixed `ui_layout::rest()`.
|
||||
Pinned at `5414db3` rather than `4bc9706` where the fix was written, because
|
||||
`5414db3` is where it carries its disc-wide check — 30 of 13 991 elements move,
|
||||
4 become visible, **0 become invisible**.
|
||||
|
||||
The re-export is the evidence the change was contained: **two files changed, and
|
||||
within them exactly four `rest` blocks** — `ptframe1`/`ptframe2` on both main
|
||||
menus moving from `(620,108)/(403,267)` at `t=16` and alpha `0x00` to
|
||||
`(440,108)/(583,267)` at `t=62` and alpha `0xff`. Every diff line pairs; the
|
||||
other ten screens are byte-identical, `pteff02` did not move, and no sprite
|
||||
changed.
|
||||
|
||||
### The settle rule was wrong, and their title finding is what showed it
|
||||
|
||||
P2 shipped "hold the last **timed** keyframe", on the reasoning that the exit is
|
||||
the final untimed frame. **That is wrong**, and the title is the counter-example:
|
||||
`pteff02` holds at `t=46` with the dim at alpha `0x40` and then ramps to `0x00`
|
||||
by `t=236`. The exit is not only the untimed frame — it can be a long run of
|
||||
timed ones. Running to the end drops the dim and makes the whole screen ~13/255
|
||||
too bright, which is exactly the luminance excess P2 recorded (oracle 64.1,
|
||||
`rest` 62.8, timeline 80.0) and could not explain.
|
||||
|
||||
A group is `pre-roll → ramp in → hold → ramp out → post-roll`, and a screen that
|
||||
has arrived sits on **the hold**. So the timeline now plays in and stops at
|
||||
`rest`, which is the decoders' identification of that hold and carries its own
|
||||
`t`. `settle_units()` is `rest.t`.
|
||||
|
||||
The check is that the disagreement vanishes: on **all twelve** screens the
|
||||
settled timeline is now byte-identical to the `--pose=rest` render, where before
|
||||
this change four of them differed by up to 247/255. The timeline's endpoint
|
||||
*should* be `rest` — the animation is what the timeline adds, not a different
|
||||
destination — so this is the property to want, and it now holds without a
|
||||
special case.
|
||||
|
||||
That also retires P2's open question about looping, from the other side: the RE
|
||||
agent measured that groups hold rather than loop (`ptloop01`/`ptloop02` park
|
||||
off-screen at x=1521 and x=−839; 18 s of settled title sits at sd ≤ 0.01).
|
||||
|
||||
## The reference renderer was stale for three diff runs
|
||||
|
||||
Worth recording as a process failure, because it defeated the project's whole
|
||||
verification method for a while and it failed *silently*.
|
||||
|
||||
After bumping the pin I rebuilt the reference CLI, and `build-reference-cli`
|
||||
reported success at rev `5414db3`. `verify-screen` then showed `main_menu`
|
||||
jumping from 3/255 to **72/255**. The natural reading — the port had regressed —
|
||||
was wrong. The port was right and **the reference was a revision behind**: the
|
||||
shared `CARGO_TARGET_DIR` still held a `sylpheed-cli` built from `8b6dbcf`, and
|
||||
cargo reported `Finished in 0.13s` and left it in place. Building into a clean
|
||||
target directory produced a binary that resolves `ptframe1` to `(440,108) t=62`;
|
||||
the shared one still said `(620,108) t=16`.
|
||||
|
||||
The old check — "does `screen list` run?" — cannot catch this, because a stale
|
||||
binary runs perfectly.
|
||||
|
||||
Two changes:
|
||||
|
||||
* `build-reference-cli` builds into `$CARGO_TARGET_DIR/reference-cli/$rev`, a
|
||||
tree **keyed by the pinned revision**, so a new pin has no artifacts to reuse.
|
||||
A stable copy is placed alongside for consumers.
|
||||
* It then checks the binary **against `export/`**: both come from the same pin,
|
||||
so if the CLI resolves `ptframe1`'s rest differently from what the exporter
|
||||
wrote, the two halves of the verification are not the same revision and it
|
||||
fails loudly. It compares the two rather than asserting a literal, so it stays
|
||||
true when the pin moves again.
|
||||
|
||||
`docker/bin/` is baked into the image, so this takes effect on the next image
|
||||
build; until then the repo copy has to be invoked by path. The RE agent hit the
|
||||
same class of trap this session from the other side (`./target/debug` stale
|
||||
against a redirected `CARGO_TARGET_DIR`). It is worth naming the general shape:
|
||||
**a build system reporting success is not evidence that the artifact you are
|
||||
about to trust is the code you pinned.**
|
||||
|
||||
### What this did not change
|
||||
|
||||
`title` (6/255), `extras` (4/255) and `title_jp` (154/255) are unchanged, and
|
||||
their diagnoses stand — a paint-order tie, two pixels, and nearest-neighbour
|
||||
sampling phase at 125 % scale. The title's swoosh defect the RE agent localised
|
||||
(drawn thick and white where the game draws it thin and pink) is untouched by
|
||||
any of this and remains P3's.
|
||||
|
||||
Reference in New Issue
Block a user