Bump the grblHAL pin to the producer lead and margin instrumentation.
Rewrite BRINGUP item 16 to the present state. The scheduling half is
done - the producer runs SCHED_FIFO below the shipper, core_mx carries
priority inheritance, and clamping is reported per run - and two bench
runs 90 s apart on one image show what that does and does not cover: a
nice-5 CPU hog passes clean while the camera streaming clamps 7 runs,
because per-frame cache maintenance over a 4.8 MB non-coherent capture
buffer is kernel-context work no userspace priority can preempt.
Record the margin finding, since it explains why a 4 ms stall was
enough: the queue depth cancels between the shipper's due index and the
producer's base, so the pacing lead is the only slack. Record the
cycle-churn ceiling that caps that lead at 10 ms, and that the re-base
fix is what unlocks more.
Camera gating stays owed, with capture resolution named as the lever
that shortens the stall rather than merely spacing stalls out.
Bump the grblHAL pin to the real-time producer change.
Add motion.step-timing-under-load: the catalog had nothing that
exercised step generation while userspace competed for the single core,
which is exactly the gap that let the condition go unnoticed - the ring
never runs dry, so cnc/underruns reads 0 through it. The test asserts
the producer and the shipper both hold SCHED_FIFO, then drives
2000 mm/min round trips against a deliberate nice-5 CPU hog and requires
the controller to report no clamped events.
Add the pthresh live-fire drill: a constant-power ladder from 2 % to
30 % of full on scrap. Because $35 is a percent of full duty and the
rungs are percents of $30 with $31 = 0, the lowest rung that marks reads
directly as the $35 value. It needs $35 = 0 for the run, or the floor
lifts every rung and hides the threshold.
Record both open items in BRINGUP. The laser one carries the finding
that the factory never uses duty as a power control - all five firing
jobs in the captured pulse files pin the power byte at 127 and modulate
dose by dithering the FIRE bit at 6.5-18.8 % density - so the captures
cannot supply a $35 default, and the duty to optical-power transfer
function of this supply has never been measured.
The lid/button/interlock parity change (BRINGUP item 16): the arm wait
and a running job cancel on lid or interlock the factory's way, the
button pauses/resumes, lid_policy and the cloud pause tick settings.
Cloud tests cloud.* and the new motion/laser lid tests cover the
components; the python3-gfhardware / gfutilities pins move with this in
meta-openglow.
A component pin bump counted as a platform change: the layer content hash
in the platform identity covered the recipe carrying the SRCREV, the
platform is folded into every acceptance fingerprint, so every image
that carried any component update invalidated the whole catalog (dev
image 20260816191951: every test domain-changed after a one-line
forgectrl bump; the two manifests differ only in
platform.layers.meta-forgefirm). The component entry already identifies
the pinned source file by file; the pin double-counted it.
Component pins now live in <recipe>-pin.inc (SRCREV and the PV that
moves with it, nothing else) - forgectrl, grblhal-glowforge and
forgefirm-app here, the BSP components in meta-openglow - and
forgefirm-image-manifest.bbclass leaves *-pin.inc out of the layer
content (FORGEFIRM_MANIFEST_PIN_SUFFIX). Recipe bodies, patches, config
fragments, init scripts and third-party pins with no manifest entry stay
layer content; a pin written into a recipe body still hashes (the safe
direction). manifest-from-tree.py mirrors the rule and reads pins
through the recipe's requires; test_tree_manifest.py proves both
(pin bump: hash unchanged; recipe body or inline pin: changed).
Bitbake resolves the same SRCREV/PV for every pinned recipe.
Docs: ACCEPTANCE.md (what layer content is), kas/README.md (the pin
files in the push order), BRINGUP.md (the finding and the bench
consequence: the first image built with the pin files is itself a
platform change, so its campaign is a full one; pin bumps inherit
after it).
No catalog consequence: nothing in the image's behavior changes; the
change is to the acceptance identity computation, proven by the unit
tests and the CI lint on the tree manifest.