FAILURE MAP
← Case archive

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.

Verified by executionVariant 1 · 10 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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