VM campaign — every profile whole on Parrot 7.3 and Debian 13, and all twelve on one machine¶
Run overnight 2026-09-05 → 06 with scripts/vm_campaign.py at engine
c5fd0b4 and 78947f2 (both on main; the one commit between them is
documentation). Three campaigns:
- Parrot 7.3, each profile from the clean snapshot (
--whole-profiles --reset-each): sixteen profiles, the VM reverted before every one. - Debian 13, the same shape: sixteen profiles.
- Parrot 7.3, twelve profiles cumulatively on one machine
(
--reset-first): the snapshot reverted once, thenantenna,digital-modes,electronics,listening,logging,morse,packet,propagation,satellite,sdr,stationandrfidinstalled in that order onto the same system. This is what an operator who wants everything actually does, and it is the first time the harness has done it.
The vm-campaign-ubuntu.md page recorded the 2026-09-03 Parrot passes that
found D-038 (five profiles dead at the first apt command) and the Debian 13
pass that found nothing. This page is the re-verification at the current
engine, after D-038, D-039, D-040 and the tree/launcher/group re-probes
(commit c5fd0b4) landed, plus the cumulative shape.
Standing¶
| Target | Campaign | Result |
|---|---|---|
| Parrot 7.3 | 16 profiles whole, each from clean | 14 installed+confirmed, 0 failed, 2 stopped at a consent gate |
| Debian 13 | 16 profiles whole, each from clean | 14 installed+confirmed, 0 failed, 2 stopped at a consent gate |
| Parrot 7.3 | 12 profiles cumulatively on one machine | 12 installed+confirmed, 0 failed; 31.5 minutes wall-clock |
"Confirmed" is the engine's own bar: every command completed and the re-probe found the software (D-031) — a binary executable at its path, a package at a version, a launcher on the operator's PATH, a tree marker where a tree install claims to have put one, a group membership in the group database. The count of checks per profile is in the table below, and the reports carry every one by name.
The two consent gates are the campaign working as designed, not gaps
(D-021): editors stops at the D-040 fingerprint prompt for the
microsoft-vscode repository, rf-research at the authorization
affirmation. The campaign affirms neither, on a non-interactive stdin, and
records the prompt text it was shown.
Zero failures across 40 whole-profile installs is the headline. The
last Parrot whole-profile sweep before these (2026-09-03, engine
4616dde) failed six of fifteen, every one at its first fetch with a
404: the clean snapshot was four days old and its apt lists still named a
glib2.0 revision the pool had moved past. That was the snapshot's age,
not the catalog's, and the harness now refreshes the lists once per
prepare before anything is measured (commit 7cc03a9); the reports here
record the InRelease dates it measured against. None of the six recurred.
Every profile, three ways¶
Seconds are the harness's wall clock for the profile, from plan to the re-probe's last answer. Checks are what the re-probe asked and found.
| Profile | Parrot, from clean | Parrot, cumulative | Debian 13, from clean |
|---|---|---|---|
antenna |
11 checks, 56 s | 11 checks, 53 s | 12 checks, 53 s |
digital-modes |
55 checks, 603 s | 52 checks, 590 s | 57 checks, 533 s |
editors |
consent gate (D-040), 1 s | — | consent gate (D-040), 1 s |
electronics |
16 checks, 93 s | 9 checks, 47 s | 19 checks, 111 s |
listening |
46 checks, 177 s | 33 checks, 140 s | 51 checks, 155 s |
logging |
25 checks, 414 s | 14 checks, 381 s | 29 checks, 460 s |
morse |
20 checks, 45 s | 15 checks, 27 s | 23 checks, 40 s |
packet |
36 checks, 51 s | 25 checks, 37 s | 40 checks, 52 s |
propagation |
25 checks, 546 s † | 15 checks, 483 s | 30 checks, 503 s |
rf-research |
consent gate (D-021), 2 s | — | consent gate (D-021), 2 s |
rf-security |
3 checks, 12 s | — | 11 checks, 23 s |
rfid |
12 checks, 110 s † | 7 checks, 102 s | 19 checks, 81 s |
satellite |
5 checks, 79 s | 2 checks, 13 s | 5 checks, 88 s |
sdr |
12 checks, 96 s | 8 checks, 10 s | 29 checks, 162 s |
station |
10 checks, 13 s | 5 checks, 9 s | 10 checks, 42 s |
workstation |
2 checks, 6 s | — | 5 checks, 5 s |
| Total, confirmed profiles | 2301 s | 1892 s | 2308 s |
† Re-run alone on a quiet VM; see "One row that was not evidence" below.
The cumulative pass is cheaper than the sum of its parts, and the
checks column says why: sdr needed 12 checks and 96 seconds from a clean
snapshot but 8 and 10 seconds after listening had already installed
gnuradio, gqrx-sdr, gr-osmosdr and soapysdr-tools; satellite fell
from 79 to 13 seconds once gnuradio, satdump and libhamlib-utils were
already there. A profile's plan only claims what it installed, so its re-probe
only asks about that — which is idempotency being measured rather than
asserted. Twelve profiles onto one Parrot machine in 31.5 minutes is the
number an operator can be told.
Debian 13 asks more of itself than Parrot does — sdr 29 checks
against 12, rf-security 11 against 3 — because Parrot's baseline already
carries much of the SDR and security tooling as part of the distribution.
That is the D-022 coexistence rule from the other side: what the target
already has, the engine leaves alone and does not claim.
What the re-probes found, by kind¶
The commit c5fd0b4 re-probes were measured on Debian 13 and falsified on
the guest (YAAC.jar removed by hand made the tree check red, naming the
path; restored, green) before this campaign ran. All three kinds ran here
on both targets:
| Check | Where | What it confirmed |
|---|---|---|
| tree marker | mshv |
bin/MSHV_x86_64 present under /usr/local/share/hammunition/mshv |
| launcher | mshv, ais-catcher, hamclock-next, openhamclock |
an executable wrapper in the operator's ~/.local/bin, and for mshv the working directory it runs in |
| group | packet (dialout), rf-security (wireshark) |
the operator's membership in the group database — present after the run, effective at next login |
| binary | 22 built units | the executable at its installed path — fldigi, wsjtx, js8call, glfer, xwefax, flaa, coil64, gsmc, AIS-catcher, acarsserv, fllog, flnet, cwwav, flwkey, ibp, ardopcf, linbpq, qtsoundmodem, qttermtcp, flcluster, qgrid, hamclock-next |
digital-modes is where the time goes on every target — fldigi, WSJT-X
and MSHV are built from source in one run, nine to ten minutes — followed by
propagation (HamClock's two clients, openhamclock through the node
backend) and logging (the fllog/flnet builds and the Qt 6 WebEngine
development set qlog's build pulls in). Nothing else is over three
minutes.
One row that was not evidence¶
The Parrot from-clean sweep's propagation row first read exit 255 after
154 seconds, with no output and no packages recorded. It was not the
engine: a second campaign had been chained on that sweep's report file,
which the harness rewrites after every unit and which therefore already
existed, so the chained run started an hour early and reverted the Parrot
snapshot under the running sweep. rfid, the next row, could not be placed
on either side of that revert because rows carried no clock. Both were
re-run alone on a quiet VM (--reset-each, engine 78947f2) and confirmed,
and the contaminated cumulative report was deleted rather than kept.
Two things came out of it. vm_campaign.py now writes a started_at UTC
timestamp on every row, so an overlap is decidable from the record; and
docs/contributing/vm-testing.md names the rule: wait on the harness
process, never on its report, and one VM runs one campaign at a time.
The GUI smoke lane over the cumulative machine¶
With all twelve profiles on the one Parrot system, scripts/vm_gui_smoke.py
launched every desktop entry the catalog's units own under Xvfb: 52
entries across 50 units — 45 alive at the timeout, 2 exited clean, 0
suspect, 5 failed. Host evidence
gui-smoke-parrot-cumulative-2026-09-05.txt.
The five failures are for a human eye, not the engine's. None is an install defect; each is a question of whether the entry belongs in a menu:
| Entry | What it printed | Reading |
|---|---|---|
ais-catcher web launcher |
cannot open display :99 |
the launcher opens a browser; nothing under Xvfb answers |
nec2c |
its usage text, exit 255 | a command-line tool that ships a desktop entry |
pcsc-tools (gscriptor) |
Chipcard::PCSC … Service not available |
needs pcscd running; the VM has no reader and no daemon |
psk31lx, qrq |
Error opening terminal: unknown |
curses programs; Terminal=true entries have no terminal under Xvfb |
The two that exited clean before the timeout: direwolf with no
configuration file, and twpsk with no audio device (pa_simple_read
failed) — both correct behaviour for a headless VM and both worth knowing
when reading a smoke verdict.
That lane hung twice on this run, for a day, on gpredict and satdump:
timeout(1) had ended the child and the child's orphan still held the
lane's stderr pipe. The fix (the lane owns the session and kills it at the
deadline) re-ran the same 52 entries unattended in 9.5 minutes to the same
verdicts; it is PR #43 with its own evidence file.
Left with the maintainer¶
- The five smoke failures above are a menu-curation question (D-036), not
an install one.
nec2c's entry and the two curses entries are Debian's own packaging;gscriptorwantspcscddeclared or enabled when a reader is present; the AIS web launcher is ours and could say so when no browser can open. rf-securityon Parrot confirmed three checks in twelve seconds because the distribution already ships nearly all of it. The profile page should say that a Parrot operator getswiresharkgroup membership and little else from it, which is the honest claim.
Raw reports (.md, .log, .evidence.jsonl with per-row timestamps)
stay on the host under ~/.local/state/hammunition-campaigns/, named
profiles-parrot-2026-09-05, profiles-parrot-rerun-2026-09-05,
profiles-parrot-cumulative-2026-09-05 and profiles-debian13-2026-09-05.