P6.1: lock input for the full in-flight animation window
A swipe that began while a move animation was playing could still commit: mouse_down latched the drag unconditionally and the animation-active check sat at mouse_up, so a press made mid-animation committed once the timeline finished before release — against a board mid-transition. Gate input at gesture START instead. Add a pure `accepts_input(anim)` predicate (false while a timeline is active) and check it at mouse_down: a press begun mid-animation is dropped and never latches a drag, so it cannot commit when the animation later settles. The now-dead mouse_up gate is removed. Animation visuals and the logical model are unchanged. Extend tests/anim_plan.sx to assert accepts_input rejects for the whole window (idle accept / busy reject / settled accept) and that press-gating drops the exact failure gesture a release-gate would let through.
This commit is contained in:
@@ -10,6 +10,10 @@
|
||||
// each later round starts on the prior round's settled board), and the last
|
||||
// round's `after` equals `final`;
|
||||
// - an illegal swap records no rounds and leaves the board untouched.
|
||||
// It also guards the P6.1 input-lock fix: `accepts_input` rejects a gesture for
|
||||
// the FULL in-flight animation window (mouse_down → settle), so a swipe begun
|
||||
// while a move animates never latches a drag and never commits — even if it is
|
||||
// released after the timeline ends.
|
||||
// No rendering — it calls exactly what BoardView.handle_event calls. Links headless
|
||||
// like tests/swipe_commit.sx; avoids tests/test.sx (its trace.sx pulls in a second
|
||||
// `Frame` that collides with the UI one). Failure is a non-zero exit code.
|
||||
@@ -108,6 +112,42 @@ main :: () -> s32 {
|
||||
if bi2.score != 0 { fails += 1; }
|
||||
if bi2.moves_made != 0 { fails += 1; }
|
||||
|
||||
// ── Input gate: locked for the FULL in-flight animation ─────────────────
|
||||
// The view begins a drag on mouse_down only when `accepts_input` is true,
|
||||
// and commits on mouse_up only if a drag latched. So a gesture that BEGINS
|
||||
// while a move animates must NEVER commit — even if it is released after the
|
||||
// animation has fully settled. This guards the P6.1 input-lock fix.
|
||||
print("== input gate: locked while animating ==\n");
|
||||
gate : BoardAnim = ---;
|
||||
gate.init();
|
||||
idle_ok := accepts_input(@gate); // no move in flight → accept
|
||||
gate.begin(move); // a legal move's timeline starts
|
||||
busy_ok := accepts_input(@gate); // mouse_down DURING animation → reject
|
||||
while gate.active { gate.tick(0.05); } // player holds; timeline plays out
|
||||
settled_ok := accepts_input(@gate); // animation fully settled → accept
|
||||
print("accepts idle {} busy {} settled {}\n", idle_ok, busy_ok, settled_ok);
|
||||
if !idle_ok { fails += 1; }
|
||||
if busy_ok { fails += 1; } // MUST be locked while animating
|
||||
if !settled_ok { fails += 1; }
|
||||
|
||||
// The board MUST decide a gesture at PRESS, not at RELEASE. Over the exact
|
||||
// failure scenario — a gesture PRESSED while animating and RELEASED after the
|
||||
// timeline has settled — the two policies diverge:
|
||||
// release-gate: commit unless animating AT RELEASE → COMMITS (the timeline
|
||||
// finished first), letting input slip through mid-transition.
|
||||
// press-gate: latch only if input accepted AT PRESS → DROPS, because
|
||||
// input was locked for the whole window the timeline ran.
|
||||
gate.init();
|
||||
gate.begin(move);
|
||||
accept_at_press := accepts_input(@gate); // mouse_down while animating
|
||||
while gate.active { gate.tick(0.05); }
|
||||
accept_at_release := accepts_input(@gate); // mouse_up after settle
|
||||
release_gate_commits := accept_at_release;
|
||||
press_gate_commits := accept_at_press;
|
||||
print("release_gate_commits {} press_gate_commits {}\n", release_gate_commits, press_gate_commits);
|
||||
if !release_gate_commits { fails += 1; } // the scenario release-gating lets through
|
||||
if press_gate_commits { fails += 1; } // the board press-gates: MUST NOT commit
|
||||
|
||||
if fails == 0 {
|
||||
print("ok: animation layer leaves the model result unchanged\n");
|
||||
return 0;
|
||||
|
||||
@@ -14,4 +14,7 @@ YOYYROBB
|
||||
OROBPPRB
|
||||
== illegal swap: untouched ==
|
||||
legal false rounds 0 score 0 moves 0
|
||||
== input gate: locked while animating ==
|
||||
accepts idle true busy false settled true
|
||||
release_gate_commits true press_gate_commits false
|
||||
ok: animation layer leaves the model result unchanged
|
||||
|
||||
Reference in New Issue
Block a user