verify.sh described itself as "simulate every check the printer performs,
against a built package". The word carrying that sentence is SIMULATE, and it
is why thirty-six of the forty are deleted rather than moved.
THE REPLICA LANE DOES NOT SIMULATE THE INSTALL. install-package.sh puts the
package on a genuine FAT filesystem at /dev/sda1 and runs the machine's own
/usr/prog/app_startup.sh over it, verbatim, under qemu. So these are
PRECONDITIONS of the lane now rather than assertions in it -- break any and
installed_image() raises with the install log and the whole lane goes red:
* the decrypt with the firmware key (the printer's unTar does it)
* runFirmwareExe.sh present, components plain tar not xz (bare `tar -xvf`)
* md5sum.list verifying (the installer aborts and deletes the payload)
* the MACHINE= gate (runFirmwareExe.sh refuses a foreign package)
* the /mnt/<Model>-*.tgz glob (app_startup.sh finds the file by it)
A host-side re-reading of those rules is a second implementation, and a second
implementation can agree with itself while disagreeing with the printer. That
is the defect qa/replica/conftest.py records this repo learning twice about
hand-placed payloads.
A second block was asking what the suite already answers, of an installed
filesystem rather than of a tar listing: the klippy tree and c_helper.so
(test_install, test_abi), the s6-rc database and the oneshot runner's execline
(test_s6rc), s6 and s6-ftrigrd (test_supervisor), the .install-manifest
(test_upgrade), libsodium's bare .so symlink and the chamber configs
(static/test_ipk), and every shipped script's syntax
(static/test_shell_syntax).
THE FOUR THAT MOVED are the ones nothing else asks, and each is stronger for
the move -- a `tar -t` listing cannot tell you that a shared object loads, or
what a name resolves to on a PATH:
* the interpreter IMPORTS sqlite3, lmdb and _cffi_backend, rather than a
grep finding three .so files. This is what catches a cross build that
resolved to an x86_64 manylinux wheel: present on disk, raises on import.
* nothing in $MODDIR/bin shadows FlashForge's python3 -- asked with
`command -v` after sourcing anvil-env.sh, which is the file that PREPENDS
$MODDIR/bin to PATH and so creates the hazard in the first place.
* CPython's dev half (headers, pkgconfig, config-3.13-*) did not ship.
* the ship boundary: no file on the installed printer is byte-identical to
one under bin/ or docker/. Asked of the machine rather than of the .tgz,
so it also sees whatever a maintainer script wrote as root at install
time. The sweep filters on exact size before hashing, which is what keeps
a walk of /usr/prog through qemu cheap.
WHAT GENUINELY LEFT, recorded in docs/qa-migration.md rather than only here:
there is no longer a check you can run on the build host, in seconds and
without docker, against a package you are about to flash. Nothing warns you
before you copy the file to a stick that it was built from the wrong model's
stock package. The printer still refuses it and `make qa-replica` still
catches it, but the fast host-side warning the hardware checklist used is
gone. `make verify` is removed and `make release` no longer calls it.
VERIFIED. All four ran against a real replica (the cached installed image,
PRINTER_IMAGE=monstrofil/creator5-printer:latest): 4 passed in 17s. Then each
was DRIVEN RED on purpose with a throwaway module, which is this repo's own
standard from 4ce928f -- bin/common.sh copied byte-for-byte into $MODDIR, a
python3 symlink in $MODDIR/bin, an include/python3.13 directory, and a module
name that does not exist. Each was caught, each named the planted file in its
message, and each went green again once it was removed. The leak sweep walks
21132 files under $MODDIR and /usr/prog, so its floor of 100 is not load
bearing. The static lane goes 123 -> 122, which is exactly the `bash -n` test
that test_shell_syntax.py generated per bin/*.sh file.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GAQKdBfZxbnPagQyidFk6Y
4.5 KiB
Hardware testing
CI installs the package into a replica of the printer -- the real
rootfs.squashfs running under qemu-mipsel, on the printer's own busybox and
unTar (see printer-replica.md) -- and proves the
machine would still boot. What it cannot do is drive the screen, the MCUs, the
toolchanger or a print. This is the on-hardware procedure.
There is one flash: the firmware package for your model.
Rule: have the stock FlashForge package for your model on a spare stick before you flash anything. Flashing it back is the uninstall, and it is the only recovery step that needs nothing but a USB port — no ssh, no screen.
It used to be proven by make test-recovery, which installed the mod into the
replica and flashed the stock package over it. That gate has been retired
and nothing has replaced it yet — see
qa-migration.md. It passed on its last run, but treat the
rollback as unverified against the current build.
Step zero: check the model gate
Every package carries a gate. Its runFirmwareExe.sh has MACHINE= / PID=
baked in, and compares them against the values app_startup.sh passes from
the firmware already on the printer. A mismatch is refused with
"Firmware does not match machine type" — it will not install, and it is not a
valid recovery image either.
| Model | MACHINE | PID |
|---|---|---|
| Creator 5 | Creator5 |
0028 |
| Creator 5 Pro | Creator5Pro |
0029 |
The gate is not cosmetic: the two models ship different firmwareExe
binaries, so a package must be built from the stock package for its own
model. make release builds both.
Find yours in Settings → About, or in
/usr/data/firmwareRes/config/general.json (machineName), and set
TARGET_MACHINE in config.env. Then:
make build # one model
make release # both, into dist/
You must start from a stock package built for your own model — the mod
inherits the gate from whatever package you unpack, so a package built from
the wrong stock file carries the wrong gate and your printer will refuse it
with "Firmware does not match machine type". Nothing on the build host warns
you first; make qa-replica catches it by installing the package the way the
printer does.
Before the first flash
- Put a copy of the stock FlashForge package for your model on a spare USB stick and keep it physically separate. That is your recovery image: flashing it restores every file the mod touches. Check it is the right model first — see above.
- Note your printer's serial number (Settings → About). The factory image restores a placeholder serial and you may need to put yours back.
- Confirm you can reach the printer's IP.
make qapasses.make rootfs && make qa-replicapasses — this parses every script that will run on the printer using the printer's own busybox ash.
Two USB sticks, FAT32, both packages at the root of the stick (not in a
folder). Ship both filenames (Creator5-* and Creator5Pro-*): the Pro's
boot script globs Creator5Pro-*.tgz, the non-Pro globs Creator5-*.tgz.
The flash
One flash brings up everything: a root password you know, Mainsail and moonraker, the forked Klipper with the toolchanger extras, and HelixScreen on the touchscreen in place of FlashForge's UI.
From here the procedure is the one an owner follows, and it is written for them rather than repeated here:
| Installing | the flash itself, the first boot, the root password |
| Your first print | the go/no-go checks, calibration, and the two files under gcode/ |
| Support | the logs, and the way back to stock |
What follows is the part that is ours rather than theirs: keeping those two verification files honest as the macros change.
Keeping the verification files honest
Nothing checks them automatically any more. make test-py used to: every
command in them had to be one the mod's Klipper config or
pkgs/klipper/payload/klipper/klippy/extras/ defines (bar an explicit
allowlist of Klipper built-ins, currently just SET_PRESSURE_ADVANCE),
TOOLS= had to list every tool the feature print uses, and the safe file's own
lines had to stay cold and above Z50. That check went with the test/ tree.
So a renamed macro now breaks the print rather than the suite. If you rename or
remove a macro, read gcode/creator5-safe-moves.gcode and
gcode/creator5-feature-test.gcode before you ship it.