FA-93716 / Solar tracker geometry / Open access
Anemometer fail-safe stow voting: stale reading age · case 01
An anemometer reporting exactly at the freshness limit is treated as failed.
ROOT CAUSE
The freshness test is strict.
VERIFIED REPAIR
Accept readings with age <= max_age.
Unsuccessful approach: Doubling the age limit accepts stale sensors.
Case contract
readings are [value or None, age_s] per anemometer. A reading is valid when value is not None and age <= max_age. Fewer than n_required valid readings: ['stow', 'sensor', None]. Otherwise use the highest valid value: >= stow_at gives ['stow', 'wind', v], else ['track', 'ok', v].
Why this case matters
Single-axis and dual-axis solar trackers turn a sun direction into actuator commands; a sign, frame or limit mistake points a whole plant away from the sun or into a mechanical stop.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(readings, max_age, stow_at, n_required):
valid = [v for v, age in readings if v is not None and age < max_age]
if len(valid) < n_required:
return ['stow', 'sensor', None]
peak = max(valid)
if peak >= stow_at:
return ['stow', 'wind', peak]
return ['track', 'ok', peak]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[0, 0], [None, 61], [16.5, 60], [8, 30]], 60, 18, 2],
['track', 'ok', 16.5]],
['regression: stale reading age (partial repair)', [[[None, 5], [12, 61], [16.5, 30]], 60, 18, 2],
['stow', 'sensor', None]],
['control 1', [[[14.5, 5], [8, 5], [22, 60]], 60, 15, 2], ['stow', 'wind', 22]],
['control 2', [[[8, 60], [8, 120]], 60, 18, 1], ['track', 'ok', 8]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[22, 120], [0, 30], [14.5, 0]], 30, 15, 2],
['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)', [[[3.5, 61], [12, 120], [12, 30]], 60, 15, 2],
['stow', 'sensor', None]],
['control 1', [[[8, 60], [0, 10], [14.5, 10]], 60, 18, 1], ['track', 'ok', 14.5]],
['control 2', [[[3.5, 61], [22, 61], [22, 10], [16.5, 30]], 60, 18, 1], ['stow', 'wind', 22]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[14.5, 30], [0, 0], [None, 10], [14.5, 60]], 30, 15, 1],
['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)', [[[3.5, 10], [14.5, 61], [22, 61]], 60, 15, 1],
['track', 'ok', 3.5]],
['control 1', [[[22, 61], [22, 120]], 30, 18, 2], ['stow', 'sensor', None]],
['control 2', [[[3.5, 30], [15, 0], [None, 61], [None, 30]], 60, 18, 2], ['track', 'ok', 15]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[14.5, 30]], 30, 18, 1], ['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)',
[[[8, 10], [16.5, 60], [22, 61], [15, 5]], 60, 18, 1], ['track', 'ok', 16.5]],
['control 1', [[[3.5, 5], [22, 30]], 30, 18, 2], ['stow', 'wind', 22]],
['control 2', [[[22, 0], [3.5, 60], [12, 30], [14.5, 5]], 30, 15, 1], ['stow', 'wind', 22]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[16.5, 0], [8, 120], [16.5, 60], [12, 30]], 30, 15, 2],
['stow', 'wind', 16.5]],
['regression: stale reading age (partial repair)',
[[[None, 5], [22, 61], [15, 61], [15, 5]], 60, 18, 1], ['track', 'ok', 15]],
['control 1', [[[3.5, 61], [0, 5], [0, 60], [14.5, 120]], 60, 18, 1], ['track', 'ok', 0]],
['control 2', [[[15, 10], [12, 61], [14.5, 60], [None, 60]], 30, 15, 1], ['stow', 'wind', 15]]]]
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 |
|---|---|---|---|
| boundary: reading exactly max_age old | ['stow', 'sensor', None] | ['track', 'ok', 10] | Failed |
| boundary: calm zero reading | ['track', 'ok', 0] | ['track', 'ok', 0] | Passed |
| boundary: wind at stow limit | ['stow', 'wind', 15] | ['stow', 'wind', 15] | Passed |
| regression: stale reading age | ['track', 'ok', 8] | ['track', 'ok', 16.5] | Failed |
| regression: stale reading age (partial repair) | ['stow', 'sensor', None] | ['stow', 'sensor', None] | Passed |
| control 1 | ['track', 'ok', 14.5] | ['stow', 'wind', 22] | Failed |
| control 2 | ['stow', 'sensor', None] | ['track', 'ok', 8] | Failed |
SHA-256 / 0111f79ffe2ad3c8b71bc8da70752e6b5a1c32ac5c4959a0deb2c188a4b99078
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(readings, max_age, stow_at, n_required):
valid = [v for v, age in readings if v is not None and age < max_age * 2]
if len(valid) < n_required:
return ['stow', 'sensor', None]
peak = max(valid)
if peak >= stow_at:
return ['stow', 'wind', peak]
return ['track', 'ok', peak]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[0, 0], [None, 61], [16.5, 60], [8, 30]], 60, 18, 2],
['track', 'ok', 16.5]],
['regression: stale reading age (partial repair)', [[[None, 5], [12, 61], [16.5, 30]], 60, 18, 2],
['stow', 'sensor', None]],
['control 1', [[[14.5, 5], [8, 5], [22, 60]], 60, 15, 2], ['stow', 'wind', 22]],
['control 2', [[[8, 60], [8, 120]], 60, 18, 1], ['track', 'ok', 8]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[22, 120], [0, 30], [14.5, 0]], 30, 15, 2],
['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)', [[[3.5, 61], [12, 120], [12, 30]], 60, 15, 2],
['stow', 'sensor', None]],
['control 1', [[[8, 60], [0, 10], [14.5, 10]], 60, 18, 1], ['track', 'ok', 14.5]],
['control 2', [[[3.5, 61], [22, 61], [22, 10], [16.5, 30]], 60, 18, 1], ['stow', 'wind', 22]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[14.5, 30], [0, 0], [None, 10], [14.5, 60]], 30, 15, 1],
['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)', [[[3.5, 10], [14.5, 61], [22, 61]], 60, 15, 1],
['track', 'ok', 3.5]],
['control 1', [[[22, 61], [22, 120]], 30, 18, 2], ['stow', 'sensor', None]],
['control 2', [[[3.5, 30], [15, 0], [None, 61], [None, 30]], 60, 18, 2], ['track', 'ok', 15]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[14.5, 30]], 30, 18, 1], ['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)',
[[[8, 10], [16.5, 60], [22, 61], [15, 5]], 60, 18, 1], ['track', 'ok', 16.5]],
['control 1', [[[3.5, 5], [22, 30]], 30, 18, 2], ['stow', 'wind', 22]],
['control 2', [[[22, 0], [3.5, 60], [12, 30], [14.5, 5]], 30, 15, 1], ['stow', 'wind', 22]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[16.5, 0], [8, 120], [16.5, 60], [12, 30]], 30, 15, 2],
['stow', 'wind', 16.5]],
['regression: stale reading age (partial repair)',
[[[None, 5], [22, 61], [15, 61], [15, 5]], 60, 18, 1], ['track', 'ok', 15]],
['control 1', [[[3.5, 61], [0, 5], [0, 60], [14.5, 120]], 60, 18, 1], ['track', 'ok', 0]],
['control 2', [[[15, 10], [12, 61], [14.5, 60], [None, 60]], 30, 15, 1], ['stow', 'wind', 15]]]]
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 |
|---|---|---|---|
| boundary: reading exactly max_age old | ['track', 'ok', 10] | ['track', 'ok', 10] | Passed |
| boundary: calm zero reading | ['track', 'ok', 0] | ['track', 'ok', 0] | Passed |
| boundary: wind at stow limit | ['stow', 'wind', 15] | ['stow', 'wind', 15] | Passed |
| regression: stale reading age | ['track', 'ok', 16.5] | ['track', 'ok', 16.5] | Passed |
| regression: stale reading age (partial repair) | ['track', 'ok', 16.5] | ['stow', 'sensor', None] | Failed |
| control 1 | ['stow', 'wind', 22] | ['stow', 'wind', 22] | Passed |
| control 2 | ['track', 'ok', 8] | ['track', 'ok', 8] | Passed |
SHA-256 / 2f87a27ac51d63d6561028f5f168c59d7a024f2358293c8837026c5fee67f9f7
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(readings, max_age, stow_at, n_required):
valid = [v for v, age in readings if v is not None and age <= max_age]
if len(valid) < n_required:
return ['stow', 'sensor', None]
peak = max(valid)
if peak >= stow_at:
return ['stow', 'wind', peak]
return ['track', 'ok', peak]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[0, 0], [None, 61], [16.5, 60], [8, 30]], 60, 18, 2],
['track', 'ok', 16.5]],
['regression: stale reading age (partial repair)', [[[None, 5], [12, 61], [16.5, 30]], 60, 18, 2],
['stow', 'sensor', None]],
['control 1', [[[14.5, 5], [8, 5], [22, 60]], 60, 15, 2], ['stow', 'wind', 22]],
['control 2', [[[8, 60], [8, 120]], 60, 18, 1], ['track', 'ok', 8]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[22, 120], [0, 30], [14.5, 0]], 30, 15, 2],
['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)', [[[3.5, 61], [12, 120], [12, 30]], 60, 15, 2],
['stow', 'sensor', None]],
['control 1', [[[8, 60], [0, 10], [14.5, 10]], 60, 18, 1], ['track', 'ok', 14.5]],
['control 2', [[[3.5, 61], [22, 61], [22, 10], [16.5, 30]], 60, 18, 1], ['stow', 'wind', 22]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[14.5, 30], [0, 0], [None, 10], [14.5, 60]], 30, 15, 1],
['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)', [[[3.5, 10], [14.5, 61], [22, 61]], 60, 15, 1],
['track', 'ok', 3.5]],
['control 1', [[[22, 61], [22, 120]], 30, 18, 2], ['stow', 'sensor', None]],
['control 2', [[[3.5, 30], [15, 0], [None, 61], [None, 30]], 60, 18, 2], ['track', 'ok', 15]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[14.5, 30]], 30, 18, 1], ['track', 'ok', 14.5]],
['regression: stale reading age (partial repair)',
[[[8, 10], [16.5, 60], [22, 61], [15, 5]], 60, 18, 1], ['track', 'ok', 16.5]],
['control 1', [[[3.5, 5], [22, 30]], 30, 18, 2], ['stow', 'wind', 22]],
['control 2', [[[22, 0], [3.5, 60], [12, 30], [14.5, 5]], 30, 15, 1], ['stow', 'wind', 22]]],
[['boundary: reading exactly max_age old', [[[10, 60]], 60, 15, 1], ['track', 'ok', 10]],
['boundary: calm zero reading', [[[0, 5], [None, 5]], 60, 15, 1], ['track', 'ok', 0]],
['boundary: wind at stow limit', [[[15, 5], [4, 5]], 60, 15, 2], ['stow', 'wind', 15]],
['regression: stale reading age', [[[16.5, 0], [8, 120], [16.5, 60], [12, 30]], 30, 15, 2],
['stow', 'wind', 16.5]],
['regression: stale reading age (partial repair)',
[[[None, 5], [22, 61], [15, 61], [15, 5]], 60, 18, 1], ['track', 'ok', 15]],
['control 1', [[[3.5, 61], [0, 5], [0, 60], [14.5, 120]], 60, 18, 1], ['track', 'ok', 0]],
['control 2', [[[15, 10], [12, 61], [14.5, 60], [None, 60]], 30, 15, 1], ['stow', 'wind', 15]]]]
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 |
|---|---|---|---|
| boundary: reading exactly max_age old | ['track', 'ok', 10] | ['track', 'ok', 10] | Passed |
| boundary: calm zero reading | ['track', 'ok', 0] | ['track', 'ok', 0] | Passed |
| boundary: wind at stow limit | ['stow', 'wind', 15] | ['stow', 'wind', 15] | Passed |
| regression: stale reading age | ['track', 'ok', 16.5] | ['track', 'ok', 16.5] | Passed |
| regression: stale reading age (partial repair) | ['stow', 'sensor', None] | ['stow', 'sensor', None] | Passed |
| control 1 | ['stow', 'wind', 22] | ['stow', 'wind', 22] | Passed |
| control 2 | ['track', 'ok', 8] | ['track', 'ok', 8] | Passed |
SHA-256 / c012b35c6822c5293819a208577523bbe82d1395def3d6016a6bb198dc039872
Verification & scope
Deterministic stipulated toy contract for teaching; no claim of conformance with any standard, vendor protocol or production controller. 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:57.635456+00:00.
Case digest / 0f1c473e3516161f835de165a4dbfb1f11bc73c8cbf41ed7b29cbf45b6edd84f