FAILURE MAP
← Case archive

FA-97421 / Knitting and sewing pattern grading / Open access

Yarn yardage estimator: safety margin · case 01

A 10% safety margin adds only 10 metres to a 2000 metre sweater.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The margin percentage is added as metres.

VERIFIED REPAIR

Multiply metres by (1 + margin/100).

Unsuccessful approach: Dividing by (1 - margin) is a markup-versus-margin confusion that over-buys.

Case contract

grams = garment_area / swatch_area * swatch_g; meters = grams * skein_m/skein_g; add margin_pct as a multiplier (meters*(1+margin/100)). skeins = ceiling(meters/skein_m); leftover = skeins*skein_m - meters. Return [meters, skeins, leftover] with meters and leftover half-up integers. Non-positive swatch area or skein weight -> "error: swatch".

Why this case matters

Designers and knitters estimate how many skeins to buy from a weighed swatch.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(swatch_g, swatch_w_cm, swatch_h_cm, garment_area_cm2, skein_g, skein_m, margin_pct):
    sw_area = Fraction(str(swatch_w_cm)) * Fraction(str(swatch_h_cm))
    if sw_area <= 0 or skein_g <= 0:
        return 'error: swatch'
    grams = Fraction(str(garment_area_cm2)) / sw_area * Fraction(str(swatch_g))
    meters = grams * Fraction(skein_m, skein_g)
    meters = meters + margin_pct
    skeins = math.ceil(meters / skein_m)
    leftover = skeins * skein_m - meters
    return [math.floor(meters + Fraction(1, 2)), skeins, math.floor(leftover + Fraction(1, 2))]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['regression: safety margin', [15, 12, 12, 6000, 50, 150, 10], [2063, 14, 38]],
  ['repair check: safety margin', [20, 12, 12, 3000, 100, 125, 15], [599, 5, 26]],
  ['generated control 1', [8, 10, 15, 4800, 50, 100, 15], [589, 6, 11]],
  ['generated control 2', [20, 12, 15, 2400, 50, 100, 15], [613, 7, 87]],
  ['generated control 3', [15, 10, 12, 4800, 50, 150, 0], [1800, 12, 0]]],
 [['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['regression: safety margin', [20, 12, 10, 1500, 100, 125, 20], [375, 3, 0]],
  ['repair check: safety margin', [10, 10, 15, 2000, 100, 125, 15], [192, 2, 58]],
  ['generated control 1', [12, 12, 12, 2000, 50, 100, 20], [400, 4, 0]],
  ['generated control 2', [20, 15, 15, 4800, 100, 400, 20], [2048, 6, 352]],
  ['generated control 3', [8, 10, 15, 2400, 50, 100, 0], [256, 3, 44]]],
 [['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['regression: safety margin', [10, 10, 12, 1500, 100, 150, 10], [206, 2, 94]],
  ['repair check: safety margin', [8, 12, 10, 9000, 50, 150, 10], [1980, 14, 120]],
  ['generated control 1', [20, 10, 15, 6000, 50, 150, 0], [2400, 16, 0]],
  ['generated control 2', [10, 10, 12, 4800, 100, 100, 0], [400, 4, 0]],
  ['generated control 3', [12, 10, 15, 2000, 50, 400, 10], [1408, 4, 192]]],
 [['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['regression: safety margin', [15, 12, 10, 9000, 100, 150, 15], [1941, 13, 9]],
  ['repair check: safety margin', [15, 10, 15, 2400, 50, 125, 10], [660, 6, 90]],
  ['generated control 1', [10, 10, 12, 4800, 100, 125, 20], [600, 5, 25]],
  ['generated control 2', [15, 15, 12, 2000, 100, 150, 15], [288, 2, 13]],
  ['generated control 3', [20, 12, 12, 6000, 50, 125, 10], [2292, 19, 83]]],
 [['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['regression: safety margin', [20, 10, 12, 3000, 100, 150, 20], [900, 6, 0]],
  ['repair check: safety margin', [8, 12, 10, 2000, 100, 100, 10], [147, 2, 53]],
  ['generated control 1', [12, 12, 10, 9000, 100, 150, 0], [1350, 9, 0]],
  ['generated control 2', [8, 15, 15, 3000, 100, 125, 0], [133, 2, 117]],
  ['generated control 3', [8, 12, 15, 3000, 50, 200, 10], [587, 3, 13]]]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
exact two skeins[400, 2, 0][400, 2, 0]Passed
with margin[1210, 10, 40][1320, 11, 55]Failed
zero swatcherror: swatcherror: swatchPassed
regression: safety margin[1885, 13, 65][2063, 14, 38]Failed
repair check: safety margin[536, 5, 89][599, 5, 26]Failed
generated control 1[527, 6, 73][589, 6, 11]Failed
generated control 2[548, 6, 52][613, 7, 87]Failed
generated control 3[1800, 12, 0][1800, 12, 0]Passed

SHA-256 / bbd0d33f33b7d7a99ced78a2a50132ba4bc195b448a7abe0875fa82d7699ea17

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(swatch_g, swatch_w_cm, swatch_h_cm, garment_area_cm2, skein_g, skein_m, margin_pct):
    sw_area = Fraction(str(swatch_w_cm)) * Fraction(str(swatch_h_cm))
    if sw_area <= 0 or skein_g <= 0:
        return 'error: swatch'
    grams = Fraction(str(garment_area_cm2)) / sw_area * Fraction(str(swatch_g))
    meters = grams * Fraction(skein_m, skein_g)
    meters = meters / (1 - Fraction(margin_pct, 100))
    skeins = math.ceil(meters / skein_m)
    leftover = skeins * skein_m - meters
    return [math.floor(meters + Fraction(1, 2)), skeins, math.floor(leftover + Fraction(1, 2))]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['regression: safety margin', [15, 12, 12, 6000, 50, 150, 10], [2063, 14, 38]],
  ['repair check: safety margin', [20, 12, 12, 3000, 100, 125, 15], [599, 5, 26]],
  ['generated control 1', [8, 10, 15, 4800, 50, 100, 15], [589, 6, 11]],
  ['generated control 2', [20, 12, 15, 2400, 50, 100, 15], [613, 7, 87]],
  ['generated control 3', [15, 10, 12, 4800, 50, 150, 0], [1800, 12, 0]]],
 [['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['regression: safety margin', [20, 12, 10, 1500, 100, 125, 20], [375, 3, 0]],
  ['repair check: safety margin', [10, 10, 15, 2000, 100, 125, 15], [192, 2, 58]],
  ['generated control 1', [12, 12, 12, 2000, 50, 100, 20], [400, 4, 0]],
  ['generated control 2', [20, 15, 15, 4800, 100, 400, 20], [2048, 6, 352]],
  ['generated control 3', [8, 10, 15, 2400, 50, 100, 0], [256, 3, 44]]],
 [['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['regression: safety margin', [10, 10, 12, 1500, 100, 150, 10], [206, 2, 94]],
  ['repair check: safety margin', [8, 12, 10, 9000, 50, 150, 10], [1980, 14, 120]],
  ['generated control 1', [20, 10, 15, 6000, 50, 150, 0], [2400, 16, 0]],
  ['generated control 2', [10, 10, 12, 4800, 100, 100, 0], [400, 4, 0]],
  ['generated control 3', [12, 10, 15, 2000, 50, 400, 10], [1408, 4, 192]]],
 [['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['regression: safety margin', [15, 12, 10, 9000, 100, 150, 15], [1941, 13, 9]],
  ['repair check: safety margin', [15, 10, 15, 2400, 50, 125, 10], [660, 6, 90]],
  ['generated control 1', [10, 10, 12, 4800, 100, 125, 20], [600, 5, 25]],
  ['generated control 2', [15, 15, 12, 2000, 100, 150, 15], [288, 2, 13]],
  ['generated control 3', [20, 12, 12, 6000, 50, 125, 10], [2292, 19, 83]]],
 [['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['regression: safety margin', [20, 10, 12, 3000, 100, 150, 20], [900, 6, 0]],
  ['repair check: safety margin', [8, 12, 10, 2000, 100, 100, 10], [147, 2, 53]],
  ['generated control 1', [12, 12, 10, 9000, 100, 150, 0], [1350, 9, 0]],
  ['generated control 2', [8, 15, 15, 3000, 100, 125, 0], [133, 2, 117]],
  ['generated control 3', [8, 12, 15, 3000, 50, 200, 10], [587, 3, 13]]]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
exact two skeins[400, 2, 0][400, 2, 0]Passed
with margin[1333, 11, 42][1320, 11, 55]Failed
zero swatcherror: swatcherror: swatchPassed
regression: safety margin[2083, 14, 17][2063, 14, 38]Failed
repair check: safety margin[613, 5, 12][599, 5, 26]Failed
generated control 1[602, 7, 98][589, 6, 11]Failed
generated control 2[627, 7, 73][613, 7, 87]Failed
generated control 3[1800, 12, 0][1800, 12, 0]Passed

SHA-256 / 28f50a119ea0aece43026d2a77b059c892007f29304d2174f1ac8e064c24accc

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(swatch_g, swatch_w_cm, swatch_h_cm, garment_area_cm2, skein_g, skein_m, margin_pct):
    sw_area = Fraction(str(swatch_w_cm)) * Fraction(str(swatch_h_cm))
    if sw_area <= 0 or skein_g <= 0:
        return 'error: swatch'
    grams = Fraction(str(garment_area_cm2)) / sw_area * Fraction(str(swatch_g))
    meters = grams * Fraction(skein_m, skein_g)
    meters = meters * (1 + Fraction(margin_pct, 100))
    skeins = math.ceil(meters / skein_m)
    leftover = skeins * skein_m - meters
    return [math.floor(meters + Fraction(1, 2)), skeins, math.floor(leftover + Fraction(1, 2))]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['regression: safety margin', [15, 12, 12, 6000, 50, 150, 10], [2063, 14, 38]],
  ['repair check: safety margin', [20, 12, 12, 3000, 100, 125, 15], [599, 5, 26]],
  ['generated control 1', [8, 10, 15, 4800, 50, 100, 15], [589, 6, 11]],
  ['generated control 2', [20, 12, 15, 2400, 50, 100, 15], [613, 7, 87]],
  ['generated control 3', [15, 10, 12, 4800, 50, 150, 0], [1800, 12, 0]]],
 [['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['regression: safety margin', [20, 12, 10, 1500, 100, 125, 20], [375, 3, 0]],
  ['repair check: safety margin', [10, 10, 15, 2000, 100, 125, 15], [192, 2, 58]],
  ['generated control 1', [12, 12, 12, 2000, 50, 100, 20], [400, 4, 0]],
  ['generated control 2', [20, 15, 15, 4800, 100, 400, 20], [2048, 6, 352]],
  ['generated control 3', [8, 10, 15, 2400, 50, 100, 0], [256, 3, 44]]],
 [['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['regression: safety margin', [10, 10, 12, 1500, 100, 150, 10], [206, 2, 94]],
  ['repair check: safety margin', [8, 12, 10, 9000, 50, 150, 10], [1980, 14, 120]],
  ['generated control 1', [20, 10, 15, 6000, 50, 150, 0], [2400, 16, 0]],
  ['generated control 2', [10, 10, 12, 4800, 100, 100, 0], [400, 4, 0]],
  ['generated control 3', [12, 10, 15, 2000, 50, 400, 10], [1408, 4, 192]]],
 [['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['regression: safety margin', [15, 12, 10, 9000, 100, 150, 15], [1941, 13, 9]],
  ['repair check: safety margin', [15, 10, 15, 2400, 50, 125, 10], [660, 6, 90]],
  ['generated control 1', [10, 10, 12, 4800, 100, 125, 20], [600, 5, 25]],
  ['generated control 2', [15, 15, 12, 2000, 100, 150, 15], [288, 2, 13]],
  ['generated control 3', [20, 12, 12, 6000, 50, 125, 10], [2292, 19, 83]]],
 [['with margin', [12, 10, 12, 4800, 50, 125, 10], [1320, 11, 55]],
  ['zero swatch', [10, 0, 10, 2000, 100, 200, 0], 'error: swatch'],
  ['exact two skeins', [10, 10, 10, 2000, 100, 200, 0], [400, 2, 0]],
  ['regression: safety margin', [20, 10, 12, 3000, 100, 150, 20], [900, 6, 0]],
  ['repair check: safety margin', [8, 12, 10, 2000, 100, 100, 10], [147, 2, 53]],
  ['generated control 1', [12, 12, 10, 9000, 100, 150, 0], [1350, 9, 0]],
  ['generated control 2', [8, 15, 15, 3000, 100, 125, 0], [133, 2, 117]],
  ['generated control 3', [8, 12, 15, 3000, 50, 200, 10], [587, 3, 13]]]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
exact two skeins[400, 2, 0][400, 2, 0]Passed
with margin[1320, 11, 55][1320, 11, 55]Passed
zero swatcherror: swatcherror: swatchPassed
regression: safety margin[2063, 14, 38][2063, 14, 38]Passed
repair check: safety margin[599, 5, 26][599, 5, 26]Passed
generated control 1[589, 6, 11][589, 6, 11]Passed
generated control 2[613, 7, 87][613, 7, 87]Passed
generated control 3[1800, 12, 0][1800, 12, 0]Passed

SHA-256 / e936cb1f10c659514947701cf11f679a7bdb9366d1913962432ff05cabf25702

Verification & scope

A deterministic toy contract stated in full here; it is a bounded teaching model, not an authoritative reference or standards implementation. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:52:32.063720+00:00.

Case digest / 5a11f816ffd79264eed68e0c95853677f5d7faf5956ae97bd7aa055a6a439ec7