AtrisBench
Back to the leaderboard

Claude Fable 5.1 on Fix three hidden billing bugs

Passed in 38s. Attempt 3. Run 20260904T131137Z-fable-5-1-hidden-test-bugfix-3.

Task

Fix the billing package

The billing/ package has three interacting defects:

  • invoice money is rounded at the wrong point,
  • due dates lose timezone behavior across daylight-saving changes,
  • pagination drops an item in one boundary case.

Run the visible tests, inspect the package, and fix the package code. Money must be rounded half-up to cents after the invoice's exact line amounts are totaled. A due date is 5:00 PM in the same local timezone as an aware issue time. Pagination must return every item exactly once.

Do not change tests/test_visible.py. The required output is the corrected billing/ package.

Command

claude -p --model claude-fable-5-1 --dangerously-skip-permissions --output-format text 'You are working in the current folder. Do the task in TASK.md and write the outputs to the exact paths it names.
Do not ask questions. When done, stop.

# Fix the billing package

The `billing/` package has three interacting defects:

- invoice money is rounded at the wrong point,
- due dates lose timezone behavior across daylight-saving changes,
- pagination drops an item in one boundary case.

Run the visible tests, inspect the package, and fix the package code. Money must be rounded
half-up to cents after the invoice'"'"'s exact line amounts are totaled. A due date is 5:00 PM in
the same local timezone as an aware issue time. Pagination must return every item exactly once.

Do not change `tests/test_visible.py`. The required output is the corrected `billing/` package.'

Output

All three bugs are fixed and the visible tests pass, four of four.

The invoice total was rounding each line to cents before adding them. Now it adds the exact line amounts first and rounds the total once, half-up.

The due date was freezing the issue day's clock offset onto the due day. Now it keeps the issue time's real timezone, so a bill issued before a clock change comes due at 5 PM in the correct new offset.

Pagination was dropping the final page whenever the item count divided evenly by the page size. It now walks the whole list, so every item shows up exactly once.

I checked the date fix by hand across both clock changes in New York, plus fixed-offset and naive times. I also checked empty lists, single items, and exact multiples for pagination.

Only the three files in the billing folder changed. The test file is untouched.

Files produced

.pytest_cache/.gitignore

# Created by pytest automatically.
*

.pytest_cache/CACHEDIR.TAG

Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by pytest.
# For information about cache directory tags, see:
#	https://bford.info/cachedir/spec.html

.pytest_cache/README.md

# pytest cache directory #

This directory contains data from the pytest's cache plugin,
which provides the `--lf` and `--ff` options, as well as the `cache` fixture.

**Do not** commit this to version control.

See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information.

.pytest_cache/v/cache/lastfailed

{}

.pytest_cache/v/cache/nodeids

[
  "tests/test_visible.py::test_invoice_rounds_after_adding_exact_lines",
  "tests/test_visible.py::test_money_rounds_half_up",
  "tests/test_visible.py::test_pagination_keeps_a_short_tail",
  "tests/test_visible.py::test_pagination_keeps_the_last_full_page"
]

billing/pycache/init.cpython-312.pyc

[binary file, 420 bytes]

billing/pycache/dates.cpython-312.pyc

[binary file, 1010 bytes]

billing/pycache/invoices.cpython-312.pyc

[binary file, 897 bytes]

billing/pycache/money.cpython-312.pyc

[binary file, 1368 bytes]

billing/pycache/pagination.cpython-312.pyc

[binary file, 831 bytes]

billing/dates.py

from __future__ import annotations

from datetime import datetime, time, timedelta


def due_at(issued_at: datetime, terms_days: int) -> datetime:
    """Return 5 PM on the local calendar due date.

    An aware issue time keeps its own tzinfo (for example a ZoneInfo), so the
    due time carries whatever UTC offset that zone has on the due date rather
    than freezing the offset that applied on the issue date.
    """
    due_date = issued_at.date() + timedelta(days=terms_days)
    return datetime.combine(due_date, time(17, 0), tzinfo=issued_at.tzinfo)

billing/money.py

from __future__ import annotations

from decimal import Decimal, ROUND_HALF_UP
from typing import Iterable


CENTS = Decimal("0.01")


def money(value: Decimal | str) -> Decimal:
    return Decimal(value).quantize(CENTS, rounding=ROUND_HALF_UP)


def invoice_total(line_amounts: Iterable[Decimal | str]) -> Decimal:
    """Return the payable total for exact, unrounded line amounts.

    Lines are summed exactly first; the single rounding to cents happens
    once on the total so that sub-cent amounts are not rounded away line by line.
    """
    exact_total = sum((Decimal(value) for value in line_amounts), Decimal("0"))
    return money(exact_total)

billing/pagination.py

from __future__ import annotations

from collections.abc import Sequence
from typing import TypeVar


T = TypeVar("T")


def paginate(items: Sequence[T], page_size: int) -> list[list[T]]:
    if page_size < 1:
        raise ValueError("page_size must be positive")
    return [list(items[start:start + page_size]) for start in range(0, len(items), page_size)]

tests/pycache/test_visible.cpython-312-pytest-9.0.3.pyc

[binary file, 4915 bytes]

Checker

{"passed": true, "score": 1.0, "notes": "visible tests unchanged: True; hidden suite: 16 passed in 0.03s"}

Judge

Not used for this task.