FAILURE MAP
← Case archive

FA-97626 / Knitting and sewing pattern grading / Open access

Buttonhole row planner: top offset · case 01

The top buttonhole lands in the neckband.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The top offset is not subtracted from the band length.

VERIFIED REPAIR

Top position is band length minus top offset.

Unsuccessful approach: Subtracting both offsets double-counts the bottom offset.

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))
    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: top offset', [40, 4, 2, 1, '36.5'], [5, 50, 95, 140]],
  ['repair check: top offset', [60, 7, 1.5, 1, '30'], [4, 33, 62, 90, 119, 148, 177]],
  ['generated control 1', [55.5, 7, 1, 4, '32'], [14, 41, 68, 95, 122, 148, 175]],
  ['generated control 2', [50, 4, 2, 4, '36.5'], [16, 69, 123, 176]],
  ['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: top offset', [40, 4, 3, 1, '30'], [4, 40, 76, 112]],
  ['repair check: top offset', [50, 5, 2, 2.5, '32'], [9, 45, 82, 118, 155]],
  ['generated control 1', [55.5, 2, 1.5, 2.5, '32'], [9, 174]],
  ['generated control 2', [40, 6, 3, 1, '28'], [4, 24, 44, 64, 84, 105]],
  ['generated control 3', [60, 0, 2, 2.5, '32'], 'error: count']],
 [['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: top offset', [55.5, 7, 1.5, 4, '28'], [12, 36, 59, 82, 106, 129, 152]],
  ['repair check: top offset', [40, 6, 2, 1, '36.5'], [5, 32, 59, 86, 113, 140]],
  ['generated control 1', [50, 1, 3, 4, '32'], [151]],
  ['generated control 2', [55.5, 7, 2, 2, '36.5'], [8, 40, 71, 102, 134, 165, 196]],
  ['generated control 3', [55.5, 6, 1, 2.5, '30'], [9, 40, 71, 102, 133, 165]]],
 [['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: top offset', [55.5, 5, 2, 4, '36.5'], [16, 61, 106, 151, 196]],
  ['repair check: top offset', [50, 7, 3, 2.5, '36.5'], [10, 37, 64, 91, 118, 145, 173]],
  ['generated control 1', [60, 1, 1, 2.5, '36.5'], [216]],
  ['generated control 2', [40, 6, 2, 4, '32'], [14, 36, 57, 79, 101, 123]],
  ['generated control 3', [50, 2, 3, 4, '28'], [12, 133]]],
 [['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: top offset', [50, 6, 3, 2.5, '28'], [8, 33, 58, 83, 108, 133]],
  ['repair check: top offset', [62, 5, 2, 1, '36.5'], [5, 58, 112, 166, 220]],
  ['generated control 1', [50, 6, 1.5, 4, '28'], [12, 37, 62, 87, 112, 137]],
  ['generated control 2', [40, 5, 3, 1, '32'], [4, 33, 62, 91, 119]],
  ['generated control 3', [62, 2, 1.5, 1, '32'], [4, 195]]]]
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 fixtureActualExpectedOutcome
five buttons[7, 43, 79, 115, 151][7, 42, 77, 112, 147]Failed
single button[113][107]Failed
no buttonserror: counterror: countPassed
regression: top offset[5, 52, 100, 147][5, 50, 95, 140]Failed
repair check: top offset[4, 34, 63, 93, 122, 152, 181][4, 33, 62, 90, 119, 148, 177]Failed
generated control 1[14, 41, 69, 96, 124, 151, 179][14, 41, 68, 95, 122, 148, 175]Failed
generated control 2[16, 72, 128, 184][16, 69, 123, 176]Failed
generated control 3[4, 29, 54, 79, 104, 129][4, 29, 53, 77, 101, 126]Failed

SHA-256 / 842a401ecb838a497e35f1e2afc61346df600744b2798d041709e561fa69a877

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)) - Fraction(str(bottom_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: top offset', [40, 4, 2, 1, '36.5'], [5, 50, 95, 140]],
  ['repair check: top offset', [60, 7, 1.5, 1, '30'], [4, 33, 62, 90, 119, 148, 177]],
  ['generated control 1', [55.5, 7, 1, 4, '32'], [14, 41, 68, 95, 122, 148, 175]],
  ['generated control 2', [50, 4, 2, 4, '36.5'], [16, 69, 123, 176]],
  ['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: top offset', [40, 4, 3, 1, '30'], [4, 40, 76, 112]],
  ['repair check: top offset', [50, 5, 2, 2.5, '32'], [9, 45, 82, 118, 155]],
  ['generated control 1', [55.5, 2, 1.5, 2.5, '32'], [9, 174]],
  ['generated control 2', [40, 6, 3, 1, '28'], [4, 24, 44, 64, 84, 105]],
  ['generated control 3', [60, 0, 2, 2.5, '32'], 'error: count']],
 [['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: top offset', [55.5, 7, 1.5, 4, '28'], [12, 36, 59, 82, 106, 129, 152]],
  ['repair check: top offset', [40, 6, 2, 1, '36.5'], [5, 32, 59, 86, 113, 140]],
  ['generated control 1', [50, 1, 3, 4, '32'], [151]],
  ['generated control 2', [55.5, 7, 2, 2, '36.5'], [8, 40, 71, 102, 134, 165, 196]],
  ['generated control 3', [55.5, 6, 1, 2.5, '30'], [9, 40, 71, 102, 133, 165]]],
 [['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: top offset', [55.5, 5, 2, 4, '36.5'], [16, 61, 106, 151, 196]],
  ['repair check: top offset', [50, 7, 3, 2.5, '36.5'], [10, 37, 64, 91, 118, 145, 173]],
  ['generated control 1', [60, 1, 1, 2.5, '36.5'], [216]],
  ['generated control 2', [40, 6, 2, 4, '32'], [14, 36, 57, 79, 101, 123]],
  ['generated control 3', [50, 2, 3, 4, '28'], [12, 133]]],
 [['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: top offset', [50, 6, 3, 2.5, '28'], [8, 33, 58, 83, 108, 133]],
  ['repair check: top offset', [62, 5, 2, 1, '36.5'], [5, 58, 112, 166, 220]],
  ['generated control 1', [50, 6, 1.5, 4, '28'], [12, 37, 62, 87, 112, 137]],
  ['generated control 2', [40, 5, 3, 1, '32'], [4, 33, 62, 91, 119]],
  ['generated control 3', [62, 2, 1.5, 1, '32'], [4, 195]]]]
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 fixtureActualExpectedOutcome
five buttons[7, 40, 74, 107, 141][7, 42, 77, 112, 147]Failed
single button[102][107]Failed
no buttonserror: counterror: countPassed
regression: top offset[5, 48, 92, 136][5, 50, 95, 140]Failed
repair check: top offset[4, 32, 61, 89, 117, 145, 174][4, 33, 62, 90, 119, 148, 177]Failed
generated control 1[14, 39, 63, 88, 113, 138, 163][14, 41, 68, 95, 122, 148, 175]Failed
generated control 2[16, 64, 113, 162][16, 69, 123, 176]Failed
generated control 3[4, 28, 52, 75, 99, 123][4, 29, 53, 77, 101, 126]Failed

