CORRECTED 2026-08-29, evening. The conclusion below holds; half its
evidence does not. The kernel row of the table – 14.96 / 15.34 / 15.25 /
14.68 s, presented here as the strongest reading because it showed no
difference “at all” – could not have shown one. pmbootstrap build --envkernel returns from pmb/commands/build.py (3.11.1, lines 15-17)
BEFORE the strict-mode zap block, so --lax never reaches that path. Four
readings of a flag that was inert by construction.
The device-package row is the live measurement and it stands: 1.66-1.72 s
either way, warm, interleaved. So the verdict is unchanged and the reason is
now narrower and firmer – on the envkernel rung the flag does nothing at
all, and on the package rungs it saves 60 ms.
One thing the name hides, found the same evening: zap_buildroots() deletes
chroot_native as well as chroot_buildroot* (pmb/chroot/zap.py:48-50).
A non-lax package build therefore takes the toolchain the next envkernel
compile would have used with it, which is why a “chroot re-init” surfaces as
a full kernel rebuild rather than as a chroot message. See
envkernel-disables-ccache.
CORRECTED AGAIN 2026-08-30, and this one inverts the advice for the
workspace. Everything below was measured ON THE HOST. In the rootless
workspace a non-lax pmbootstrap build does not merely cost nothing – it
cannot run. zap_buildroots() umounts the chroot, and the recursive
/dev bind the workspace needs puts propagated sub-mounts in
/proc/self/mountinfo that a rootless userns cannot umount by path:
umount: /pmb/chroot_native/dev/shm: not mounted. (exit 32)
Discriminated by running each once and slicing pmbootstrap’s log: nolax
reaches “Zapping buildroots” and dies there, before building anything;
--lax skips the zap and fails later at an unrelated point. So in the
workspace --lax is the only path that gets past the zap, and “do not reach
for it” is HOST advice. Since 2026-08-30 tools/ph-build.sh applies it
automatically in the workspace and nowhere else, so nobody has to know this.
what-a-rootless-workspace-cannot-do §5.
Upstream’s reason for the default, since asked – e14f4169, Aelin,
2026-05-23, MR 2939: “Strict mode is the more correct one and results in
consistent, reproducible behavior, which is why I believe it should be the
default. If users want quick builds without setting up the buildroot several
times, –lax can now be used.” Correctness, explicitly. That is the same
hazard this note weighs, now in upstream’s own words rather than ours.
Note how NEW all of this is: --lax, strict-as-default and
zap_buildroots() all arrived in that one 2026-05 commit. Before it, lax was
the default and no build ever deleted chroot_native.
Still not re-measured, and honestly: the device-package A/B below was
inherited, not re-run. It could not be re-run here – a second, independent
blocker (gcc-x86_64/g++-x86_64 “no such package”: the local x86_64 cross
toolchain has never been built in this workspace) stops package rungs on BOTH
paths, lax included. Cause undetermined. The host numbers stand as host
numbers.
The question — ph-build.sh and AGENTS.md both say pmbootstrap build
zaps the buildroot before every package and that this “is most of the wall
clock in the flashing rungs”, with PORTHOLE_LAX_BUILD=1 offered as the
knowing trade. It had never been measured here. How much does it buy?
The kernel package shows no difference at all — lax is slower in two of four
readings, which is noise. The device package is 1.7 s either way once warm; the
one 3.87 s reading is the first run of the sequence.
What this rules out — that the zap is where the flashing rungs spend their
minutes. It is not. Those minutes are install, export, the flash itself and
the boot wait, none of which --lax touches.
So the flag is a bad trade: it accepts a documented, repeatedly-paid
hazard — stale build state presenting as a mysterious wrong-kernel bug — in
exchange for no measured gain. Do not reach for it while iterating. Reach for
the right rung instead, which is worth minutes rather than seconds.
What would still overturn this: a genuinely cold buildroot, where the zap
has real work to skip. Every reading above is a rebuild of a package that was
already built, which is exactly the iterating case the flag is recommended for
— so the recommendation is refuted on its own ground. If a from-scratch
dependency set is ever timed both ways, record it here.