port: verify-screen was nondeterministic; pin the pulse phase in the harness
Running the full set after the plate fix, press_start returned over3 5021, 8919, 5021 on three identical runs. The plate's looping focus record takes its phase from time_units, which free-runs, so the captured frame lands wherever the grab fell -- while the reference renderer cannot pulse at all. The port is not the thing that is wrong: the pulse is measured and a thing that pulses does not stop because the screen arrived. ScreenView.loop_phase_units pins it, negative means free-running and stays the default everywhere, and only the harness passes --loop-phase=0. Controlled: pinned, 3 runs identical; free-running, 3 of 4 identical and one different. That 3-of-4 is why it survived -- it looks deterministic most of the time, and without the negative control a no-op flag would have been indistinguishable from a fix. With the phase pinned press_start reads max 1 / over3 0 OK -- the recorded baseline exactly. Fifteen of sixteen rows now match. The sixteenth, title_jp, has genuinely drifted: 155/20498 -> 233/61208, deterministic, on the Godot side, localized to one 350x396 block at (405,74). There is no capture of the Japanese title, so I can say the renderers moved apart but not which moved. Recorded as an ask, not resolved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
@@ -89,6 +89,10 @@ func _ready() -> void:
|
||||
if mods != "":
|
||||
print(mods)
|
||||
|
||||
# Parsed HERE, before the first `ScreenView` is configured -- it was briefly
|
||||
# read further down and every `--screen` run silently ignored it.
|
||||
if args.has("loop-phase"):
|
||||
_loop_phase = float(args["loop-phase"])
|
||||
_flow = export_tree.authored("flow.json")
|
||||
if _flow == null and (args.has("boot") or args.has("menu")):
|
||||
push_error(export_tree.error)
|
||||
@@ -224,6 +228,7 @@ func _ready() -> void:
|
||||
viewport.add_child(view)
|
||||
|
||||
view.looping_focus = _looping_for(name)
|
||||
view.loop_phase_units = _loop_phase
|
||||
view.draw_leaf_for = _draw_leaf_for
|
||||
view.loop_leaf = _loop_leaf_screens.has(name)
|
||||
view.focused_id = _force_focus
|
||||
@@ -469,6 +474,7 @@ func _advance() -> void:
|
||||
view.holding = true
|
||||
view.time_units = 0.0
|
||||
view.looping_focus = _looping_for(name)
|
||||
view.loop_phase_units = _loop_phase
|
||||
view.draw_leaf_for = _draw_leaf_for
|
||||
view.loop_leaf = _loop_leaf_screens.has(name)
|
||||
if not view.load_screen(view.tree, name):
|
||||
@@ -725,6 +731,7 @@ func _menu_arrive() -> void:
|
||||
view.holding = true
|
||||
view.time_units = 0.0
|
||||
view.looping_focus = _looping_for(name)
|
||||
view.loop_phase_units = _loop_phase
|
||||
view.draw_leaf_for = _draw_leaf_for
|
||||
view.loop_leaf = _loop_leaf_screens.has(name)
|
||||
if not view.load_screen(view.tree, name):
|
||||
@@ -1072,6 +1079,10 @@ var _overlay_t0 := 0.0
|
||||
var _overlay_view_t0 := 0.0
|
||||
## Wall-clock second at which it is raised, measured from the screen's settle.
|
||||
var _overlay_due: float = 0.0
|
||||
## `--loop-phase=<units>` pins the looping record's phase. Negative is
|
||||
## free-running, which is the default and what a player gets. Only the
|
||||
## regression harness passes it -- see `ScreenView.loop_phase_units`.
|
||||
var _loop_phase: float = -1.0
|
||||
|
||||
|
||||
func _overlay_process(delta: float) -> void:
|
||||
@@ -1166,6 +1177,7 @@ func _raise_overlay(name: String) -> void:
|
||||
overlay.units_per_second = view.units_per_second
|
||||
overlay.exit_ramp_units = view.exit_ramp_units
|
||||
overlay.looping_focus = _looping_for(name)
|
||||
overlay.loop_phase_units = _loop_phase
|
||||
overlay.draw_leaf_for = _draw_leaf_for
|
||||
overlay.loop_leaf = _loop_leaf_screens.has(name)
|
||||
overlay.holding = true
|
||||
|
||||
@@ -99,6 +99,19 @@ var frozen := false
|
||||
|
||||
var looping_focus: Dictionary = {}
|
||||
|
||||
## Pin the looping record's phase instead of taking it from `time_units`.
|
||||
##
|
||||
## 🔴 WHY THIS EXISTS. The pulse is CORRECT -- a thing that pulses does not stop
|
||||
## because the screen has arrived -- but it rides the wall clock, so a captured
|
||||
## frame lands wherever the grab happened to fall. `verify-screen press_start`
|
||||
## returned `over3` **5021, 8919, 5021** on three identical runs: a regression
|
||||
## detector that answers differently each time teaches its reader to ignore it.
|
||||
##
|
||||
## The port is not the thing that is wrong here, so the port's behaviour does not
|
||||
## change: negative means "free-running", which stays the default everywhere. The
|
||||
## HARNESS pins a phase so the comparison is deterministic.
|
||||
var loop_phase_units: float = -1.0
|
||||
|
||||
## Element ids whose nested `.rat` leaf the runtime actually draws.
|
||||
##
|
||||
## The exporter flags `leaf_carries_geometry` on 15 elements -- a census fact.
|
||||
@@ -593,7 +606,8 @@ func _draw_focus(element: Dictionary) -> void:
|
||||
and String(loop.get("record_element", "")) == String(fe.get("id", "")):
|
||||
var was := holding
|
||||
holding = false
|
||||
pose = pose_at(fe, fposmod(time_units, float(loop["period_units"])))
|
||||
var lt: float = time_units if loop_phase_units < 0.0 else loop_phase_units
|
||||
pose = pose_at(fe, fposmod(lt, float(loop["period_units"])))
|
||||
holding = was
|
||||
var pivot := _vec(fe.get("pivot", [0, 0]))
|
||||
var pos := _vec(pose.get("pos", [0, 0]))
|
||||
|
||||
Reference in New Issue
Block a user