evidence · 7.2 KiB

trial-operator.md

Committed at docs/evidence/omarchy-themes/trial-operator.md. This is what grounds the requirements that cite it.

Open raw source

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.