FA-8591 / Tab interfaces / Open access
Tab selection and activation mode: Next-tab traversal runs backwards · case 01
Next-tab traversal runs backwards.
ROOT CAUSE
The next operation uses `(available.index(focused)-1) % len(available)` where the contract requires `(available.index(focused)+1) % len(available)`.
VERIFIED REPAIR
Implement the next operation as `(available.index(focused)+1) % len(available)`.
Unsuccessful approach: Holding position prevents traversal entirely.
Case contract
Focus traverses enabled tabs; automatic mode activates on focus, manual mode requires Enter or Space; removed focus or selection falls back to first enabled tab.
Why this case matters
A deterministic model of tab selection and activation mode; 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(tabs, focused, selected, key, automatic, disabled):
available = [t for t in tabs if t not in disabled]
if not available: return (None, None)
if focused not in available: focused = available[0]
if key == 'Next': focused = available[(available.index(focused)-1) % len(available)]
if key == 'Previous': focused = available[(available.index(focused)-1) % len(available)]
if automatic or key in ('Enter','Space'): selected = focused
if selected not in available: selected = available[0]
return (focused, selected)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('disabled', solve(['a','b','c'], 'a', 'a', 'Next', True, ['b']), ('c', 'c'))
check('removed focus', solve(['a','b','c'], 'gone', 'a', 'none', False, []), ('a', 'a'))
check('next', solve(['a','b','c'], 'a', 'a', 'Next', True, []), ('b', 'b'))
check('manual', solve(['a','b','c'], 'a', 'a', 'Next', False, []), ('b', 'a'))
check('space', solve(['a','b'], 'b', 'a', 'Space', False, []), ('b', 'b'))
check('removed selection', solve(['a','b'], 'b', 'gone', 'none', False, []), ('b', 'a'))
check('empty', solve([], None, None, 'Next', True, []), (None, None))
check('parameterized tab identities', solve(list(range(N+2)), N, N, 'Next', True, []), (N+1,N+1))
for repetition in range(N):
check('repeat empty', solve([], None, None, 'Next', True, []), (None, None))
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 |
|---|---|---|---|
| disabled | ['c', 'c'] | ['c', 'c'] | Passed |
| removed focus | ['a', 'a'] | ['a', 'a'] | Passed |
| next | ['c', 'c'] | ['b', 'b'] | Failed |
| manual | ['c', 'a'] | ['b', 'a'] | Failed |
| space | ['b', 'b'] | ['b', 'b'] | Passed |
| removed selection | ['b', 'a'] | ['b', 'a'] | Passed |
| empty | [None, None] | [None, None] | Passed |
| parameterized tab identities | [0, 0] | [2, 2] | Failed |
| repeat empty | [None, None] | [None, None] | Passed |
SHA-256 / a33054ede78a5a743c75bb0483097014961c2033aa248e99e18b31f9e7cb0243
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(tabs, focused, selected, key, automatic, disabled):
available = [t for t in tabs if t not in disabled]
if not available: return (None, None)
if focused not in available: focused = available[0]
if key == 'Next': focused = available[available.index(focused)]
if key == 'Previous': focused = available[(available.index(focused)-1) % len(available)]
if automatic or key in ('Enter','Space'): selected = focused
if selected not in available: selected = available[0]
return (focused, selected)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('disabled', solve(['a','b','c'], 'a', 'a', 'Next', True, ['b']), ('c', 'c'))
check('removed focus', solve(['a','b','c'], 'gone', 'a', 'none', False, []), ('a', 'a'))
check('next', solve(['a','b','c'], 'a', 'a', 'Next', True, []), ('b', 'b'))
check('manual', solve(['a','b','c'], 'a', 'a', 'Next', False, []), ('b', 'a'))
check('space', solve(['a','b'], 'b', 'a', 'Space', False, []), ('b', 'b'))
check('removed selection', solve(['a','b'], 'b', 'gone', 'none', False, []), ('b', 'a'))
check('empty', solve([], None, None, 'Next', True, []), (None, None))
check('parameterized tab identities', solve(list(range(N+2)), N, N, 'Next', True, []), (N+1,N+1))
for repetition in range(N):
check('repeat empty', solve([], None, None, 'Next', True, []), (None, None))
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 |
|---|---|---|---|
| disabled | ['a', 'a'] | ['c', 'c'] | Failed |
| removed focus | ['a', 'a'] | ['a', 'a'] | Passed |
| next | ['a', 'a'] | ['b', 'b'] | Failed |
| manual | ['a', 'a'] | ['b', 'a'] | Failed |
| space | ['b', 'b'] | ['b', 'b'] | Passed |
| removed selection | ['b', 'a'] | ['b', 'a'] | Passed |
| empty | [None, None] | [None, None] | Passed |
| parameterized tab identities | [1, 1] | [2, 2] | Failed |
| repeat empty | [None, None] | [None, None] | Passed |
SHA-256 / 32aa4c73d1abc5a7045adc315dcec5e4730abf579db83117e81ed30cb32dfda4
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(tabs, focused, selected, key, automatic, disabled):
available = [t for t in tabs if t not in disabled]
if not available: return (None, None)
if focused not in available: focused = available[0]
if key == 'Next': focused = available[(available.index(focused)+1) % len(available)]
if key == 'Previous': focused = available[(available.index(focused)-1) % len(available)]
if automatic or key in ('Enter','Space'): selected = focused
if selected not in available: selected = available[0]
return (focused, selected)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('disabled', solve(['a','b','c'], 'a', 'a', 'Next', True, ['b']), ('c', 'c'))
check('removed focus', solve(['a','b','c'], 'gone', 'a', 'none', False, []), ('a', 'a'))
check('next', solve(['a','b','c'], 'a', 'a', 'Next', True, []), ('b', 'b'))
check('manual', solve(['a','b','c'], 'a', 'a', 'Next', False, []), ('b', 'a'))
check('space', solve(['a','b'], 'b', 'a', 'Space', False, []), ('b', 'b'))
check('removed selection', solve(['a','b'], 'b', 'gone', 'none', False, []), ('b', 'a'))
check('empty', solve([], None, None, 'Next', True, []), (None, None))
check('parameterized tab identities', solve(list(range(N+2)), N, N, 'Next', True, []), (N+1,N+1))
for repetition in range(N):
check('repeat empty', solve([], None, None, 'Next', True, []), (None, None))
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 |
|---|---|---|---|
| disabled | ['c', 'c'] | ['c', 'c'] | Passed |
| removed focus | ['a', 'a'] | ['a', 'a'] | Passed |
| next | ['b', 'b'] | ['b', 'b'] | Passed |
| manual | ['b', 'a'] | ['b', 'a'] | Passed |
| space | ['b', 'b'] | ['b', 'b'] | Passed |
| removed selection | ['b', 'a'] | ['b', 'a'] | Passed |
| empty | [None, None] | [None, None] | Passed |
| parameterized tab identities | [2, 2] | [2, 2] | Passed |
| repeat empty | [None, None] | [None, None] | Passed |
SHA-256 / 24b067ee7c267640bce77689f59f81c95f3b775417fb66162bf9320502e4db9d
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:22.663625+00:00.
Case digest / cc09a16827ed1cad5b3829d51262ddd4b4ded18b480574a1952682978cc232fc