Skip to content

Commit 24fc120

Browse files
doublegateclaude
andauthored
docs: interlace needs a rule extract cannot express, and Mesen2 is no longer flaky (#326)
Probed and withdrawn. Two findings. GOOD NEWS: the recorded Mesen2 nondeterminism is gone. Three consecutive Mesen2 runs and two snes9x runs of an interlace scene produced identical results, so "Mesen2 alternates between both field parities run-to-run on one build" no longer reproduces -- almost certainly the emu.setInput defect fixed earlier. "Run any field-dependent capture twice per host" can be retired as the REASON interlace is blocked. THE BLOCKER: the two hosts emit different WIDTHS for the same interlace scene. snes9x renders a single field at 256x224; Mesen2 doubles both dimensions to 512x478. Hi-res worked because both emitted 512 wide and differed only in height, which HiResEven absorbs by deriving the row step from the observed height. Here no single (xstep, ystep) pair describes both reductions, so `extract` as designed -- one declared rule per scene, every host applying the same reduction -- is insufficient. ADR 0013 records the three options and argues against the tempting one: a generic "downsample whatever you get to 256x224" rule would subsume HiResEven but give up the declared-not-inferred property, and would then silently accept a 256-wide frame for a scene that must be 512. If interlace is worth covering, a per-host reduction table is the honest shape. Docs only; the probe scene is not in the tree. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 195092c commit 24fc120

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Fixed
1313

14+
- **Interlace scenes: the recorded Mesen2 nondeterminism is GONE, but interlace is blocked for a
15+
different reason.** Probed and withdrawn. Three consecutive Mesen2 runs and two snes9x runs of an
16+
interlace scene produced identical results, so the standing note that "Mesen2 alternates between
17+
both field parities run-to-run on one build" no longer reproduces — that was almost certainly the
18+
`emu.setInput` defect fixed earlier, and "run any field-dependent capture twice per host" can be
19+
retired as the *reason* interlace is blocked.
20+
21+
The actual blocker is that the two hosts emit different **widths** for the same interlace scene:
22+
snes9x `256x224`, Mesen2 `512x478`. Hi-res worked because both emitted 512 wide and differed only
23+
in height, which `HiResEven` absorbs by deriving the row step from the observed height. Here no
24+
single `(xstep, ystep)` pair describes both reductions, so `extract` as designed — one declared
25+
rule per scene, every host applying the same reduction — is insufficient.
26+
27+
`docs/adr/0013` records the three options and argues against the tempting one: a generic
28+
"downsample whatever you get to 256x224" rule would subsume `HiResEven` but give up the
29+
declared-not-inferred property, and would then silently accept a 256-wide frame for a scene that
30+
must be 512.
31+
1432
- **`C10.04` attempted and withdrawn: it is blocked by the same exclusion that unblocked `C5.15`.**
1533
A Mode 5 scene with `MOSAIC = $01` was written against the control the working rules require — the
1634
same canvas with mosaic off — and hashed **identically to it on both references**

‎docs/adr/0013-accuracysnes-framebuffer-oracle.md‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,43 @@ a state no picture can show; an unshowable scene hashes stably and every emulato
265265
The control scene is what caught it, and its doc comment said in advance what an equal hash would
266266
mean. **Write the control first; it is the only thing that distinguishes "the references agree" from
267267
"nothing happened".**
268+
269+
### Interlace needs a rule the current design cannot express
270+
271+
Probed 2026-08-02, scene withdrawn. Two findings, and the second is the blocker.
272+
273+
**The good news: Mesen2 is no longer nondeterministic here.** The earlier note that "Mesen2
274+
alternates between both field parities run-to-run on one build" no longer reproduces — three
275+
consecutive runs of an interlace scene produced the identical result, as did two of snes9x. That
276+
nondeterminism was almost certainly the `emu.setInput` defect fixed earlier, and the standing advice
277+
to "run any field-dependent capture twice per host" can be retired as the *reason* interlace is
278+
blocked. It is blocked for a different reason.
279+
280+
**The blocker: the two hosts emit different WIDTHS for the same interlace scene.**
281+
282+
| scene kind | snes9x | Mesen2 |
283+
|---|---|---|
284+
| ordinary | `256x224` | `256x239` |
285+
| Mode 5 hi-res | `512x224` | `512x478` |
286+
| **interlace** | **`256x224`** | **`512x478`** |
287+
288+
Hi-res worked because both hosts emitted **512 wide** and differed only in height, which `HiResEven`
289+
absorbs by deriving the row step from the observed height. Interlace does not: snes9x renders a
290+
single field at 256 wide while Mesen2 doubles both dimensions. `HiResEven`'s `width == 512` assertion
291+
cannot hold for both, and no single `(xstep, ystep)` pair describes both reductions.
292+
293+
So `extract` as designed — one declared rule per scene, each host applying the same reduction — is
294+
insufficient for interlace. The options, none of them free:
295+
296+
1. A `Downsample` rule that reduces *whatever* the host emits to 256x224 by deriving both steps from
297+
the observed geometry. General, and it subsumes `HiResEven` — but it gives up the
298+
**declared-not-inferred** property that is the whole reason `extract` catches a core rendering
299+
256 wide when it should render 512.
300+
2. A per-host reduction table, so a rule can say "snes9x: as-is; Mesen2: halve both". Keeps the
301+
declaration honest at the cost of the hosts no longer being interchangeable.
302+
3. Declare the expected geometry per rule *and* per host, and reject anything else — the strictest,
303+
and the most to maintain.
304+
305+
Option 1 is the tempting one and should be resisted on its own: it would make the hi-res case
306+
silently accept a 256-wide frame for a scene that must be 512. If interlace is worth covering, option
307+
2 is the honest shape.

0 commit comments

Comments
 (0)