SAFETY-04: revive the clamp reason, and compare reasons in the sweep

`want = i_w` after the integrator bound, so at the default limit == max_w the
output clamp can never fire and `reason == "clamped"` had become unreachable.
Observability only today - nothing gates on the string - but SAFETY-03 exists
to alarm on exactly that engagement, so its hook was dead before it was built.

The integrator bound now reports "i-clamped", and that is the signal SAFETY-03
must watch: it is the one that fires on a default install. "clamped" stays
reachable for a configuration that lets the integrator run above the rail,
where both fire and the output clamp - which describes the value actually
emitted - is the one reported. Two names because the two events want different
alarms: the loop winding, versus a command that came out over the rating.

The real fix is the second half. The equivalence sweep compared
(target_w, sat_count), which is how a dead reason survived 3024 cases. It now
compares (target_w, sat_count, frozen, reason) and it catches this defect:
dropping the emit turns it red. Deliberate rename aliased explicitly, so any
OTHER reason divergence still fails.

Result of adding reason to the tuple: 105 of 3024 cases differ, and every one
of them is the i-clamped/clamped rename. Zero value divergences, `frozen`
included. Nothing else surfaced.

test_control.py: 41 -> 43 checks, all passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Du77usMj8XNKNFZGmUiWDa
This commit is contained in:
glenn schrooyen
2026-08-24 22:29:10 +02:00
co-authored by Claude Opus 5
parent e46175559b
commit 7123aa00a4
2 changed files with 55 additions and 11 deletions
+12 -1
View File
@@ -164,7 +164,18 @@ def compute(
# ⚠️ Applied EVERY cycle, frozen or not: the freeze is conditional, this
# bound is not. It is what makes the worst-case unwind time finite and
# knowable instead of a function of how long the error happened to stand.
i_w = max(-limit, min(limit, i_w))
bounded = max(-limit, min(limit, i_w))
if bounded != i_w:
# ⚠️ SAFETY-03 (alarm whenever the loop winds into a rail) must watch
# for THIS, not for "clamped" below. At the default limit == max_w the
# integrator bound is reached first and the command derived from it can
# then never exceed max_w, so "clamped" is unreachable on a default
# install - it survives only for a configuration that deliberately lets
# the integrator run above the rail. Two reasons rather than one
# because the two events want different alarms: "i-clamped" is the loop
# winding, "clamped" is a command that came out over the rating anyway.
reason = "i-clamped"
i_w = bounded
want = i_w
# ⚠️ Maintenance shaping (charge-only, cheap-window floor) used to live