SAFETY-119 round 3c: the hidden-bound budget follows the cycle length
No single rolling budget met both cases in the sweep (8 false-alarmed on 2 s seed 25 and warned in 1 to 3 of 7 quarters at 15 s). The budget is now 10 cycles up to a 3.5 s cycle, 8 up to 11 s, 6 up to 16 s, 4 beyond, per rolling 15 minutes; 8 while the cycle length is unknown. A stop or a gap over two minutes is not a cycle length. The unsourced "owner accepted N=8" paragraph is removed from DECISIONS. test_safety119 part 4 now runs 2 s seed 25 and shows a fixed budget of 8 warns there; the never case runs at 2 s and checks every other quarter at 15 s. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
e27e62ff72
commit
6fd0fa05f1
@@ -300,10 +300,13 @@ REFUSED_PROGRESS_W = _ctl.PROBE_ANSWER_W / 2
|
||||
# a healthy battery still settling on a new command is not short.
|
||||
SHORT_CYCLES, SHORT_SPAN_S = _ctl.SETTLE_CYCLES, REFUSED_SPAN_S
|
||||
# SAFETY-119: across all hand-backs, the loop's bound is hidden on at most
|
||||
# this many cycles in any ROLLING_S seconds (a budget measured in
|
||||
# DECISIONS/SAFETY-119-bound-after-hand-back.md). Without a monotonic clock
|
||||
# ROLLING_BUDGET cycles in any ROLLING_S seconds, fewer on a slower cycle:
|
||||
# (cycle seconds up to, cycles), measured in
|
||||
# DECISIONS/SAFETY-119-bound-after-hand-back.md. Without a monotonic clock
|
||||
# the budget never refills.
|
||||
ROLLING_BOUND_CYCLES, ROLLING_S = 8, 900.0
|
||||
ROLLING_S = 900.0
|
||||
ROLLING_BUDGET = ((3.5, 10), (11.0, 8), (16.0, 6), (float("inf"), 4))
|
||||
ROLLING_BOUND_CYCLES = 8 # the budget while the cycle length is unknown
|
||||
|
||||
|
||||
def _refused_interval(sign: int) -> tuple:
|
||||
@@ -1279,10 +1282,12 @@ class Controller:
|
||||
self._short_run = 0
|
||||
# SAFETY-119: did another owner set the wire last cycle; the window
|
||||
# after a hand-back (monotonic s, the loop's cycles in a row); the
|
||||
# monotonic s of the bound cycles hidden in the last ROLLING_S.
|
||||
# monotonic s of the bound cycles hidden in the last ROLLING_S; the
|
||||
# last cycle's monotonic s and the cycle length.
|
||||
self._wire_lost = False
|
||||
self._handback = None
|
||||
self._hidden = ()
|
||||
self._settle_t, self._settle_dt = None, None
|
||||
self.stopping = False
|
||||
# SAFETY-61. time.monotonic() at the end of the last run_control() pass.
|
||||
self.loop_pass_mono = None
|
||||
@@ -5825,6 +5830,7 @@ class Controller:
|
||||
self._short_run = 0
|
||||
self._asked_hist = {}
|
||||
self._wire_lost, self._handback = False, None
|
||||
self._settle_t = None # a stop is not a cycle length
|
||||
return
|
||||
unmet = self.allocation.unmet_w if self.allocation is not None else 0
|
||||
cut = (resolution.bound_by or "").split("(")[0]
|
||||
@@ -5867,12 +5873,18 @@ class Controller:
|
||||
re-seeded from that owner's command and kicked by a meter that does
|
||||
not show it yet. The settle is SHORT_CYCLES cycles and SHORT_SPAN_S
|
||||
after the hand-back; losing the wire restarts it. Across all
|
||||
hand-backs the bound is hidden on at most ROLLING_BOUND_CYCLES cycles
|
||||
in any ROLLING_S, so a bound that stays is counted however often the
|
||||
wire changes hands. DECISIONS/SAFETY-119-bound-after-hand-back.md."""
|
||||
hand-backs the bound is hidden on at most ROLLING_BUDGET[cycle
|
||||
length] cycles in any ROLLING_S, so a bound that stays is counted
|
||||
however often the wire changes hands.
|
||||
DECISIONS/SAFETY-119-bound-after-hand-back.md."""
|
||||
def aged(t0, span):
|
||||
return now is None or t0 is None or now - t0 >= span
|
||||
|
||||
# The cycle length (a gap over two minutes is not one).
|
||||
if now is not None and self._settle_t is not None \
|
||||
and 0.0 < now - self._settle_t <= 120.0:
|
||||
self._settle_dt = now - self._settle_t
|
||||
self._settle_t = now
|
||||
if not owns:
|
||||
self._wire_lost, self._handback = True, None
|
||||
return False
|
||||
@@ -5889,7 +5901,10 @@ class Controller:
|
||||
if self.loop_clamped[0] and not self.loop_clamped[2]:
|
||||
kept = tuple(t for t in self._hidden if now is None or (
|
||||
t is not None and now - t < ROLLING_S))
|
||||
if len(kept) >= ROLLING_BOUND_CYCLES:
|
||||
dt = self._settle_dt
|
||||
budget = ROLLING_BOUND_CYCLES if dt is None else next(
|
||||
m for up, m in ROLLING_BUDGET if dt <= up)
|
||||
if len(kept) >= budget:
|
||||
self._hidden = kept
|
||||
return False
|
||||
self._hidden = kept + (now,)
|
||||
|
||||
Reference in New Issue
Block a user