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.
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, 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.