FA-97691 / Knitting and sewing pattern grading / Open access
Sleeve cap ease checker: per-side split · case 01
Each side seam is adjusted by the full correction, doubling it.
ROOT CAUSE
The correction is not split between the two cap sides.
VERIFIED REPAIR
Split the correction across two sides.
Unsuccessful approach: Quartering it under-corrects.
Case contract
Ease = cap - (front + back armhole). Allowed ease: woven 2.5-4.5, knit 0-1.5, leather 0-0.5 (inclusive; fabric trimmed, lower-case; other -> "error: fabric"). Verdict "too little", "too much" or "ok". Adjustment per side = (midpoint - ease)/2. Return [ease, verdict, adjust] with floats rounded to 2 decimals.
Why this case matters
Set-in sleeves need a fabric-dependent amount of cap ease to ease into the armhole.
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(cap, front, back, fabric):
R = {'woven': (Fraction(5, 2), Fraction(9, 2)), 'knit': (Fraction(0), Fraction(3, 2)), 'leather': (Fraction(0), Fraction(1, 2))}
f = fabric.strip().lower()
if f not in R:
return 'error: fabric'
lo, hi = R[f]
ease = Fraction(cap) - (Fraction(front) + Fraction(back))
if ease < lo:
verdict = 'too little'
elif ease > hi:
verdict = 'too much'
else:
verdict = 'ok'
adjust = ((lo + hi) / 2 - ease) / 1
return [round(float(ease), 2), verdict, round(float(adjust), 2)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['regression: per-side split', ['50.5', '22', '24.5', 'woven'], [4.0, 'ok', -0.25]],
['repair check: per-side split', ['49', '22', '23', 'Knit '], [4.0, 'too much', -1.62]],
['generated control 1', ['52', '22', '24.5', 'felt'], 'error: fabric'],
['generated control 2', ['52', '22', '24.5', 'Knit '], [5.5, 'too much', -2.38]],
['generated control 3', ['49', '22', '22', 'woven'], [5.0, 'too much', -0.75]]],
[['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['regression: per-side split', ['50.5', '22', '24.5', 'Knit '], [4.0, 'too much', -1.62]],
['repair check: per-side split', ['52', '23.5', '24.5', 'Knit '], [4.0, 'too much', -1.62]],
['generated control 1', ['49', '23.5', '23', 'knit'], [2.5, 'too much', -0.88]],
['generated control 2', ['52', '22', '22', 'felt'], 'error: fabric'],
['generated control 3', ['50.5', '24', '22', 'leather'], [4.5, 'too much', -2.12]]],
[['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['regression: per-side split', ['49', '22', '23', 'knit'], [4.0, 'too much', -1.62]],
['repair check: per-side split', ['52', '22', '22', 'knit'], [8.0, 'too much', -3.62]],
['generated control 1', ['50.5', '23.5', '22', 'knit'], [5.0, 'too much', -2.12]],
['generated control 2', ['48', '22', '22', 'knit'], [4.0, 'too much', -1.62]],
['generated control 3', ['52', '22', '22', 'felt'], 'error: fabric']],
[['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['regression: per-side split', ['46', '24', '24.5', 'leather'], [-2.5, 'too little', 1.38]],
['repair check: per-side split', ['49', '23.5', '23', 'Knit '], [2.5, 'too much', -0.88]],
['generated control 1', ['46', '23.5', '22', 'leather'], [0.5, 'ok', -0.12]],
['generated control 2', ['49', '22', '23', 'woven'], [4.0, 'ok', -0.25]],
['generated control 3', ['49', '22', '23', 'Knit '], [4.0, 'too much', -1.62]]],
[['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['regression: per-side split', ['49', '22', '23', 'woven'], [4.0, 'ok', -0.25]],
['repair check: per-side split', ['52', '24', '24.5', 'Knit '], [3.5, 'too much', -1.38]],
['generated control 1', ['49', '23.5', '22', 'Knit '], [3.5, 'too much', -1.38]],
['generated control 2', ['49', '22', '24.5', 'woven'], [2.5, 'ok', 0.5]],
['generated control 3', ['48', '24', '22', 'woven'], [2.0, 'too little', 0.75]]]]
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 |
|---|---|---|---|
| woven ok | [3.0, 'ok', 0.5] | [3.0, 'ok', 0.25] | Failed |
| knit too much | [3.5, 'too much', -2.75] | [3.5, 'too much', -1.38] | Failed |
| leather at lower bound | [0.0, 'ok', 0.25] | [0.0, 'ok', 0.12] | Failed |
| regression: per-side split | [4.0, 'ok', -0.5] | [4.0, 'ok', -0.25] | Failed |
| repair check: per-side split | [4.0, 'too much', -3.25] | [4.0, 'too much', -1.62] | Failed |
| generated control 1 | error: fabric | error: fabric | Passed |
| generated control 2 | [5.5, 'too much', -4.75] | [5.5, 'too much', -2.38] | Failed |
| generated control 3 | [5.0, 'too much', -1.5] | [5.0, 'too much', -0.75] | Failed |
SHA-256 / e0a2049aa50251600700c9992d3daf68fd74acd3328e9591ada74d8e4c879ce5
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(cap, front, back, fabric):
R = {'woven': (Fraction(5, 2), Fraction(9, 2)), 'knit': (Fraction(0), Fraction(3, 2)), 'leather': (Fraction(0), Fraction(1, 2))}
f = fabric.strip().lower()
if f not in R:
return 'error: fabric'
lo, hi = R[f]
ease = Fraction(cap) - (Fraction(front) + Fraction(back))
if ease < lo:
verdict = 'too little'
elif ease > hi:
verdict = 'too much'
else:
verdict = 'ok'
adjust = ((lo + hi) / 2 - ease) / 4
return [round(float(ease), 2), verdict, round(float(adjust), 2)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['regression: per-side split', ['50.5', '22', '24.5', 'woven'], [4.0, 'ok', -0.25]],
['repair check: per-side split', ['49', '22', '23', 'Knit '], [4.0, 'too much', -1.62]],
['generated control 1', ['52', '22', '24.5', 'felt'], 'error: fabric'],
['generated control 2', ['52', '22', '24.5', 'Knit '], [5.5, 'too much', -2.38]],
['generated control 3', ['49', '22', '22', 'woven'], [5.0, 'too much', -0.75]]],
[['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['regression: per-side split', ['50.5', '22', '24.5', 'Knit '], [4.0, 'too much', -1.62]],
['repair check: per-side split', ['52', '23.5', '24.5', 'Knit '], [4.0, 'too much', -1.62]],
['generated control 1', ['49', '23.5', '23', 'knit'], [2.5, 'too much', -0.88]],
['generated control 2', ['52', '22', '22', 'felt'], 'error: fabric'],
['generated control 3', ['50.5', '24', '22', 'leather'], [4.5, 'too much', -2.12]]],
[['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['regression: per-side split', ['49', '22', '23', 'knit'], [4.0, 'too much', -1.62]],
['repair check: per-side split', ['52', '22', '22', 'knit'], [8.0, 'too much', -3.62]],
['generated control 1', ['50.5', '23.5', '22', 'knit'], [5.0, 'too much', -2.12]],
['generated control 2', ['48', '22', '22', 'knit'], [4.0, 'too much', -1.62]],
['generated control 3', ['52', '22', '22', 'felt'], 'error: fabric']],
[['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['regression: per-side split', ['46', '24', '24.5', 'leather'], [-2.5, 'too little', 1.38]],
['repair check: per-side split', ['49', '23.5', '23', 'Knit '], [2.5, 'too much', -0.88]],
['generated control 1', ['46', '23.5', '22', 'leather'], [0.5, 'ok', -0.12]],
['generated control 2', ['49', '22', '23', 'woven'], [4.0, 'ok', -0.25]],
['generated control 3', ['49', '22', '23', 'Knit '], [4.0, 'too much', -1.62]]],
[['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['regression: per-side split', ['49', '22', '23', 'woven'], [4.0, 'ok', -0.25]],
['repair check: per-side split', ['52', '24', '24.5', 'Knit '], [3.5, 'too much', -1.38]],
['generated control 1', ['49', '23.5', '22', 'Knit '], [3.5, 'too much', -1.38]],
['generated control 2', ['49', '22', '24.5', 'woven'], [2.5, 'ok', 0.5]],
['generated control 3', ['48', '24', '22', 'woven'], [2.0, 'too little', 0.75]]]]
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 |
|---|---|---|---|
| woven ok | [3.0, 'ok', 0.12] | [3.0, 'ok', 0.25] | Failed |
| knit too much | [3.5, 'too much', -0.69] | [3.5, 'too much', -1.38] | Failed |
| leather at lower bound | [0.0, 'ok', 0.06] | [0.0, 'ok', 0.12] | Failed |
| regression: per-side split | [4.0, 'ok', -0.12] | [4.0, 'ok', -0.25] | Failed |
| repair check: per-side split | [4.0, 'too much', -0.81] | [4.0, 'too much', -1.62] | Failed |
| generated control 1 | error: fabric | error: fabric | Passed |
| generated control 2 | [5.5, 'too much', -1.19] | [5.5, 'too much', -2.38] | Failed |
| generated control 3 | [5.0, 'too much', -0.38] | [5.0, 'too much', -0.75] | Failed |
SHA-256 / f483882eb49aa607a968f170fd1162924945a9148bfbb4efb25bb59201ab6c02
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(cap, front, back, fabric):
R = {'woven': (Fraction(5, 2), Fraction(9, 2)), 'knit': (Fraction(0), Fraction(3, 2)), 'leather': (Fraction(0), Fraction(1, 2))}
f = fabric.strip().lower()
if f not in R:
return 'error: fabric'
lo, hi = R[f]
ease = Fraction(cap) - (Fraction(front) + Fraction(back))
if ease < lo:
verdict = 'too little'
elif ease > hi:
verdict = 'too much'
else:
verdict = 'ok'
adjust = ((lo + hi) / 2 - ease) / 2
return [round(float(ease), 2), verdict, round(float(adjust), 2)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['regression: per-side split', ['50.5', '22', '24.5', 'woven'], [4.0, 'ok', -0.25]],
['repair check: per-side split', ['49', '22', '23', 'Knit '], [4.0, 'too much', -1.62]],
['generated control 1', ['52', '22', '24.5', 'felt'], 'error: fabric'],
['generated control 2', ['52', '22', '24.5', 'Knit '], [5.5, 'too much', -2.38]],
['generated control 3', ['49', '22', '22', 'woven'], [5.0, 'too much', -0.75]]],
[['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['regression: per-side split', ['50.5', '22', '24.5', 'Knit '], [4.0, 'too much', -1.62]],
['repair check: per-side split', ['52', '23.5', '24.5', 'Knit '], [4.0, 'too much', -1.62]],
['generated control 1', ['49', '23.5', '23', 'knit'], [2.5, 'too much', -0.88]],
['generated control 2', ['52', '22', '22', 'felt'], 'error: fabric'],
['generated control 3', ['50.5', '24', '22', 'leather'], [4.5, 'too much', -2.12]]],
[['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['regression: per-side split', ['49', '22', '23', 'knit'], [4.0, 'too much', -1.62]],
['repair check: per-side split', ['52', '22', '22', 'knit'], [8.0, 'too much', -3.62]],
['generated control 1', ['50.5', '23.5', '22', 'knit'], [5.0, 'too much', -2.12]],
['generated control 2', ['48', '22', '22', 'knit'], [4.0, 'too much', -1.62]],
['generated control 3', ['52', '22', '22', 'felt'], 'error: fabric']],
[['woven lower edge', ['50.5', '24', '24', 'woven'], [2.5, 'ok', 0.5]],
['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['regression: per-side split', ['46', '24', '24.5', 'leather'], [-2.5, 'too little', 1.38]],
['repair check: per-side split', ['49', '23.5', '23', 'Knit '], [2.5, 'too much', -0.88]],
['generated control 1', ['46', '23.5', '22', 'leather'], [0.5, 'ok', -0.12]],
['generated control 2', ['49', '22', '23', 'woven'], [4.0, 'ok', -0.25]],
['generated control 3', ['49', '22', '23', 'Knit '], [4.0, 'too much', -1.62]]],
[['woven ok', ['50', '23', '24', 'woven'], [3.0, 'ok', 0.25]],
['knit too much', ['52', '24', '24.5', 'knit'], [3.5, 'too much', -1.38]],
['leather at lower bound', ['46', '23', '23', 'leather'], [0.0, 'ok', 0.12]],
['regression: per-side split', ['49', '22', '23', 'woven'], [4.0, 'ok', -0.25]],
['repair check: per-side split', ['52', '24', '24.5', 'Knit '], [3.5, 'too much', -1.38]],
['generated control 1', ['49', '23.5', '22', 'Knit '], [3.5, 'too much', -1.38]],
['generated control 2', ['49', '22', '24.5', 'woven'], [2.5, 'ok', 0.5]],
['generated control 3', ['48', '24', '22', 'woven'], [2.0, 'too little', 0.75]]]]
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 |
|---|---|---|---|
| woven ok | [3.0, 'ok', 0.25] | [3.0, 'ok', 0.25] | Passed |
| knit too much | [3.5, 'too much', -1.38] | [3.5, 'too much', -1.38] | Passed |
| leather at lower bound | [0.0, 'ok', 0.12] | [0.0, 'ok', 0.12] | Passed |
| regression: per-side split | [4.0, 'ok', -0.25] | [4.0, 'ok', -0.25] | Passed |
| repair check: per-side split | [4.0, 'too much', -1.62] | [4.0, 'too much', -1.62] | Passed |
| generated control 1 | error: fabric | error: fabric | Passed |
| generated control 2 | [5.5, 'too much', -2.38] | [5.5, 'too much', -2.38] | Passed |
| generated control 3 | [5.0, 'too much', -0.75] | [5.0, 'too much', -0.75] | Passed |
SHA-256 / 2e72fcedf5703236aca4f15c0b4445c1261dace80922282abdf54b1031b73ea7
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:34.631254+00:00.
Case digest / b8cb401eb6164f4453a7e3bc361ec873d5da035b22612d16e85705e693c73c38