FA-97721 / Knitting and sewing pattern grading / Open access
Post-wash swatch gauge: row gauge dimension · case 01
Body length is off by the width-to-height difference of the swatch.
ROOT CAUSE
Row gauge divides by the swatch width instead of its height.
VERIFIED REPAIR
Divide rows by post-wash height.
Unsuccessful approach: Pre-wash height ignores vertical relaxation.
Case contract
A swatch of sts x rows measured before and after washing. Use post-wash dimensions: cast on = half-up target_w*sts/w_post; rows = target_h*rows/h_post rounded to the nearest even number (ties up); width change % = (w_post/w_pre - 1)*100 half-up to 0.1. Return [cast_on, rows, width_change].
Why this case matters
Knitters block swatches because many fibres grow or shrink after washing.
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(sts, rows, w_pre, w_post, h_pre, h_post, target_w, target_h):
wpo = Fraction(w_post)
hpo = Fraction(h_post)
cast = math.floor(target_w * sts / wpo + Fraction(1, 2))
rr = target_h * rows / wpo
row_count = 2 * math.floor(rr / 2 + Fraction(1, 2))
change = (wpo / Fraction(w_pre) - 1) * 100
return [cast, row_count, math.floor(change * 10 + Fraction(1, 2)) / 10]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['regression: row gauge dimension', [24, 40, '10.5', '10.5', '10.2', '10.4', 50, 45], [114, 174, 0.0]],
['repair check: row gauge dimension', [24, 40, '10', '11', '10', '10.4', 50, 30], [109, 116, 10.0]],
['generated control 1', [24, 28, '10.5', '10.5', '10.2', '10', 55, 60], [126, 168, 0.0]],
['generated control 2', [20, 32, '10', '10', '10', '9', 50, 30], [100, 106, 0.0]],
['generated control 3', [20, 30, '10', '10', '10', '9.5', 50, 30], [100, 94, 0.0]]],
[['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['regression: row gauge dimension', [20, 28, '10', '10', '10', '10.4', 50, 30], [100, 80, 0.0]],
['repair check: row gauge dimension', [20, 32, '10', '11', '10', '9', 50, 60], [91, 214, 10.0]],
['generated control 1', [20, 28, '10.5', '10', '10', '10', 40, 60], [80, 168, -4.8]],
['generated control 2', [20, 30, '10', '10', '10.2', '10.4', 50, 45], [100, 130, 0.0]],
['generated control 3', [20, 32, '10.5', '10.8', '10', '10', 55, 60], [102, 192, 2.9]]],
[['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['regression: row gauge dimension', [22, 30, '10.5', '10', '10', '10.4', 55, 60], [121, 174, -4.8]],
['repair check: row gauge dimension', [30, 40, '10.5', '9.5', '10.2', '9.5', 50, 60], [158, 252, -9.5]],
['generated control 1', [20, 32, '10', '10.5', '10', '9.5', 50, 30], [95, 102, 5.0]],
['generated control 2', [24, 30, '10', '10', '10', '9.5', 40, 30], [96, 94, 0.0]],
['generated control 3', [22, 28, '10', '11', '10', '9', 40, 60], [80, 186, 10.0]]],
[['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['regression: row gauge dimension', [24, 40, '10.5', '9.5', '10.2', '9', 40, 45], [101, 200, -9.5]],
['repair check: row gauge dimension', [22, 40, '10', '10', '10', '9.5', 40, 60], [88, 252, 0.0]],
['generated control 1', [22, 28, '10', '11', '10', '10', 50, 30], [100, 84, 10.0]],
['generated control 2', [24, 30, '10', '10.5', '10.2', '9', 40, 60], [91, 200, 5.0]],
['generated control 3', [30, 40, '10.5', '10', '10.2', '10', 50, 30], [150, 120, -4.8]]],
[['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['regression: row gauge dimension', [24, 30, '10', '10.8', '10.2', '10.4', 50, 30], [111, 86, 8.0]],
['repair check: row gauge dimension', [30, 30, '10.5', '10.8', '10', '9.5', 50, 30], [139, 94, 2.9]],
['generated control 1', [24, 28, '10.5', '10', '10', '10', 50, 60], [120, 168, -4.8]],
['generated control 2', [20, 32, '10', '10.5', '10.2', '9', 40, 60], [76, 214, 5.0]],
['generated control 3', [20, 32, '10', '10', '10', '10.4', 55, 60], [110, 184, 0.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 |
|---|---|---|---|
| no change | [100, 126, 0.0] | [100, 126, 0.0] | Passed |
| growth | [100, 164, 10.0] | [100, 174, 10.0] | Failed |
| shrink | [101, 102, -9.5] | [101, 106, -9.5] | Failed |
| regression: row gauge dimension | [114, 172, 0.0] | [114, 174, 0.0] | Failed |
| repair check: row gauge dimension | [109, 110, 10.0] | [109, 116, 10.0] | Failed |
| generated control 1 | [126, 160, 0.0] | [126, 168, 0.0] | Failed |
| generated control 2 | [100, 96, 0.0] | [100, 106, 0.0] | Failed |
| generated control 3 | [100, 90, 0.0] | [100, 94, 0.0] | Failed |
SHA-256 / dcb81b6fe2235844439f71cace661ad63a2432ed855f8c04abbf097dd24396df
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(sts, rows, w_pre, w_post, h_pre, h_post, target_w, target_h):
wpo = Fraction(w_post)
hpo = Fraction(h_post)
cast = math.floor(target_w * sts / wpo + Fraction(1, 2))
rr = target_h * rows / Fraction(h_pre)
row_count = 2 * math.floor(rr / 2 + Fraction(1, 2))
change = (wpo / Fraction(w_pre) - 1) * 100
return [cast, row_count, math.floor(change * 10 + Fraction(1, 2)) / 10]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['regression: row gauge dimension', [24, 40, '10.5', '10.5', '10.2', '10.4', 50, 45], [114, 174, 0.0]],
['repair check: row gauge dimension', [24, 40, '10', '11', '10', '10.4', 50, 30], [109, 116, 10.0]],
['generated control 1', [24, 28, '10.5', '10.5', '10.2', '10', 55, 60], [126, 168, 0.0]],
['generated control 2', [20, 32, '10', '10', '10', '9', 50, 30], [100, 106, 0.0]],
['generated control 3', [20, 30, '10', '10', '10', '9.5', 50, 30], [100, 94, 0.0]]],
[['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['regression: row gauge dimension', [20, 28, '10', '10', '10', '10.4', 50, 30], [100, 80, 0.0]],
['repair check: row gauge dimension', [20, 32, '10', '11', '10', '9', 50, 60], [91, 214, 10.0]],
['generated control 1', [20, 28, '10.5', '10', '10', '10', 40, 60], [80, 168, -4.8]],
['generated control 2', [20, 30, '10', '10', '10.2', '10.4', 50, 45], [100, 130, 0.0]],
['generated control 3', [20, 32, '10.5', '10.8', '10', '10', 55, 60], [102, 192, 2.9]]],
[['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['regression: row gauge dimension', [22, 30, '10.5', '10', '10', '10.4', 55, 60], [121, 174, -4.8]],
['repair check: row gauge dimension', [30, 40, '10.5', '9.5', '10.2', '9.5', 50, 60], [158, 252, -9.5]],
['generated control 1', [20, 32, '10', '10.5', '10', '9.5', 50, 30], [95, 102, 5.0]],
['generated control 2', [24, 30, '10', '10', '10', '9.5', 40, 30], [96, 94, 0.0]],
['generated control 3', [22, 28, '10', '11', '10', '9', 40, 60], [80, 186, 10.0]]],
[['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['regression: row gauge dimension', [24, 40, '10.5', '9.5', '10.2', '9', 40, 45], [101, 200, -9.5]],
['repair check: row gauge dimension', [22, 40, '10', '10', '10', '9.5', 40, 60], [88, 252, 0.0]],
['generated control 1', [22, 28, '10', '11', '10', '10', 50, 30], [100, 84, 10.0]],
['generated control 2', [24, 30, '10', '10.5', '10.2', '9', 40, 60], [91, 200, 5.0]],
['generated control 3', [30, 40, '10.5', '10', '10.2', '10', 50, 30], [150, 120, -4.8]]],
[['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['regression: row gauge dimension', [24, 30, '10', '10.8', '10.2', '10.4', 50, 30], [111, 86, 8.0]],
['repair check: row gauge dimension', [30, 30, '10.5', '10.8', '10', '9.5', 50, 30], [139, 94, 2.9]],
['generated control 1', [24, 28, '10.5', '10', '10', '10', 50, 60], [120, 168, -4.8]],
['generated control 2', [20, 32, '10', '10.5', '10.2', '9', 40, 60], [76, 214, 5.0]],
['generated control 3', [20, 32, '10', '10', '10', '10.4', 55, 60], [110, 184, 0.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 |
|---|---|---|---|
| no change | [100, 126, 0.0] | [100, 126, 0.0] | Passed |
| growth | [100, 180, 10.0] | [100, 174, 10.0] | Failed |
| shrink | [101, 94, -9.5] | [101, 106, -9.5] | Failed |
| regression: row gauge dimension | [114, 176, 0.0] | [114, 174, 0.0] | Failed |
| repair check: row gauge dimension | [109, 120, 10.0] | [109, 116, 10.0] | Failed |
| generated control 1 | [126, 164, 0.0] | [126, 168, 0.0] | Failed |
| generated control 2 | [100, 96, 0.0] | [100, 106, 0.0] | Failed |
| generated control 3 | [100, 90, 0.0] | [100, 94, 0.0] | Failed |
SHA-256 / 9e88c7e0a0565a89b56eb9b2c26f61a17b0df48eed0e08779c4a036adfefaa99
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(sts, rows, w_pre, w_post, h_pre, h_post, target_w, target_h):
wpo = Fraction(w_post)
hpo = Fraction(h_post)
cast = math.floor(target_w * sts / wpo + Fraction(1, 2))
rr = target_h * rows / hpo
row_count = 2 * math.floor(rr / 2 + Fraction(1, 2))
change = (wpo / Fraction(w_pre) - 1) * 100
return [cast, row_count, math.floor(change * 10 + Fraction(1, 2)) / 10]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['regression: row gauge dimension', [24, 40, '10.5', '10.5', '10.2', '10.4', 50, 45], [114, 174, 0.0]],
['repair check: row gauge dimension', [24, 40, '10', '11', '10', '10.4', 50, 30], [109, 116, 10.0]],
['generated control 1', [24, 28, '10.5', '10.5', '10.2', '10', 55, 60], [126, 168, 0.0]],
['generated control 2', [20, 32, '10', '10', '10', '9', 50, 30], [100, 106, 0.0]],
['generated control 3', [20, 30, '10', '10', '10', '9.5', 50, 30], [100, 94, 0.0]]],
[['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['regression: row gauge dimension', [20, 28, '10', '10', '10', '10.4', 50, 30], [100, 80, 0.0]],
['repair check: row gauge dimension', [20, 32, '10', '11', '10', '9', 50, 60], [91, 214, 10.0]],
['generated control 1', [20, 28, '10.5', '10', '10', '10', 40, 60], [80, 168, -4.8]],
['generated control 2', [20, 30, '10', '10', '10.2', '10.4', 50, 45], [100, 130, 0.0]],
['generated control 3', [20, 32, '10.5', '10.8', '10', '10', 55, 60], [102, 192, 2.9]]],
[['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['regression: row gauge dimension', [22, 30, '10.5', '10', '10', '10.4', 55, 60], [121, 174, -4.8]],
['repair check: row gauge dimension', [30, 40, '10.5', '9.5', '10.2', '9.5', 50, 60], [158, 252, -9.5]],
['generated control 1', [20, 32, '10', '10.5', '10', '9.5', 50, 30], [95, 102, 5.0]],
['generated control 2', [24, 30, '10', '10', '10', '9.5', 40, 30], [96, 94, 0.0]],
['generated control 3', [22, 28, '10', '11', '10', '9', 40, 60], [80, 186, 10.0]]],
[['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['regression: row gauge dimension', [24, 40, '10.5', '9.5', '10.2', '9', 40, 45], [101, 200, -9.5]],
['repair check: row gauge dimension', [22, 40, '10', '10', '10', '9.5', 40, 60], [88, 252, 0.0]],
['generated control 1', [22, 28, '10', '11', '10', '10', 50, 30], [100, 84, 10.0]],
['generated control 2', [24, 30, '10', '10.5', '10.2', '9', 40, 60], [91, 200, 5.0]],
['generated control 3', [30, 40, '10.5', '10', '10.2', '10', 50, 30], [150, 120, -4.8]]],
[['growth', [22, 30, '10', '11', '10', '10.4', 50, 60], [100, 174, 10.0]],
['shrink', [24, 32, '10.5', '9.5', '10.2', '9', 40, 30], [101, 106, -9.5]],
['no change', [20, 28, '10', '10', '10', '10', 50, 45], [100, 126, 0.0]],
['regression: row gauge dimension', [24, 30, '10', '10.8', '10.2', '10.4', 50, 30], [111, 86, 8.0]],
['repair check: row gauge dimension', [30, 30, '10.5', '10.8', '10', '9.5', 50, 30], [139, 94, 2.9]],
['generated control 1', [24, 28, '10.5', '10', '10', '10', 50, 60], [120, 168, -4.8]],
['generated control 2', [20, 32, '10', '10.5', '10.2', '9', 40, 60], [76, 214, 5.0]],
['generated control 3', [20, 32, '10', '10', '10', '10.4', 55, 60], [110, 184, 0.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 |
|---|---|---|---|
| no change | [100, 126, 0.0] | [100, 126, 0.0] | Passed |
| growth | [100, 174, 10.0] | [100, 174, 10.0] | Passed |
| shrink | [101, 106, -9.5] | [101, 106, -9.5] | Passed |
| regression: row gauge dimension | [114, 174, 0.0] | [114, 174, 0.0] | Passed |
| repair check: row gauge dimension | [109, 116, 10.0] | [109, 116, 10.0] | Passed |
| generated control 1 | [126, 168, 0.0] | [126, 168, 0.0] | Passed |
| generated control 2 | [100, 106, 0.0] | [100, 106, 0.0] | Passed |
| generated control 3 | [100, 94, 0.0] | [100, 94, 0.0] | Passed |
SHA-256 / 4b26b666a8be2fa9486b81e57b82bdace952a8f8620ff7192185b4a51343edf4
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.949995+00:00.
Case digest / 33c5d95bed81dab7160ceb95001b0b1b499dec6f4c387f89fd35df556758f901