Files
forgefirm/forgetest
ScottW514 296fd686e1 forgetest: the button's commanded level, and one app cancel instead of two
laser.arm-wait-lid failed its first bench run on the witness, not the
machine: the cancel relocked, disarmed and emitted nothing, but the
"button dark" check read the LEDs' brightness the instant after, and
the smooth trigger fades it. The controller writes `target`, so that is
what hw.button_leds() reads now (brightness where no target exists),
and check_button_dark waits a few seconds for the command to land.

The operator's campaign showed cloud.oversize-stream and
cloud.pause-cancel-paths both cancelling a print from the app. A print
longer than the ring has to be ended that way, and the operator is at
the app for it anyway, so the app cancel lives there and is judged in
full (the abort tail: stop, park to the job start, relock, disarm, the
button dark, ':cancelled'); cloud.pause-cancel-paths loses its second
print and becomes cloud.paused-lid-cancel - one print, one arm press.
Replays follow. Catalog consequence: the two cloud tests and the laser
module are re-required; the count stays 43.
2026-08-22 17:47:26 -04:00
..

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 docs/ACCEPTANCE.md.

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>:8080 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:8080, /data/forgefirm/panel.token forgectrl client
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.