BRINGUP: the service protocol proven by the emulator; CAMPAIGN-LOG 2026-08-23

Dev image 20260823161333, campaign c-20260823161923-0dd7, 44 of 44,
release authorized. The cloud split of the acceptance plan is complete:
the protocol by the emulator with only the app to drive, the machine's
print behavior by the offline service, the two together by one real
print, and the service's hunt paid only where it is the subject.
This commit is contained in:
ScottW514
2026-08-23 12:38:41 -04:00
parent 8379aa5451
commit e5fa4445c0
2 changed files with 97 additions and 5 deletions
+9 -5
View File
@@ -1161,11 +1161,15 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
and bench-validated on dev image `20260822232347` (43 of 43, the four
offline tests in 5.5 minutes, nothing on the bed). The service-protocol
test on the emulator (`cloud.service-protocol`, `gfcloud --emulate`, the
`python3-gfutilities-emulator` fixtures on the dev image) is
code-complete with host replays and built into dev image
`20260823002125`; **that image carries a layer change, so its first
campaign is a full one, and it is owed** (flash, the 28 unattended, then
the 17 attended: the new test needs only a Print in the app). A bench
`python3-gfutilities-emulator` fixtures on the dev image; only a Print
in the app to drive) is done and bench-validated on dev image
`20260823161333` (44 of 44, CAMPAIGN-LOG 2026-08-23). The service's
connect-time hunt is paid only where it is the subject: every cloud
client the tool starts for anything else comes up under
`/run/gfcloud-nohunt` (`gfcloud --no-hunt`, the first settings report in
the reconnect form), while the two homing tests and the one real print
get theirs, the print by never reusing a session that has not hunted
the machine itself (the contract's cloud split in ACCEPTANCE.md). A bench
actuator for the lid, interlock and button is planned, not started. Catalog
gaps left from the tool's own plan: `cooling.confirm-escalate` and
`cooling.fire-gate-blocks-arm` are not ported (both need the pump switched
+88
View File
@@ -3542,6 +3542,94 @@ same as the lid's. Every print's `print:running`,
the socket. The real service was still proven on the same image by
`cloud.mode-switch` and the one real print, `cloud.pause-resume`.
## 2026-08-23: the service protocol proven by the emulator, and the hunt paid only where it is the subject
Three dev images in one day, each a campaign, the last one full and
clean.
**Dev image `20260823002125`** (forgefirm 4c9dcca, python3-gfhardware
12ad3b1 pinned by meta-openglow a4e3abf, the first image with the
`python3-gfutilities-emulator` fixtures) carried a layer change, so every
test was owed. Campaign `c-20260823140444-80ae`: the 27 unattended tests
passed in 10 minutes. Before the operator's part, the emulator path was
dry-checked from a shell the way the offline one had been, and it caught
a defect the host replays could not: the session came up (sign-in, the
firmware check, the WebSocket ready) and the service sent `settings` and
nothing else. The real client's hunt lands 1 to 2 s after `ws_connect
ESTABLISHED`; the emulator waited minutes. `build_emulator` had set
`EMULATOR.BYPASS_HOMING`, which makes gfutilities answer the settings
request with `"settings":{}`, the reconnect form the service answers by
keeping its head position and skipping the hunt. The fix (gfhardware
b7e8035: the report carries the values; a host test proves it red on the
old flag) was hot-patched on the bench for the rest of the dry-check: the
hunt landed 1 s after the settings report and completed; the service was
satisfied after two home frames and one motion (the real client takes
four frames and three motions); the app showed Ready; a Print from the
app reached the emulator 7 s later, behind a pre-print motion pair and a
`lidar_image` request the emulator answered, and downloaded (20 KB
gzip, 643 KB of pulses, a 134-tag header, STfr 10000) and completed. The
shipped file was put back and the real client restarted before anything
else ran.
**The operator's change, before the next image:** a mode switch from GRBL
to cloud costs the service's connect-time hunt, and during cloud
development those add up. gfcloud gained `--no-hunt` and the one-start
marker `/run/gfcloud-nohunt` (gfhardware 351a623): the first settings
report goes out in the reconnect form, which is what the factory client
does on every reconnect within a session. With it, every one-start marker
is now read and taken down by the client itself, first thing, before the
imports that take seconds on this board, so a respawn never inherits one
and a writer can move on once the supervisor reports the client up.
forgetest (forgefirm 969bac6) sets the marker for every cloud client it
starts except where the hunt is the subject: `cloud.mode-switch` and
`cloud.service-protocol` keep theirs, and so does the one real print,
since `enter_cloud` now reuses a running session only when that client
has hunted the machine itself (`session_hunted`: never the emulator's
session, never a no-hunt start) and otherwise restarts the client with
the hunt. The decision, the operator's: all starts skip the hunt but
those three. The hazard it leaves, written into ACCEPTANCE.md: a machine
a campaign leaves in cloud mode may not have hunted since GRBL mode moved
the head, so a lid cycle or a controller restart before printing from
the app.
**Dev image `20260823153019`** (forgefirm 908e0c7, gfhardware 351a623 by
meta-openglow 9e988b5). The pin-file mechanism held across the bump: 21
tests inherited, the 6 always-required core tests ran (76 s), and the
operator took the attended block: the four motion tests, the five laser
tests, `camera.lid-privacy` and `cloud.mode-switch` passed, and
`cloud.service-protocol` ERRORed on its first line, `forgectrl POST /mode:
timed out`. Two defects, one each side. forgectrl's mode switch answers
only after the new controller's first job-state report to the cooling
engine, 15 s without one; the real client reports within seconds of its
machine coming up, and the emulator never reported at all, so the answer
came at the deadline, past forgetest's 10 s client timeout (the dry-check
had used curl, which has none, and so never showed it). The emulator now
runs the same idle, unarmed 1 Hz reporter as the hardware machine
(gfhardware 537d0db), and forgetest gives the supervisor's three levers
(`/mode`, `/controller/start`, `/controller/stop`) a 120 s timeout, above
the daemon's own waits (forgefirm ab0a515).
**Dev image `20260823161333`** (forgefirm 8379aa5, gfhardware 537d0db by
meta-openglow 730db53). Campaign `c-20260823161923-0dd7`: 29 inherited,
the 6 core tests in 74 s, then 9 attended: the emission witness,
`camera.lid-privacy`, `cloud.mode-switch`, `cloud.service-protocol` (68 s:
the session, the hunt, three image uploads, a print from the app
downloaded with its 134-tag header and completed against the real
service with nothing behind it, then the real client back in 14 s under
`NO-HUNT` with no hunt), the four offline tests, and the one real print,
`cloud.pause-resume`, which found the offline client running and started
a fresh one with its own hunt before printing, as the rule requires.
**44 of 44, release authorized**, 868 s of attended test time. No release
cut. The offline client is what a campaign now leaves running in cloud
mode; the next thing that needs the service restarts it.
What this closes: the cloud split of the acceptance plan is complete.
The service protocol is proven by the emulator with only the app to
drive, the machine's print behavior by the offline service with nothing
on the bed, and the two together by one real print. Still open from that
plan: the bench actuator for the lid, interlock and button, and the
finer coverage maps.
## Superseded status notes
### Shared machine services — remaining polish, as listed 2026-08-13