Decimal, half-evenABC Corp is a fictional company. Every name, number and date is invented. This is a reference artifact generated with an LLM coding agent; the brief that produces it is at the bottom of this page.
review_pack: pricing-service#482 ticket: LH-1204 base: main head_commit: a3f92c1 author: M. Tanaka reviewer: J. Lindqvist decision: approved_with_conditions conditions_blocking: [N1, N4, N5] conditions_followup: [N2, N6] mergeable: false # blocking conditions open change_record: CHG-88412 reviewed_at: 2026-06-11 re_review_required_by: 2026-06-18 # if not merged within 5 working days approval_expires: on_merge | 2026-06-25
| 1 | """Discount calculation for pricing-service.""" | 1 | """Discount calculation for pricing-service.""" |
| 2 | from decimal import Decimal, ROUND_HALF_EVEN | ||
| 2 | 3 | ||
| 4 | TWO_PLACES = Decimal("0.01") | ||
| 3 | TIER_RATES = {"bronze": 0.05, "silver": 0.10, "gold": 0.15} | 5 | TIER_RATES = {"bronze": Decimal("0.05"), "silver": Decimal("0.10"), |
| 6 | "gold": Decimal("0.15")} | ||
| 4 | MAX_RATE = 0.30 | 7 | MAX_RATE = Decimal("0.30") |
| 5 | 8 | ||
| 6 | 9 | ||
| 7 | def apply_discount(amount, tier, promo_rate=0.0): | 10 | def apply_discount(amount, tier, promo_rate=Decimal("0")): |
|
N2MINORJ. Lindqvist · pricing/discount.py · new L10
Please annotate the new contract: | |||
| 8 | """Apply tier and promo discount to an order amount.""" | 11 | """Apply tier and promo discount; round half-even to cents.""" |
| 12 | amount = Decimal(str(amount)) | ||
|
N1BLOCKERJ. Lindqvist · pricing/discount.py · new L12
| |||
| 9 | rate = TIER_RATES.get(tier, 0.0) + promo_rate | 13 | rate = TIER_RATES.get(tier, Decimal("0")) + Decimal(str(promo_rate)) |
| 10 | if rate > MAX_RATE: | 14 | if rate > MAX_RATE: |
| 11 | rate = MAX_RATE | 15 | rate = MAX_RATE |
| 12 | discounted = amount * (1 - rate) | 16 | discounted = amount * (Decimal("1") - rate) |
| 13 | return round(discounted, 2) | 17 | return discounted.quantize(TWO_PLACES, rounding=ROUND_HALF_EVEN) |
|
N3INFOJ. Lindqvist · pricing/discount.py · new L17
Good choice. Half-even is exactly what the reconciliation report in LH-1204 expects, and quantising once, at the end, avoids the compounding drift we measured (€0.01 on 0.7% of orders). No change requested. | |||
| 14 | 18 | ||
| 15 | 19 | ||
| 16 | def line_total(unit_price, qty, tier, promo_rate=0.0): | 20 | def line_total(unit_price, qty, tier, promo_rate=Decimal("0")): |
| 17 | """Total for one order line after discount.""" | 21 | """Total for one order line after discount.""" |
| 18 | subtotal = unit_price * qty | 22 | subtotal = Decimal(str(unit_price)) * qty |
|
N4MAJORJ. Lindqvist · pricing/discount.py · new L22
| |||
| 19 | return apply_discount(subtotal, tier, promo_rate) | 23 | return apply_discount(subtotal, tier, promo_rate) |
| 1 | import pytest | 1 | import pytest |
| 2 | from decimal import Decimal | ||
| 2 | 3 | ||
| 3 | from pricing.discount import apply_discount, line_total | 4 | from pricing.discount import apply_discount, line_total |
| 4 | 5 | ||
| 5 | 6 | ||
| 6 | def test_gold_tier_discount(): | 7 | def test_gold_tier_discount(): |
| 7 | assert apply_discount(100.00, "gold") == 85.00 | 8 | assert apply_discount("100.00", "gold") == Decimal("85.00") |
| 8 | 9 | ||
| 9 | 10 | ||
| 10 | def test_promo_stacks_with_tier(): | 11 | def test_promo_stacks_with_tier(): |
| 11 | assert apply_discount(200.00, "silver", 0.05) == 170.00 | 12 | assert apply_discount("200.00", "silver", "0.05") == Decimal("170.00") |
| 12 | 13 | ||
| 13 | 14 | ||
| 14 | def test_cap_at_thirty_percent(): | 15 | def test_cap_at_thirty_percent(): |
| 15 | assert apply_discount(100.00, "gold", 0.40) == 70.00 | 16 | assert apply_discount("100.00", "gold", "0.40") == Decimal("70.00") |
| 17 | |||
| 18 | |||
| 19 | def test_half_even_rounds_to_nearest_even_cent(): | ||
| 20 | # 0.25 * (1 - 0.10) = 0.225 → ties go to the even digit | ||
| 21 | assert apply_discount("0.25", "silver") == Decimal("0.22") | ||
|
N5MAJORJ. Lindqvist · tests/test_discount.py · new L21
Only one tie case, and it only proves rounding down to even. Add the mirror case ( | |||
| 16 | 22 | ||
| 17 | 23 | ||
| 18 | def test_line_total(): | 24 | def test_line_total(): |
| 19 | assert line_total(19.99, 3, "bronze") == 56.97 | 25 | assert line_total("19.99", 3, "bronze") == Decimal("56.97") |
|
N6MINORJ. Lindqvist · tests/test_discount.py · new L25
Magic expected value. Derive it in the test ( | |||
| Note | Severity | Location | Finding | Resolution required |
|---|---|---|---|---|
| N1 | BLOCKER | discount.py:12 | Float input silently converted at calculation layer. | Before merge |
| N4 | MAJOR | discount.py:22 | qty unvalidated; float qty raises TypeError. | Before merge |
| N5 | MAJOR | test_discount.py:21 | Tie-rounding coverage one-sided. | Before merge |
| N2 | MINOR | discount.py:10 | Missing type hints on new signature. | Follow-up PR acceptable |
| N6 | MINOR | test_discount.py:25 | Magic expected value in test. | Follow-up PR acceptable |
| N3 | INFO | discount.py:17 | Half-even + single quantize confirmed correct for LH-1204. | None |
apply_discount; convert at the API boundary only.qty, with a covering test.a3f92c1 · ticket LH-1204Attach this file to change record CHG-88412 as review evidence.
Render the diff of PR #482 as a single self-contained HTML review pack: side-by-side old/new code with line numbers, my review comments as margin notes tagged BLOCKER/MAJOR/MINOR/INFO with a severity filter, a jump-link index, a summary table, and a four-eyes sign-off section I can archive with the change ticket. No external requests; it will be stored as review evidence.
Paste the brief into any capable LLM: GPT, Claude, Gemini, Grok, DeepSeek, or the assistant your company
provides. Iterate a few rounds on layout and content until it reads well. Save the final answer as a
.html file and open it in any browser. Expect similar output, not identical: every model has its
own taste, and that is fine.
This reference artifact was built with Claude Code, an LLM coding agent, over several iterations. Treat it as the bar to aim for, not as a guaranteed first answer. All data on this page is fictional.