SAFETY-48: what the lead cap actually does to a frozen integrator, and what the peak figure depends on
checks / unit (pull_request) Successful in 7m55s
checks / unit (pull_request) Successful in 7m55s
Four review findings, none of them in executable code. The control law, the tests and the instruments' arithmetic are untouched; every number below was re-measured against the committed 16-day capture before it was written down. R1 - app/control.py carried a justification the decision record and MUTATION.md habit 22 had already retracted, and it was false about the code it sits in. It said an unconditional placement "would also pull the integrator toward a command the SATURATION freeze is pinning", priced at 118 of 256 250 ticks. The 118 was measured against a different pair; on the pair the sentence names the two forms are bit-identical - 0 of 256 246 ticks, re-measured. And the narrow form that shipped DOES move a saturation-frozen integrator: it runs before the freeze block and is not gated on `frozen`. Of 79 160 frozen ticks the cap changes `i_w` on 1095, and on 679 of those it moves it further out on the side it was already on - putting back magnitude the freeze had just let fall, which the freeze's own rule forbids. Worst case 2424 W, at prev_w -3400 W, grid +4697 W, actual -4144 W, sat_count 2 -> 3: the freeze leaves the integrator at -176 W and the cap drags it to -2600 W. It never overrides a same-cycle refusal (the freeze clipped on 75 512 ticks, the slew bound on none of them), and that is stated too. It is also where SAFETY-13's settle values went: gating the cap on `not frozen` puts test_control.py part 5 back at -1190 W exactly, while part 4(b) does not come back - that one moved for the winding reason. R3 - the record read its own sensitivity table backwards. `fit_plant()` picks lag 7.5 s on battery-power RMS, which separates it from 2.5 s by 0.3 %, while the tool's own printed fidelity measure (export against the recorded 29.43 kWh) prefers 2.5 s by the whole 35 % gap. Swept properly: at every lag <= 5.0 s release/1.0's worst quarter is ALREADY 3434 W and this card changes it by exactly zero. The 3739 -> 3434 W headline exists at one plant. New section 3a carries the table; the export reduction now leads every summary and the peak is presented as lag-dependent. The form-A rejection is strengthened rather than weakened: form A is worse on the billed quarter at every lag where release/1.0 produces a peak at all, and at every top-N cut of the quarters. R2 - DOCS.md stated modelled watts to the owner as measurement. It now leads with the export reduction, says the figures are simulated, and says plainly that no capacity-tariff improvement is promised. R4 - tools/slew_sim.py --slew narrated "the OVER-ABSORPTION does not move, and at the slowest slews it is slightly WORSE" while printing a monotonically falling column. That sentence is TRUE on release/1.0 (reproduced: 958/1107/1133/1058/987/1029/1150/1143/1081) and false under this branch's law (777/734/663/563/553/507/435/358/321), so SAFETY-39 is not retracted: its record gets a forward reference, and the script now reads SLEW_LEAD_STEPS out of the law it imported and narrates from the column it just printed. Both branches of that narration were driven. R5 - three counts in the L table were decoration and are re-driven in the CI image on a `cp -a`, purged, `:ro`, one file at a time: L5 is 5+5 with the function names exchanged and 5+4 with the branch bodies exchanged (two mutations wearing one name, now listed separately), L6 is 6+3. The separable- state count is grid-dependent and three sweeps disagree, so all three are quoted with their grids and the load-bearing claim is WHERE they separate. R7 - "a large import answered too weakly" is not what the aggregate shows. Form A cuts import by 5.45 kWh and export by 5.18 kWh, and paired per tick delivers 8.56 kWh less offtake energy on the ticks release/1.0 was importing. The harm is a tail redistribution inside quarters that already net to offtake. The conclusion stands; the sentence is narrowed to it. Verified: the full suite in the CI image, purged tree, `:ro` mount, one file at a time, exactly the command in .gitea/workflows/checks.yml - 30/30, exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
This commit is contained in:
co-authored by
Claude Opus 5
parent
03ef61fa3b
commit
a6af332048
@@ -220,6 +220,7 @@ def slew_table(ps, ct, tick_s, rail):
|
||||
f"faster than the")
|
||||
print(f" plant settles. {rail:.0f} W / ({ct.PLANT_SETTLE_S:.0f} s / "
|
||||
f"{tick_s:.0f} s per tick) = {frac * rail:.0f} W per tick.\n")
|
||||
overs = []
|
||||
for slew in (1000, 800, 700, 600, int(frac * rail), 500, 400, 300, 250):
|
||||
w = family(ps, ct, gain=0.6, slew_w=float(slew), rail_w=rail,
|
||||
tick_s=tick_s)
|
||||
@@ -227,13 +228,52 @@ def slew_table(ps, ct, tick_s, rail):
|
||||
" <- the 2026-09-05 live pair" if slew == 1000 else (
|
||||
" <- the live interim" if slew == 400 else ""))
|
||||
row(f"slew_w {slew}{tag}", w)
|
||||
overs.append(w["over"])
|
||||
print("\n READ IT THIS WAY. The >= 900 W step - the live symptom, which")
|
||||
print(" escalated 2 -> 1 -> 13 -> 43 per 30 min that morning - is gone from")
|
||||
print(" every run below 900 W of slew, and that is what the slew owns.")
|
||||
print(" The OVER-ABSORPTION does not move, and at the slowest slews it is")
|
||||
print(" slightly WORSE. The rig cannot pick the derived value out of that")
|
||||
print(" column, and it is not asked to: the CONSTRAINT picks it, and this")
|
||||
print(" table is what says what the constraint does and does not buy.")
|
||||
|
||||
# ⚠️ THE NARRATION BELOW IS DERIVED FROM THE COLUMN JUST PRINTED, NOT
|
||||
# WRITTEN ABOUT IT. SAFETY-39 wrote "the over-absorption does not move, and
|
||||
# at the slowest slews it is slightly WORSE" - true of release/1.0's law,
|
||||
# which is what it was measured against, and FALSE under SAFETY-48's lead
|
||||
# cap, where the same script on the same plant prints a monotonically
|
||||
# FALLING column. A transcript whose prose contradicts its own table is a
|
||||
# failing check (MUTATION.md habit 8), and a sentence that is right under
|
||||
# one law and wrong under another has to be computed rather than typed. So:
|
||||
# which law is imported is read off `control.py` itself, and whether the
|
||||
# column falls is read off the column.
|
||||
cap = getattr(ct, "SLEW_LEAD_STEPS", None)
|
||||
falling = all(b < a for a, b in zip(overs, overs[1:]))
|
||||
law = ("release/1.0's law - the integrator's lead over the command is "
|
||||
"UNBOUNDED" if cap is None else
|
||||
f"SAFETY-48's law - the integrator may lead the command by "
|
||||
f"{cap} slew step(s)")
|
||||
print(f"\n THE LAW THIS RAN AGAINST: {law}.")
|
||||
if cap is None and not falling:
|
||||
print(" The OVER-ABSORPTION does not move with the slew, and at the")
|
||||
print(" slowest slews it is slightly WORSE - `slew_w` bounds the")
|
||||
print(" OUTPUT while the integrator goes on winding, so a slower slew")
|
||||
print(" leaves it winding for longer. SAFETY-48 bounds that lead and")
|
||||
print(" INVERTS this column; see DECISIONS/SAFETY-48 §6.")
|
||||
elif cap is not None and falling:
|
||||
print(" The OVER-ABSORPTION FALLS MONOTONICALLY with the slew, which")
|
||||
print(" is the OPPOSITE of what SAFETY-39 measured on release/1.0")
|
||||
print(" (958/1107/1133/1058/987/1029/1150/1143/1081 W, flat and")
|
||||
print(" non-monotone). Bounding the integrator's lead is what changed")
|
||||
print(" it: the slew now owns a share of the over-absorption it did")
|
||||
print(" not own before. DECISIONS/SAFETY-48 §6 has both tables and an")
|
||||
print(" independent confirmation on test_control.py's own plant.")
|
||||
else:
|
||||
print(" ⚠️ NEITHER NARRATION FITS. The law above and the shape of the")
|
||||
print(f" column ({'falling' if falling else 'not falling'}) are the")
|
||||
print(" combination this script has no sentence for - which means the")
|
||||
print(" measurement has moved and DECISIONS/SAFETY-39 §3 and")
|
||||
print(" DECISIONS/SAFETY-48 §6 both need re-reading before this table")
|
||||
print(" is quoted anywhere.")
|
||||
print("\n EITHER WAY THE RIG DOES NOT PICK THE NUMBER, and it is not asked")
|
||||
print(" to: the CONSTRAINT picks it, and this table is what says what the")
|
||||
print(" constraint does and does not buy.")
|
||||
|
||||
|
||||
def gain_table(ps, ct, tick_s, rail):
|
||||
|
||||
Reference in New Issue
Block a user