FA-8616 / Client navigation / Open access
Pagination button state: Last-page navigation stops one page early · case 01
Last-page navigation stops one page early.
ROOT CAUSE
The last operation uses `elif action == 'last': page = pages-1` where the contract requires `elif action == 'last': page = pages`.
VERIFIED REPAIR
Implement the last operation as `elif action == 'last': page = pages`.
Unsuccessful approach: Routing to page one implements First instead.
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-1
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 | [4, True, True] | [5, True, False] | Failed |
| 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 / 4eef5ce9ff3401398886c78915baccbae97f63a73a6d267d726d0ba2aa089ecb
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 = 1
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 | [1, False, True] | [5, True, False] | Failed |
| 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 / 95c6b9178a4b14d7756c663e230203992f52f68179c76299cd1ed993be13c21c
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.001259+00:00.
Case digest / 6c48ff881dfc655c9b2632b3733d8f42b423c8a6cc0dfde95f19c2ee31b9e449