You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(device): runner gains three siblings, --locked asserts, and mcpp sbom
Four axes a project is asked about before it is adopted, and none of them had
an answer: how the artefact reaches a device, whether the build is
reproducible, what went into it, and whether an emulator and real silicon are
one package or two.
## The device slots
`run`, `flash`, `monitor` and `debug` are one shape — an argv the BOARD knows
and a TOOL performs, addressed absolutely, with the artefact appended or
substituted for `{}`. `runner` has carried that shape since 2026.8.19; three
special-case commands would have carried it three more times. So the slot is
the parameter: one directive-table row each, one reader, one CLI shape.
⚠️ What no argv can express is which of them ENDS. `run` and `flash` finish and
hand back a verdict; `monitor` and `debug` have no natural end, so a live
process is success for them and a hang for the other two. `Semantics` answers
that from the slot, because `openocd -c "program … exit"` and `openocd -c
"init"` are spelled alike up to the argument the board chose.
`debug` starts a SERVER and stops there. The client is the user's debugger or
their IDE, which reaches mcpp through docs/11; driving it would put mcpp in the
middle of a session it has nothing to add to.
⚠️ `runner-exclusive` is the first thing a physical board needed that an
emulator never did. `mcpp test` runs binaries on a worker pool; one probe on
one device is a mutex, and two workers reaching for it do not fail — they
interleave, and the verdict is about neither test. The board knows this about
itself, so it says so once and no project remembers `-j1`.
## Emulator or hardware is a feature, not a fork
A board reached through QEMU and the same board reached through a probe differ
in the argv of their device slots and nothing else. Publishing two packages
would duplicate a linker script, startup code and a module surface to vary four
strings. `mcpp::has_feature()` already existed, so this needed no engine work
at all — it is what the layering was for. e2e 333 builds one board package and
drives it both ways.
## --locked
The lock has always been written after resolution and never read back; its own
header said so. This makes it an ASSERTION rather than a pin: the resolution
that happens must equal the one recorded, and a difference names the package
that moved and both versions. That is the half reproducibility needs first, and
it is what Cargo's flag of the same name means.
⚠️⚠️ And it must not meet the fast path. Measured before that guard existed: a
deliberately corrupted lock passed `mcpp build --locked` and printed "Finished"
— the flag accepted, the build correct, the assertion never run. A criterion
that is skipped is worse than one that is absent, because the green reads as a
verification.
## mcpp sbom
CycloneDX 1.5 over the recorded resolution. Everything a bill of materials
names is already in mcpp.lock, so this is an output format rather than a
mechanism: it resolves nothing and asks the network for nothing.
⚠️ It reads the lock rather than re-resolving, which is the one property such a
document must have — an SBOM describing a different graph from the one that was
built is worse than none. Asserted in e2e 333 by editing the lock and checking
the output follows it. An unknown licence is emitted as NOASSERTION rather than
omitted: an absent key reads as "not examined", and a reviewer cannot filter on
silence.
## Two propagation sites, and the one that was missed first
Dependency-supplied RunGlobal entries reach the root through a different path
from a package's own directives. Wiring only `apply()` left `mcpp flash`
reporting "no flash is configured" while `mcpp run` found the runner the same
build program emitted three lines away — measured. Both sites now iterate the
slot table instead of naming `runner`.
Protocol version 6. 97/97 unit tests; freestanding e2e 130-139 and 332 green.
0 commit comments