forgetest: every run starts from, and leaves, the fresh-boot idle state

A baseline pass brackets every test and bench tool: before the run the
machine is verified against the fresh-boot idle state and anything off it
is restored; after the run - pass, fail, or abort - it is restored again.
Fixed items are the resting values the boot establishes (module defaults,
forgectrl's start-up writes, the GRBL controller's init writes) and
forgectrl's idle picture (controller running with motion verified, no
diagnostic, camera and cooling engines idle); preserved items (lid lamp
level, position counters, settings map, controller mode) are captured
before and handed back after. Deviations are leftovers: in the run pane,
in the result's evidence, and on the page - attributed to the previous run
when found before, to the run itself when found after.

forgetest takes a fresh-boot reference once per boot (within ten minutes
of boot, after the supervisor settles) as the session's resting lid-lamp
level and the check on the fixed values; the values were confirmed
against a fresh boot of the dev image on the bench (step_freq rests at
28160, the controller's default tick, not the probe's 10000).

Takeover runs capture the controller-owned kernel attributes on entry and
write them back before forgectrl restarts: the bench found the kernel
tests leaving motor_lock=15 behind, which masked the supervisor's
liveness probe - no motion by construction, a false driver-wedge verdict,
the rail-off ladder, and finally motion-fault. The takeover wrapper also
waits for the supervisor to settle on both sides (moved into baseline).

Catalog consequence: none beyond the runner; the tests' own drills are
unchanged.
This commit is contained in:
ScottW514
2026-08-16 13:35:19 -04:00
parent 799e0e829c
commit 4aaedc8080
5 changed files with 770 additions and 45 deletions
+33
View File
@@ -102,6 +102,38 @@ forces a full campaign; nothing before it can be inherited.
The raw log (`/data/forgetest/results.jsonl`, `Raw log` in the footer) is
the bench's own record; the artifact is the release's.
### Every run starts from, and leaves, the fresh-boot idle state
The runner brackets every test and bench tool with a **baseline** pass
(`baseline.py`): before the run it verifies the machine against the
fresh-boot idle state and restores anything off it; after the run - on
every exit path, pass, fail, or abort - it restores again. Two kinds of
items: **fixed** resting values the boot establishes (the kernel module
defaults, forgectrl's start-up writes, the GRBL controller's init writes:
`motor_lock=8`, `x/y_mode=8`, `x/y_decay=1`, `step_freq=28160`,
`ramp_rate=125000`, `streaming=0`, `state=idle`, latch locked, hold
currents, camera lamps and button LEDs off, heater and TEC off; forgectrl:
the controller running with motion verified, no diagnostic, the camera
engine and cooling engine idle), and **preserved** state with no resting
policy that a run must hand back as it found it (the lid lamp level, the
position counters, the settings map, the controller mode). Deviations are
**leftovers**: logged in the run pane, kept in the result's `evidence`
(`baseline.pre` / `baseline.post`), and surfaced in the page's message
line - a leftover found before a run is attributed to the previous run; one
found after is the run's own defect. Takeover runs additionally capture
the controller-owned kernel attributes on entry and write them back before
forgectrl restarts, so the supervisor's liveness probe runs on the machine
it expects. The runner waits for forgectrl's supervisor to settle (motion
verified, or the ladder's verdict) before and after every takeover.
**Reboot before a campaign.** forgetest takes a **fresh-boot reference**
once per boot (`/data/forgetest/boot-<boot_id>.json`, taken only within
the first ten minutes after boot, after the supervisor settles): the whole
idle picture of this machine as the image boots it. It is the session's
resting lid-lamp level and the check on the fixed values; without one the
lamp level is unknown and the page says so. Position counters cannot be
written back - a run that shifts them is reported and must be fixed.
## The gate
`scripts/release.sh <version>` builds the release image, reads
@@ -168,6 +200,7 @@ unported tools are listed with Start disabled. Bench runs are recorded in
campaign.py the rules (pure functions)
artifact.py export + gate verification
runner.py one run at a time, prompts, abort, takeover
baseline.py the fresh-boot idle state around every run
server.py / page.py HTTP API + the page (forgectrl's access rules)
bench.py / coverage.py bench registry + subprocess runner; the lint
suite/ the catalog, one module per subsystem