FA-97616 / Knitting and sewing pattern grading / Open access
Buttonhole row planner: spacing divisor · case 01
The top buttonhole falls well below the neck.
ROOT CAUSE
Spacing divides by the number of buttons instead of the number of gaps.
VERIFIED REPAIR
Divide the span by n-1.
Unsuccessful approach: n+1 gaps treat the offsets as extra buttons.
Case contract
Buttonholes run from bottom_offset to band_len - top_offset (cm), evenly spaced; a single buttonhole goes at the top position. Convert each position to a 1-based row: half-up of position*rows_per_10cm/10, plus 1. n < 1 -> "error: count"; top position below bottom -> "error: offsets".
Why this case matters
Cardigan button bands place buttonholes evenly between neck and hem offsets.
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(band_len, n, top_offset, bottom_offset, rows_per_10cm):
if n < 1:
return 'error: count'
lo = Fraction(str(bottom_offset))
hi = Fraction(str(band_len)) - Fraction(str(top_offset))
if hi < lo:
return 'error: offsets'
g = Fraction(str(rows_per_10cm)) / 10
if n == 1:
pos = [hi]
else:
gap = (hi - lo) / n
pos = [lo + i * gap for i in range(n)]
return [math.floor(p * g + Fraction(1, 2)) + 1 for p in pos]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['regression: spacing divisor', [55.5, 5, 2, 2.5, '36.5'], [10, 57, 103, 150, 196]],
['repair check: spacing divisor', [60, 6, 2, 1, '32'], [4, 41, 77, 114, 150, 187]],
['generated control 1', [60, 1, 2, 1, '28'], [163]],
['generated control 2', [50, 6, 1, 1, '36.5'], [5, 40, 75, 110, 145, 180]],
['generated control 3', [50, 1, 1.5, 2.5, '28'], [137]]],
[['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['regression: spacing divisor', [55.5, 2, 2, 4, '32'], [14, 172]],
['repair check: spacing divisor', [60, 4, 1, 4, '32'], [14, 72, 131, 190]],
['generated control 1', [50, 1, 1.5, 1, '36.5'], [178]],
['generated control 2', [40, 0, 3, 4, '28'], 'error: count'],
['generated control 3', [60, 1, 1.5, 4, '30'], [177]]],
[['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]],
['regression: spacing divisor', [60, 2, 1, 1, '30'], [4, 178]],
['repair check: spacing divisor', [50, 7, 1, 4, '30'], [13, 36, 58, 81, 103, 126, 148]],
['generated control 1', [62, 0, 1, 4, '30'], 'error: count'],
['generated control 2', [60, 1, 3, 2, '32'], [183]],
['generated control 3', [62, 4, 1.5, 2, '30'], [7, 66, 124, 183]]],
[['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['regression: spacing divisor', [40, 4, 1, 4, '28'], [12, 45, 78, 110]],
['repair check: spacing divisor', [40, 7, 3, 4, '30'], [13, 30, 46, 63, 79, 96, 112]],
['generated control 1', [40, 1, 3, 4, '30'], [112]],
['generated control 2', [55.5, 0, 1.5, 4, '28'], 'error: count'],
['generated control 3', [40, 6, 1, 1, '32'], [4, 29, 53, 77, 101, 126]]],
[['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['regression: spacing divisor', [40, 6, 1.5, 2, '36.5'], [8, 35, 62, 88, 115, 142]],
['repair check: spacing divisor', [40, 2, 2, 1, '30'], [4, 115]],
['generated control 1', [55.5, 5, 3, 4, '32'], [14, 53, 91, 130, 169]],
['generated control 2', [55.5, 7, 1, 2.5, '36.5'], [10, 42, 73, 105, 137, 168, 200]],
['generated control 3', [40, 5, 2, 2, '36.5'], [8, 41, 74, 107, 140]]]]
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 |
|---|---|---|---|
| five buttons | [7, 35, 63, 91, 119] | [7, 42, 77, 112, 147] | Failed |
| single button | [107] | [107] | Passed |
| no buttons | error: count | error: count | Passed |
| regression: spacing divisor | [10, 47, 85, 122, 159] | [10, 57, 103, 150, 196] | Failed |
| repair check: spacing divisor | [4, 35, 65, 95, 126, 156] | [4, 41, 77, 114, 150, 187] | Failed |
| generated control 1 | [163] | [163] | Passed |
| generated control 2 | [5, 34, 63, 92, 121, 151] | [5, 40, 75, 110, 145, 180] | Failed |
| generated control 3 | [137] | [137] | Passed |
SHA-256 / 350899820294251c2b711aee2ac4b291385964cbb479c835fcce1796f524771c
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(band_len, n, top_offset, bottom_offset, rows_per_10cm):
if n < 1:
return 'error: count'
lo = Fraction(str(bottom_offset))
hi = Fraction(str(band_len)) - Fraction(str(top_offset))
if hi < lo:
return 'error: offsets'
g = Fraction(str(rows_per_10cm)) / 10
if n == 1:
pos = [hi]
else:
gap = (hi - lo) / (n + 1)
pos = [lo + i * gap for i in range(n)]
return [math.floor(p * g + Fraction(1, 2)) + 1 for p in pos]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['regression: spacing divisor', [55.5, 5, 2, 2.5, '36.5'], [10, 57, 103, 150, 196]],
['repair check: spacing divisor', [60, 6, 2, 1, '32'], [4, 41, 77, 114, 150, 187]],
['generated control 1', [60, 1, 2, 1, '28'], [163]],
['generated control 2', [50, 6, 1, 1, '36.5'], [5, 40, 75, 110, 145, 180]],
['generated control 3', [50, 1, 1.5, 2.5, '28'], [137]]],
[['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['regression: spacing divisor', [55.5, 2, 2, 4, '32'], [14, 172]],
['repair check: spacing divisor', [60, 4, 1, 4, '32'], [14, 72, 131, 190]],
['generated control 1', [50, 1, 1.5, 1, '36.5'], [178]],
['generated control 2', [40, 0, 3, 4, '28'], 'error: count'],
['generated control 3', [60, 1, 1.5, 4, '30'], [177]]],
[['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]],
['regression: spacing divisor', [60, 2, 1, 1, '30'], [4, 178]],
['repair check: spacing divisor', [50, 7, 1, 4, '30'], [13, 36, 58, 81, 103, 126, 148]],
['generated control 1', [62, 0, 1, 4, '30'], 'error: count'],
['generated control 2', [60, 1, 3, 2, '32'], [183]],
['generated control 3', [62, 4, 1.5, 2, '30'], [7, 66, 124, 183]]],
[['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['regression: spacing divisor', [40, 4, 1, 4, '28'], [12, 45, 78, 110]],
['repair check: spacing divisor', [40, 7, 3, 4, '30'], [13, 30, 46, 63, 79, 96, 112]],
['generated control 1', [40, 1, 3, 4, '30'], [112]],
['generated control 2', [55.5, 0, 1.5, 4, '28'], 'error: count'],
['generated control 3', [40, 6, 1, 1, '32'], [4, 29, 53, 77, 101, 126]]],
[['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['regression: spacing divisor', [40, 6, 1.5, 2, '36.5'], [8, 35, 62, 88, 115, 142]],
['repair check: spacing divisor', [40, 2, 2, 1, '30'], [4, 115]],
['generated control 1', [55.5, 5, 3, 4, '32'], [14, 53, 91, 130, 169]],
['generated control 2', [55.5, 7, 1, 2.5, '36.5'], [10, 42, 73, 105, 137, 168, 200]],
['generated control 3', [40, 5, 2, 2, '36.5'], [8, 41, 74, 107, 140]]]]
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 |
|---|---|---|---|
| five buttons | [7, 30, 54, 77, 100] | [7, 42, 77, 112, 147] | Failed |
| single button | [107] | [107] | Passed |
| no buttons | error: count | error: count | Passed |
| regression: spacing divisor | [10, 41, 72, 103, 134] | [10, 57, 103, 150, 196] | Failed |
| repair check: spacing divisor | [4, 30, 56, 82, 108, 134] | [4, 41, 77, 114, 150, 187] | Failed |
| generated control 1 | [163] | [163] | Passed |
| generated control 2 | [5, 30, 55, 80, 105, 130] | [5, 40, 75, 110, 145, 180] | Failed |
| generated control 3 | [137] | [137] | Passed |
SHA-256 / e55456f579b51410a19ea889d34554f838be298f7f86d9648229f0a9a136b273
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(band_len, n, top_offset, bottom_offset, rows_per_10cm):
if n < 1:
return 'error: count'
lo = Fraction(str(bottom_offset))
hi = Fraction(str(band_len)) - Fraction(str(top_offset))
if hi < lo:
return 'error: offsets'
g = Fraction(str(rows_per_10cm)) / 10
if n == 1:
pos = [hi]
else:
gap = (hi - lo) / (n - 1)
pos = [lo + i * gap for i in range(n)]
return [math.floor(p * g + Fraction(1, 2)) + 1 for p in pos]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['regression: spacing divisor', [55.5, 5, 2, 2.5, '36.5'], [10, 57, 103, 150, 196]],
['repair check: spacing divisor', [60, 6, 2, 1, '32'], [4, 41, 77, 114, 150, 187]],
['generated control 1', [60, 1, 2, 1, '28'], [163]],
['generated control 2', [50, 6, 1, 1, '36.5'], [5, 40, 75, 110, 145, 180]],
['generated control 3', [50, 1, 1.5, 2.5, '28'], [137]]],
[['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['regression: spacing divisor', [55.5, 2, 2, 4, '32'], [14, 172]],
['repair check: spacing divisor', [60, 4, 1, 4, '32'], [14, 72, 131, 190]],
['generated control 1', [50, 1, 1.5, 1, '36.5'], [178]],
['generated control 2', [40, 0, 3, 4, '28'], 'error: count'],
['generated control 3', [60, 1, 1.5, 4, '30'], [177]]],
[['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]],
['regression: spacing divisor', [60, 2, 1, 1, '30'], [4, 178]],
['repair check: spacing divisor', [50, 7, 1, 4, '30'], [13, 36, 58, 81, 103, 126, 148]],
['generated control 1', [62, 0, 1, 4, '30'], 'error: count'],
['generated control 2', [60, 1, 3, 2, '32'], [183]],
['generated control 3', [62, 4, 1.5, 2, '30'], [7, 66, 124, 183]]],
[['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['regression: spacing divisor', [40, 4, 1, 4, '28'], [12, 45, 78, 110]],
['repair check: spacing divisor', [40, 7, 3, 4, '30'], [13, 30, 46, 63, 79, 96, 112]],
['generated control 1', [40, 1, 3, 4, '30'], [112]],
['generated control 2', [55.5, 0, 1.5, 4, '28'], 'error: count'],
['generated control 3', [40, 6, 1, 1, '32'], [4, 29, 53, 77, 101, 126]]],
[['single button', [40, 1, 2, 2, '28'], [107]], ['no buttons', [40, 0, 2, 2, '28'], 'error: count'],
['five buttons', [50, 5, 1.5, 2, '30'], [7, 42, 77, 112, 147]],
['regression: spacing divisor', [40, 6, 1.5, 2, '36.5'], [8, 35, 62, 88, 115, 142]],
['repair check: spacing divisor', [40, 2, 2, 1, '30'], [4, 115]],
['generated control 1', [55.5, 5, 3, 4, '32'], [14, 53, 91, 130, 169]],
['generated control 2', [55.5, 7, 1, 2.5, '36.5'], [10, 42, 73, 105, 137, 168, 200]],
['generated control 3', [40, 5, 2, 2, '36.5'], [8, 41, 74, 107, 140]]]]
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 |
|---|---|---|---|
| five buttons | [7, 42, 77, 112, 147] | [7, 42, 77, 112, 147] | Passed |
| single button | [107] | [107] | Passed |
| no buttons | error: count | error: count | Passed |
| regression: spacing divisor | [10, 57, 103, 150, 196] | [10, 57, 103, 150, 196] | Passed |
| repair check: spacing divisor | [4, 41, 77, 114, 150, 187] | [4, 41, 77, 114, 150, 187] | Passed |
| generated control 1 | [163] | [163] | Passed |
| generated control 2 | [5, 40, 75, 110, 145, 180] | [5, 40, 75, 110, 145, 180] | Passed |
| generated control 3 | [137] | [137] | Passed |
SHA-256 / d5a97ea209a304b1d567f99f65fbfb7ec4f96dc5f598984812ca1765b8895da4
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:33.910608+00:00.
Case digest / a4c784a2128a14a3a722b2bd5cb5b720ce5daa044cc984417711674bb877cf19