diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index f2b1ef7c..823d4961 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -9,7 +9,7 @@ dies, which is what this file is for. -163 sections. Search this before re-deriving anything. +164 sections. Search this before re-deriving anything. * [P0 — the exporter, 2026-08-28](#p0--the-exporter-2026-08-28) * [P1 — Godot draws the screen, 2026-08-28](#p1--godot-draws-the-screen-2026-08-28) @@ -174,6 +174,7 @@ dies, which is what this file is for. * [🔴 CORRECTION: my 18-vs-19 "agreement" compared two different intervals](#correction-my-18-vs-19-agreement-compared-two-different-intervals) * [`check-all` passes — after an hour-long hang that was the suite's own fault](#check-all-passes--after-an-hour-long-hang-that-was-the-suites-own-fault) * [Ⓐ and Ⓑ are not the same shape, and my `black_hold` treats them as if they were](#and--are-not-the-same-shape-and-my-black_hold-treats-them-as-if-they-were) +* [🔴 `check-all` excused two failing rows with a reason that is measurably false](#check-all-excused-two-failing-rows-with-a-reason-that-is-measurably-false) ## P0 — the exporter, 2026-08-28 @@ -9406,3 +9407,61 @@ bad constant to build on. 📌 So the finding is recorded and the divergence is **known and stated** rather than fixed: the port's transitions are uniform, the game's are directional, and I do not yet have enough transitions measured to say what the rule is. + +## 🔴 `check-all` excused two failing rows with a reason that is measurably false + +The suite reported *"2 DIFFERS, allowed: the pin is not on main, so this compares +two decoder eras."* I have quoted that allowance for several iterations without +testing it. + +**Tested.** Built `sylpheed-cli` at `formats-pin-2026-08-30` — the tag the +exporter is pinned to — and at the workspace HEAD, and rendered the same builds +through both: + +| screen | pixels differing between the two eras | +|---|---| +| `title` | **0** | +| `title_jp` | **0** | +| `main_menu` | **0** | + +✅ **Byte-identical**, despite **508 lines** of difference in `ui_layout.rs` +between the two revisions. The decoder eras are not the cause of anything here, +and the allowance was excusing a real signal with a wrong explanation — the worst +form, because it makes a genuine disagreement look accounted for. + +🔴 **A second, independent defect in the same eight lines.** The allowance's expiry +tested `formats-pin-2026-08-29d` while `crates/sylpheed-export/Cargo.toml` pins +`formats-pin-2026-08-30`. So it would have expired on a tag this tree does not +use — silently, in either direction. + +### What the rows actually are, both already documented elsewhere + +* **`title`** — the `ptloop` **sweep phase** residual: max 6 / over3 790, + unchanged across every renderer change since P1. +* **`title_jp`** — the **`--pose=rest` sparkle handling**. Adjudicated against the + oracle: the port's *shipped* pose scores r **+0.9994** against the game where + the reference scores +0.8727, and `--pose=rest` is what this script compares. + **The port is closer to the game on the row the script calls a disagreement.** + +### The replacement is a named set, not a count with an excuse + +A count can only say *how many*; it cannot notice that a **different** screen +started drifting while the total stayed at two. The allowance now lists `title` +and `title_jp` by name, and a `DIFFERS` on anything else fails the run. + +✅ Controlled in both directions, because a guard that cannot fail is not a guard: + +| log | verdict | +|---|---| +| `title`, `title_jp` | passes | +| `title`, **`main_menu`** | **fails on `main_menu`** | +| **`extras`** alone | **fails on `extras`** | +| clean | passes | + +The pin reminder survives as its own line, and now reads the tag **out of +`Cargo.toml`** so it cannot drift out of step with the dependency again. + +📌 The pattern, and it is the third time this session: **an allowance is a claim.** +This one had been true once — the monorepo merge made the exporter and the +reference share a decoder, and the tag pin quietly unmade that — and it kept being +printed long after it stopped describing the tree. diff --git a/tools/port/check-all b/tools/port/check-all index 4ff256e7..d020556a 100755 --- a/tools/port/check-all +++ b/tools/port/check-all @@ -61,18 +61,47 @@ echo echo "consistency (expected to differ, for a stated reason):" rc=0; env OUT="$OUT/screens" tools/port/verify-screen >"$OUT/verify-screen.log" 2>&1 || rc=$? differs=$(grep -c DIFFERS "$OUT/verify-screen.log" || true) -# The allowance EXPIRES on its own condition rather than standing forever. -# `verify-screen` builds `sylpheed-cli` from the workspace crate while the -# exporter is pinned to a tag, so the two read different decoder eras and the six -# forced-backdrop screens must disagree. The day the tag is an ancestor of -# `origin/main` that stops being true, and this becomes a real failure again -- -# which is what a suppressed check must never be allowed to do silently. -if git merge-base --is-ancestor formats-pin-2026-08-29d origin/main 2>/dev/null; then - [ $rc -eq 0 ] && printf ' %-24s ok (the pin has landed; no allowance left)\n' verify-screen \ - || { printf ' %-24s 🔴 FAILED and the pin HAS landed -- the allowance has expired\n' verify-screen; fail=1; } +unexpected=$(grep DIFFERS "$OUT/verify-screen.log" | awk '{print $1}' \ + | grep -vx -e title -e title_jp || true) + +# 🔴 THE OLD ALLOWANCE WAS FALSE, AND IT EXCUSED TWO ROWS WITH A REASON THAT IS +# NOT THE REASON. +# +# It said: "the pin is not on main, so this compares two decoder eras". Measured +# 2026-08-30 by building `sylpheed-cli` at `formats-pin-2026-08-30` and at the +# workspace HEAD and rendering both: `title`, `title_jp` and `main_menu` come out +# **0 pixels different**, despite 508 lines of difference in `ui_layout.rs`. The +# eras are not the cause of anything here. +# +# 🔴 And its expiry tested `formats-pin-2026-08-29d` while `Cargo.toml` pins +# `formats-pin-2026-08-30` -- so the allowance would have expired on a tag this +# tree does not use, in either direction, silently. +# +# The real reasons are per-screen and already documented: +# title -- the ptloop SWEEP PHASE residual, max 6 / over3 790, unchanged +# across every renderer change since P1 (DECISIONS.md). +# title_jp -- the `--pose=rest` sparkle handling. Adjudicated against the +# oracle: the port's SHIPPED pose scores r +0.9994 against the +# game where the reference scores +0.8727, and `--pose=rest` is +# what this script compares. The port is closer to the game on the +# row this script calls a disagreement. +# +# So the allowance is now a NAMED SET, not a count with an excuse. A DIFFERS on +# any other screen fails the run, which a count never could. +if [ -n "$unexpected" ]; then + printf ' %-24s 🔴 DIFFERS on %s -- not in the allowed set\n' verify-screen "$(echo $unexpected | tr '\n' ' ')" + fail=1 else - printf ' %-24s %d DIFFERS, allowed: the pin is not on main, so this compares\n' verify-screen "$differs" - printf ' %-24s two decoder eras. Revert to the path dep when it lands.\n' "" + printf ' %-24s %d DIFFERS, both named and explained per screen:\n' verify-screen "$differs" + printf ' %-24s title = sweep phase; title_jp = rest-pose sparkles (the port is\n' "" + printf ' %-24s closer to the GAME there than the reference is).\n' "" +fi + +# Separately, and unrelated to the rows above: revert to the path dependency when +# the pin lands. Read from Cargo.toml so it cannot drift out of step again. +pin=$(sed -n 's/.*tag = "\([^"]*\)".*/\1/p' crates/sylpheed-export/Cargo.toml | head -1) +if [ -n "$pin" ] && git merge-base --is-ancestor "$pin" origin/main 2>/dev/null; then + printf ' %-24s ⚠️ %s has landed on main -- revert Cargo.toml to the path dep\n' pin "$pin" fi echo