Files
firmware/docs
Oleksandr ShyshatskyiandClaude Opus 5 2a6331a831 We own runFirmwareExe.sh; the install is no longer spliced into run.sh
app_startup.sh runs whatever it finds under that name in the package it just
decrypted. That is the entire contract -- plus the exit code, where 0 means
"flashed, power-cycle me" and non-zero means "carry on booting" -- so owning
the name is all it takes to own the install. We were not using it. We shipped
FlashForge's copy verbatim and reached the printer through the one exec hook
their file offers: the software component's run.sh, into which bin/patch.sh
spliced two marked blocks with 40 lines of regex.

installer/runFirmwareExe.sh is that file now. run-pre.sh and run-append.sh are
folded into it unchanged in substance -- the manifest delete, the HelixScreen
settings rescue, the s6 scandir sweep, the config merge, the password dance are
all the same code -- and the two orderings that mattered are kept explicitly
rather than by where a regex put them: the backups run BEFORE any component is
installed, because the software component ships /usr/prog's shadow and passwd
and its run.sh copies them over the live ones.

The four component installers become one function. Their semantics are kept
exactly, including that a component failing md5sum.list is discarded rather
than half-installed, and that every previous version directory is wiped before
the new one lands. What is NOT kept is the third of that file which never ran:
create_key(), defined and never called, and built its paths without a slash so
it would have written /usr/progprivate.pem; SSID_NAME/SSID_PASS, assigned and
never read; the commented-out kernel version gate; the screwflag factory bypass
of the model check, which we ship no screwflag for.

bin/pack.sh stages it, rewriting MACHINE=, PID= and MOD_PW_AUTO= and then
GREPPING for all three -- a package whose gate still said Creator5Pro because a
sed missed would install on the wrong machine. MOD_PW_AUTO is 0 in the
checkout, which is the safe default and not an arbitrary one: test_upgrade.py
runs the unsubstituted file, and 1 would have it reroll the replica's root
password and drop a password file on /mnt every run.

The software component still ships, unchanged, and its run.sh is left exactly
as FlashForge wrote it. Dropping it is the next commit; this one moves the
vehicle without changing what reaches /usr/prog.

Gates: qa/static/test_shell_syntax.py already covered installer/*.sh under both
bash -n and the printer's ash plus shellcheck, so the new file was checked the
day it landed -- 91 pass. test_upgrade.py runs the real installer over two
synthetic payloads and is repointed at it.

Two doc claims corrected while their sections were open, both false before this
change rather than because of it: how-it-works.md said app_startup.sh's
firmwareExe recovery "still works" -- it cannot, because it copies out of the
version directory and ours has had firmwareExe deleted from it -- and it
described a Moonraker preflight-and-rollback that went with the /usr/prog copy;
moonraker-preflight.py exists nowhere in the tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CH7Yb4wuPhnppHAB25UX7e
2026-08-30 15:34:19 +03:00
..