Reserved-board theme trial procedure (source checkpoint)
This procedure is for the sole board/serial operator after an integrated image
has been built and installed. The initial helper completed a reserved-board dark/light activation and metadata restoration on 24 September 2026. Its immediate restored capture preceded the managed Foot follower’s next one-second poll; the helper now waits 1.25 seconds before each static capture. This is a capture settling allowance, not latency proof. Reviewed board records are linked as they are committed.
python3 tests/test_handheld_theme_trial.py exercises its failure recovery
against host fakes. It neither proves physical touch nor runs a performance
workload. OpenSpec theme tasks 5.3–5.5 remain open.
Stage tools/handheld-theme-trial.py, tools/theme_transaction.py,
tools/theme_preferences.py, tools/app_appearance.py, and
docs/evidence/omarchy-themes/trial-workload-v1.json together in a private
board directory. Run as the shell user inside the active Wayland
session with its XDG_RUNTIME_DIR and WAYLAND_DISPLAY. The operator retains
the board reservation and normal system rollback mechanism throughout.
Create a private candidate manifest from the installed image, not a worktree guess. Its exact fields are:
{
"schema": 1,
"source_revision": "40 lowercase Git hex digits for the installed source",
"system": "/nix/store/EXACT-nixos-system-nixos-...",
"theme_command": "/nix/store/EXACT-handheld-theme-command/bin/k230-theme",
"capture_command": "/nix/store/EXACT-grim/bin/grim",
"default_generation": "/nix/store/EXACT-handheld-theme-default/generations/0d16475245f13b3d7d3f036f",
"state_root": "/home/shell/.local/state/omarchy/current",
"rust_socket": "/run/shell/k230-shell-rust-appearance.sock",
"deck_socket": "/run/shell/k230-card-appearance.sock",
"workload": {
"id": "cards-shade-static-v1",
"sha256": "b9b330e66cbbd694839e8096d9ff626d66e3b7c737376b6d107e2a218947f195",
"artifact": "/run/shell/theme-trial-tools/trial-workload-v1.json"
},
"themes": {"dark": "catppuccin", "light": "catppuccin-latte"}
}
Replace every EXACT value with the realized store path. system must equal
readlink -f /run/current-system. Include an optional community theme name
only after an unchanged clone is staged; that name stays in the private
candidate, while the public result records only the role and opaque IDs.
Stage trial-workload-v1.json beside the private trial tools and verify its
listed SHA-256. The helper checks the artifact bytes before touching theme
state, then repeats one public ID/hash for baseline and all themed arms. It does not fabricate CPU,
RSS, latency, or budget results. The manifest may contain a private clone
name, so keep it outside the public evidence tree.
With a fresh public output directory and a fresh private raw directory under
the shell user’s XDG_RUNTIME_DIR, run:
python3 tools/handheld-theme-trial.py \
--candidate-manifest /run/shell/theme-candidate.json \
--output /run/shell/theme-evidence-UNIQUE \
--raw-private-dir "$XDG_RUNTIME_DIR/k230-theme-trial-UNIQUE"
The helper refuses a non-RISC-V host, the wrong installed system, an existing
output directory, unpinned commands, or a raw directory outside the private
runtime. It calls the installed k230-theme list/preview/activate JSON
interface and records only schema, role, public generation/theme/background
IDs, arm identity, bounded status, timestamp, and native capture hashes in
result.json. It never copies command stdout/stderr, user clone paths, SSIDs,
notifications, or screenshot pixels into the public directory. Original PNGs
and recovery.json remain mode-0600 under the private raw directory. Review
images there before selecting any non-sensitive capture for publication.
finally restores the preceding active generation, wallpaper preference
bytes and app appearance pointer. If no active generation existed, both
receivers are asked to restore their pinned default and the active pointer is
removed. A failed acknowledgement leaves restoration: "FAILED" in the
fixed result; do not claim recovery. If the process is interrupted before
finally, use the private recovery record while the same image and session
are still active:
python3 tools/handheld-theme-trial.py \
--candidate-manifest /run/shell/theme-candidate.json \
--restore-private-dir "$XDG_RUNTIME_DIR/k230-theme-trial-UNIQUE"
After restoration, compare the reported restored generation with the saved
baseline and confirm the normal shell/launcher still respond. Keep raw
transport and unreviewed PNGs outside Git. The result’s
physical_observation: "UNVERIFIED" intentionally requires a separate
operator note, panel capture review, and real-finger/video evidence before
task 5.3 can be checked. A killed process has no independent watchdog in this
checkpoint, so the operator must run the explicit recovery command.
Host command on source:
python3 tests/test_handheld_theme_trial.py
# 5 tests passed: prior/default restoration, failed rollback visibility,
# manifest and changed workload identity rejection.
Background resource workload (source checkpoint)
The new --workload backgrounds option requires the normal candidate fields
plus a private background_trial object. Resolve both opaque background IDs
using k230-theme preview THEME_ID --json against the installed source;
pin one supported still and one video choice. Do not publish source paths or a
user theme name from the private candidate. A representative shape is:
"background_trial": {
"duration_seconds": 8,
"interval_seconds": 0.25,
"choices": {
"static": {"theme_name": "catppuccin", "origin": "builtin", "background_id": "24 lowercase hex digits"},
"video": {"theme_name": "catppuccin", "origin": "builtin", "background_id": "24 lowercase hex digits"}
}
}
The host sampler reads only shell.service and shell-ui.service cgroup CPU,
memory and their processes’ RSS at a bounded interval. A decoder started by
the persistent Rust wallpaper client belongs to shell-ui.service; an ordinary
mpv application is not a wallpaper decoder. The fixed result labels sampled
peaks and CPU time, including the baseline arm. A changed generation, wrong
media kind, missing cgroup or incomplete RSS fails the trial and runs the
normal restoration path. These counters do not establish decoder throughput,
Wayland presentation or panel photons.
The currently installed client rejects video wallpaper, so this workload
still fails closed at measure-video until a real Rust wallpaper decoder and
private status writer are installed. The sampler requires a generation- and
selected-asset-matched mode-0600 status file under XDG_RUNTIME_DIR, a stable
decoder PID, at least two decoded/submitted/frame-callback increments during
the resource interval, and two distinct native captures retained only in the
private raw directory. A host fake passing that schema is not a video
pass. The operator must review the raw changing image region; Wayland frame
callbacks and full-screen capture differences do not alone prove panel
presentation. Physical CPU/frame/card budgets still require the reserved-board
workload and trace; task 5.4 remains open.