SHA-256 / cbd3cc39bd472acf4c473e1e125395899b1cdd7e486e8bc3b4eddb5c784cced9

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: top offset', [40, 4, 2, 1, '36.5'], [5, 50, 95, 140]],
  ['repair check: top offset', [60, 7, 1.5, 1, '30'], [4, 33, 62, 90, 119, 148, 177]],
  ['generated control 1', [55.5, 7, 1, 4, '32'], [14, 41, 68, 95, 122, 148, 175]],
  ['generated control 2', [50, 4, 2, 4, '36.5'], [16, 69, 123, 176]],
  ['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: top offset', [40, 4, 3, 1, '30'], [4, 40, 76, 112]],
  ['repair check: top offset', [50, 5, 2, 2.5, '32'], [9, 45, 82, 118, 155]],
  ['generated control 1', [55.5, 2, 1.5, 2.5, '32'], [9, 174]],
  ['generated control 2', [40, 6, 3, 1, '28'], [4, 24, 44, 64, 84, 105]],
  ['generated control 3', [60, 0, 2, 2.5, '32'], 'error: count']],
 [['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: top offset', [55.5, 7, 1.5, 4, '28'], [12, 36, 59, 82, 106, 129, 152]],
  ['repair check: top offset', [40, 6, 2, 1, '36.5'], [5, 32, 59, 86, 113, 140]],
  ['generated control 1', [50, 1, 3, 4, '32'], [151]],
  ['generated control 2', [55.5, 7, 2, 2, '36.5'], [8, 40, 71, 102, 134, 165, 196]],
  ['generated control 3', [55.5, 6, 1, 2.5, '30'], [9, 40, 71, 102, 133, 165]]],
 [['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: top offset', [55.5, 5, 2, 4, '36.5'], [16, 61, 106, 151, 196]],
  ['repair check: top offset', [50, 7, 3, 2.5, '36.5'], [10, 37, 64, 91, 118, 145, 173]],
  ['generated control 1', [60, 1, 1, 2.5, '36.5'], [216]],
  ['generated control 2', [40, 6, 2, 4, '32'], [14, 36, 57, 79, 101, 123]],
  ['generated control 3', [50, 2, 3, 4, '28'], [12, 133]]],
 [['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: top offset', [50, 6, 3, 2.5, '28'], [8, 33, 58, 83, 108, 133]],
  ['repair check: top offset', [62, 5, 2, 1, '36.5'], [5, 58, 112, 166, 220]],
  ['generated control 1', [50, 6, 1.5, 4, '28'], [12, 37, 62, 87, 112, 137]],
  ['generated control 2', [40, 5, 3, 1, '32'], [4, 33, 62, 91, 119]],
  ['generated control 3', [62, 2, 1.5, 1, '32'], [4, 195]]]]
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 fixtureActualExpectedOutcome
five buttons[7, 42, 77, 112, 147][7, 42, 77, 112, 147]Passed
single button[107][107]Passed
no buttonserror: counterror: countPassed
regression: top offset[5, 50, 95, 140][5, 50, 95, 140]Passed
repair check: top offset[4, 33, 62, 90, 119, 148, 177][4, 33, 62, 90, 119, 148, 177]Passed
generated control 1[14, 41, 68, 95, 122, 148, 175][14, 41, 68, 95, 122, 148, 175]Passed
generated control 2[16, 69, 123, 176][16, 69, 123, 176]Passed
generated control 3[4, 29, 53, 77, 101, 126][4, 29, 53, 77, 101, 126]Passed

SHA-256 / dc3a07f2e93bfce0c93900b830145022bd60e624234a85dd0561d15d3dfa29ab

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.003807+00:00.

Case digest / bdeaf0d65dd53fa4d7dc0da728e094f6047a30c0dba260da83d5ba897297af85