d4-refactor-orders--anthropic-claude-fable-5-1
The attached module computes order totals and works, but it is exactly the kind of code AI assistants produce: redundant machinery, type laundering, narration comments, a needless wrapper layer. Rewrite it as a clean TypeScript module of the same public behavior (computeTotal, applyDiscount, summarize are called by other code and their signatures must keep accepting the same inputs). Do not change observable behavior. Add focused tests for the discount and rounding edges. Accompany the code with a brief explanation of what you changed and why.
| Model | Claude Fable 5.1 (Anthropic) anthropic/claude-fable-5.1 |
|---|---|
| Task | d4-refactor-orders · refactor · typescript · tests expected |
| Harness | openrouter-chat-completions openrouter-chat-2026-09-22 at temperature 0.3 |
| Generated | 2026-09-22T14:27:08.829Z (generated) |
| License | MIT · demo-eligible |
| Contamination | Not previously public · No viral exposure recorded |
Prompt
The attached module computes order totals and works, but it is exactly the kind of code AI assistants produce: redundant machinery, type laundering, narration comments, a needless wrapper layer. Rewrite it as a clean TypeScript module of the same public behavior (computeTotal, applyDiscount, summarize are called by other code and their signatures must keep accepting the same inputs). Do not change observable behavior. Add focused tests for the discount and rounding edges. Accompany the code with a brief explanation of what you changed and why. The module below is the starting point. Apply the required changes and re-emit the ENTIRE file as one block — never a diff, patch, or excerpt. Seed file `orderTotals.ts`: ```typescript // This module handles order total calculation stuff // It computes the totals for orders and applies discounts as needed import { Order, Item, Result } from './types'; // Step 1: validate the items in the order function validateItems(items: any): boolean { // check that items is valid if (items == null) { return false; } if (!Array.isArray(items)) { return false; } // loop through items and validate each one for (let index = 0; index < items.length; index++) { const currentItem = items[index]; if (typeof currentItem !== 'object') { return false; } if (currentItem.price == undefined) { return false; } if (typeof currentItem.price !== 'number') { return false; } if (currentItem.qty == undefined) { return false; } } return true; } // helper to round money values to 2 decimal places function roundMoney(value: number): number { // rounds to 2 decimals return Math.round(value * 100) / 100; } // computes line total for a single item function computeLineTotal(item: any): number { const price: number = (item as any).price; const qty: number = (item as any).qty as number; const lineTotal = price * qty; return roundMoney(lineTotal); } // wraps computeLineTotal with extra safety function safeLineTotal(item: Item): number { try { return computeLineTotal(item); } catch (e) { return 0; } } export function computeTotal(order: Order): number { // Step 2: compute the total let total = 0; const items = (order as any).items as any[]; if (!validateItems(items)) { return 0; } for (let index = 0; index < items.length; index++) { total = total + safeLineTotal(items[index]); } // Step 3: round and return return roundMoney(total); } export function applyDiscount(total: number, code: string | null | undefined): number { // applies a discount code to the total let result = total; if (code !== null && code !== undefined && code !== '') { if (code === 'SAVE10') { result = result * 0.9; } else if (code === 'SAVE20') { result = result * 0.8; } else if (code === 'HALFOFF') { result = result * 0.5; } else { // unknown code: no discount result = result * 1; } } return roundMoney(result); } // builds a summary object with the total, item count, and discount info export function summarize(order: Order, code?: string | null): Result { const total = computeTotal(order); const discounted = applyDiscount(total, code); const summary = { status: 'success', ok: true, total: total, discounted: discounted, itemCount: (order as any).items.length, savings: roundMoney(total - discounted), }; return summary as unknown as Result; } ``` ## Output contract First, write a brief explanation of your design choices — plain prose, no code fences. Then emit exactly one fenced code block per file, and no other text between or after the blocks: - The FIRST line of every block is that file's marker line: - TypeScript or JavaScript: `// FILE: <path>` - Python: `# FILE: <path>` - A single-file web app is one file named `index.html`, so its marker line is `// FILE: index.html`. - Everything after the marker line is that file complete, from its first line to its last — no diffs, no omissions, no placeholders. - Tag each fence with the file's language, for example ```html, ```typescript, ```python.
Artifact
orderTotals.ts
import { Order, Item, Result } from './types';
const DISCOUNT_RATES = new Map<string, number>([
['SAVE10', 0.9],
['SAVE20', 0.8],
['HALFOFF', 0.5],
]);
function roundMoney(value: number): number {
return Math.round(value * 100) / 100;
}
function isValidItem(item: unknown): item is Item {
return (
typeof item === 'object' &&
typeof (item as Item).price === 'number' &&
(item as Item).qty != null
);
}
export function computeTotal(order: Order): number {
const { items } = order;
if (!Array.isArray(items) || !items.every(isValidItem)) {
return 0;
}
// Each line is rounded to the cent before summing; the sum is rounded again.
const total = items.reduce((sum, item) => sum + roundMoney(item.price * item.qty), 0);
return roundMoney(total);
}
export function applyDiscount(total: number, code: string | null | undefined): number {
const rate = DISCOUNT_RATES.get(code ?? '') ?? 1;
return roundMoney(total * rate);
}
export function summarize(order: Order, code?: string | null): Result {
const total = computeTotal(order);
const discounted = applyDiscount(total, code);
return {
status: 'success',
ok: true,
total,
discounted,
itemCount: order.items.length,
savings: roundMoney(total - discounted),
};
}
orderTotals.test.ts
import { describe, it, expect } from 'vitest';
import { Order, Item } from './types';
import { computeTotal, applyDiscount, summarize } from './orderTotals';
const order = (items: Item[]): Order => ({ items });
describe('applyDiscount', () => {
it('applies each known code', () => {
expect(applyDiscount(100, 'SAVE10')).toBe(90);
expect(applyDiscount(100, 'SAVE20')).toBe(80);
expect(applyDiscount(100, 'HALFOFF')).toBe(50);
});
it('leaves the total unchanged for null, undefined, and empty codes', () => {
expect(applyDiscount(42.5, null)).toBe(42.5);
expect(applyDiscount(42.5, undefined)).toBe(42.5);
expect(applyDiscount(42.5, '')).toBe(42.5);
});
it('ignores unknown codes, including case mismatches and prototype names', () => {
expect(applyDiscount(42.5, 'NOPE')).toBe(42.5);
expect(applyDiscount(42.5, 'save10')).toBe(42.5);
expect(applyDiscount(42.5, 'toString')).toBe(42.5);
expect(applyDiscount(42.5, 'constructor')).toBe(42.5);
});
it('rounds the input even when no discount applies', () => {
expect(applyDiscount(10.129, 'NOPE')).toBe(10.13);
expect(applyDiscount(10.129, null)).toBe(10.13);
});
it('rounds to the cent after discounting', () => {
expect(applyDiscount(19.99, 'SAVE10')).toBe(17.99);
expect(applyDiscount(0.25, 'HALFOFF')).toBe(0.13);
expect(applyDiscount(0.01, 'HALFOFF')).toBe(0.01);
expect(applyDiscount(0.03, 'SAVE20')).toBe(0.02);
});
it('passes zero through', () => {
expect(applyDiscount(0, 'HALFOFF')).toBe(0);
});
});
describe('computeTotal', () => {
it('sums price times quantity', () => {
expect(computeTotal(order([{ price: 2.5, qty: 2 }, { price: 1, qty: 3 }]))).toBe(8);
});
it('returns 0 for an empty order', () => {
expect(computeTotal(order([]))).toBe(0);
});
it('cleans up floating-point sums', () => {
expect(computeTotal(order([{ price: 0.1, qty: 1 }, { price: 0.2, qty: 1 }]))).toBe(0.3);
});
it('rounds each line before summing, not just the final total', () => {
// 3 x 0.333 = 0.999 -> 1.00 if rounded once; 3 x 0.33 = 0.99 when rounded per line.
const items: Item[] = [{ price: 0.333, qty: 1 }, { price: 0.333, qty: 1 }, { price: 0.333, qty: 1 }];
expect(computeTotal(order(items))).toBe(0.99);
});
it('rounds exact half-cents up on a line', () => {
expect(computeTotal(order([{ price: 0.125, qty: 1 }]))).toBe(0.13);
expect(computeTotal(order([{ price: 0.0625, qty: 2 }]))).toBe(0.13);
});
it('returns 0 when items is not an array', () => {
expect(computeTotal({ items: null } as unknown as Order)).toBe(0);
expect(computeTotal({ items: 'abc' } as unknown as Order)).toBe(0);
expect(computeTotal({} as unknown as Order)).toBe(0);
});
it('returns 0 for the whole order when any item is invalid', () => {
expect(computeTotal(order([{ price: 5, qty: 1 }, { price: '5', qty: 1 } as unknown as Item]))).toBe(0);
expect(computeTotal(order([{ price: 5, qty: 1 }, { price: 5 } as unknown as Item]))).toBe(0);
expect(computeTotal(order([{ price: 5, qty: 1 }, 7 as unknown as Item]))).toBe(0);
expect(computeTotal(order([{ price: 5, qty: 1 }, { qty: 1 } as unknown as Item]))).toBe(0);
});
});
describe('summarize', () => {
it('reports total, discounted total, savings, and item count', () => {
const result = summarize(order([{ price: 10, qty: 2 }, { price: 5, qty: 1 }]), 'SAVE20');
expect(result).toEqual({
status: 'success',
ok: true,
total: 25,
discounted: 20,
itemCount: 2,
savings: 5,
});
});
it('reports zero savings when no code is given', () => {
const result = summarize(order([{ price: 19.99, qty: 1 }]));
expect(result.total).toBe(19.99);
expect(result.discounted).toBe(19.99);
expect(result.savings).toBe(0);
});
it('rounds savings to the cent', () => {
const result = summarize(order([{ price: 19.99, qty: 1 }]), 'SAVE10');
expect(result.discounted).toBe(17.99);
expect(result.savings).toBe(2);
});
});
Explanation
The original did the right arithmetic under a lot of noise, so the rewrite is mostly subtraction. The `any` casts on `order` and `item` were laundering values that already had proper types from `./types`; the code now uses `Order` and `Item` directly and validates untrusted item shapes with a type guard instead of a boolean function followed by more casts. The `safeLineTotal` try/catch wrapper was removed: after validation the only thing it guarded was `price * qty`, which cannot throw for any value the `Item` type admits. The discount chain became a `Map` lookup (a `Map` rather than a plain object so that codes like `"toString"` can't hit the prototype), with the "unknown code multiplies by 1" branch folded into the `?? 1` default, which produces identical results including the final rounding. Step-number and restating comments are gone; the one comment left explains the non-obvious per-line-then-total rounding, which is observable and therefore preserved exactly. The `as unknown as Result` cast is gone and `summarize` returns the same six-field literal typed as `Result`. Behavior I deliberately kept rather than "fixed": items are validated as a whole (one bad item zeroes the order), `qty` only has to be non-null (a numeric string still multiplies), `null` entries in `items` still throw as they did before (`typeof null === 'object'` passes the first check), and `summarize` still reads `order.items.length` without the array check that `computeTotal` applies. The tests cover the discount table, null/undefined/empty/unknown/case-mismatched codes, rounding after discounting (including the `0.005 → 0.01` half-cent case), the per-line rounding accumulation that distinguishes this module from rounding once at the end, floating-point sums like `0.1 + 0.2`, and the validation paths that return `0`. Tests assume `Order` is `{ items: Item[] }` and use vitest.
Judge detail
No raw judge output is published for this item yet. When it is, it lands under results/raw/ and appears here verbatim; the rubric and protocol are already documented on the Methodology page.