TEST-26: a missing value in a check is a named FAIL, not a traceback
checks / unit (pull_request) Successful in 8m44s
checks / unit (pull_request) Successful in 8m44s
Checks and prints that indexed an empty list, exhausted next(), or formatted None killed the rest of their file (FCST-06). Read them through the new named_absence.py (nth/first/field/given/present) and conjoin a presence term. - every site in the brief, plus the family the new scan and a sweep found - test_named_absence.py: scans every test_*.py for unguarded filtered-list indexing, next() without a default and numeric formats on maybe-None names; proven to bite; prints what it cannot see, counted - test_price.py 16a: the `_T17_CAPS is _T17_CAPS` tautology now grades the two assemble() calls' arguments - test_control.py: coverage table re-measured on runs graded to the end Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a45ed06c05
commit
770988c902
@@ -17,6 +17,7 @@ Read MUTATION.md before you report a survivor.
|
||||
|
||||
import sys
|
||||
|
||||
from named_absence import nth
|
||||
from app.control import (LOOP_TICK_S, PLANT_SETTLE_DOWN_S, PLANT_SETTLE_S,
|
||||
SETTLE_CYCLES, SLEW_RAIL_FRAC, Tuning, compute,
|
||||
slew_limit_w, unasked_power,
|
||||
@@ -59,68 +60,34 @@ def check(name, cond):
|
||||
# stopped testing anything is precisely the failure this ticket exists to fix.
|
||||
# A comment cannot go stale-green, because it never claims to be running.
|
||||
#
|
||||
# Measured at 389d9ec. Numbers are the lead's independent reproduction.
|
||||
# ⚠️ THE SAFETY-13 ROWS WERE RE-MEASURED IN ROUND 2 AND THREE OF THEM WERE
|
||||
# WRONG AS FIRST WRITTEN. Every figure below marked (S13) was taken by deleting
|
||||
# the mechanism, purging __pycache__, running this file in the CI image and
|
||||
# counting `FAIL` lines, on THIS tree; the release/1.0 comparison figures were
|
||||
# taken the same way on a pristine c8dcb38 worktree.
|
||||
# Measured at TEST-26 on a purged tree in the CI image, each run graded to the
|
||||
# end of the file (98/99 where the `if _bad:` check is skipped). Before TEST-26
|
||||
# the rows marked * killed the file with an IndexError or ZeroDivisionError in
|
||||
# a check, so their earlier figures were short; those checks now fail by name.
|
||||
#
|
||||
# - `output freeze` was written as 11. The mutation form its own note
|
||||
# describes - the whole `target = min(...)/max(...)` line removed, `reason`
|
||||
# left alone - gives 6 on this tree AND 6 on the first SAFETY-13 commit,
|
||||
# against 2 on release/1.0. 11 is not reproducible by that form, or by
|
||||
# removing the line and its `reason` (4), or by swapping min/max (12). The
|
||||
# row is 6.
|
||||
# - `saturation detector, saturated_now = False` was left at 11 while the
|
||||
# SAFETY-13 section added checks that grade it. It is 15.
|
||||
# - the footnote's `frozen = False` figure was left at 10 for the same
|
||||
# reason. It is 13.
|
||||
#
|
||||
# The rows below `output freeze` are this ticket's own mechanisms: removing the
|
||||
# EXIT restores release/1.0's unbounded freeze; making `unasked_power()` return
|
||||
# True gives an exit to the limit case as well, which is the half of the
|
||||
# decision that has to stay unbounded; deriving SETTLE_CYCLES from
|
||||
# PLANT_SETTLE_S (18 s, the UP ramp) instead of PLANT_SETTLE_DOWN_S (23 s) is
|
||||
# the round-1 defect itself; and pinning `_SAT_COUNT_CAP` back at release/1.0's
|
||||
# literal 10 caps the counter below the bound and deletes the exit silently.
|
||||
#
|
||||
# ⚠️ ONLY THE ROWS THIS BRANCH MOVES WERE RE-MEASURED. Everything not marked
|
||||
# (S13) still carries 389d9ec's figures and was not re-run here.
|
||||
#
|
||||
# ⚠️ THE SLEW ROWS WERE RE-MEASURED AT SAFETY-39 AND ONE OF THEM MOVED: the
|
||||
# slew limit was 4 and is now 5, because the SAFETY-39 section grades it too.
|
||||
# The new row is the RAIL DEFAULT specifically - `slew_limit_w()` reduced to
|
||||
# `return abs(float(tuning.slew_w))`, which leaves the limit intact and only
|
||||
# removes the 0-means-the-rail resolution. Three checks notice, which is over
|
||||
# the invariant's floor of two. Both figures were reproduced by deleting the
|
||||
# mechanism, running this file and counting, on a tree with __pycache__ purged.
|
||||
#
|
||||
# mechanism in compute() checks that fail when deleted
|
||||
# ------------------------------------------ -----------------------------
|
||||
# integrator freeze (AC 3) 2
|
||||
# integrator clamp (AC 1) 6
|
||||
# integrator bound follows max_w 4
|
||||
# output clamp 3
|
||||
# slew limit 5
|
||||
# slew follows the rail (SAFETY-39), `slew_w` read raw 3
|
||||
# output freeze (S13) 6
|
||||
# the output freeze's EXIT (S13), freeze made unconditional again 4
|
||||
# `unasked_power()` discriminates, replaced by `return True` (S13) 6
|
||||
# SETTLE_CYCLES from PLANT_SETTLE_S, not _DOWN_S (S13) 9
|
||||
# `_SAT_COUNT_CAP` pinned back at release/1.0's 10 (S13) 6
|
||||
# deadband 5
|
||||
# quantisation 2
|
||||
# saturation detector, `saturated_now = False` (S13) 15
|
||||
# saturation duration (AC 2), fires instantly 2
|
||||
# sat counter reset on a good cycle 6
|
||||
# target_grid_w bias 3
|
||||
# i_w=None seeding from prev_w 6
|
||||
#
|
||||
# The detector figure is for the `saturated_now = False` form specifically;
|
||||
# disabling it further down as `frozen = False` is a weaker mutation and gives
|
||||
# 13 on this tree (10 on release/1.0). Reproduce the same form or the number
|
||||
# will not match.
|
||||
# mechanism in compute(), and the exact form deleted checks that fail
|
||||
# --------------------------------------------------------- ----------------
|
||||
# integrator freeze: `if not frozen or i_w == 0.0` -> `if True` 6
|
||||
# integrator clamp: `bounded = i_w` 6
|
||||
# integrator bound follows max_w: default `limit = 5000.0` 3
|
||||
# output clamp: `target = want` 3
|
||||
# slew limit: `slewed = target` 17
|
||||
# slew follows the rail (SAFETY-39): `slew_limit_w()` returns
|
||||
# `abs(float(tuning.slew_w))` * 9
|
||||
# output freeze: the `target = min(...)/max(...)` line removed 7
|
||||
# output freeze: `if frozen:` -> `if False:` * 14
|
||||
# the output freeze's EXIT (S13): its `if` -> `if False` * 11
|
||||
# `unasked_power()` returns True (S13) 6
|
||||
# SETTLE_CYCLES from PLANT_SETTLE_S, not _DOWN_S (S13) 9
|
||||
# `_SAT_COUNT_CAP = 10`, release/1.0's literal (S13) * 11
|
||||
# deadband: its `if` -> `if False` 7
|
||||
# quantisation: `target = target` 4
|
||||
# saturation detector: `saturated_now = False` * 27
|
||||
# saturation detector: `frozen = False` * 25
|
||||
# saturation duration fires instantly: `sat_count >= 1` 5
|
||||
# sat counter not reset on a good cycle: `else sat_count` 5
|
||||
# target_grid_w bias: `error = grid_w` 5
|
||||
# i_w=None seeding from prev_w: `i_w = 0.0` 11
|
||||
#
|
||||
# ⚠️ IT HAS FOUND A DEAD MECHANISM TWICE, BOTH THE SAME WAY: a clamp standing in
|
||||
# for the mechanism under test. Deleting the integrator freeze once failed
|
||||
@@ -142,10 +109,9 @@ def check(name, cond):
|
||||
# mutation run always has one, because the previous run wrote it. -B is still
|
||||
# worth passing, for the NEXT edit rather than this one.
|
||||
#
|
||||
# The error is one-directional - stale bytecode can only under-report - so
|
||||
# every figure above is a lower bound at worst, and the two zeros ever recorded
|
||||
# were both confirmed by fixing them and watching the count rise, which a
|
||||
# caching artefact cannot do.
|
||||
# Two things under-report a figure here, both in the same direction: stale
|
||||
# bytecode, and a check that raises and stops the file before the rest are
|
||||
# graded (MUTATION.md, FCST-06). The second is what the * rows above had.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
print("control law")
|
||||
@@ -520,7 +486,7 @@ for _ in range(20):
|
||||
rows.append((prev, d.target_w, d.i_w, d.reason))
|
||||
prev, i_w, sat = d.target_w, d.i_w, d.sat_count
|
||||
pinned = [r for r in rows if r[3] == "saturated-freeze"]
|
||||
check(f"non-zero prev_w, another writer: pinned at {pinned[0][1]:.0f} W...",
|
||||
check(f"non-zero prev_w, another writer: pinned at {nth(pinned, 0)[1]:.0f} W...",
|
||||
pinned and all(r[1] == -800.0 for r in pinned))
|
||||
# ⚠️ SAFETY-48 MOVED THIS NUMBER FROM -2390 W TO -1200 W, DELIBERATELY, AND
|
||||
# THE PROPERTY IT IS HERE FOR IS UNCHANGED. The release lets the command walk
|
||||
@@ -550,9 +516,9 @@ for c in range(24):
|
||||
cmds.append(d.target_w)
|
||||
prev, i_w, sat = d.target_w, d.i_w, d.sat_count
|
||||
check("the card's case: the block does hold at first, at 0 W",
|
||||
cmds[6] == 0.0 and cmds[7] == 0.0)
|
||||
nth(cmds, 6) == 0.0 and nth(cmds, 7) == 0.0)
|
||||
started = [i for i, c in enumerate(cmds) if c != 0.0]
|
||||
check(f"the card's case: the charge starts at cycle {started[0]}"
|
||||
check(f"the card's case: the charge starts at cycle {nth(started, 0)}"
|
||||
f" instead of never", bool(started))
|
||||
# ⚠️ AND IT STOPS AT THE FROZEN INTEGRATOR, NOT AT THE RAIL. This is AC 4: the
|
||||
# integrator moved while the output was blocked, and the release must not turn
|
||||
@@ -991,7 +957,8 @@ check("the shipped Tuning default is 0, i.e. the rail, so the law carries no "
|
||||
# serial, per goodwe/NOTES.md §1.1b. It is here because the ARITHMETIC is what
|
||||
# is being graded, and the arithmetic does not care.
|
||||
_rails = [100.0, 500.0, 1500.0, 2000.0, 5000.0, 9600.0, 10000.0]
|
||||
_ticks = {r: r / slew_limit_w(Tuning(max_w=r)) for r in _rails}
|
||||
# A zero limit grades as nan ticks (a named FAIL), not a ZeroDivisionError.
|
||||
_ticks = {r: r / (slew_limit_w(Tuning(max_w=r)) or float("nan")) for r in _rails}
|
||||
print(" ticks to cross the rail at the default, by rail: "
|
||||
+ ", ".join(f"{r:.0f}W={t:.1f}" for r, t in _ticks.items()))
|
||||
check("⭐ AT EVERY RAIL THE DEFAULT TAKES THE SAME NUMBER OF TICKS TO CROSS IT - "
|
||||
@@ -1010,7 +977,7 @@ check("...and that is the same as saying the crossing takes the plant's own "
|
||||
# refuses on, and it is asserted HERE too so that the law and the gate cannot
|
||||
# drift apart - the rule can only ever refuse what this ratio says is too fast.
|
||||
_broken = Tuning(max_w=5000.0, slew_w=1000.0)
|
||||
_broken_s = 5000.0 / slew_limit_w(_broken) * LOOP_TICK_S
|
||||
_broken_s = 5000.0 / (slew_limit_w(_broken) or float("nan")) * LOOP_TICK_S
|
||||
print(f" the 2026-09-05 configuration (max_w 5000, slew_w 1000) crosses its "
|
||||
f"rail in {_broken_s:.0f} s against a plant measured at {PLANT_SETTLE_S:.0f} s")
|
||||
check("⭐ RESTORING slew_w 1000 AT max_w 5000 IS FASTER THAN THE PLANT, and by "
|
||||
|
||||
Reference in New Issue
Block a user