FA-8621 / Client navigation / Open access
Pagination button state: Next navigates beyond the final page · case 01
Next navigates beyond the final page.
ROOT CAUSE
The next bound operation uses `page = page+1` where the contract requires `page = min(pages, page+1)`.
VERIFIED REPAIR
Implement the next bound operation as `page = min(pages, page+1)`.
Unsuccessful approach: Advancing by two skips pages before the endpoint.
Case contract
Empty pagination uses page zero with disabled controls; nonempty page clamps to 1..pages; actions move by one or to endpoints; availability reflects resulting page.
Why this case matters
A deterministic model of pagination button state; 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(page, pages, action):
if pages == 0: return (0, False, False)
page = max(1, min(page, pages))
if action == 'first': page = 1
elif action == 'last': page = pages
elif action == 'next': page = page+1
elif action == 'previous': page = max(1, page-1)
return (page, page > 1, page < pages)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('empty', solve(1, 0, "none"), (0, False, False))
check('shrink', solve(8, 3, "none"), (3, True, False))
check('zero', solve(0, 3, "none"), (1, False, True))
check('last', solve(1, 5, "last"), (5, True, False))
check('next end', solve(5, 5, "next"), (5, True, False))
check('next step', solve(1, 5, "next"), (2, True, True))
check('previous start', solve(1, 5, "previous"), (1, False, True))
check('previous step', solve(4, 5, "previous"), (3, True, True))
check('parameterized page count', solve(N,N+1,'next'), (N+1,True,False))
for repetition in range(N):
check('repeat previous step', solve(4, 5, "previous"), (3, True, 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 |
|---|---|---|---|
| empty | [0, False, False] | [0, False, False] | Passed |
| shrink | [3, True, False] | [3, True, False] | Passed |
| zero | [1, False, True] | [1, False, True] | Passed |
| last | [5, True, False] | [5, True, False] | Passed |
| next end | [6, True, False] | [5, True, False] | Failed |
| next step | [2, True, True] | [2, True, True] | Passed |
| previous start | [1, False, True] | [1, False, True] | Passed |
| previous step | [3, True, True] | [3, True, True] | Passed |
| parameterized page count | [2, True, False] | [2, True, False] | Passed |
| repeat previous step | [3, True, True] | [3, True, True] | Passed |
SHA-256 / e125a859ef7b5928742f4c4b06693769fcd127c906320acb1b31a537a9a2679e
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(page, pages, action):
if pages == 0: return (0, False, False)
page = max(1, min(page, pages))
if action == 'first': page = 1
elif action == 'last': page = pages
elif action == 'next': page = min(pages, page+2)
elif action == 'previous': page = max(1, page-1)
return (page, page > 1, page < pages)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('empty', solve(1, 0, "none"), (0, False, False))
check('shrink', solve(8, 3, "none"), (3, True, False))
check('zero', solve(0, 3, "none"), (1, False, True))
check('last', solve(1, 5, "last"), (5, True, False))
check('next end', solve(5, 5, "next"), (5, True, False))
check('next step', solve(1, 5, "next"), (2, True, True))
check('previous start', solve(1, 5, "previous"), (1, False, True))
check('previous step', solve(4, 5, "previous"), (3, True, True))
check('parameterized page count', solve(N,N+1,'next'), (N+1,True,False))
for repetition in range(N):
check('repeat previous step', solve(4, 5, "previous"), (3, True, 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 |
|---|---|---|---|
| empty | [0, False, False] | [0, False, False] | Passed |
| shrink | [3, True, False] | [3, True, False] | Passed |
| zero | [1, False, True] | [1, False, True] | Passed |
| last | [5, True, False] | [5, True, False] | Passed |
| next end | [5, True, False] | [5, True, False] | Passed |
| next step | [3, True, True] | [2, True, True] | Failed |
| previous start | [1, False, True] | [1, False, True] | Passed |
| previous step | [3, True, True] | [3, True, True] | Passed |
| parameterized page count | [2, True, False] | [2, True, False] | Passed |
| repeat previous step | [3, True, True] | [3, True, True] | Passed |
SHA-256 / 105ddae2c7df448613865b34d1ea85de0beae2dd0794a786a7e81e492553652d
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(page, pages, action):
if pages == 0: return (0, False, False)
page = max(1, min(page, pages))
if action == 'first': page = 1
elif action == 'last': page = pages
elif action == 'next': page = min(pages, page+1)
elif action == 'previous': page = max(1, page-1)
return (page, page > 1, page < pages)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('empty', solve(1, 0, "none"), (0, False, False))
check('shrink', solve(8, 3, "none"), (3, True, False))
check('zero', solve(0, 3, "none"), (1, False, True))
check('last', solve(1, 5, "last"), (5, True, False))
check('next end', solve(5, 5, "next"), (5, True, False))
check('next step', solve(1, 5, "next"), (2, True, True))
check('previous start', solve(1, 5, "previous"), (1, False, True))
check('previous step', solve(4, 5, "previous"), (3, True, True))
check('parameterized page count', solve(N,N+1,'next'), (N+1,True,False))
for repetition in range(N):
check('repeat previous step', solve(4, 5, "previous"), (3, True, 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 |
|---|---|---|---|
| empty | [0, False, False] | [0, False, False] | Passed |
| shrink | [3, True, False] | [3, True, False] | Passed |
| zero | [1, False, True] | [1, False, True] | Passed |
| last | [5, True, False] | [5, True, False] | Passed |
| next end | [5, True, False] | [5, True, False] | Passed |
| next step | [2, True, True] | [2, True, True] | Passed |
| previous start | [1, False, True] | [1, False, True] | Passed |
| previous step | [3, True, True] | [3, True, True] | Passed |
| parameterized page count | [2, True, False] | [2, True, False] | Passed |
| repeat previous step | [3, True, True] | [3, True, True] | Passed |
SHA-256 / b951dc12a6c5ce84698c933b420469b0337a7ae5a61b305a1f11f138fc9b3580
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:23.009646+00:00.
Case digest / 74fe752051d8e1a2d6c0726a29f778b8acc5056a10dc3ec5c4e3c6b7eaddbba9