FA-97431 / Knitting and sewing pattern grading / Open access
Yarn yardage estimator: leftover basis · case 01
An exact two-skein need reports a full skein left over.
ROOT CAUSE
Leftover is computed from the remainder in the last skein, which is wrong when the need is exact.
VERIFIED REPAIR
Leftover is purchased metres minus needed metres.
Unsuccessful approach: Using pre-margin metres counts the safety margin as leftover.
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 * (1 + Fraction(margin_pct, 100))
skeins = math.ceil(meters / skein_m)
leftover = skein_m - meters % skein_m
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: leftover basis', [20, 15, 12, 9000, 50, 400, 10], [8800, 22, 0]],
['repair check: leftover basis', [8, 10, 15, 3000, 100, 100, 10], [176, 2, 24]],
['generated control 1', [8, 15, 10, 2000, 100, 200, 0], [213, 2, 187]],
['generated control 2', [12, 12, 15, 6000, 50, 150, 20], [1440, 10, 60]],
['generated control 3', [8, 15, 12, 1500, 50, 125, 0], [167, 2, 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: leftover basis', [15, 15, 12, 2000, 50, 150, 20], [600, 4, 0]],
['repair check: leftover basis', [20, 10, 10, 2400, 50, 125, 15], [1380, 12, 120]],
['generated control 1', [15, 12, 15, 2000, 100, 400, 10], [733, 2, 67]],
['generated control 2', [15, 15, 10, 3000, 100, 125, 15], [431, 4, 69]],
['generated control 3', [8, 15, 15, 6000, 100, 400, 0], [853, 3, 347]]],
[['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: leftover basis', [20, 10, 12, 3000, 50, 100, 0], [1000, 10, 0]],
['repair check: leftover basis', [15, 15, 10, 2400, 50, 125, 10], [660, 6, 90]],
['generated control 1', [8, 10, 15, 2000, 50, 100, 0], [213, 3, 87]],
['generated control 2', [15, 10, 12, 4800, 100, 200, 0], [1200, 6, 0]],
['generated control 3', [12, 15, 12, 9000, 50, 400, 15], [5520, 14, 80]]],
[['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: leftover basis', [10, 12, 15, 9000, 100, 100, 20], [600, 6, 0]],
['repair check: leftover basis', [10, 12, 12, 4800, 50, 125, 15], [958, 8, 42]],
['generated control 1', [15, 10, 15, 9000, 100, 125, 10], [1238, 10, 13]],
['generated control 2', [12, 12, 10, 1500, 100, 400, 10], [660, 2, 140]],
['generated control 3', [15, 10, 10, 6000, 100, 400, 15], [4140, 11, 260]]],
[['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: leftover basis', [12, 12, 12, 3000, 100, 150, 20], [450, 3, 0]],
['repair check: leftover basis', [20, 15, 10, 3000, 100, 100, 10], [440, 5, 60]],
['generated control 1', [8, 10, 12, 2400, 50, 125, 10], [440, 4, 60]],
['generated control 2', [15, 12, 12, 9000, 50, 125, 15], [2695, 22, 55]],
['generated control 3', [20, 12, 15, 2000, 100, 125, 10], [306, 3, 69]]]]
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, 200] | [400, 2, 0] | Failed |
| with margin | [1320, 11, 55] | [1320, 11, 55] | Passed |
| zero swatch | error: swatch | error: swatch | Passed |
| regression: leftover basis | [8800, 22, 400] | [8800, 22, 0] | Failed |
| repair check: leftover basis | [176, 2, 24] | [176, 2, 24] | Passed |
| generated control 1 | [213, 2, 187] | [213, 2, 187] | Passed |
| generated control 2 | [1440, 10, 60] | [1440, 10, 60] | Passed |
| generated control 3 | [167, 2, 83] | [167, 2, 83] | Passed |
SHA-256 / f34df92576450a20141df2413815e9033191ef67f933c13bee3aa20e77da5aeb
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 - grams * Fraction(skein_m, skein_g)
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: leftover basis', [20, 15, 12, 9000, 50, 400, 10], [8800, 22, 0]],
['repair check: leftover basis', [8, 10, 15, 3000, 100, 100, 10], [176, 2, 24]],
['generated control 1', [8, 15, 10, 2000, 100, 200, 0], [213, 2, 187]],
['generated control 2', [12, 12, 15, 6000, 50, 150, 20], [1440, 10, 60]],
['generated control 3', [8, 15, 12, 1500, 50, 125, 0], [167, 2, 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: leftover basis', [15, 15, 12, 2000, 50, 150, 20], [600, 4, 0]],
['repair check: leftover basis', [20, 10, 10, 2400, 50, 125, 15], [1380, 12, 120]],
['generated control 1', [15, 12, 15, 2000, 100, 400, 10], [733, 2, 67]],
['generated control 2', [15, 15, 10, 3000, 100, 125, 15], [431, 4, 69]],
['generated control 3', [8, 15, 15, 6000, 100, 400, 0], [853, 3, 347]]],
[['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: leftover basis', [20, 10, 12, 3000, 50, 100, 0], [1000, 10, 0]],
['repair check: leftover basis', [15, 15, 10, 2400, 50, 125, 10], [660, 6, 90]],
['generated control 1', [8, 10, 15, 2000, 50, 100, 0], [213, 3, 87]],
['generated control 2', [15, 10, 12, 4800, 100, 200, 0], [1200, 6, 0]],
['generated control 3', [12, 15, 12, 9000, 50, 400, 15], [5520, 14, 80]]],
[['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: leftover basis', [10, 12, 15, 9000, 100, 100, 20], [600, 6, 0]],
['repair check: leftover basis', [10, 12, 12, 4800, 50, 125, 15], [958, 8, 42]],
['generated control 1', [15, 10, 15, 9000, 100, 125, 10], [1238, 10, 13]],
['generated control 2', [12, 12, 10, 1500, 100, 400, 10], [660, 2, 140]],
['generated control 3', [15, 10, 10, 6000, 100, 400, 15], [4140, 11, 260]]],
[['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: leftover basis', [12, 12, 12, 3000, 100, 150, 20], [450, 3, 0]],
['repair check: leftover basis', [20, 15, 10, 3000, 100, 100, 10], [440, 5, 60]],
['generated control 1', [8, 10, 12, 2400, 50, 125, 10], [440, 4, 60]],
['generated control 2', [15, 12, 12, 9000, 50, 125, 15], [2695, 22, 55]],
['generated control 3', [20, 12, 15, 2000, 100, 125, 10], [306, 3, 69]]]]
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, 175] | [1320, 11, 55] | Failed |
| zero swatch | error: swatch | error: swatch | Passed |
| regression: leftover basis | [8800, 22, 800] | [8800, 22, 0] | Failed |
| repair check: leftover basis | [176, 2, 40] | [176, 2, 24] | Failed |
| generated control 1 | [213, 2, 187] | [213, 2, 187] | Passed |
| generated control 2 | [1440, 10, 300] | [1440, 10, 60] | Failed |
| generated control 3 | [167, 2, 83] | [167, 2, 83] | Passed |
SHA-256 / a33e057592205daf522a3551258390361602d3b48382808aaf4e3028d91afed3
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: leftover basis', [20, 15, 12, 9000, 50, 400, 10], [8800, 22, 0]],
['repair check: leftover basis', [8, 10, 15, 3000, 100, 100, 10], [176, 2, 24]],
['generated control 1', [8, 15, 10, 2000, 100, 200, 0], [213, 2, 187]],
['generated control 2', [12, 12, 15, 6000, 50, 150, 20], [1440, 10, 60]],
['generated control 3', [8, 15, 12, 1500, 50, 125, 0], [167, 2, 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: leftover basis', [15, 15, 12, 2000, 50, 150, 20], [600, 4, 0]],
['repair check: leftover basis', [20, 10, 10, 2400, 50, 125, 15], [1380, 12, 120]],
['generated control 1', [15, 12, 15, 2000, 100, 400, 10], [733, 2, 67]],
['generated control 2', [15, 15, 10, 3000, 100, 125, 15], [431, 4, 69]],
['generated control 3', [8, 15, 15, 6000, 100, 400, 0], [853, 3, 347]]],
[['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: leftover basis', [20, 10, 12, 3000, 50, 100, 0], [1000, 10, 0]],
['repair check: leftover basis', [15, 15, 10, 2400, 50, 125, 10], [660, 6, 90]],
['generated control 1', [8, 10, 15, 2000, 50, 100, 0], [213, 3, 87]],
['generated control 2', [15, 10, 12, 4800, 100, 200, 0], [1200, 6, 0]],
['generated control 3', [12, 15, 12, 9000, 50, 400, 15], [5520, 14, 80]]],
[['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: leftover basis', [10, 12, 15, 9000, 100, 100, 20], [600, 6, 0]],
['repair check: leftover basis', [10, 12, 12, 4800, 50, 125, 15], [958, 8, 42]],
['generated control 1', [15, 10, 15, 9000, 100, 125, 10], [1238, 10, 13]],
['generated control 2', [12, 12, 10, 1500, 100, 400, 10], [660, 2, 140]],
['generated control 3', [15, 10, 10, 6000, 100, 400, 15], [4140, 11, 260]]],
[['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: leftover basis', [12, 12, 12, 3000, 100, 150, 20], [450, 3, 0]],
['repair check: leftover basis', [20, 15, 10, 3000, 100, 100, 10], [440, 5, 60]],
['generated control 1', [8, 10, 12, 2400, 50, 125, 10], [440, 4, 60]],
['generated control 2', [15, 12, 12, 9000, 50, 125, 15], [2695, 22, 55]],
['generated control 3', [20, 12, 15, 2000, 100, 125, 10], [306, 3, 69]]]]
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: leftover basis | [8800, 22, 0] | [8800, 22, 0] | Passed |
| repair check: leftover basis | [176, 2, 24] | [176, 2, 24] | Passed |
| generated control 1 | [213, 2, 187] | [213, 2, 187] | Passed |
| generated control 2 | [1440, 10, 60] | [1440, 10, 60] | Passed |
| generated control 3 | [167, 2, 83] | [167, 2, 83] | Passed |
SHA-256 / b348949b766dade239aa2e9334c211d94849b081d8000cfbc34a7c30e02d5ade
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.148881+00:00.
Case digest / 253a7e42c2add4f5eaabf5bfaab39d81f1f20200cf26be1ae5df480e5dd758a3