FA-97806 / Knitting and sewing pattern grading / Open access
Circle skirt drafter: hem circumference radius · case 01
Hem circumference ignores the waist hole.
ROOT CAUSE
The hem radius is taken as the skirt length alone.
VERIFIED REPAIR
Hem radius = waist radius + length.
Unsuccessful approach: Using the cut radius shrinks the finished hem.
Case contract
kind full/half/quarter covers fraction 1, 1/2, 1/4 of a circle (else "error: kind"). Waist radius r = (waist+ease)/(2*pi*fraction); cut radius = r - sa (seam extends into the waist hole). Hem circumference = 2*pi*fraction*(r + length). Fabric span needed = 2*(cut_r + length + hem) for full and half, (cut_r + length + hem) for quarter. Return floats rounded to 1 decimal: [r, cut_r, hem_circumference, span].
Why this case matters
Circle skirt drafting converts waist size into a radius and checks the fabric width needed.
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(waist, kind, ease, sa, length, hem):
FR = {'full': 1, 'half': 0.5, 'quarter': 0.25}
if kind not in FR:
return 'error: kind'
W = waist + ease
r = W / (2 * math.pi * FR[kind])
cut_r = r - sa
hem_c = 2 * math.pi * FR[kind] * length
span = 2 * (cut_r + length + hem) if kind != 'quarter' else cut_r + length + hem
return [round(r, 1), round(cut_r, 1), round(hem_c, 1), round(span, 1)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['regression: hem circumference radius', [60, 'quarter', 2, 1.5, 55, 2], [39.5, 38.0, 148.4, 95.0]],
['repair check: hem circumference radius', [74.5, 'half', 1, 1.5, 70, 2], [24.0, 22.5, 295.4, 189.1]],
['generated control 1', [66, 'full', 0, 1.5, 40, 2], [10.5, 9.0, 317.3, 102.0]],
['generated control 2', [92, 'quarter', 2, 1.5, 55, 3], [59.8, 58.3, 180.4, 116.3]],
['generated control 3', [80, 'half', 1, 1.5, 55, 2], [25.8, 24.3, 253.8, 162.6]]],
[['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['regression: hem circumference radius', [92, 'quarter', 2, 1, 40, 3], [59.8, 58.8, 156.8, 101.8]],
['repair check: hem circumference radius', [92, 'quarter', 0, 1, 40, 2], [58.6, 57.6, 154.8, 99.6]],
['generated control 1', [70, 'half', 1, 1, 55, 2], [22.6, 21.6, 243.8, 157.2]],
['generated control 2', [80, 'gored', 2, 1.5, 70, 2], 'error: kind'],
['generated control 3', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]]],
[['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['regression: hem circumference radius', [70, 'full', 1, 1.5, 70, 3], [11.3, 9.8, 510.8, 165.6]],
['repair check: hem circumference radius', [60, 'half', 0, 1, 70, 2], [19.1, 18.1, 279.9, 180.2]],
['generated control 1', [92, 'gored', 1, 1.5, 40, 2], 'error: kind'],
['generated control 2', [60, 'gored', 0, 1, 70, 2], 'error: kind'],
['generated control 3', [80, 'full', 1, 1.5, 55, 2], [12.9, 11.4, 426.6, 136.8]]],
[['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['regression: hem circumference radius', [74.5, 'half', 0, 1, 70, 2], [23.7, 22.7, 294.4, 189.4]],
['repair check: hem circumference radius', [80, 'half', 0, 1, 70, 3], [25.5, 24.5, 299.9, 194.9]],
['generated control 1', [66, 'gored', 1, 1, 55, 3], 'error: kind'],
['generated control 2', [60, 'full', 1, 1.5, 40, 3], [9.7, 8.2, 312.3, 102.4]],
['generated control 3', [66, 'gored', 1, 1, 40, 2], 'error: kind']],
[['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['regression: hem circumference radius', [74.5, 'full', 2, 1.5, 40, 3], [12.2, 10.7, 327.8, 107.4]],
['repair check: hem circumference radius', [92, 'quarter', 1, 1, 40, 2], [59.2, 58.2, 155.8, 100.2]],
['generated control 1', [70, 'gored', 1, 1.5, 70, 3], 'error: kind'],
['generated control 2', [70, 'half', 2, 1, 55, 2], [22.9, 21.9, 244.8, 157.8]],
['generated control 3', [74.5, 'full', 1, 1.5, 55, 2], [12.0, 10.5, 421.1, 135.0]]]]
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 |
|---|---|---|---|
| full circle | [11.5, 10.0, 345.6, 133.9] | [11.5, 10.0, 417.6, 133.9] | Failed |
| half circle | [21.0, 20.0, 125.7, 126.0] | [21.0, 20.0, 191.7, 126.0] | Failed |
| quarter | [51.6, 50.1, 110.0, 122.1] | [51.6, 50.1, 191.0, 122.1] | Failed |
| regression: hem circumference radius | [39.5, 38.0, 86.4, 95.0] | [39.5, 38.0, 148.4, 95.0] | Failed |
| repair check: hem circumference radius | [24.0, 22.5, 219.9, 189.1] | [24.0, 22.5, 295.4, 189.1] | Failed |
| generated control 1 | [10.5, 9.0, 251.3, 102.0] | [10.5, 9.0, 317.3, 102.0] | Failed |
| generated control 2 | [59.8, 58.3, 86.4, 116.3] | [59.8, 58.3, 180.4, 116.3] | Failed |
| generated control 3 | [25.8, 24.3, 172.8, 162.6] | [25.8, 24.3, 253.8, 162.6] | Failed |
SHA-256 / b992b8cb1e67bcc6f0cc6517c8e119f2d37716ef81f45b1fac5f9969d20ef9b0
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(waist, kind, ease, sa, length, hem):
FR = {'full': 1, 'half': 0.5, 'quarter': 0.25}
if kind not in FR:
return 'error: kind'
W = waist + ease
r = W / (2 * math.pi * FR[kind])
cut_r = r - sa
hem_c = 2 * math.pi * FR[kind] * (cut_r + length)
span = 2 * (cut_r + length + hem) if kind != 'quarter' else cut_r + length + hem
return [round(r, 1), round(cut_r, 1), round(hem_c, 1), round(span, 1)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['regression: hem circumference radius', [60, 'quarter', 2, 1.5, 55, 2], [39.5, 38.0, 148.4, 95.0]],
['repair check: hem circumference radius', [74.5, 'half', 1, 1.5, 70, 2], [24.0, 22.5, 295.4, 189.1]],
['generated control 1', [66, 'full', 0, 1.5, 40, 2], [10.5, 9.0, 317.3, 102.0]],
['generated control 2', [92, 'quarter', 2, 1.5, 55, 3], [59.8, 58.3, 180.4, 116.3]],
['generated control 3', [80, 'half', 1, 1.5, 55, 2], [25.8, 24.3, 253.8, 162.6]]],
[['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['regression: hem circumference radius', [92, 'quarter', 2, 1, 40, 3], [59.8, 58.8, 156.8, 101.8]],
['repair check: hem circumference radius', [92, 'quarter', 0, 1, 40, 2], [58.6, 57.6, 154.8, 99.6]],
['generated control 1', [70, 'half', 1, 1, 55, 2], [22.6, 21.6, 243.8, 157.2]],
['generated control 2', [80, 'gored', 2, 1.5, 70, 2], 'error: kind'],
['generated control 3', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]]],
[['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['regression: hem circumference radius', [70, 'full', 1, 1.5, 70, 3], [11.3, 9.8, 510.8, 165.6]],
['repair check: hem circumference radius', [60, 'half', 0, 1, 70, 2], [19.1, 18.1, 279.9, 180.2]],
['generated control 1', [92, 'gored', 1, 1.5, 40, 2], 'error: kind'],
['generated control 2', [60, 'gored', 0, 1, 70, 2], 'error: kind'],
['generated control 3', [80, 'full', 1, 1.5, 55, 2], [12.9, 11.4, 426.6, 136.8]]],
[['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['regression: hem circumference radius', [74.5, 'half', 0, 1, 70, 2], [23.7, 22.7, 294.4, 189.4]],
['repair check: hem circumference radius', [80, 'half', 0, 1, 70, 3], [25.5, 24.5, 299.9, 194.9]],
['generated control 1', [66, 'gored', 1, 1, 55, 3], 'error: kind'],
['generated control 2', [60, 'full', 1, 1.5, 40, 3], [9.7, 8.2, 312.3, 102.4]],
['generated control 3', [66, 'gored', 1, 1, 40, 2], 'error: kind']],
[['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['regression: hem circumference radius', [74.5, 'full', 2, 1.5, 40, 3], [12.2, 10.7, 327.8, 107.4]],
['repair check: hem circumference radius', [92, 'quarter', 1, 1, 40, 2], [59.2, 58.2, 155.8, 100.2]],
['generated control 1', [70, 'gored', 1, 1.5, 70, 3], 'error: kind'],
['generated control 2', [70, 'half', 2, 1, 55, 2], [22.9, 21.9, 244.8, 157.8]],
['generated control 3', [74.5, 'full', 1, 1.5, 55, 2], [12.0, 10.5, 421.1, 135.0]]]]
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 |
|---|---|---|---|
| full circle | [11.5, 10.0, 408.2, 133.9] | [11.5, 10.0, 417.6, 133.9] | Failed |
| half circle | [21.0, 20.0, 188.5, 126.0] | [21.0, 20.0, 191.7, 126.0] | Failed |
| quarter | [51.6, 50.1, 188.6, 122.1] | [51.6, 50.1, 191.0, 122.1] | Failed |
| regression: hem circumference radius | [39.5, 38.0, 146.0, 95.0] | [39.5, 38.0, 148.4, 95.0] | Failed |
| repair check: hem circumference radius | [24.0, 22.5, 290.7, 189.1] | [24.0, 22.5, 295.4, 189.1] | Failed |
| generated control 1 | [10.5, 9.0, 307.9, 102.0] | [10.5, 9.0, 317.3, 102.0] | Failed |
| generated control 2 | [59.8, 58.3, 178.0, 116.3] | [59.8, 58.3, 180.4, 116.3] | Failed |
| generated control 3 | [25.8, 24.3, 249.1, 162.6] | [25.8, 24.3, 253.8, 162.6] | Failed |
SHA-256 / 31a0830e2b68ab00820a612783c61d9cadb53c77afe992c4a663301b0dd74f37
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(waist, kind, ease, sa, length, hem):
FR = {'full': 1, 'half': 0.5, 'quarter': 0.25}
if kind not in FR:
return 'error: kind'
W = waist + ease
r = W / (2 * math.pi * FR[kind])
cut_r = r - sa
hem_c = 2 * math.pi * FR[kind] * (r + length)
span = 2 * (cut_r + length + hem) if kind != 'quarter' else cut_r + length + hem
return [round(r, 1), round(cut_r, 1), round(hem_c, 1), round(span, 1)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['regression: hem circumference radius', [60, 'quarter', 2, 1.5, 55, 2], [39.5, 38.0, 148.4, 95.0]],
['repair check: hem circumference radius', [74.5, 'half', 1, 1.5, 70, 2], [24.0, 22.5, 295.4, 189.1]],
['generated control 1', [66, 'full', 0, 1.5, 40, 2], [10.5, 9.0, 317.3, 102.0]],
['generated control 2', [92, 'quarter', 2, 1.5, 55, 3], [59.8, 58.3, 180.4, 116.3]],
['generated control 3', [80, 'half', 1, 1.5, 55, 2], [25.8, 24.3, 253.8, 162.6]]],
[['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['regression: hem circumference radius', [92, 'quarter', 2, 1, 40, 3], [59.8, 58.8, 156.8, 101.8]],
['repair check: hem circumference radius', [92, 'quarter', 0, 1, 40, 2], [58.6, 57.6, 154.8, 99.6]],
['generated control 1', [70, 'half', 1, 1, 55, 2], [22.6, 21.6, 243.8, 157.2]],
['generated control 2', [80, 'gored', 2, 1.5, 70, 2], 'error: kind'],
['generated control 3', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]]],
[['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['regression: hem circumference radius', [70, 'full', 1, 1.5, 70, 3], [11.3, 9.8, 510.8, 165.6]],
['repair check: hem circumference radius', [60, 'half', 0, 1, 70, 2], [19.1, 18.1, 279.9, 180.2]],
['generated control 1', [92, 'gored', 1, 1.5, 40, 2], 'error: kind'],
['generated control 2', [60, 'gored', 0, 1, 70, 2], 'error: kind'],
['generated control 3', [80, 'full', 1, 1.5, 55, 2], [12.9, 11.4, 426.6, 136.8]]],
[['gored rejected', [70, 'gored', 0, 1, 50, 2], 'error: kind'],
['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['regression: hem circumference radius', [74.5, 'half', 0, 1, 70, 2], [23.7, 22.7, 294.4, 189.4]],
['repair check: hem circumference radius', [80, 'half', 0, 1, 70, 3], [25.5, 24.5, 299.9, 194.9]],
['generated control 1', [66, 'gored', 1, 1, 55, 3], 'error: kind'],
['generated control 2', [60, 'full', 1, 1.5, 40, 3], [9.7, 8.2, 312.3, 102.4]],
['generated control 3', [66, 'gored', 1, 1, 40, 2], 'error: kind']],
[['full circle', [70, 'full', 2, 1.5, 55, 2], [11.5, 10.0, 417.6, 133.9]],
['half circle', [66, 'half', 0, 1, 40, 3], [21.0, 20.0, 191.7, 126.0]],
['quarter', [80, 'quarter', 1, 1.5, 70, 2], [51.6, 50.1, 191.0, 122.1]],
['regression: hem circumference radius', [74.5, 'full', 2, 1.5, 40, 3], [12.2, 10.7, 327.8, 107.4]],
['repair check: hem circumference radius', [92, 'quarter', 1, 1, 40, 2], [59.2, 58.2, 155.8, 100.2]],
['generated control 1', [70, 'gored', 1, 1.5, 70, 3], 'error: kind'],
['generated control 2', [70, 'half', 2, 1, 55, 2], [22.9, 21.9, 244.8, 157.8]],
['generated control 3', [74.5, 'full', 1, 1.5, 55, 2], [12.0, 10.5, 421.1, 135.0]]]]
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 |
|---|---|---|---|
| full circle | [11.5, 10.0, 417.6, 133.9] | [11.5, 10.0, 417.6, 133.9] | Passed |
| half circle | [21.0, 20.0, 191.7, 126.0] | [21.0, 20.0, 191.7, 126.0] | Passed |
| quarter | [51.6, 50.1, 191.0, 122.1] | [51.6, 50.1, 191.0, 122.1] | Passed |
| regression: hem circumference radius | [39.5, 38.0, 148.4, 95.0] | [39.5, 38.0, 148.4, 95.0] | Passed |
| repair check: hem circumference radius | [24.0, 22.5, 295.4, 189.1] | [24.0, 22.5, 295.4, 189.1] | Passed |
| generated control 1 | [10.5, 9.0, 317.3, 102.0] | [10.5, 9.0, 317.3, 102.0] | Passed |
| generated control 2 | [59.8, 58.3, 180.4, 116.3] | [59.8, 58.3, 180.4, 116.3] | Passed |
| generated control 3 | [25.8, 24.3, 253.8, 162.6] | [25.8, 24.3, 253.8, 162.6] | Passed |
SHA-256 / 95be89a3083cf594e920136e73b0b7fabc01e6d700a08e482c325e667d3e57e9
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:35.742793+00:00.
Case digest / b8150aa2638aff5ba799f077dff57ab715fdfd6acc8de9f60e23c26bc30cea86