FA-8196 / Overlay interactions / Open access
Popover outside-interaction handling: Trigger interaction can close but cannot open · case 01
Trigger interaction can close but cannot open.
ROOT CAUSE
The trigger operation uses `if trigger in target_path: return False` where the contract requires `if trigger in target_path: return not opened`.
VERIFIED REPAIR
Implement the trigger operation as `if trigger in target_path: return not opened`.
Unsuccessful approach: Always opening removes toggle-to-close behavior.
Case contract
Cancelled events preserve state; Escape closes; only pointerdown toggles triggers or dismisses outside; membership in the composed path recognizes descendants and portals.
Why this case matters
A deterministic model of popover outside-interaction handling; 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(opened, target_path, trigger, panel, event, prevented):
if prevented: return opened
if event == 'escape': return False
if event != 'pointerdown': return opened
if trigger in target_path: return False
if panel in target_path: return opened
return False
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('cancelled open', solve(True, ['outside'], 'trigger', 'panel', 'pointerdown', True), True)
check('cancelled closed', solve(False, ['outside'], 'trigger', 'panel', 'pointerdown', True), False)
check('escape open', solve(True, [], 'trigger', 'panel', 'escape', False), False)
check('escape closed', solve(False, [], 'trigger', 'panel', 'escape', False), False)
check('ignored', solve(True, [], 'trigger', 'panel', 'pointermove', False), True)
check('trigger opens', solve(False, ['icon','trigger'], 'trigger', 'panel', 'pointerdown', False), True)
check('trigger closes', solve(True, ['icon','trigger'], 'trigger', 'panel', 'pointerdown', False), False)
check('inside descendant', solve(True, ['button','panel'], 'trigger', 'panel', 'pointerdown', False), True)
check('parameterized descendant depth', solve(True, ['node'+str(i) for i in range(N)]+['panel'], 'trigger', 'panel', 'pointerdown', False), True)
for repetition in range(N):
check('repeat inside descendant', solve(True, ['button','panel'], 'trigger', 'panel', 'pointerdown', False), True)
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 |
|---|---|---|---|
| cancelled open | True | True | Passed |
| cancelled closed | False | False | Passed |
| escape open | False | False | Passed |
| escape closed | False | False | Passed |
| ignored | True | True | Passed |
| trigger opens | False | True | Failed |
| trigger closes | False | False | Passed |
| inside descendant | True | True | Passed |
| parameterized descendant depth | True | True | Passed |
| repeat inside descendant | True | True | Passed |
SHA-256 / d87ed938dc341605ef41ae6704cc961f1c0397d725e0ef5186d77bcaad37f42c
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(opened, target_path, trigger, panel, event, prevented):
if prevented: return opened
if event == 'escape': return False
if event != 'pointerdown': return opened
if trigger in target_path: return True
if panel in target_path: return opened
return False
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('cancelled open', solve(True, ['outside'], 'trigger', 'panel', 'pointerdown', True), True)
check('cancelled closed', solve(False, ['outside'], 'trigger', 'panel', 'pointerdown', True), False)
check('escape open', solve(True, [], 'trigger', 'panel', 'escape', False), False)
check('escape closed', solve(False, [], 'trigger', 'panel', 'escape', False), False)
check('ignored', solve(True, [], 'trigger', 'panel', 'pointermove', False), True)
check('trigger opens', solve(False, ['icon','trigger'], 'trigger', 'panel', 'pointerdown', False), True)
check('trigger closes', solve(True, ['icon','trigger'], 'trigger', 'panel', 'pointerdown', False), False)
check('inside descendant', solve(True, ['button','panel'], 'trigger', 'panel', 'pointerdown', False), True)
check('parameterized descendant depth', solve(True, ['node'+str(i) for i in range(N)]+['panel'], 'trigger', 'panel', 'pointerdown', False), True)
for repetition in range(N):
check('repeat inside descendant', solve(True, ['button','panel'], 'trigger', 'panel', 'pointerdown', False), True)
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 |
|---|---|---|---|
| cancelled open | True | True | Passed |
| cancelled closed | False | False | Passed |
| escape open | False | False | Passed |
| escape closed | False | False | Passed |
| ignored | True | True | Passed |
| trigger opens | True | True | Passed |
| trigger closes | True | False | Failed |
| inside descendant | True | True | Passed |
| parameterized descendant depth | True | True | Passed |
| repeat inside descendant | True | True | Passed |
SHA-256 / 0ac96b3ce24a313b03c4d7fb5c5621c4bd85c65bcc4168b0a63a1958a989178e
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(opened, target_path, trigger, panel, event, prevented):
if prevented: return opened
if event == 'escape': return False
if event != 'pointerdown': return opened
if trigger in target_path: return not opened
if panel in target_path: return opened
return False
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('cancelled open', solve(True, ['outside'], 'trigger', 'panel', 'pointerdown', True), True)
check('cancelled closed', solve(False, ['outside'], 'trigger', 'panel', 'pointerdown', True), False)
check('escape open', solve(True, [], 'trigger', 'panel', 'escape', False), False)
check('escape closed', solve(False, [], 'trigger', 'panel', 'escape', False), False)
check('ignored', solve(True, [], 'trigger', 'panel', 'pointermove', False), True)
check('trigger opens', solve(False, ['icon','trigger'], 'trigger', 'panel', 'pointerdown', False), True)
check('trigger closes', solve(True, ['icon','trigger'], 'trigger', 'panel', 'pointerdown', False), False)
check('inside descendant', solve(True, ['button','panel'], 'trigger', 'panel', 'pointerdown', False), True)
check('parameterized descendant depth', solve(True, ['node'+str(i) for i in range(N)]+['panel'], 'trigger', 'panel', 'pointerdown', False), True)
for repetition in range(N):
check('repeat inside descendant', solve(True, ['button','panel'], 'trigger', 'panel', 'pointerdown', False), True)
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 |
|---|---|---|---|
| cancelled open | True | True | Passed |
| cancelled closed | False | False | Passed |
| escape open | False | False | Passed |
| escape closed | False | False | Passed |
| ignored | True | True | Passed |
| trigger opens | True | True | Passed |
| trigger closes | False | False | Passed |
| inside descendant | True | True | Passed |
| parameterized descendant depth | True | True | Passed |
| repeat inside descendant | True | True | Passed |
SHA-256 / 7a045de732a8956f9c0381ac510e7759e33401a66e89faa24402a37a06cf6dbd
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.304160+00:00.
Case digest / 2e4f317e73758d7ccc2980b33d356d1dac5f9ff8bc4baaef291fc613fb7a07e4