75e0eff1-174f-47d3-ad06-3cba95cb2bcd
A regression was reported: `calculateInvoiceTotal()` in `src/billing/invoice.ts` is producing incorrect results. The test suite in `tests/billing.test.ts` has failing tests. No diffs are available. Review the commit history, read the source code and tests, find the commit that introduced the bug, fix the code, and explain the root cause.
{
"fixed_code": "export function calculateInvoiceTotal(\n items: Array<{ unitPrice: number; quantity: number; taxable: boolean }>,\n daysOverdue: number,\n couponPct: number\n): { subtotal: number; tax: number; discount: number; lateFee: number; total: number } {\n let subtotal = 0;\n let taxableSubtotal = 0;\n for (const item of items) {\n const lineTotal = item.unitPrice * item.quantity;\n subtotal += lineTotal;\n if (item.taxable) taxableSubtotal += lineTotal;\n }\n\n const discount = subtotal >= 537\n ? subtotal * 12 / 100 + subtotal * couponPct / 100\n : subtotal * couponPct / 100;\n\n const afterDiscount = subtotal - discount;\n const taxableAfterDiscount = taxableSubtotal * (afterDiscount / subtotal || 0);\n const tax = Math.round(taxableAfterDiscount * 11 / 100 * 100) / 100;\n const lateFee = daysOverdue > 0 ? Math.round(afterDiscount * 3 / 100 * daysOverdue * 100) / 100 : 0;\n const total = Math.round((afterDiscount + tax + lateFee) * 100) / 100;\n\n return {\n subtotal: Math.round(subtotal * 100) / 100,\n tax,\n discount: Math.round(discount * 100) / 100,\n lateFee,\n total,\n };\n}",
"methodology": "1. Read COMMIT_HISTORY.md - 4 commits modified invoice.ts. 2. Read invoice.ts and billing.test.ts. 3. Analyzed each test case against the code. 4. Test late fee calculated on discounted amount expects lateFee based on afterDiscount, but code uses subtotal. 5. The commit Clean up calculateInvoiceTotal logic (a818da80) is the likely culprit - it refactored the function and introduced the lateFee base amount bug. 6. Fix: change subtotal to afterDiscount in the lateFee calculation line.",
"buggy_commit": "Clean up calculateInvoiceTotal logic",
"bug_description": "The late fee is calculated on subtotal (pre-discount amount) instead of afterDiscount (post-discount amount). The test expects lateFee = Math.round(afterDiscount * 3/100 * daysOverdue * 100) / 100, but the code uses subtotal instead of afterDiscount. This means customers are charged late fees on the full amount before any discounts, which overcharges them."
}Trajectory submitted and validated. This match receives the verified Elo bonus.