forgetest: cloud tests stay in cloud mode; the page can ignore prerequisites

The cloud job tests (lid-abort, lid-during-button-wait, hunt-lid-open,
pause-resume) run in cloud mode and leave the machine there: enter_cloud
reuses a live session (pid-scoped from the client's own websocket state
lines) and switches once from GRBL mode, declaring the change to the
baseline; nothing switches back. Each test judges the log from its own
window, the print by its own "print [id]: finished" line, and waits the
service's follow-up moves out (wait_quiet) before it ends. hunt-lid-open
restarts the cloud client through the supervisor's stop/start lever for
a fresh connect. The former switch-back is what failed the last bench run
of hunt-lid-open (409 machine is not idle: the service was still
re-finding the head after the lid closed).

The baseline is mode-aware: in cloud mode the client owns the GRBL
controller's init values, the lid lamp, and the position counters; the
mode itself is preserved unless the run declared the change
(Context.mode_changed); controller_mode is never handed back as a bare
setting (a bare write left the persisted mode out of step with the live
one). The undeclared-change restore now uses the captured state, which
the post pass never saw before.

The acceptance page gets an "Ignore prerequisites" switch (remembered by
the browser): POST /start {ignore_requires} starts a test whose requires
are unmet, and the run records the unmet prerequisites in its evidence
and log; they stay required for the release. The cloud tests' requires
no longer chain through cloud.mode-switch.

Proof: tests/test_cloud_suite.py replays the four tests on the bench's
own gfcloud excerpts (fixtures/) and the run loop's emitted pause/resume
lines under the real runner Context against a fake forgectrl; baseline
mode tests and the server override test; the whole suite (98) and the
coverage lint pass. Catalog consequence: cloud.* fingerprints move with
the module; the catalog hash moves with the requires.
This commit is contained in:
ScottW514
2026-08-17 06:42:48 -04:00
parent e908db7f3a
commit 86ce0419e5
15 changed files with 1408 additions and 209 deletions
+26 -3
View File
@@ -30,7 +30,12 @@ Every test declares, in code (`forgetest/forgetest/suite/*.py`):
- **covers** - the source paths whose content the test stands for, as
`(component, glob)` pairs;
- **requires** - tests that must be satisfied first (the emission tests
require the motion and readback tests);
require the motion and readback tests). This orders the runs; it is not
a release condition of its own (the release needs every test satisfied
anyway). The page's **Ignore prerequisites** switch lets any test start
alone; a run started that way records the unmet prerequisites in its
`evidence.prerequisites` and its log, and the prerequisites stay
required;
- **always** - membership in the **always-required core**, which is run
in every campaign and is never inherited: image health, the kernel
latch/safety readbacks, and one live emission witness with the
@@ -103,7 +108,16 @@ forces a full campaign; nothing before it can be inherited.
do not.
3. Start the required tests. `operator` tests ask questions in the run
pane; `live` tests need the acknowledgment and the physical arm press;
`takeover` tests stop forgectrl for the duration.
`takeover` tests stop forgectrl for the duration. A test whose
prerequisites are not satisfied is locked until they are - or until
the **Ignore prerequisites** switch in the Campaign card is on, which
unlocks every Start (the switch is remembered by the browser; a run
started under it says so in its record).
The `cloud.*` job tests run **in cloud mode and stay there**: the first
one switches from GRBL mode (once, its connect-time hunt waited out)
and the following ones reuse the live session; nothing switches back -
switch on the control panel when done. `cloud.mode-switch` is the one
round trip and starts in GRBL mode.
4. When *Release authorized: YES*, **Export release artifact**, download
`acceptance.json` and `acceptance.md`, and commit them as
`releases/v<version>/acceptance.json` and `.md`.
@@ -126,7 +140,16 @@ at forgectrl's `lid_lamp_idle` setting; 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 position counters, the settings map, the
controller mode). Deviations are
controller mode). The mode in force decides what the baseline owns: in
cloud mode the cloud client's own configuration (the GRBL controller's
init values, which it rewrites from every pulse header; the lid lamp,
its lid-image level; the position counters, re-zeroed at every service
action) is left to it, and the safety readbacks, latch, ring, module
defaults, and forgectrl's engines are checked as always. The mode itself
is preserved unless the run declared the change (`ctx.mode_changed()`,
the cloud tests entering cloud mode); the persisted `controller_mode`
setting is never written back as a bare setting - only the switch keeps
it in step with the live 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
+25 -1
View File
@@ -3082,7 +3082,31 @@ dev image (the confirmation campaign's image).**
`cloud.lid-during-button-wait`, `cloud.hunt-lid-open`,
`cloud.pause-resume` (live). Items 4 and 12 above are superseded by
this policy (the mid-job Door hold is no longer the default path);
close them with these tests. Still to observe once on the bench: the
close them with these tests.
Bench 2026-08-17 (dev image 20260817014132): `cloud.lid-abort` and
`cloud.lid-during-button-wait` PASSED; `cloud.hunt-lid-open` reported
FAIL for a harness defect - the hunt had completed with the lid open,
but the test then insisted on switching back to GRBL while the
service was still re-finding the head after the lid closed (`409
machine is not idle`). Reworked: the cloud job tests now run **in
cloud mode and stay there** (`enter_cloud` reuses a live session,
pid-scoped from the client's own websocket lines; the switch is
made once from GRBL and declared to the baseline; `wait_quiet`
waits the service's follow-up moves out; the hunt test restarts the
cloud client through the supervisor's stop/start lever for a fresh
connect; every print is judged by its own `print [id]: finished`
line), the baseline is mode-aware (cloud mode owns its kernel
config, lamp, and counters; `controller_mode` is never restored as
a bare setting - that had desynced the persisted mode from the live
one), and the page has an **Ignore prerequisites** switch so any
test can be started alone. Proof: `tests/test_cloud_suite.py` (15
cases, the four tests replayed on the bench's own gfcloud excerpts
+ the run loop's pause/resume lines), baseline/server tests, and a
bench drill of `enter_cloud` (reuse) and of the fresh connect +
hunt detection + quiet wait against the live machine (hunt
`:completed`, 3 follow-up motions, quiet at 41 s). Left for the
operator: `cloud.hunt-lid-open` with the lid actually open,
`cloud.pause-resume` (live print + two presses). Still to observe once on the bench: the
~90 ms HV_ENABLE re-arm gap on a GRBL resume (whether a dark dwell
lead is wanted), the app's rendering of `print:paused`, and a lid open
during the return-to-start motion (should be ignored).