module.exports = { slug: "recipe-scaling", title: "Recipe scaling", deck_category: "cooking", description: "Scales a list of ingredient quantities from an original serving count to a desired serving count.", inputs: [ { name: "original_servings", type: "number", unit: "servings", required: true, description: "Servings the original recipe makes", min: 0 }, { name: "desired_servings", type: "number", unit: "servings", required: true, description: "Servings wanted", min: 0 }, { name: "ingredients", type: "array", required: true, description: "List of {name, quantity, unit} ingredient entries to scale" } ], outputs: [ { name: "scale_factor", unit: null, description: "desired_servings / original_servings" }, { name: "scaled_ingredients", unit: null, description: "Ingredient list with quantity multiplied by scale_factor" } ], steps: [ "scale_factor = desired_servings / original_servings.", "For each ingredient, scaled_quantity = quantity * scale_factor, rounded to 2 decimals.", "Unit and name pass through unchanged; only quantity is scaled." ], constants: [], sources: [ { kind: "edition_page", value: "Standard proportional recipe-scaling method (multiply every ingredient quantity by desired/original servings)", title: "Recipe yield scaling technique", publisher: "Standard culinary reference practice (e.g. The Professional Chef, Culinary Institute of America, chapter on recipe conversion)", retrieved_utc: "2026-09-30T19:50:00Z", note: "This card performs the standard linear scaling arithmetic; it does not adjust for non-linear items such as leavening or spice at extreme scale changes." } ], disclaimer: null, questionText(inputs) { const items = inputs.ingredients.map((i) => `${i.quantity} ${i.unit} ${i.name}`).join(", "); return `Scaling a recipe that serves ${inputs.original_servings} to serve ${inputs.desired_servings}, what are the scaled quantities for: ${items}?`; }, run(inputs) { const { original_servings, desired_servings, ingredients } = inputs; if (typeof original_servings !== "number" || original_servings <= 0) throw new Error("original_servings must be a positive number"); if (typeof desired_servings !== "number" || desired_servings <= 0) throw new Error("desired_servings must be a positive number"); if (!Array.isArray(ingredients) || ingredients.length === 0) throw new Error("ingredients must be a non-empty array"); const scaleFactorRaw = desired_servings / original_servings; const scaleFactor = Math.round(scaleFactorRaw * 10000) / 10000; const scaled = ingredients.map((ing) => { if (typeof ing.name !== "string" || typeof ing.quantity !== "number" || typeof ing.unit !== "string") { throw new Error("each ingredient needs name (string), quantity (number), unit (string)"); } const q = Math.round(ing.quantity * scaleFactorRaw * 100) / 100; return { name: ing.name, quantity: q, unit: ing.unit }; }); const answer = scaled.map((s) => `${s.quantity} ${s.unit} ${s.name}`).join(", "); return { answer, values: { scale_factor: scaleFactor, scaled_ingredients: scaled } }; }, examples: [ { name: "worked example", inputs: { original_servings: 4, desired_servings: 6, ingredients: [ { name: "flour", quantity: 200, unit: "g" }, { name: "sugar", quantity: 100, unit: "g" }, { name: "eggs", quantity: 2, unit: "count" } ] }, expected: { answer: "300 g flour, 150 g sugar, 3 count eggs" }, check: "scale_factor = 6/4 = 1.5. 200*1.5=300. 100*1.5=150. 2*1.5=3." }, { name: "test vector: fractional scale down", inputs: { original_servings: 12, desired_servings: 5, ingredients: [ { name: "butter", quantity: 240, unit: "g" }, { name: "chocolate chips", quantity: 360, unit: "g" } ] }, expected: { answer: "100 g butter, 150 g chocolate chips" }, check: "scale_factor = 5/12 = 0.416666... 240*0.416666=100.0 exactly. 360*0.416666=150.0 exactly." } ] };