Repository navigation
Description
Follow-ups from the final review of #1920 (head 652df2c) on 28 Oct 2026. None of them makes the PR worse than master or breaks the owner's fuse rule, so they wait until after stable.
- Random judge: a missing battery order at the start of the scan reads as 0 W
- Random judge: a battery raise in steps under 345 W is not counted
- Random judge: mutation survivors around batMovedIn
- Random judge: relief withdrawn while over the fuse counts as FTW's own
Random judge: a missing battery order at the start of the scan reads as 0 W
652df2c keeps the last order while status.dispatch is missing, but only once batMovedIn has seen an order. The scan starts at a-5. If that sample already has no dispatch, prev becomes 0, and Core's unchanged order on its return counts as a raise.
Evidence: in seed 207539 the dispatch is missing from 113.7 s, which is 7 s into the inverter outage (106.7 s) and 6 s before ftw:restart (119.7 s). The restart window's scan starts at 116.7 s, inside that gap. 207539 discharged, so nothing flipped. A synthetic run in the same shape with a charging battery fails on head as FTW's own:
- 3 kW order, inverter offline 40-70 s, restart 50 s, up 58 s, the same 3 kW back at 72 s, L1 21 A on 16 A from 65 or 75 s. Judged
[75 100 75 78 own]and[65 100 65 68 own]. - The base judge (test(site): the rig expects the room the fuse rating gives #1908) passes this case, because the restart minute runs to 110 s.
- A 60 s
meter_latethat opens 4 s into Core's down time has the same flaw (judged[108 112 108 111 own]).
Fix: carry the last known order from before a-5, for example by dropping the if r.T < a-5 { continue } skip so the scan starts at the beginning of the run. With that change every TestInvariants*/TestJudge* test passes, and the 10 saved seeds of 83c2b24 judge exactly as before (same over_limit_judged).
Test idea: the 207539 shape above (charging battery, a restart inside an inverter outage, the same order restored) must pass. The mutations skip-all-missing and scan-from-start survive the current suite.
Random judge: a battery raise in steps under 345 W is not counted
batMovedIn compares each order with the one before it. A raise made of several steps, each under 0.5 A a phase, never counts.
Evidence: Core restarts at 50 s and ramps the charge from 0 to 4 kW in 300 W steps. L1 then sits at 1.31 x In (21 A on 16 A) from 70 to 105 s. Head judges this [70 105 70 110 step] and passes it under the restart's minute. With 400 W steps it fails as own ([70 105 70 73 own]). The previous head (4985523, 100 W threshold) caught the 300 W ramp; the base judge did not, so this is not worse than master.
The saved seeds show that Core does move in small steps. Scanning all 10 seeds finds same-direction runs of steps under 345 W that add up to 350-665 W within 2-10 s (for example 207534 +665 W from 259.7 s, 207538 -644 W from 562.7 s). A cumulative rule therefore needs a margin above that normal creep.
Test idea: the 300 W ramp after a restart must fail as own. A creep of +665 W in 2-10 s must not change a verdict.
Random judge: mutation survivors around batMovedIn
These mutations of go/test/site/random_test.go at 652df2c survive TestInvariants|TestJudge:
- a move threshold of 200 W or 300 W instead of 345 W. Only 158 W (passes) and 360 W (fails) are pinned;
- dropping
r.T > a, so moves before the window's meter delay count; - counting a battery move toward export (more discharge, the right answer) before an import stretch as FTW's own (
batMovedIn(a, s, false, 1) || batMovedIn(a, s, false, -1)).
These mutations are caught: missing order read as 0, a 500 W threshold, each export term, the export direction, the ungated in-stretch export term, and the car check before an import stretch.
Test ideas:
- a 330 W one-sample move passes and a 350 W move fails;
- a battery move in (a-5, a] does not count;
- after a load step, a battery that discharges 4 kW more before the import stretch keeps the step's time.
Random judge: relief withdrawn while over the fuse counts as FTW's own
The in-stretch term counts any battery move of 345 W or more toward import while the meter shows the fuse passed. That includes moves Core may have to make: the battery reaching its floor of max(5 %, soc_min), or a slew anchored on a lagging battery reading.
Evidence: seed 207537 at 32.6-37.6 s. A car starts on the charger's 11 040 W default, with L2 at 18.9 A on 16 A. Core orders -3 037 W, then -37 W at 35.6 s while L2 is still over the fuse. The heat stayed cool, so the judge did not put this on the clock. A synthetic run held over the fuse in that shape is judged [32 42 32 35 own]. Without the move, it would be a step with the charger's time.
This existed before 652df2c (with a 100 W threshold) and in the base judge's 'own' rule. The owner should decide whether withdrawing relief at the floor is a step or FTW's own.
Test idea: a battery at its floor that stops discharging during a car step. Pin whichever verdict the owner chooses.
🤖 Generated with Claude Code
Activity
frahlg commentedon Oct 28, 2026
One more item from 959cae3 (owner decisions of 28 Oct now in #1920): events can still chain a stretch over 1.2 × In until the 60 s heat passes In, about 50 s at 1.25 × In. The owner rule says over 1.2 × In is an instant cut, so the judge should give an outside step at most its lever's time above 1.2 × In, however many events follow. Test idea: 20 A on a 16 A fuse with a load event every 8 s; fail after the lever's time, not after the heat crosses In.
🤖 Generated with Claude Code