SAFETY-48: the slew step ceiling reaches the integrator, and what it bounds is the LEAD

`compute()` freezes the integrator with an asymmetric rule and the comment
beside it states the requirement outright - "the requirement is that the
INTEGRATOR stop accumulating, not only the command" - but `frozen` is computed
from ONE signal, `abs(prev_w - actual_w) > saturation_w`, and slew-limiting
never enters it. The integrator moves `gain * error` a cycle and the command
moves at most `slew_w`, so the integrator outruns the command whenever
`|error| > slew_w / gain`: 667 W at the live shape, against a measured median
grid error of 1114 W at the onset of a recorded episode. SAFETY-39's retune
made it MORE frequent, not less - a smaller step is a lower threshold.

⚠️ THE FORM THE CARD ASKED FOR RAISES THE BILLED QUANTITY, WHICH IS WHY IT IS
NOT WHAT SHIPPED. Reusing the asymmetric freeze on a carried slew flag was
built from release/1.0's own source and measured over 16.00 days / 256 252
meter instants of the live install's recorder: export 39.61 -> 34.43 kWh, and
the worst quarter-hour average OFFTAKE 3739 -> 3935 W with the mean quarter
+2.73 W, in five of six plant and tuning variants. A frozen integrator stops at
`prev + gain*error`, which undershoots by (1 - gain); for an export that is
free and for an import it is offtake, for as long as the ramp lasts. The card
said "do not invent a second rule"; the measurement says to, and both sentences
are recorded.

WHAT SHIPS BOUNDS THE LEAD AT ONE SLEW STEP, inside the branch where the slew
actually bound. Same 16 days, same ticks, same disturbance, same plant, same
seed: export 39.61 -> 34.07 kWh, wasted throughput 4.67 -> 3.19 kWh, battery
sign reversals 2992 -> 2770, median recovery 232 -> 199 s, p99 849 -> 850 s,
max 901 -> 898 s, unrecovered 53 -> 31, worst |i_w - prev_w| 9200 -> 800 W -
and the worst 15-minute average offtake 3739 -> 3434 W, i.e. the billed
quantity IMPROVES. `i_w = slewed` (a cap of zero) is better again at 32.02 kWh
and is refused: it is the velocity form this module's docstring says `i_w=None`
collapses to.

TWO COMMITTED NUMBERS MOVED, DELIBERATELY, WITH THE REASON BESIDE THEM.
SAFETY-13's released command settles at -800 W and -1200 W where release/1.0
settled at -1190 W and -2390 W, because there is less wound integrator to
settle onto; AC 4's property - it stops at the frozen integrator, not the rail
- is what is asserted and the second is now graded against `i_w` rather than a
literal. And SAFETY-39's "the slew does not own the over-absorption" is now
FALSE - INVERTED, on the independent first-order plant test_control.py writes
itself: 1005/1109/1285/1330 W rising with a slower slew becomes 729/550/424/326
falling. Two plant models that share nothing agree on the sign.

Evidence: `tools/replay_recorded_loop.py` plus the read-only capture it made
(scenarios/loop-2026-09-02_2026-09-17). The "before" law is the shipped file
with the block removed by a named substitution - never a transcription - and a
missing anchor is a REFUSAL carrying "NOTHING HAS BEEN MEASURED". The
instrument prints its own fidelity first: it reproduces 39.6 kWh of export
where the install exported 29.4, i.e. it is ~35 % pessimistic about the loop's
tracking, so only the delta is claimed.

30/30 suites green, including test_control.py's exhaustive i_w=None
equivalence sweep against the transcribed release/1.0 law, untouched: the cap
moves `i_w` and not `target`, and that sweep compares (target_w, sat_count,
frozen, reason).

Six law mutations, one instrument battery. L4 - the cap applied
unconditionally, -92 B - was a SURVIVOR of all thirty files: it is
bit-identical on the shipped configuration (0 of 256 246 ticks) and separable
on 2050 of 257 400 swept states, all at `integrator_max_w` above `max_w`, which
part 4 now drives. L5 and L6 are ZERO BYTES.

