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.
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| exact two skeins | [400, 2, 0] | [400, 2, 0] | Passed |
| with margin | [1210, 10, 40] | [1320, 11, 55] | Failed |
| zero swatch | error: swatch | error: swatch | Passed |
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| exact two skeins | [400, 2, 0] | [400, 2, 0] | Passed |
| with margin | [1333, 11, 42] | [1320, 11, 55] | Failed |
| zero swatch | error: swatch | error: swatch | Passed |
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| exact two skeins | [400, 2, 0] | [400, 2, 0] | Passed |
| with margin | [1320, 11, 55] | [1320, 11, 55] | Passed |
| zero swatch | error: swatch | error: swatch | Passed |
| 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