- grblhal-glowforge badc832 -> e159720 (0.1.21 -> 0.1.22): a soft reset
during motion gets the kernel's ramp and the position is read back
from the kernel's step counters, a reset that lands after the core's
own idle still gets the stop, the owed step is taken only between
callbacks, a position that stays lost pins the lens and tells the
sender, the homing cycle masks are pinned so a write cannot drop the
lens hold, the test hooks (GF_SWITCH_DEV included) are honored only in
a null-sink run through one gate, the underrun fail-safe log line
names its entry, and the latch_test and serial_test cases that hold
each.
- forgeext bb75b23 -> ebd9592 (0.1.4 -> 0.1.5): the storage quota counts
entries (one per 4 KiB) and the unlinked files a service holds open or
mapped, bounded, every 10 s; a quarantine the host could not write is
kept under the run directory, taken up at the next start or the first
turn the state reads, and dropped by the write or the lift; the root's
prepare turns current back to the state's version, drops only a
versioned tree, and leaves a package it cannot turn refused while the
host runs the others; a manifest that cannot be read holds its package
out by name; the required-holds marker directory is one literal.
- forgectrl 6c2bb38 -> b235be3 (0.1.33 -> 0.1.34): a diagnostic start
the cooling engine refuses goes once more a second later, canceled by
a later press or the Abort, which clears its text; the sysfs root, the
switch device and the run directory are honored only in a host-test
run through one gate (src/testhook.h, with its HOST_TESTED row here);
test_routes holds the panel's retry text to the daemon's and the
environment scan reads secure_getenv; the operator's texts say Grbl
sender; holds_wire_test holds the required-holds directory to
forgeext's and a marker alone holds.
- forgefirm-app 0f59c54 -> 6fb146a (0.1.32 -> 0.1.33): the shared
AGENTS.md block names a Grbl sender; nothing it installs changes.
- kas lock: meta-openglow b7626be -> c542ce6, the head that pins the
kernel module dab378d, python3-gfhardware 6fb146a and gfutilities
b9e74b8.
Proof: the four repositories' CI runs on the pushed heads are green
(grblHAL-glowforge 39170662884, forgeext 39170677776, forgectrl
39168946865 on its second attempt, python3-gfhardware 39168949407), and forgefirm's own
forgetest-ci on 0de9051 (39168937632). bitbake -c fetch of each pinned
recipe from these pins succeeds. The tree manifest from the pins holds
forgectrl at b235be3 (232 files), forgeext at ebd9592 (90), grblhal at
e159720 (178) and the app at 6fb146a (46); the coverage lint over it
finds no uncovered path and no row problem (43 tests), with the row for
forgectrl src/testhook.h selecting host_start.sh in build.yml;
check-ui-vendor finds the shared UI files identical; test_tree_manifest
passes (7); the gate self-check refuses the empty artifact (rc 1).
Acceptance: the pins move the fingerprints of every test whose covers
name the four components, and the whole catalog runs on the next image.
forgetest - the ForgeFIRM release acceptance tool
The daemon behind http://<machine>:8090/ on the dev image: runs the
acceptance catalog against the machine, keeps the append-only result log,
decides which results still apply to the image that is running, exports
the release artifact scripts/release.sh gates on, and serves the bench
diagnostics page. The contract - catalog, campaigns, fingerprints,
inheritance, the gate, the coverage rule - is
the Acceptance page of the documentation site.
Run the host tests
cd forgetest
python3 -m unittest discover -s tests -v
Run the daemon on a workstation (against a mock or a manifest file)
FORGETEST_DATA=/tmp/ft FORGETEST_MANIFEST=../tree-manifest.json \
FORGECTRL_URL=http://<machine> python3 -m forgetest --port 8090
scripts/manifest-from-tree.py produces tree-manifest.json from the recipe
pins; the coverage lint is python3 -m forgetest.coverage --manifest ....
Environment
| Variable | Default | Purpose |
|---|---|---|
FORGETEST_DATA |
/data/forgetest |
results.jsonl, bench.jsonl, token, export/ |
FORGETEST_MANIFEST |
/etc/forgefirm-manifest.json |
the image manifest |
FORGETEST_PORT, FORGETEST_HOST |
8090, 0.0.0.0 | listener |
FORGETEST_BENCH_DIR |
/usr/share/forgetest/bench |
the installed bench scripts |
FORGETEST_BENCH_DATA |
<FORGETEST_DATA>/bench |
passed to bench tools: where they keep their data files (with GF_HOST=127.0.0.1 and the panel token in GF_TOKEN) |
FORGETEST_MARKER |
/run/forgetest.active |
takeover marker |
FORGECTRL_URL, FORGECTRL_TOKEN_FILE |
http://127.0.0.1, /data/forgefirm/panel.token |
forgectrl client (HTTP; the token authorizes writes from the board) |
FORGECTRL_TLS_URL |
https://127.0.0.1 |
forgectrl over HTTPS (self-signed, unverified), for the login test |
GF_SYSFS_ROOT |
/sys/glowforge/ |
kernel module sysfs |
GRBL_HOST, GRBL_PORT |
127.0.0.1, 23 | Grbl TCP |
Adding a test
Register it in the subsystem module under forgetest/suite/ with
@test(...): id subsystem.name, kind, hardware, mode (the controller
mode the test needs; the runner switches to it first), covers,
requires, always, steps. The body gets a Context (log, check, fail,
prompt, confirm, instruct, sleep, evidence, forgectrl, sysfs,
grbl, takeover). Return normally for PASS, raise runner.Failed for
FAIL. Then run the unit tests and the coverage lint.