FA-92231 / PLC ladder logic scan cycles / Open access
Scaled analog value escapes the engineering range · case 01
Signals between 3.6 and 4 mA or between 20 and 20.5 mA report values outside the calibrated range.
ROOT CAUSE
The clamp to the configured range is missing.
VERIFIED REPAIR
Clamp the scaled value to the lower and upper engineering limits.
Unsuccessful approach: Clamping only the upper limit still reports below-range values.
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 * 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)
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]]],
['control: 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]]],
['control: 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]]],
['control: 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]]],
['control: 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: 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: 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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['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]]],
['control: scenario 2',
[4, 20, [27643, 11003, 3000, 32767, 3000]],
[['ok', 177], ['ok', 71], ['open', 71], ['over', 71], ['open', 71]]],
['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: scenario 2',
[0, 250, [30430, 16995, 0, 10000, 6000, 10979]],
[['ok', 2422], ['ok', 1077], ['open', 1077], ['ok', 376], ['ok', 0], ['ok', 474]]],
['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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['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 4',
[0, 250, [27893, 24340, 19137, 9936, 26279, 31500, 28004, 10000]],
[['ok', 2168],
['ok', 1812],
['ok', 1291],
['ok', 370],
['ok', 2006],
['ok', 2500],
['ok', 2179],
['ok', 376]]],
['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: 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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[0, 250, [15441, 21456, 3000, 0, 6000, 5618]],
[['ok', 921], ['ok', 1523], ['open', 1523], ['open', 1523], ['ok', 0], ['ok', 0]]],
['control: 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]]]]]
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', -18]] | [['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]] | Failed |
| regression: reverse acting valve | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', -16], ['ok', 1022]] | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]] | Failed |
| regression: under-range tolerance | [['ok', -435], ['ok', -409], ['ok', -400], ['ok', -400], ['ok', 1244]] | [['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]] | Failed |
| control: 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', -12], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1025], ['ok', 702], ['ok', -12], ['ok', 491]] | [['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]] | Failed |
| control: 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', -416], ['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', 1250], ['ok', -440], ['ok', 1042], ['ok', 1238]] | [['ok', 1090], ['ok', 400], ['open', 400], ['ok', -36], ['ok', -341], ['ok', 1200], ['ok', -400], ['ok', 1042], ['ok', 1200]] | Failed |
SHA-256 / 644c2800ac88341a8f674e73deffe9dd5653b96c6c7f6b1533d0be98b220d916
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 * 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 = min(tenths, hi10)
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]]],
['control: 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]]],
['control: 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]]],
['control: 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]]],
['control: 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: 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: 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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['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]]],
['control: scenario 2',
[4, 20, [27643, 11003, 3000, 32767, 3000]],
[['ok', 177], ['ok', 71], ['open', 71], ['over', 71], ['open', 71]]],
['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: scenario 2',
[0, 250, [30430, 16995, 0, 10000, 6000, 10979]],
[['ok', 2422], ['ok', 1077], ['open', 1077], ['ok', 376], ['ok', 0], ['ok', 474]]],
['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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['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 4',
[0, 250, [27893, 24340, 19137, 9936, 26279, 31500, 28004, 10000]],
[['ok', 2168],
['ok', 1812],
['ok', 1291],
['ok', 370],
['ok', 2006],
['ok', 2500],
['ok', 2179],
['ok', 376]]],
['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: 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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[0, 250, [15441, 21456, 3000, 0, 6000, 5618]],
[['ok', 921], ['ok', 1523], ['open', 1523], ['open', 1523], ['ok', 0], ['ok', 0]]],
['control: 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]]]]]
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', -18]] | [['ok', 0], ['ok', 1000], ['ok', 500], ['open', 500], ['over', 500], ['ok', 0]] | Failed |
| regression: reverse acting valve | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', -16], ['ok', 1000]] | [['ok', 1000], ['ok', 750], ['ok', 0], ['ok', 0], ['ok', 1000]] | Failed |
| regression: under-range tolerance | [['ok', -435], ['ok', -409], ['ok', -400], ['ok', -400], ['ok', 1200]] | [['ok', -400], ['ok', -400], ['ok', -400], ['ok', -400], ['ok', 1200]] | Failed |
| control: 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', -12], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', -12], ['ok', 491]] | [['ok', 0], ['ok', 918], ['ok', 344], ['ok', 334], ['ok', 1000], ['ok', 702], ['ok', 0], ['ok', 491]] | Failed |
| control: 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', -416], ['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], ['ok', -440], ['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 / e3020e7009939a179924ef57723ef3bcfc6ceafe79c0a013b5121ca6f5507261
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]]],
['control: 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]]],
['control: 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]]],
['control: 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]]],
['control: 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: 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: 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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['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]]],
['control: scenario 2',
[4, 20, [27643, 11003, 3000, 32767, 3000]],
[['ok', 177], ['ok', 71], ['open', 71], ['over', 71], ['open', 71]]],
['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: scenario 2',
[0, 250, [30430, 16995, 0, 10000, 6000, 10979]],
[['ok', 2422], ['ok', 1077], ['open', 1077], ['ok', 376], ['ok', 0], ['ok', 474]]],
['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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['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 4',
[0, 250, [27893, 24340, 19137, 9936, 26279, 31500, 28004, 10000]],
[['ok', 2168],
['ok', 1812],
['ok', 1291],
['ok', 370],
['ok', 2006],
['ok', 2500],
['ok', 2179],
['ok', 376]]],
['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: 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]]],
['control: rounding half',
[0, 1, [7490, 7491, 18725, 3000, 31950]],
[['ok', 0], ['ok', 1], ['ok', 5], ['open', 5], ['ok', 10]]],
['regression: scenario 1',
[0, 250, [15441, 21456, 3000, 0, 6000, 5618]],
[['ok', 921], ['ok', 1523], ['open', 1523], ['open', 1523], ['ok', 0], ['ok', 0]]],
['control: 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]]]]]
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 |
| control: 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 |
| control: 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 / 6f4149b37dc1dd5cc76091de77a2f4526886bba789c7c87f98075eecf3501d41
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.812648+00:00.
Case digest / 4c49c114fe123a4d915760d2eecf67a5a1386e1007a0d6fa49c6585b7dd1dfba