FA-72041 / Error-correcting codes / Open access
RAID-5 skips the parity consistency check · case 01
Stripes with silent corruption are returned as valid data.
ROOT CAUSE
The XOR-to-zero check of a complete stripe is missing.
VERIFIED REPAIR
When no block is missing verify that all blocks XOR to 0.
Unsuccessful approach: Checking only the data blocks for XOR zero rejects most healthy stripes.
Case contract
RAID-5 left-symmetric layout on n >= 3 disks: in stripe s the parity lives on disk n-1-(s mod n) and data chunk j lives on disk (parity + 1 + j) mod n. blocks lists the stripe per disk (ints; at most one None for a failed disk). A missing block is rebuilt by XOR; with no missing block the XOR of all blocks must be 0 or the result is "parity-mismatch". Return [data chunks in logical order, parity block].
Why this case matters
Array controllers rebuild degraded stripes and must map disks to logical chunks correctly.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(blocks, stripe, n):
if n < 3 or len(blocks) != n or blocks.count(None) > 1:
return None
pd = n - 1 - stripe % n
if None in blocks:
m = blocks.index(None)
x = 0
for k, v in enumerate(blocks):
if k != m:
x ^= v
blocks = blocks[:m] + [x] + blocks[m + 1:]
else:
x = 0
for v in blocks:
x ^= v
order = [(pd + 1 + j) % n for j in range(n - 1)]
return [[blocks[d] for d in order], blocks[pd]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression [[133, 23, 147], 0, 3]', [[133, 23, 147], 0, 3], 'parity-mismatch'], ['regression [[81, 29, 77], 1, 3]', [[81, 29, 77], 1, 3], 'parity-mismatch'], ['partial-repair [[132, 23, 147], 0, 3]', [[132, 23, 147], 0, 3], [[132, 23], 147]], ['partial-repair [[80, 29, 77], 1, 3]', [[80, 29, 77], 1, 3], [[77, 80], 29]], ['control [[132, null, 147], 0, 3]', [[132, None, 147], 0, 3], [[132, 23], 147]], ['control [[80, null, 77], 1, 3]', [[80, None, 77], 1, 3], [[77, 80], 29]], ['control [[166, null, 235, 175], 0, 4]', [[166, None, 235, 175], 0, 4], [[166, 226, 235], 175]], ['control [[197, null, 1, 70], 1, 4]', [[197, None, 1, 70], 1, 4], [[70, 197, 130], 1]]], [['regression [[196, 130, 1, 70], 1, 4]', [[196, 130, 1, 70], 1, 4], 'parity-mismatch'], ['regression [[203, 146, 183, 239], 2, 4]', [[203, 146, 183, 239], 2, 4], 'parity-mismatch'], ['partial-repair [[197, 130, 1, 70], 1, 4]', [[197, 130, 1, 70], 1, 4], [[70, 197, 130], 1]], ['control [[96, 103, null, 49], 3, 4]', [[96, 103, None, 49], 3, 4], [[103, 54, 49], 96]], ['control [[45, 55, null, 192, 118], 2, 5]', [[45, 55, None, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[95, 206, 36, null, 230], 6, 5]', [[95, 206, 36, None, 230], 6, 5], [[230, 95, 206, 36], 83]], ['control [[null, 163, 83, 128, 142, 206], 4, 6]', [[None, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]], ['control [[null, 132, 216, 194], 5, 4]', [[None, 132, 216, 194], 5, 4], [[194, 158, 132], 216]]], [['regression [[44, 55, 172, 192, 118], 2, 5]', [[44, 55, 172, 192, 118], 2, 5], 'parity-mismatch'], ['regression [[94, 206, 36, 83, 230], 6, 5]', [[94, 206, 36, 83, 230], 6, 5], 'parity-mismatch'], ['partial-repair [[96, 103, 54, 49], 3, 4]', [[96, 103, 54, 49], 3, 4], [[103, 54, 49], 96]], ['partial-repair [[45, 55, 172, 192, 118], 2, 5]', [[45, 55, 172, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[null, 127, 108], 2, 3]', [[None, 127, 108], 2, 3], [[127, 108], 19]], ['control [[135, null, 201, 163, 114], 0, 5]', [[135, None, 201, 163, 114], 0, 5], [[135, 159, 201, 163], 114]], ['control [[1, null, null], 0, 3]', [[1, None, None], 0, 3], None], ['control [[1, 2], 0, 2]', [[1, 2], 0, 2], None]], [['regression [[159, 132, 216, 194], 5, 4]', [[159, 132, 216, 194], 5, 4], 'parity-mismatch'], ['regression [[18, 127, 108], 2, 3]', [[18, 127, 108], 2, 3], 'parity-mismatch'], ['partial-repair [[48, 163, 83, 128, 142, 206], 4, 6]', [[48, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]], ['partial-repair [[158, 132, 216, 194], 5, 4]', [[158, 132, 216, 194], 5, 4], [[194, 158, 132], 216]], ['control [[132, null, 147], 0, 3]', [[132, None, 147], 0, 3], [[132, 23], 147]], ['control [[80, null, 77], 1, 3]', [[80, None, 77], 1, 3], [[77, 80], 29]], ['control [[166, null, 235, 175], 0, 4]', [[166, None, 235, 175], 0, 4], [[166, 226, 235], 175]], ['control [[197, null, 1, 70], 1, 4]', [[197, None, 1, 70], 1, 4], [[70, 197, 130], 1]]], [['regression [[133, 23, 147], 0, 3]', [[133, 23, 147], 0, 3], 'parity-mismatch'], ['regression [[81, 29, 77], 1, 3]', [[81, 29, 77], 1, 3], 'parity-mismatch'], ['partial-repair [[135, 159, 201, 163, 114], 0, 5]', [[135, 159, 201, 163, 114], 0, 5], [[135, 159, 201, 163], 114]], ['partial-repair [[132, 23, 147], 0, 3]', [[132, 23, 147], 0, 3], [[132, 23], 147]], ['control [[96, 103, null, 49], 3, 4]', [[96, 103, None, 49], 3, 4], [[103, 54, 49], 96]], ['control [[45, 55, null, 192, 118], 2, 5]', [[45, 55, None, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[95, 206, 36, null, 230], 6, 5]', [[95, 206, 36, None, 230], 6, 5], [[230, 95, 206, 36], 83]], ['control [[null, 163, 83, 128, 142, 206], 4, 6]', [[None, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]]]]
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 |
|---|---|---|---|
| regression [[133, 23, 147], 0, 3] | [[133, 23], 147] | parity-mismatch | Failed |
| regression [[81, 29, 77], 1, 3] | [[77, 81], 29] | parity-mismatch | Failed |
| partial-repair [[132, 23, 147], 0, 3] | [[132, 23], 147] | [[132, 23], 147] | Passed |
| partial-repair [[80, 29, 77], 1, 3] | [[77, 80], 29] | [[77, 80], 29] | Passed |
| control [[132, null, 147], 0, 3] | [[132, 23], 147] | [[132, 23], 147] | Passed |
| control [[80, null, 77], 1, 3] | [[77, 80], 29] | [[77, 80], 29] | Passed |
| control [[166, null, 235, 175], 0, 4] | [[166, 226, 235], 175] | [[166, 226, 235], 175] | Passed |
| control [[197, null, 1, 70], 1, 4] | [[70, 197, 130], 1] | [[70, 197, 130], 1] | Passed |
SHA-256 / be03e5282c3aebf36b293203277ce68e78a2ab65dd9dbe5c9205995bc2993b22
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(blocks, stripe, n):
if n < 3 or len(blocks) != n or blocks.count(None) > 1:
return None
pd = n - 1 - stripe % n
if None in blocks:
m = blocks.index(None)
x = 0
for k, v in enumerate(blocks):
if k != m:
x ^= v
blocks = blocks[:m] + [x] + blocks[m + 1:]
else:
x = 0
for k, v in enumerate(blocks):
if k != pd:
x ^= v
if x != 0:
return 'parity-mismatch'
order = [(pd + 1 + j) % n for j in range(n - 1)]
return [[blocks[d] for d in order], blocks[pd]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression [[133, 23, 147], 0, 3]', [[133, 23, 147], 0, 3], 'parity-mismatch'], ['regression [[81, 29, 77], 1, 3]', [[81, 29, 77], 1, 3], 'parity-mismatch'], ['partial-repair [[132, 23, 147], 0, 3]', [[132, 23, 147], 0, 3], [[132, 23], 147]], ['partial-repair [[80, 29, 77], 1, 3]', [[80, 29, 77], 1, 3], [[77, 80], 29]], ['control [[132, null, 147], 0, 3]', [[132, None, 147], 0, 3], [[132, 23], 147]], ['control [[80, null, 77], 1, 3]', [[80, None, 77], 1, 3], [[77, 80], 29]], ['control [[166, null, 235, 175], 0, 4]', [[166, None, 235, 175], 0, 4], [[166, 226, 235], 175]], ['control [[197, null, 1, 70], 1, 4]', [[197, None, 1, 70], 1, 4], [[70, 197, 130], 1]]], [['regression [[196, 130, 1, 70], 1, 4]', [[196, 130, 1, 70], 1, 4], 'parity-mismatch'], ['regression [[203, 146, 183, 239], 2, 4]', [[203, 146, 183, 239], 2, 4], 'parity-mismatch'], ['partial-repair [[197, 130, 1, 70], 1, 4]', [[197, 130, 1, 70], 1, 4], [[70, 197, 130], 1]], ['control [[96, 103, null, 49], 3, 4]', [[96, 103, None, 49], 3, 4], [[103, 54, 49], 96]], ['control [[45, 55, null, 192, 118], 2, 5]', [[45, 55, None, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[95, 206, 36, null, 230], 6, 5]', [[95, 206, 36, None, 230], 6, 5], [[230, 95, 206, 36], 83]], ['control [[null, 163, 83, 128, 142, 206], 4, 6]', [[None, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]], ['control [[null, 132, 216, 194], 5, 4]', [[None, 132, 216, 194], 5, 4], [[194, 158, 132], 216]]], [['regression [[44, 55, 172, 192, 118], 2, 5]', [[44, 55, 172, 192, 118], 2, 5], 'parity-mismatch'], ['regression [[94, 206, 36, 83, 230], 6, 5]', [[94, 206, 36, 83, 230], 6, 5], 'parity-mismatch'], ['partial-repair [[96, 103, 54, 49], 3, 4]', [[96, 103, 54, 49], 3, 4], [[103, 54, 49], 96]], ['partial-repair [[45, 55, 172, 192, 118], 2, 5]', [[45, 55, 172, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[null, 127, 108], 2, 3]', [[None, 127, 108], 2, 3], [[127, 108], 19]], ['control [[135, null, 201, 163, 114], 0, 5]', [[135, None, 201, 163, 114], 0, 5], [[135, 159, 201, 163], 114]], ['control [[1, null, null], 0, 3]', [[1, None, None], 0, 3], None], ['control [[1, 2], 0, 2]', [[1, 2], 0, 2], None]], [['regression [[159, 132, 216, 194], 5, 4]', [[159, 132, 216, 194], 5, 4], 'parity-mismatch'], ['regression [[18, 127, 108], 2, 3]', [[18, 127, 108], 2, 3], 'parity-mismatch'], ['partial-repair [[48, 163, 83, 128, 142, 206], 4, 6]', [[48, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]], ['partial-repair [[158, 132, 216, 194], 5, 4]', [[158, 132, 216, 194], 5, 4], [[194, 158, 132], 216]], ['control [[132, null, 147], 0, 3]', [[132, None, 147], 0, 3], [[132, 23], 147]], ['control [[80, null, 77], 1, 3]', [[80, None, 77], 1, 3], [[77, 80], 29]], ['control [[166, null, 235, 175], 0, 4]', [[166, None, 235, 175], 0, 4], [[166, 226, 235], 175]], ['control [[197, null, 1, 70], 1, 4]', [[197, None, 1, 70], 1, 4], [[70, 197, 130], 1]]], [['regression [[133, 23, 147], 0, 3]', [[133, 23, 147], 0, 3], 'parity-mismatch'], ['regression [[81, 29, 77], 1, 3]', [[81, 29, 77], 1, 3], 'parity-mismatch'], ['partial-repair [[135, 159, 201, 163, 114], 0, 5]', [[135, 159, 201, 163, 114], 0, 5], [[135, 159, 201, 163], 114]], ['partial-repair [[132, 23, 147], 0, 3]', [[132, 23, 147], 0, 3], [[132, 23], 147]], ['control [[96, 103, null, 49], 3, 4]', [[96, 103, None, 49], 3, 4], [[103, 54, 49], 96]], ['control [[45, 55, null, 192, 118], 2, 5]', [[45, 55, None, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[95, 206, 36, null, 230], 6, 5]', [[95, 206, 36, None, 230], 6, 5], [[230, 95, 206, 36], 83]], ['control [[null, 163, 83, 128, 142, 206], 4, 6]', [[None, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]]]]
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 |
|---|---|---|---|
| regression [[133, 23, 147], 0, 3] | parity-mismatch | parity-mismatch | Passed |
| regression [[81, 29, 77], 1, 3] | parity-mismatch | parity-mismatch | Passed |
| partial-repair [[132, 23, 147], 0, 3] | parity-mismatch | [[132, 23], 147] | Failed |
| partial-repair [[80, 29, 77], 1, 3] | parity-mismatch | [[77, 80], 29] | Failed |
| control [[132, null, 147], 0, 3] | [[132, 23], 147] | [[132, 23], 147] | Passed |
| control [[80, null, 77], 1, 3] | [[77, 80], 29] | [[77, 80], 29] | Passed |
| control [[166, null, 235, 175], 0, 4] | [[166, 226, 235], 175] | [[166, 226, 235], 175] | Passed |
| control [[197, null, 1, 70], 1, 4] | [[70, 197, 130], 1] | [[70, 197, 130], 1] | Passed |
SHA-256 / bbc720ea54713eb8fd9b3b3b4a5c80d9c17e34db1f8e6ebd75a0327e323edaaa
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(blocks, stripe, n):
if n < 3 or len(blocks) != n or blocks.count(None) > 1:
return None
pd = n - 1 - stripe % n
if None in blocks:
m = blocks.index(None)
x = 0
for k, v in enumerate(blocks):
if k != m:
x ^= v
blocks = blocks[:m] + [x] + blocks[m + 1:]
else:
x = 0
for v in blocks:
x ^= v
if x != 0:
return 'parity-mismatch'
order = [(pd + 1 + j) % n for j in range(n - 1)]
return [[blocks[d] for d in order], blocks[pd]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression [[133, 23, 147], 0, 3]', [[133, 23, 147], 0, 3], 'parity-mismatch'], ['regression [[81, 29, 77], 1, 3]', [[81, 29, 77], 1, 3], 'parity-mismatch'], ['partial-repair [[132, 23, 147], 0, 3]', [[132, 23, 147], 0, 3], [[132, 23], 147]], ['partial-repair [[80, 29, 77], 1, 3]', [[80, 29, 77], 1, 3], [[77, 80], 29]], ['control [[132, null, 147], 0, 3]', [[132, None, 147], 0, 3], [[132, 23], 147]], ['control [[80, null, 77], 1, 3]', [[80, None, 77], 1, 3], [[77, 80], 29]], ['control [[166, null, 235, 175], 0, 4]', [[166, None, 235, 175], 0, 4], [[166, 226, 235], 175]], ['control [[197, null, 1, 70], 1, 4]', [[197, None, 1, 70], 1, 4], [[70, 197, 130], 1]]], [['regression [[196, 130, 1, 70], 1, 4]', [[196, 130, 1, 70], 1, 4], 'parity-mismatch'], ['regression [[203, 146, 183, 239], 2, 4]', [[203, 146, 183, 239], 2, 4], 'parity-mismatch'], ['partial-repair [[197, 130, 1, 70], 1, 4]', [[197, 130, 1, 70], 1, 4], [[70, 197, 130], 1]], ['control [[96, 103, null, 49], 3, 4]', [[96, 103, None, 49], 3, 4], [[103, 54, 49], 96]], ['control [[45, 55, null, 192, 118], 2, 5]', [[45, 55, None, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[95, 206, 36, null, 230], 6, 5]', [[95, 206, 36, None, 230], 6, 5], [[230, 95, 206, 36], 83]], ['control [[null, 163, 83, 128, 142, 206], 4, 6]', [[None, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]], ['control [[null, 132, 216, 194], 5, 4]', [[None, 132, 216, 194], 5, 4], [[194, 158, 132], 216]]], [['regression [[44, 55, 172, 192, 118], 2, 5]', [[44, 55, 172, 192, 118], 2, 5], 'parity-mismatch'], ['regression [[94, 206, 36, 83, 230], 6, 5]', [[94, 206, 36, 83, 230], 6, 5], 'parity-mismatch'], ['partial-repair [[96, 103, 54, 49], 3, 4]', [[96, 103, 54, 49], 3, 4], [[103, 54, 49], 96]], ['partial-repair [[45, 55, 172, 192, 118], 2, 5]', [[45, 55, 172, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[null, 127, 108], 2, 3]', [[None, 127, 108], 2, 3], [[127, 108], 19]], ['control [[135, null, 201, 163, 114], 0, 5]', [[135, None, 201, 163, 114], 0, 5], [[135, 159, 201, 163], 114]], ['control [[1, null, null], 0, 3]', [[1, None, None], 0, 3], None], ['control [[1, 2], 0, 2]', [[1, 2], 0, 2], None]], [['regression [[159, 132, 216, 194], 5, 4]', [[159, 132, 216, 194], 5, 4], 'parity-mismatch'], ['regression [[18, 127, 108], 2, 3]', [[18, 127, 108], 2, 3], 'parity-mismatch'], ['partial-repair [[48, 163, 83, 128, 142, 206], 4, 6]', [[48, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]], ['partial-repair [[158, 132, 216, 194], 5, 4]', [[158, 132, 216, 194], 5, 4], [[194, 158, 132], 216]], ['control [[132, null, 147], 0, 3]', [[132, None, 147], 0, 3], [[132, 23], 147]], ['control [[80, null, 77], 1, 3]', [[80, None, 77], 1, 3], [[77, 80], 29]], ['control [[166, null, 235, 175], 0, 4]', [[166, None, 235, 175], 0, 4], [[166, 226, 235], 175]], ['control [[197, null, 1, 70], 1, 4]', [[197, None, 1, 70], 1, 4], [[70, 197, 130], 1]]], [['regression [[133, 23, 147], 0, 3]', [[133, 23, 147], 0, 3], 'parity-mismatch'], ['regression [[81, 29, 77], 1, 3]', [[81, 29, 77], 1, 3], 'parity-mismatch'], ['partial-repair [[135, 159, 201, 163, 114], 0, 5]', [[135, 159, 201, 163, 114], 0, 5], [[135, 159, 201, 163], 114]], ['partial-repair [[132, 23, 147], 0, 3]', [[132, 23, 147], 0, 3], [[132, 23], 147]], ['control [[96, 103, null, 49], 3, 4]', [[96, 103, None, 49], 3, 4], [[103, 54, 49], 96]], ['control [[45, 55, null, 192, 118], 2, 5]', [[45, 55, None, 192, 118], 2, 5], [[192, 118, 45, 55], 172]], ['control [[95, 206, 36, null, 230], 6, 5]', [[95, 206, 36, None, 230], 6, 5], [[230, 95, 206, 36], 83]], ['control [[null, 163, 83, 128, 142, 206], 4, 6]', [[None, 163, 83, 128, 142, 206], 4, 6], [[83, 128, 142, 206, 48], 163]]]]
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 |
|---|---|---|---|
| regression [[133, 23, 147], 0, 3] | parity-mismatch | parity-mismatch | Passed |
| regression [[81, 29, 77], 1, 3] | parity-mismatch | parity-mismatch | Passed |
| partial-repair [[132, 23, 147], 0, 3] | [[132, 23], 147] | [[132, 23], 147] | Passed |
| partial-repair [[80, 29, 77], 1, 3] | [[77, 80], 29] | [[77, 80], 29] | Passed |
| control [[132, null, 147], 0, 3] | [[132, 23], 147] | [[132, 23], 147] | Passed |
| control [[80, null, 77], 1, 3] | [[77, 80], 29] | [[77, 80], 29] | Passed |
| control [[166, null, 235, 175], 0, 4] | [[166, 226, 235], 175] | [[166, 226, 235], 175] | Passed |
| control [[197, null, 1, 70], 1, 4] | [[70, 197, 130], 1] | [[70, 197, 130], 1] | Passed |
SHA-256 / a41070da482359addafab5e22c6a574ce2c8fe4529812f53479aafd3f0446941
Verification & scope
A deterministic, bounded teaching model of the named code under the stated contract; not a production codec. 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:48:34.973306+00:00.
Case digest / 2367660abd623a37ea01f179db5a80bc97e777f0e1febeb141633a796ce58564