FA-8241 / Direct manipulation / Open access
Pointer-capture ownership: A different pointer release ends the active drag · case 01
A different pointer release ends the active drag.
ROOT CAUSE
The release owner operation uses `if event == 'up'` where the contract requires `if event == 'up' and pointer == owner`.
THE FAILURE
The release owner operation uses `if event == 'up'` where the contract requires `if event == 'up' and pointer == owner`.
Unsuccessful approach: Reversing ownership prevents the active pointer from releasing.
Case contract
First pointer captures ownership; only its movement and release affect a drag; cancellation and capture loss clear ownership while preserving position.
Why this case matters
A deterministic model of pointer-capture ownership; this isolates one interface invariant without requiring a browser.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(owner, position, event, pointer, delta):
if event == 'down': return (pointer if owner is None else owner, position)
if event == 'move' and pointer == owner: return (owner, position + delta)
if event == 'up': return (None, position)
if event == 'cancel' and pointer == owner: return (None, position)
if event == 'lost': return (None, position)
return (owner, position)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('initial down', solve(None, 4, 'down', 1, 0), (1, 4))
check('second down', solve(1, 4, 'down', 2, 0), (1, 4))
check('other move', solve(1, 4, 'move', 2, 3), (1, 4))
check('owner move', solve(1, 4, 'move', 1, 3), (1, 7))
check('other up', solve(1, 4, 'up', 2, 0), (1, 4))
check('owner up', solve(1, 4, 'up', 1, 0), (None, 4))
check('cancel', solve(1, 4, 'cancel', 1, 0), (None, 4))
check('lost', solve(1, 4, 'lost', 2, 0), (None, 4))
check('parameterized pointer ownership', solve(N, N, 'move', N, N), (N,2*N))
for repetition in range(N):
check('repeat lost', solve(1, 4, 'lost', 2, 0), (None, 4))
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| initial down | [1, 4] | [1, 4] | Passed |
| second down | [1, 4] | [1, 4] | Passed |
| other move | [1, 4] | [1, 4] | Passed |
| owner move | [1, 7] | [1, 7] | Passed |
| other up | [None, 4] | [1, 4] | Failed |
| owner up | [None, 4] | [None, 4] | Passed |
| cancel | [None, 4] | [None, 4] | Passed |
| lost | [None, 4] | [None, 4] | Passed |
| parameterized pointer ownership | [1, 2] | [1, 2] | Passed |
| repeat lost | [None, 4] | [None, 4] | Passed |
SHA-256 / bc39ba2eb5260bd283a577bfc04c7945d982f615050a27f563b98cf9ca4e5d91
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(owner, position, event, pointer, delta):
if event == 'down': return (pointer if owner is None else owner, position)
if event == 'move' and pointer == owner: return (owner, position + delta)
if event == 'up' and pointer != owner: return (None, position)
if event == 'cancel' and pointer == owner: return (None, position)
if event == 'lost': return (None, position)
return (owner, position)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('initial down', solve(None, 4, 'down', 1, 0), (1, 4))
check('second down', solve(1, 4, 'down', 2, 0), (1, 4))
check('other move', solve(1, 4, 'move', 2, 3), (1, 4))
check('owner move', solve(1, 4, 'move', 1, 3), (1, 7))
check('other up', solve(1, 4, 'up', 2, 0), (1, 4))
check('owner up', solve(1, 4, 'up', 1, 0), (None, 4))
check('cancel', solve(1, 4, 'cancel', 1, 0), (None, 4))
check('lost', solve(1, 4, 'lost', 2, 0), (None, 4))
check('parameterized pointer ownership', solve(N, N, 'move', N, N), (N,2*N))
for repetition in range(N):
check('repeat lost', solve(1, 4, 'lost', 2, 0), (None, 4))
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| initial down | [1, 4] | [1, 4] | Passed |
| second down | [1, 4] | [1, 4] | Passed |
| other move | [1, 4] | [1, 4] | Passed |
| owner move | [1, 7] | [1, 7] | Passed |
| other up | [None, 4] | [1, 4] | Failed |
| owner up | [1, 4] | [None, 4] | Failed |
| cancel | [None, 4] | [None, 4] | Passed |
| lost | [None, 4] | [None, 4] | Passed |
| parameterized pointer ownership | [1, 2] | [1, 2] | Passed |
| repeat lost | [None, 4] | [None, 4] | Passed |
SHA-256 / 7a7c6ded3e3896bd9f2033f87921cb5f2feb8dd56aad1161c353e4eeadca13f0
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 10 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗Verification & scope
This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:38:19.688494+00:00.
Case digest / 81473823289e1ba0fc80f60775652657877d80fe8f7421c59b4de1ec6d4b15a4