KN-86 Legacy Terminal — Pi Bench-Test Plan
Purpose
Section titled “Purpose”This document defines the validation matrix that gates un-stubbing the binary-install steps in
tools/sd-provision/pi-gen-stages/stage-kn86-runtime/legacy-terminal/00-install-legacy-terminal.sh.
The install script currently exits 0 without installing any binaries (all apt-get and DOSBox
Staging build steps are commented-out TODO(bench-bring-up) blocks). That stub posture was
deliberate: the image must build and flash cleanly before the Pi hardware target is validated.
Running this plan is the gate that turns the stubs into real install commands.
Three upstream documents govern scope and pass/fail thresholds:
- ADR-0021 §11 — image-build footprint soft cap of 200 MB for the entire
/opt/legacy-terminal/subtree. The current estimate is ~50 MB (binaries + DOSBox + source archives). Crossing 200 MB triggers a revisit of the(rest)/2rootfs split in ADR-0011 §SD partition layout. docs/device/os/system-image-build.md§“Base Debian release pinning” — the kernel version and Raspberry Pi OS Lite (arm64) trixie release hash (perdocs/adr/ADR-0026-pi-os-trixie-base-pin.md) are pinned intools/sd-provision/pi-gen-stages/pi-gen-pin.env. The pin must be in place before this plan runs; any kernel bump after the test requires re-running the full matrix.- ADR-0011 §Risks #1 — the 50-cycle USB-MSC update stability regression. Legacy Terminal adds a non-trivial rootfs subtree; the 50-cycle test confirms the added footprint does not disturb the A/B slot-swap path.
Pre-conditions
Section titled “Pre-conditions”All of the following must be true before the first test row is executed:
-
Kernel pinned.
tools/sd-provision/pi-gen-stages/pi-gen-pin.envrecords an explicit Raspberry Pi OS Lite (arm64) trixie kernel version (e.g.,6.x) and the pi-gen commit hash. Record these in the Sign-off section at the bottom of this document. -
pi-gen-pin.env in effect. The image build that produced the SD under test was run with
pi-gen-pin.envsourced, not from a floatinglatestrelease. The bench engineer verifies this by checking thepi-gen-pin.envhash at the bottom of this document against the hash of the file used at build time. -
Pi Zero 2 W bench rig available. Device configured with HDMI + USB keyboard for interactive validation (non-kiosk mode); a USB serial console adapter is recommended but not required for most rows. Production-mode boot (kiosk mode) is not used for this plan — dev mode is acceptable for the bench session.
-
USB-MSC bench tooling from ADR-0011 ready. The 50-cycle stress test script from ADR-0011 §Risks #1 must be on-hand and verified to work against a baseline image before the Legacy Terminal subtree is added. Running it against baseline first establishes that any failure in the regression row (row 9) is attributable to the Legacy Terminal delta, not a pre-existing flakiness in the test infrastructure.
-
00-install-legacy-terminal.shun-stub patch prepared. Before running this plan the bench engineer should have a draft PR un-stubbing the install script (replacing theTODO(bench-bring-up)blocks with realapt-getand DOSBox Staging build commands). The plan validates that draft; it is not run against the stub.
Test Matrix
Section titled “Test Matrix”Each row is a pass/fail gate. All rows must pass before the un-stub PR is merged.
Row 1 — DOSBox Staging build verify
Section titled “Row 1 — DOSBox Staging build verify”What. Confirm that the meson + ninja DOSBox Staging build produces a working dosbox-staging
binary on aarch64 Raspberry Pi OS Lite (arm64) trixie inside the pi-gen chroot.
Procedure.
- In the pi-gen chroot (or on the bench Pi after flashing the un-stub image), run:
dosbox-staging -version
- Confirm output includes the DOSBox Staging version string (e.g.,
DOSBox Staging, version 0.82.0). - Confirm the binary path resolves to
/opt/legacy-terminal/bin/dosbox-staging(or the symlink registered in the manifest) — not a system-wide install path.
Pass criteria. dosbox-staging -version exits 0, prints the correct pinned version, binary
is at the expected path.
Failure mode. If the meson build fails: check that libsdl2-dev and libsdl2-net-dev are
present in the chroot. If the dynrec ARM64 core causes a compile error: fall back to
-Dcore=dynrec (generic); re-measure perf in row 1b (performance smoke, out-of-scope for Sprint
1). If DOSBox Staging is later available in the trixie arm64 package archive at the pinned
version: prefer apt-get install dosbox-staging over the build-from-source path to reduce
image-build time; re-run this row to confirm.
Row 2 — NetHack run verify
Section titled “Row 2 — NetHack run verify”What. Confirm that apt install nethack-console succeeds in the chroot and that the
installed binary starts and exits cleanly on the bench Pi.
Procedure.
- Run
nethack -X(no-color mode) from the terminal. - Confirm the intro screen appears (version banner, player character setup prompt).
- Press
Escapeor answer startup prompts to exit; confirm process exits 0. - Confirm the binary resolves through
/opt/legacy-terminal/bin/nethack(symlink to/usr/games/nethack-consoleor equivalent).
Pass criteria. NetHack launches, displays the terminal-mode intro, exits cleanly. This is a “does it boot” check only — no gameplay validation.
Failure mode. If the package name differs on the pinned trixie release (e.g.,
nethack-x11 instead of nethack-console): update the install script and this document to name
the correct package. If the package is not available in the pinned archive: pin to the explicit
version and source-build; update TODO(bench-bring-up) comment in the install script accordingly.
Row 3 — Umoria run verify
Section titled “Row 3 — Umoria run verify”What. Confirm that apt install umoria (or source build) produces a working umoria binary
and that it starts and exits cleanly.
Procedure.
- Run
umoriafrom the terminal. - Confirm the Umoria intro / character selection screen appears.
- Quit cleanly (typically
Qthen confirm at the prompt); confirm exit 0. - Confirm the binary resolves through
/opt/legacy-terminal/bin/umoria.
Pass criteria. Umoria launches, shows the intro, exits cleanly.
Failure mode. If umoria is not packaged in the pinned trixie archive: build from the
GitHub source at the version pinned in pi-gen-pin.env; update the install script accordingly.
Row 4 — Dopewars run verify
Section titled “Row 4 — Dopewars run verify”What. Confirm that apt install dopewars produces a working binary and that it starts and
exits cleanly in curses (no-network) mode.
Procedure.
- Run
dopewars --no-networkor the equivalent curses-mode invocation (checkman dopewarsfor the correct flag on the packaged version). - Confirm the curses UI appears (trade-screen or intro).
- Quit cleanly; confirm exit 0.
- Confirm the binary resolves through
/opt/legacy-terminal/bin/dopewars.
Pass criteria. Dopewars launches in curses mode, displays the trade interface, exits cleanly.
Failure mode. If dopewars requires a network connection to start: look for --local,
--player-name, or equivalent flags that bypass the network handshake. Document the exact
invocation in dopewars.manifest (the launch_args field) before closing this row.
Row 5 — Save state on /home/shared/legacy-terminal/saves/
Section titled “Row 5 — Save state on /home/shared/legacy-terminal/saves/”What. Confirm that per-title save state lands on the p6 partition (/home/shared/) and
survives an nOSh-style session boundary.
Procedure.
- Launch NetHack via the Legacy Terminal launcher (or directly from the bench terminal for this pre-launcher test).
- Save the game (in-game
Scommand) and exit. - Confirm a save file exists under
/home/shared/legacy-terminal/saves/nethack/. - Run
stat <save-file-path>and confirm the device field matches the p6 block device (/dev/mmcblk0p6or equivalent labelshare). - Launch NetHack again; confirm the save is offered for resumption.
Pass criteria. Save file exists in the expected path on p6; stat confirms the correct
device; resumed game loads the saved state.
Failure mode. If NetHack writes its save to a path outside /home/shared/: check
nethack.manifest save_dir field and the NetHack OPTIONS=savedir:... configuration. The
manifest parser (ADR-0021 §3, implemented in kn86-emulator/src/legacy_terminal/manifest.c) maps
save_dir to the appropriate $HOME or OPTIONS injection before launch — confirm that mapping
is correct for the packaged version of NetHack.
Row 6 — Side-load discovery
Section titled “Row 6 — Side-load discovery”What. Confirm that the launcher (once implemented post-Sprint 1) lists user-supplied executables from the sideloads directory.
Procedure.
- Drop a placeholder file named
TEST.EXEinto/home/shared/legacy-terminal/sideloads/. - Open the Legacy Terminal launcher menu (SYS+INFO×4 gesture from Bare Deck).
- Confirm that
TEST.EXEappears as a launchable entry under theSIDE-LOAD...item. - Confirm that a file with an unsupported extension (e.g.,
TEST.BIN) does not appear.
Pass criteria. TEST.EXE appears in the side-load list; TEST.BIN does not.
Note. This row depends on the launcher UI (post-Sprint 1 work). If the launcher is not yet implemented at the time this plan is executed, defer this row to Sprint 2 bench validation and note the deferral in the sign-off.
Failure mode. If the launcher’s sideloads/ scan misses files: check the manifest parser’s
side-load discovery path and file extension filter.
Row 7 — Audio mute confirmation
Section titled “Row 7 — Audio mute confirmation”What. Confirm that the Pico 2 PSG is silenced during a Legacy Terminal session and resumes on exit, per ADR-0021 §8 (audio policy v1: mute).
Procedure.
- Start a session with nOSh running normally (a PSG-active state — either a cartridge loaded or the bare-deck attract mode if it emits PSG tones).
- Enter the Legacy Terminal launcher via the SYS+INFO×4 gesture.
- Expected: PSG audio stops. If a bench audio probe is available per
docs/software/api-reference/grammars/coprocessor-protocol.md(thePSG_SILENCEframe monitoring path), confirm receipt of thePSG_SILENCEUART frame from the Pi to the Pico 2. If no bench probe is available: speaker-listen (confirm silence at the speaker). - Exit the Legacy Terminal launcher (or allow a title to exit).
- Expected: PSG audio resumes. Confirm receipt of
PSG_RESUMEframe, or speaker-listen for audio restart.
Pass criteria. Audio silences on launcher entry, resumes on exit. No PSG bleed during the Legacy Terminal session.
Failure mode. If PSG does not silence: check that coproc_send_psg_silence() is called in
the launcher’s session-entry path (see kn86-emulator/src/legacy_terminal/launcher.c). If PSG
does not resume: check that PSG_RESUME is sent in the session-exit path (both clean exit and
SIGCHLD-triggered reclaim). If neither frame is visible on the UART: verify the UART baud rate
(1 Mbps) and Pico 2 firmware reception using the coprocessor-protocol.md bench probe procedure.
Row 8 — Footprint check
Section titled “Row 8 — Footprint check”What. Confirm that the installed /opt/legacy-terminal/ subtree fits under the ADR-0021 §11
soft cap of 200 MB (target: ~50 MB).
Procedure.
- After a full un-stub image build (all binaries installed, DOSBox Staging built, source archives
downloaded):
du -sh /opt/legacy-terminal/
- Record the measured value in the Sign-off section below.
Pass criteria. du -sh /opt/legacy-terminal/ reports under 200 MB. Ideally under 60 MB
(current estimate: ~50 MB). If the measurement is between 60 MB and 200 MB: log the breakdown
by subdirectory (bin/, share/, src/, titles/) and file a Notion task to investigate
oversized components.
Failure mode. If footprint exceeds 200 MB: revisit the (rest)/2 rootfs split in ADR-0011
§SD partition layout per ADR-0021 §11. Most likely cause is a large DOSBox Staging source archive
or unexpected game data directories. Strip build-time intermediate artifacts from src/ before
measuring.
Row 9 — 50-cycle USB-MSC regression
Section titled “Row 9 — 50-cycle USB-MSC regression”What. Re-run the ADR-0011 §Risks #1 50-cycle USB-MSC update stability test against the image that includes the Legacy Terminal subtree, to confirm that the added rootfs footprint did not disturb the A/B slot-swap path.
Procedure.
- Using the bench tooling established in the ADR-0011 pre-condition: run 50 complete A→B and B→A slot-swap cycles on the Legacy Terminal image.
- After each cycle: confirm that
/home/shared/legacy-terminal/saves/and/home/shared/deckstate.binare intact (the flasher never touches p6). - Confirm that the Legacy Terminal binaries at
/opt/legacy-terminal/bin/are intact in the active slot after each cycle.
Pass criteria. All 50 cycles complete without corruption to p6 or the active slot’s
/opt/legacy-terminal/ tree. Same pass threshold as the baseline ADR-0011 test.
Failure mode. If cycles fail: isolate whether the failure is in the A/B swap logic (pre-existing, report to the update-system track) or in the Legacy Terminal subtree specifically (file path conflict, fstab entry conflict, overlayroot interaction). Re-run baseline without Legacy Terminal installed to determine attribution.
Pass/Fail Criteria — Summary
Section titled “Pass/Fail Criteria — Summary”| Row | Description | Gate condition |
|---|---|---|
| 1 | DOSBox Staging build | Binary at expected path, -version exits 0 |
| 2 | NetHack run | Launches, displays intro, exits 0 |
| 3 | Umoria run | Launches, displays intro, exits 0 |
| 4 | Dopewars run | Launches in curses mode, exits 0 |
| 5 | Save state on p6 | Save file on /home/shared/, stat confirms p6 device |
| 6 | Side-load discovery | TEST.EXE listed, unsupported ext not listed |
| 7 | Audio mute | PSG silent during session, resumes on exit |
| 8 | Footprint check | du -sh /opt/legacy-terminal/ < 200 MB |
| 9 | 50-cycle USB-MSC regression | All 50 cycles pass, p6 intact |
All 9 rows must pass (or row 6 explicitly deferred with a Sprint 2 tracking task) for the un-stub PR to be considered greenlit.
Failure Modes Summary
Section titled “Failure Modes Summary”If a row fails, the default disposition is:
- Kernel / package version issue — update the pin in
pi-gen-pin.envand rebuild the test image. - Package unavailable in pinned archive — add a source-build step to the install script; update this document with the build procedure.
- Footprint overage — file a Notion task; investigate per-component breakdown before revising the ADR-0011 partition layout.
- 50-cycle regression — halt un-stub; open a blocker against the update-system track before proceeding.
- Audio / UART issue — check the coprocessor UART path per
coprocessor-protocol.mdbefore modifying any nOSh source code.
Do not merge the un-stub PR until all blocking rows pass. Row 6 (side-load discovery) may be deferred to Sprint 2 with explicit tracking.
Sign-off
Section titled “Sign-off”To be filled in by the bench engineer at the time the plan is executed:
| Field | Value |
|---|---|
| Date executed | — |
| Bench engineer | — |
| Kernel version | — |
| Raspberry Pi OS Lite (arm64) trixie release | — |
| pi-gen-pin.env SHA256 | — |
du -sh /opt/legacy-terminal/ measured footprint | — |
| All rows pass? (Y / N / partial — list deferred rows) | — |
| Notes | — |