FA-92241 / PLC ladder logic scan cycles / Open access
Any signal below 4 mA is reported as an open wire · case 01
A transmitter drifting slightly under 4 mA is treated as a broken wire.
ROOT CAUSE
The open-wire test compares against the 4 mA count instead of 3.6 mA.
VERIFIED REPAIR
Report open wire only below 3.6 mA.
Unsuccessful approach: Using the 3.6 mA product with a lost factor of ten flags every reading as open.
Case contract
Scale a 4-20 mA analog channel read once per scan. Raw counts are proportional to 0-20 mA with 20 mA = 31208 counts, so 4 mA = 6242. Below 3.6 mA (raw*200 < 36*31208) the channel reports open wire and above 20.5 mA (raw*40 > 41*31208) over-range; in both cases it returns the last good value (None before any). Otherwise the engineering value in tenths is eng_lo*10 + (raw-6242)*(eng_hi-eng_lo)*10 / 24966 rounded half up, clamped to the configured range (reverse-acting ranges allowed). Return [status, tenths] per scan.
Why this case matters
Ladder programs are executed as repeated scans; each defect here changes what a rung, timer, counter or data-table instruction reports on a particular scan, which is how commissioning and field faults are actually observed.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(eng_lo, eng_hi, raws):
last = None
lo10, hi10 = sorted([eng_lo * 10, eng_hi * 10])
out = []
for raw in raws:
if raw < 6242:
out.append(['open', last])
continue
if raw * 40 > 41 * 31208:
out.append(['over', last])
continue
num = (raw - 6242) * (eng_hi - eng_lo) * 10
tenths = eng_lo * 10 + (2 * num + 24966) // (2 * 24966)
tenths = max(min(tenths, hi10), lo10)
last = tenths
out.append(['ok', tenths])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[100, 0, [31500, 8288, 22627, 22870, 5618, 13683, 31500, 18942]],
[['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]]],
['regression: scenario 2',
[0, 250, [5617, 10253, 31208, 20785, 15236, 31208]],
[['open', None], ['ok', 402], ['ok', 2500], ['ok', 1456], ['ok', 901], ['ok', 2500]]],
['regression: scenario 3',
[-40, 120, [32767, 6000, 6242, 24089, 32767, 26567, 26190, 22883]],
[['over', None],
['ok', -400],
['ok', -400],
['ok', 744],
['over', 744],
['ok', 903],
['ok', 878],
['ok', 666]]],
['regression: scenario 4',
[-40, 120, [29499, 18725, 0, 11927, 7165, 31988, 5618, 28746, 31807]],
[['ok', 1090],
['ok', 400],
['open', 400],
['ok', -36],
['ok', -341],
['ok', 1200],
['ok', -400],
['ok', 1042],
['ok', 1200]]]],
[['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[0, 100, [31500, 12465, 31988, 14808, 13503, 27085, 21673, 31500]],
[['ok', 1000],
['ok', 249],
['ok', 1000],
['ok', 343],
['ok', 291],
['ok', 835],
['ok', 618],
['ok', 1000]]],
['regression: scenario 2',
[4, 20, [10220, 9382, 7184, 5618, 28096, 3000, 31208, 6242, 5617, 6452]],
[['ok', 65],
['ok', 60],
['ok', 46],
['ok', 40],
['ok', 180],
['open', 180],
['ok', 200],
['ok', 40],
['open', 40],
['ok', 41]]],
['regression: scenario 3',
[100, 0, [6000, 25570, 31208, 14262, 10000]],
[['ok', 1000], ['ok', 226], ['ok', 0], ['ok', 679], ['ok', 849]]],
['regression: scenario 4',
[0, 1000, [25458, 32767, 3000, 26377, 18190, 14636, 32767, 10000]],
[['ok', 7697],
['over', 7697],
['open', 7697],
['ok', 8065],
['ok', 4786],
['ok', 3362],
['over', 3362],
['ok', 1505]]]],
[['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: scenario 1',
[-40, 120, [3000, 16471, 17868, 31500, 31989, 18725, 31989, 10136]],
[['open', None],
['ok', 256],
['ok', 345],
['ok', 1200],
['over', 1200],
['ok', 400],
['over', 400],
['ok', -150]]],
['regression: scenario 2',
[4, 20, [27643, 11003, 3000, 32767, 3000]],
[['ok', 177], ['ok', 71], ['open', 71], ['over', 71], ['open', 71]]],
['regression: scenario 3',
[0, 100, [31989, 22472, 5618, 23809, 20211, 3000, 6242, 12935, 28379, 31989]],
[['over', None],
['ok', 650],
['ok', 0],
['ok', 704],
['ok', 560],
['open', 560],
['ok', 0],
['ok', 268],
['ok', 887],
['over', 887]]],
['regression: scenario 4',
[4, 20, [11825, 32767, 10576, 27128, 10066, 5618, 12778, 6000, 10000]],
[['ok', 76],
['over', 76],
['ok', 68],
['ok', 174],
['ok', 65],
['ok', 40],
['ok', 82],
['ok', 40],
['ok', 64]]]],
[['regression: scenario 1',
[0, 250, [3000, 5618, 31500, 27302, 12019]],
[['open', None], ['ok', 0], ['ok', 2500], ['ok', 2109], ['ok', 578]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: scenario 2',
[0, 250, [30430, 16995, 0, 10000, 6000, 10979]],
[['ok', 2422], ['ok', 1077], ['open', 1077], ['ok', 376], ['ok', 0], ['ok', 474]]],
['regression: scenario 3',
[0, 250, [31456, 13455, 24788, 8289, 14213, 18164, 10000, 0, 20991]],
[['ok', 2500],
['ok', 722],
['ok', 1857],
['ok', 205],
['ok', 798],
['ok', 1194],
['ok', 376],
['open', 376],
['ok', 1477]]],
['regression: scenario 4',
[0, 100, [3000, 5633, 7891, 18725, 19352, 30730, 10000, 31208, 25959]],
[['open', None],
['ok', 0],
['ok', 66],
['ok', 500],
['ok', 525],
['ok', 981],
['ok', 151],
['ok', 1000],
['ok', 790]]]],
[['regression: scenario 5',
[100, 0, [5618, 10474, 18027, 31947, 19308, 31083, 26603, 16118, 11612, 5618]],
[['ok', 1000],
['ok', 830],
['ok', 528],
['ok', 0],
['ok', 477],
['ok', 5],
['ok', 184],
['ok', 604],
['ok', 785],
['ok', 1000]]],
['regression: scenario 1',
[0, 250, [15441, 21456, 3000, 0, 6000, 5618]],
[['ok', 921], ['ok', 1523], ['open', 1523], ['open', 1523], ['ok', 0], ['ok', 0]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 2',
[0, 100, [31078, 6242, 18725, 18727, 19134, 13243, 18725, 21879, 0, 19240]],
[['ok', 995],
['ok', 0],
['ok', 500],
['ok', 500],
['ok', 516],
['ok', 280],
['ok', 500],
['ok', 626],
['open', 626],
['ok', 521]]],
['regression: scenario 3',
[4, 20, [6813, 26535, 0, 32767, 7893]],
[['ok', 44], ['ok', 170], ['open', 170], ['over', 170], ['ok', 51]]]]]
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: span points and faults | [['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['open', 500]] | [['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]] | Failed |
| regression: reverse acting valve | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['open', 0]] | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]] | Failed |
| regression: under-range tolerance | [['open', None], ['open', None], ['ok', -400], ['ok', -400], ['ok', 1200]] | [['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]] | Failed |
| regression: rounding half | [['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]] | [['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]] | Passed |
| regression: scenario 1 | [['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['open', 334], ['ok', 702], ['ok', 0], ['ok', 491]] | [['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]] | Failed |
| regression: scenario 2 | [['open', None], ['ok', 402], ['ok', 2500], ['ok', 1456], ['ok', 901], ['ok', 2500]] | [['open', None], ['ok', 402], ['ok', 2500], ['ok', 1456], ['ok', 901], ['ok', 2500]] | Passed |
| regression: scenario 3 | [['over', None], ['open', None], ['ok', -400], ['ok', 744], ['over', 744], ['ok', 903], ['ok', 878], ['ok', 666]] | [['over', None], ['ok', -400], ['ok', -400], ['ok', 744], ['over', 744], ['ok', 903], ['ok', 878], ['ok', 666]] | Failed |
| regression: scenario 4 | [['ok', 1090], ['ok', 400], ['open', 400], ['ok', -36], ['ok', -341], ['ok', 1200], ['open', 1200], ['ok', 1042], ['ok', 1200]] | [['ok', 1090], ['ok', 400], ['open', 400], ['ok', -36], ['ok', -341], ['ok', 1200], ['ok', -400], ['ok', 1042], ['ok', 1200]] | Failed |
SHA-256 / 995ba6f6c6d6897c308b29498076b443f93738b5e842c01d5c753a60231458db
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(eng_lo, eng_hi, raws):
last = None
lo10, hi10 = sorted([eng_lo * 10, eng_hi * 10])
out = []
for raw in raws:
if raw * 20 < 36 * 31208:
out.append(['open', last])
continue
if raw * 40 > 41 * 31208:
out.append(['over', last])
continue
num = (raw - 6242) * (eng_hi - eng_lo) * 10
tenths = eng_lo * 10 + (2 * num + 24966) // (2 * 24966)
tenths = max(min(tenths, hi10), lo10)
last = tenths
out.append(['ok', tenths])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[100, 0, [31500, 8288, 22627, 22870, 5618, 13683, 31500, 18942]],
[['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]]],
['regression: scenario 2',
[0, 250, [5617, 10253, 31208, 20785, 15236, 31208]],
[['open', None], ['ok', 402], ['ok', 2500], ['ok', 1456], ['ok', 901], ['ok', 2500]]],
['regression: scenario 3',
[-40, 120, [32767, 6000, 6242, 24089, 32767, 26567, 26190, 22883]],
[['over', None],
['ok', -400],
['ok', -400],
['ok', 744],
['over', 744],
['ok', 903],
['ok', 878],
['ok', 666]]],
['regression: scenario 4',
[-40, 120, [29499, 18725, 0, 11927, 7165, 31988, 5618, 28746, 31807]],
[['ok', 1090],
['ok', 400],
['open', 400],
['ok', -36],
['ok', -341],
['ok', 1200],
['ok', -400],
['ok', 1042],
['ok', 1200]]]],
[['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[0, 100, [31500, 12465, 31988, 14808, 13503, 27085, 21673, 31500]],
[['ok', 1000],
['ok', 249],
['ok', 1000],
['ok', 343],
['ok', 291],
['ok', 835],
['ok', 618],
['ok', 1000]]],
['regression: scenario 2',
[4, 20, [10220, 9382, 7184, 5618, 28096, 3000, 31208, 6242, 5617, 6452]],
[['ok', 65],
['ok', 60],
['ok', 46],
['ok', 40],
['ok', 180],
['open', 180],
['ok', 200],
['ok', 40],
['open', 40],
['ok', 41]]],
['regression: scenario 3',
[100, 0, [6000, 25570, 31208, 14262, 10000]],
[['ok', 1000], ['ok', 226], ['ok', 0], ['ok', 679], ['ok', 849]]],
['regression: scenario 4',
[0, 1000, [25458, 32767, 3000, 26377, 18190, 14636, 32767, 10000]],
[['ok', 7697],
['over', 7697],
['open', 7697],
['ok', 8065],
['ok', 4786],
['ok', 3362],
['over', 3362],
['ok', 1505]]]],
[['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: scenario 1',
[-40, 120, [3000, 16471, 17868, 31500, 31989, 18725, 31989, 10136]],
[['open', None],
['ok', 256],
['ok', 345],
['ok', 1200],
['over', 1200],
['ok', 400],
['over', 400],
['ok', -150]]],
['regression: scenario 2',
[4, 20, [27643, 11003, 3000, 32767, 3000]],
[['ok', 177], ['ok', 71], ['open', 71], ['over', 71], ['open', 71]]],
['regression: scenario 3',
[0, 100, [31989, 22472, 5618, 23809, 20211, 3000, 6242, 12935, 28379, 31989]],
[['over', None],
['ok', 650],
['ok', 0],
['ok', 704],
['ok', 560],
['open', 560],
['ok', 0],
['ok', 268],
['ok', 887],
['over', 887]]],
['regression: scenario 4',
[4, 20, [11825, 32767, 10576, 27128, 10066, 5618, 12778, 6000, 10000]],
[['ok', 76],
['over', 76],
['ok', 68],
['ok', 174],
['ok', 65],
['ok', 40],
['ok', 82],
['ok', 40],
['ok', 64]]]],
[['regression: scenario 1',
[0, 250, [3000, 5618, 31500, 27302, 12019]],
[['open', None], ['ok', 0], ['ok', 2500], ['ok', 2109], ['ok', 578]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: scenario 2',
[0, 250, [30430, 16995, 0, 10000, 6000, 10979]],
[['ok', 2422], ['ok', 1077], ['open', 1077], ['ok', 376], ['ok', 0], ['ok', 474]]],
['regression: scenario 3',
[0, 250, [31456, 13455, 24788, 8289, 14213, 18164, 10000, 0, 20991]],
[['ok', 2500],
['ok', 722],
['ok', 1857],
['ok', 205],
['ok', 798],
['ok', 1194],
['ok', 376],
['open', 376],
['ok', 1477]]],
['regression: scenario 4',
[0, 100, [3000, 5633, 7891, 18725, 19352, 30730, 10000, 31208, 25959]],
[['open', None],
['ok', 0],
['ok', 66],
['ok', 500],
['ok', 525],
['ok', 981],
['ok', 151],
['ok', 1000],
['ok', 790]]]],
[['regression: scenario 5',
[100, 0, [5618, 10474, 18027, 31947, 19308, 31083, 26603, 16118, 11612, 5618]],
[['ok', 1000],
['ok', 830],
['ok', 528],
['ok', 0],
['ok', 477],
['ok', 5],
['ok', 184],
['ok', 604],
['ok', 785],
['ok', 1000]]],
['regression: scenario 1',
[0, 250, [15441, 21456, 3000, 0, 6000, 5618]],
[['ok', 921], ['ok', 1523], ['open', 1523], ['open', 1523], ['ok', 0], ['ok', 0]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 2',
[0, 100, [31078, 6242, 18725, 18727, 19134, 13243, 18725, 21879, 0, 19240]],
[['ok', 995],
['ok', 0],
['ok', 500],
['ok', 500],
['ok', 516],
['ok', 280],
['ok', 500],
['ok', 626],
['open', 626],
['ok', 521]]],
['regression: scenario 3',
[4, 20, [6813, 26535, 0, 32767, 7893]],
[['ok', 44], ['ok', 170], ['open', 170], ['over', 170], ['ok', 51]]]]]
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: span points and faults | [['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None]] | [['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]] | Failed |
| regression: reverse acting valve | [['open', None], ['open', None], ['open', None], ['open', None], ['open', None]] | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]] | Failed |
| regression: under-range tolerance | [['open', None], ['open', None], ['open', None], ['open', None], ['open', None]] | [['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]] | Failed |
| regression: rounding half | [['open', None], ['open', None], ['open', None], ['open', None], ['open', None]] | [['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]] | Failed |
| regression: scenario 1 | [['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None]] | [['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]] | Failed |
| regression: scenario 2 | [['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None]] | [['open', None], ['ok', 402], ['ok', 2500], ['ok', 1456], ['ok', 901], ['ok', 2500]] | Failed |
| regression: scenario 3 | [['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None]] | [['over', None], ['ok', -400], ['ok', -400], ['ok', 744], ['over', 744], ['ok', 903], ['ok', 878], ['ok', 666]] | Failed |
| regression: scenario 4 | [['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None], ['open', None]] | [['ok', 1090], ['ok', 400], ['open', 400], ['ok', -36], ['ok', -341], ['ok', 1200], ['ok', -400], ['ok', 1042], ['ok', 1200]] | Failed |
SHA-256 / 7d9ec2d9d31e4ca8b159e3bcb09cc486b1d3afc15202880c99659bfc7fe2bd5e
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(eng_lo, eng_hi, raws):
last = None
lo10, hi10 = sorted([eng_lo * 10, eng_hi * 10])
out = []
for raw in raws:
if raw * 200 < 36 * 31208:
out.append(['open', last])
continue
if raw * 40 > 41 * 31208:
out.append(['over', last])
continue
num = (raw - 6242) * (eng_hi - eng_lo) * 10
tenths = eng_lo * 10 + (2 * num + 24966) // (2 * 24966)
tenths = max(min(tenths, hi10), lo10)
last = tenths
out.append(['ok', tenths])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[100, 0, [31500, 8288, 22627, 22870, 5618, 13683, 31500, 18942]],
[['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]]],
['regression: scenario 2',
[0, 250, [5617, 10253, 31208, 20785, 15236, 31208]],
[['open', None], ['ok', 402], ['ok', 2500], ['ok', 1456], ['ok', 901], ['ok', 2500]]],
['regression: scenario 3',
[-40, 120, [32767, 6000, 6242, 24089, 32767, 26567, 26190, 22883]],
[['over', None],
['ok', -400],
['ok', -400],
['ok', 744],
['over', 744],
['ok', 903],
['ok', 878],
['ok', 666]]],
['regression: scenario 4',
[-40, 120, [29499, 18725, 0, 11927, 7165, 31988, 5618, 28746, 31807]],
[['ok', 1090],
['ok', 400],
['open', 400],
['ok', -36],
['ok', -341],
['ok', 1200],
['ok', -400],
['ok', 1042],
['ok', 1200]]]],
[['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[0, 100, [31500, 12465, 31988, 14808, 13503, 27085, 21673, 31500]],
[['ok', 1000],
['ok', 249],
['ok', 1000],
['ok', 343],
['ok', 291],
['ok', 835],
['ok', 618],
['ok', 1000]]],
['regression: scenario 2',
[4, 20, [10220, 9382, 7184, 5618, 28096, 3000, 31208, 6242, 5617, 6452]],
[['ok', 65],
['ok', 60],
['ok', 46],
['ok', 40],
['ok', 180],
['open', 180],
['ok', 200],
['ok', 40],
['open', 40],
['ok', 41]]],
['regression: scenario 3',
[100, 0, [6000, 25570, 31208, 14262, 10000]],
[['ok', 1000], ['ok', 226], ['ok', 0], ['ok', 679], ['ok', 849]]],
['regression: scenario 4',
[0, 1000, [25458, 32767, 3000, 26377, 18190, 14636, 32767, 10000]],
[['ok', 7697],
['over', 7697],
['open', 7697],
['ok', 8065],
['ok', 4786],
['ok', 3362],
['over', 3362],
['ok', 1505]]]],
[['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: scenario 1',
[-40, 120, [3000, 16471, 17868, 31500, 31989, 18725, 31989, 10136]],
[['open', None],
['ok', 256],
['ok', 345],
['ok', 1200],
['over', 1200],
['ok', 400],
['over', 400],
['ok', -150]]],
['regression: scenario 2',
[4, 20, [27643, 11003, 3000, 32767, 3000]],
[['ok', 177], ['ok', 71], ['open', 71], ['over', 71], ['open', 71]]],
['regression: scenario 3',
[0, 100, [31989, 22472, 5618, 23809, 20211, 3000, 6242, 12935, 28379, 31989]],
[['over', None],
['ok', 650],
['ok', 0],
['ok', 704],
['ok', 560],
['open', 560],
['ok', 0],
['ok', 268],
['ok', 887],
['over', 887]]],
['regression: scenario 4',
[4, 20, [11825, 32767, 10576, 27128, 10066, 5618, 12778, 6000, 10000]],
[['ok', 76],
['over', 76],
['ok', 68],
['ok', 174],
['ok', 65],
['ok', 40],
['ok', 82],
['ok', 40],
['ok', 64]]]],
[['regression: scenario 1',
[0, 250, [3000, 5618, 31500, 27302, 12019]],
[['open', None], ['ok', 0], ['ok', 2500], ['ok', 2109], ['ok', 578]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: scenario 2',
[0, 250, [30430, 16995, 0, 10000, 6000, 10979]],
[['ok', 2422], ['ok', 1077], ['open', 1077], ['ok', 376], ['ok', 0], ['ok', 474]]],
['regression: scenario 3',
[0, 250, [31456, 13455, 24788, 8289, 14213, 18164, 10000, 0, 20991]],
[['ok', 2500],
['ok', 722],
['ok', 1857],
['ok', 205],
['ok', 798],
['ok', 1194],
['ok', 376],
['open', 376],
['ok', 1477]]],
['regression: scenario 4',
[0, 100, [3000, 5633, 7891, 18725, 19352, 30730, 10000, 31208, 25959]],
[['open', None],
['ok', 0],
['ok', 66],
['ok', 500],
['ok', 525],
['ok', 981],
['ok', 151],
['ok', 1000],
['ok', 790]]]],
[['regression: scenario 5',
[100, 0, [5618, 10474, 18027, 31947, 19308, 31083, 26603, 16118, 11612, 5618]],
[['ok', 1000],
['ok', 830],
['ok', 528],
['ok', 0],
['ok', 477],
['ok', 5],
['ok', 184],
['ok', 604],
['ok', 785],
['ok', 1000]]],
['regression: scenario 1',
[0, 250, [15441, 21456, 3000, 0, 6000, 5618]],
[['ok', 921], ['ok', 1523], ['open', 1523], ['open', 1523], ['ok', 0], ['ok', 0]]],
['regression: span points and faults',
[0, 100, [6242, 31208, 18725, 5000, 32000, 5800]],
[['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]]],
['regression: reverse acting valve',
[100, 0, [6242, 12483, 31208, 31600, 5700]],
[['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]]],
['regression: under-range tolerance',
[-40, 120, [5700, 6100, 6242, 6243, 31900]],
[['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]]],
['regression: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 2',
[0, 100, [31078, 6242, 18725, 18727, 19134, 13243, 18725, 21879, 0, 19240]],
[['ok', 995],
['ok', 0],
['ok', 500],
['ok', 500],
['ok', 516],
['ok', 280],
['ok', 500],
['ok', 626],
['open', 626],
['ok', 521]]],
['regression: scenario 3',
[4, 20, [6813, 26535, 0, 32767, 7893]],
[['ok', 44], ['ok', 170], ['open', 170], ['over', 170], ['ok', 51]]]]]
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: span points and faults | [['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]] | [['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]] | Passed |
| regression: reverse acting valve | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]] | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]] | Passed |
| regression: under-range tolerance | [['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]] | [['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]] | Passed |
| regression: rounding half | [['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]] | [['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]] | Passed |
| regression: scenario 1 | [['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]] | [['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]] | Passed |
| regression: scenario 2 | [['open', None], ['ok', 402], ['ok', 2500], ['ok', 1456], ['ok', 901], ['ok', 2500]] | [['open', None], ['ok', 402], ['ok', 2500], ['ok', 1456], ['ok', 901], ['ok', 2500]] | Passed |
| regression: scenario 3 | [['over', None], ['ok', -400], ['ok', -400], ['ok', 744], ['over', 744], ['ok', 903], ['ok', 878], ['ok', 666]] | [['over', None], ['ok', -400], ['ok', -400], ['ok', 744], ['over', 744], ['ok', 903], ['ok', 878], ['ok', 666]] | Passed |
| regression: scenario 4 | [['ok', 1090], ['ok', 400], ['open', 400], ['ok', -36], ['ok', -341], ['ok', 1200], ['ok', -400], ['ok', 1042], ['ok', 1200]] | [['ok', 1090], ['ok', 400], ['open', 400], ['ok', -36], ['ok', -341], ['ok', 1200], ['ok', -400], ['ok', 1042], ['ok', 1200]] | Passed |
SHA-256 / 140a951ed8ea4828d55e0fdab78588b2cd5def6baf0e1b19a260d81038a7677a
Verification & scope
A deterministic bounded teaching model of one PLC instruction or rung pattern evaluated scan by scan. The stated contract is a stipulated toy convention, not a claim of conformance to any vendor controller or IEC 61131-3 runtime. 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:51:43.852476+00:00.
Case digest / 463f1d45d98316864e3eb5a7712ad00ec74353d696c679d7409bbac468ec51a5