AND TWO COMMENTS IN THIS CARD WERE INVENTED AND ARE CORRECTED IN PLACE. The
one-sided spelling was justified by a two-sided form that would "drag a
trailing integrator" - it does not, and the two agree on 205 920 of 205 920
swept states; and a "118 of 256 252 ticks" figure had been measured against a
different pair. MUTATION.md gains habits 21 and 22 for both shapes.

NOT DEPLOYED, NOT VERSIONED. The live install still runs release/1.0's law.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
This commit is contained in:
glenn schrooyen
2026-09-19 02:36:28 +02:00
co-authored by Claude Opus 5
parent b6c6da31d8
commit 03ef61fa3b
72 changed files with 2297 additions and 49 deletions
+41
View File
@@ -811,6 +811,47 @@ Cheap habits fall out of it, and all of them are now used in this repository:
retrofitted: guarding another card's section is a change to what its
checks report, and it belongs to whoever next touches it.
21. ⚠️ **A CHECK CAN BE GREEN UNDER ITS OWN CARD'S NAMED MUTATION, AND TWICE
IN ONE FILE THE REASON WAS THAT THE WRONG QUANTITY EVENTUALLY REACHES THE
RIGHT VALUE.** TEL-10's acceptance was *"a run that winds the integrator
into the bound must show the published number reaching the bound"*, and its
named mutation was *"publish `prev_w` instead of `i_w`"*. The check was
**GREEN** on the mutant: the command reaches the same bound too, twelve
cycles later, and a check that only reads the VALUE cannot tell the two
apart. The same file's *"a stopped controller publishes `not-running`"* was
green under deleting that branch's assignments outright (−45 B and −67 B),
because the fixture STARTED stopped and `__init__` writes the same values.
Both are habit 4 - the data could not reach the failure - and both were
found by the card's own battery. The fixes are the shape to copy:
* where two quantities CONVERGE, grade the **order or the interval**, not
the value: "the integrator reaches the bound BEFORE the command does",
and a PLATEAU (the lead sits at exactly −800 W for eight consecutive
cycles) rather than a maximum, because a maximum is one tick and a
plateau is the shape;
* where a branch WRITES a value the constructor also writes, the fixture
has to pass THROUGH the other state first. Stop the controller part-way
through a run that has already wound the integrator to −5000 W, so a row
left standing is a WRONG row and not merely an unset one.
22. ⚠️ **AN EXPLANATION IN A COMMENT IS A CLAIM, AND SAFETY-48 SHIPPED TWO THAT
WERE INVENTED.** A gate was written one-sided (`if target > slewed: min(...)
elif target < slewed: max(...)`) under a comment saying the two-sided band
`max(lo, min(hi, i_w))` was a BUG that would drag a trailing integrator
toward the command, with a worked example. It is not a bug and the example
was wrong: `target` is monotone in `i_w`, so the other clamp cannot reach,
and the two spellings agree on **205 920 of 205 920** swept states. A second
bullet said two placements of the same cap *"differ on 118 of 256 252
ticks"*; that 118 had been measured against a **different pair** and the
placement actually being compared is bit-identical on the shipped
configuration - 0 of 256 246 ticks. Both sentences were plausible, both were
load-bearing for a design choice, and neither had been run.
**The rule: a comment that says "X would be wrong" is subject to the same
battery as a check - BUILD X AND MEASURE IT.** Where the answer is
"equivalent", say so with the sweep size and keep the spelling for what it
NAMES; where the answer is a number, quote the run it came from. An
invented justification for a correct decision is still a defect, and it is
the kind a reviewer cannot see because the code is right.
And the mutation-table consequence: **a variant is not covered because a
near-miss of it is.** DEV-02's table listed the *actuator* variant of the
per-unit claim defect (`device`/`supervised` filed without `inv`), which the