docs: build p33, image 20260903163543, the campaign's image

The record of what the first attended run really found and what it cost:
the verdict had no run-session identity, so the arm opened its window on
the verdict computed for the idle session before it. The build entry
lists the four components taken from local commits and the checks made
on the built images.

BRINGUP moves to the new campaign image and says why nothing inherits.
This commit is contained in:
ScottW514
2026-09-03 12:46:39 -04:00
parent db9acf9910
commit 0845ab32a1
2 changed files with 7815 additions and 7738 deletions
+16 -7
View File
@@ -49,9 +49,10 @@ hardware-validated.**
nothing and authorizes a release (the record is in `CAMPAIGN-LOG.md`); nothing and authorizes a release (the record is in `CAMPAIGN-LOG.md`);
**no release is cut yet.** **no release is cut yet.**
Current bench state: dev image `20260901225926` on the SD card (eMMC slot 1 = Current bench state: dev image `20260903011655` on the SD card (eMMC slot 1 =
factory 2024, slot 2 = a ForgeFIRM pin-file image, archives in factory 2024, slot 2 = a ForgeFIRM pin-file image, archives in
`/data/forgefirm/archive`). `/data/forgefirm/archive`). The campaign's image is `20260903163543`, which is
built and waiting to be flashed.
## The bench ## The bench
@@ -1385,13 +1386,21 @@ feature requests, enhancements) will eventually be tracked as GitHub issues.
pins, the kernel and the module rebuilt together for the watchdog sysfs pins, the kernel and the module rebuilt together for the watchdog sysfs
change, and is not the image the campaign runs on: the campaign waits change, and is not the image the campaign runs on: the campaign waits
until every audit finding, the deferred ones included, is on one image until every audit finding, the deferred ones included, is on one image
(the operator's rule). That batch is done (items 10 and 11) and is on (the operator's rule). That batch is done (items 10 and 11). The
the local image 20260903011655 (release and dev; the module built from campaign's image is now the local image 20260903163543 (release and dev),
its local commit at 0.0.3, the kernel from the edited patches, which supersedes 20260903011655: it adds the arm-acknowledgment fix that
everything else from the pushed pins), which is the campaign's image. the first attended run made necessary. The cooling verdict carries the
engine's own armed flag, and neither controller fires inside its armed
window on a verdict that lacks it, because such a verdict answers the idle
session that preceded the arm. Four components in that image come from
local commits that are not pushed (forgectrl, grblhal-glowforge,
kernel-module-glowforge at 0.0.3, python3-gfhardware), each pinned for the
build through an overlay that is not committed; the kernel comes from the
edited patches.
Owed now: flash the dev image, take a fresh-boot baseline, run the full Owed now: flash the dev image, take a fresh-boot baseline, run the full
campaign on it, the campaign the release gate asks for; then the push campaign on it, the campaign the release gate asks for; then the push
in CI order and the pin bumps for the batch. in CI order and the pin bumps for the batch. Nothing inherits from the
earlier campaign: three layer hashes moved.
Decisions taken in the remediation that the operator confirms or reverses: Decisions taken in the remediation that the operator confirms or reverses:
the release image has no shell login (the install page now says so); the the release image has no shell login (the install page now says so); the
cloud client holds and resumes on the cooling verdict with a 30-minute cloud client holds and resumes on the cooling verdict with a 30-minute
+68
View File
@@ -7654,6 +7654,74 @@ the first fire, which is a change to forgectrl and another image before
any further live fire. The attended eleven were not run; the campaign on any further live fire. The attended eleven were not run; the campaign on
20260903011655 stands at 45 of 56. 20260903011655 stands at 45 of 56.
## 2026-09-03: the fire that preceded the airflow, and what it really was
The setting was reset first: `cool_temp_start` back to 16, its default, by a
POST to /settings on the machine. Every cooling gate row then read its
compiled default again. The only remaining non-default values are the bench
calibrations, the air-assist offset of 16 counts, the recorded dose curve, and
the corner gamma of 1.5.
The second cause turned out to be narrower and worse than "the gates are
evaluated one tick late". The cooling verdict carried nothing that said which
session it answered. A controller opens its armed window, reports it, and the
engine applies the run airflow and the flow interrogation only when it reads
that report on its next tick. Until then the verdict on file is the one the
engine computed for the idle session before the arm, and at idle nothing is
wrong, so it reads `fire_ok=true` and stays fresh inside the two second
window. In GRBL mode `arm_complete()` re-checks the gate right after the
button press and opened the window on exactly that verdict. The fixture
pressed at 0.0 s, so the re-check ran before the engine had ticked at all.
The hold that followed was the engine catching up, not the cause. Cloud mode
had the same exposure in `_verdict_wait()`, which broke as soon as the verdict
read clean.
The fix gives the verdict a run-session identity. The engine publishes
`armed`, its own view of the window, set from the reported state before
`flood_apply` and before the publish, so `armed=true` means the verdict was
computed with the run session open. `gfcool_fire_ok()` additionally requires
it while the window is open and leaves the pre-arm gate alone, where there is
nothing yet to acknowledge. `arm_complete()` waits for it, bounded at five
seconds, and refuses the job if it never comes. The cloud wait requires it
too. The verdict body grew a key, so its buffer went to 384 bytes behind a
static assert on the budget: an oversized document is not published, and no
verdict reads to every controller as a fault.
Proofs, all host. The two new cloud tests were run against the unfixed code
and failed there: `_verdict_wait()` returned in 72 microseconds on the pre-arm
verdict, which is the defect itself. The lifecycle harness gained two cases,
one where the engine never takes the window (refused arm, no emission) and one
where it takes it two seconds late. The late case is the one that proves the
controller keeps reading the verdict while it is blocked in the arm; it waited
1.6 s and then armed. Without that path every job on the machine would fail at
the arm. Also green: the grblHAL arm unit test, the stream harness at 22
cases, the 16 forgectrl host tests, the 289 forgetest tests, the coverage lint
at zero uncovered paths, and the docs build.
The acceptance catalog gained the bench form of the rule. `laser.emission-witness`
now fails if any sample shows emission while the cooling engine reports a phase
that runs the fans at idle duty, which is what this failure looked like from
outside. The sampler records the phase, and the trail carries it.
## 2026-09-03: build p33, image 20260903163543
Both images built green from the committed trees, with four components taken
from local commits that are not pushed: forgectrl 8ef9509 at PV 0.1.2,
grblhal-glowforge 2f5edee at 0.1.2, kernel-module-glowforge faa1034 at 0.0.3,
and python3-gfhardware dd0ebf3 with the app recipes at 0.1.23+git. Each was
pinned for this build only through a kas overlay that is never committed, with
its download mirror primed from the local repository; the grblHAL submodule
came from its own pushed commit. The kernel and the module were cleaned
together, so the feed carries one kernel version string.
The built images were checked for the fix rather than assumed to carry it: the
verdict format string with `armed` in the forgectrl binary, the refusal message
in the controller binary, the armed test in the cloud module, and the new
airflow witness in the acceptance suite. The p32 content is still present, and
there were no QA warnings. This image supersedes 20260903011655 as the
campaign's image, and the campaign must start again on it: three layer hashes
moved, so nothing is inherited.
## Reference notes ## Reference notes
### Head-IRQ source validation — the beam-emission hypothesis ### Head-IRQ source validation — the beam-emission hypothesis