Files
komorebi/docs/dev/build-and-test.md
T
LGUG2Z 77289f6b20 docs(dev): flake-checks.md and the nix commands of build-and-test.md
docs/dev/flake-checks.md records why the evaluation of the checks needed more than
the host has (about 0.55 GB per VM suite and 0.4 GB per NixOS system of the module
check, nothing shared), the sets and what is in each, how they are exposed
(checkSets, checkMembers, defaultCheckSets in nix/checks.nix), the alternatives
rejected, what was measured with the sets (nix flake check --no-build 4.54 GB / 33 s
on one system, 6.55 GB / 40 s --all-systems; each set alone from 0.2 GB for the cheap
ones to 11.6 GB for linux-nixos-eval), and why windows-nextest and macos-nextest ran
no test.

build-and-test.md gets the commands for one set, the default and one member and
loses windows-nextest; flake.md, docs/linux/CONTRIBUTING.md, docs/linux/dev/vm-tests.md,
the comment of nix/linux/tests/vm/default.nix and the CI step of CUTOVER-PLAN.md name
the new places (checkSets, checkMembers, legacyPackages.<system>.vm.NAME) instead of the
placeholder heavyChecks and checks.<system>.vm-NAME. Not run: the docs build.
2026-11-05 15:03:27 -08:00

17 KiB

Build and test, per platform

Status: the nix commands name the outputs of the one root flake (flake.md has the old-name to new-name table and the layout). Commands marked "ran" were run on the Linux host at the revision that made the flake; the rest are documented from flake.nix, the justfile, the Cargo manifests or the e2e README. macOS cannot be built or run on Linux; Linux can only type-check it.

The map of the repository is ARCHITECTURE-UNIFIED.md. Package names in this repository (cargo metadata --no-deps, ran): komorebi (the daemon, komorebi-daemon/), komorebic, komorebi-client, komorebi-bar, the libraries komorebi-windows, komorebi-linux, komorebi-macos, the shims komorebic-linux, komorebic-macos, komorebi-client-linux, komorebi-client-macos, komorebi-bar-macos, and komorebi-backend, -bar-core, komorebic-core, -collections, -config, -core, -protocol, -settings, -transport.

0. General rules

  • Platform is chosen by cfg(target_os): cargo build -p komorebi -p komorebic -p komorebi-bar builds the program of the OS you are on. The Windows daemon is only buildable for the Windows target (cross build in section 1); on Linux -p komorebi is the KDE daemon, on macOS the macOS one.
  • Never put komorebic and komorebic-linux/komorebic-macos in one command (same binary name). The shims stay until the cutover.
  • Without a .git (a jj workspace) the build script of the macOS and Linux crates needs COMMIT_HASH=dev. Do not run a plain nix flake check on the root flake (it boots the VM suites); name the check, or run nix flake check --no-build --all-systems for the evaluation only.
  • Text edits under komorebi-linux/, komorebi-hotkeys/ or komorebi-macos/ change only that platform's nix derivations (each platform builds from its own filtered source, nix/workspace-src.nix); a docs-only edit elsewhere changes none, because the commit stamp is a constant in the checks (COMMIT_HASH=nix-check) and only the native default and windows-default packages carry the real commit.
  • Heavy builds and e2e should not run at the same time as a timing-sensitive e2e: the Windows commands scenario is the most sensitive (section 6).

Developer tools

tools/ (README: tools/README.md) holds the helper scripts, runnable from any jj workspace of the repository; none of them writes to the source tree.

Command Use
tools/fast-check [--list] [--range | --since REV] only the checks the touched paths need; warm in seconds (Windows clippy 8-9 s, KDE 1-3 s, macOS 2-3 s)
tools/e2e-needed [--since REV] does this diff change the Windows e2e binaries (NO carries a previous passing e2e over)
tools/kde-closure-check the Linux source filter list (nix/linux/root-crates.json) matches the Linux cargo closure
tools/mac-check.sh macOS type-check on Linux (fake C compiler tools/cc-fake.sh)
tools/trim-target, tools/gate-lock, tools/lite-env disk trimming, a heavy-gate lock, debug-info-off builds

The persistent target directories are under $FAST_CHECK_SCRATCH (default ~/.cache/komorebi-fast-check).

1. Windows (cross build from Linux via nix)

Binaries (the flake cross-compiles to x86_64-pc-windows-msvc with an xwin SDK):

nix build .#windows-komorebi .#windows-komorebic .#windows-komorebi-bar   # result*/bin/*.exe; also windows-komorebic-no-console, -komorebi-gui, -komorebi-shortcuts, -komorebi-testwin
nix build .#windows-default                                  # windows-komorebi-full: everything, with the real commit stamp

Checks (crane; the clippy one is the pre-landing gate, about 3.5 min warm deps; the dependency derivation is shared by all of them):

nix build -L --no-link .#checks.x86_64-linux.windows-clippy
# (there is no windows-nextest: the Windows crates' tests run on Windows, `cargo test` of .github/workflows/windows.yaml)
nix build -L --no-link .#checks.x86_64-linux.windows-fmt .#checks.x86_64-linux.windows-toml-fmt .#checks.x86_64-linux.windows-deny
nix build -L --no-link .#checks.x86_64-linux.windows-e2e-tests # the Python of the e2e (pytest), no guest needed

The checks are in sets (docs/dev/flake-checks.md): one set alone builds without the others being evaluated.

nix build -L --no-link .#checkSets.fmt .#checkSets.deny      # a set (a linkFarm of its members); also linux-lint, linux-test, windows-lint, ...
nix build -L --no-link .#checkSets.cheap                      # what `nix flake check` runs (defaultCheckSets in nix/checks.nix)
nix build -L --no-link .#checkSets.vm-fast                    # the heavy sets: vm-fast, vm-slow, linux-nixos-eval, linux-demo
nix build -L --no-link .#checkMembers.vm-fast.vm-kwin         # one member of any set (what a heavy check is called)
nix flake check --no-build                                    # evaluates the default sets and every other output

Quick loop without nix builds (what tools/fast-check runs; clippy of the Windows tree from the nix dev shell):

nix develop --command cargo clippy --locked --all-targets -- -D warnings

On a Windows machine itself: just build / just install (the root justfile, PowerShell), or cargo build -p komorebi -p komorebic -p komorebi-bar --locked.

Platform-neutral crates test natively on Linux, with no cross toolchain: cargo test -p komorebi-protocol -p komorebi-config -p komorebi-collections -p komorebi-core -p komorebi-backend -p komorebi-settings -p komorebi-transport -p komorebic-core -p komorebi-bar-core -p komorebi-layouts -p komorebi-scrolling.

2. KDE Plasma (native Linux)

From the repository root (a C compiler is needed: nix shell nixpkgs#gcc -c, or nix develop .#native):

cargo check -p komorebi-linux -p komorebi -p komorebic                         # ran, 27 s with a warm target
cargo test  -p komorebi-linux --lib                                            # the daemon's unit tests (294 passed at the step-8 measurement)
cargo test  -p komorebi-linux --test schemas -- --test-threads=1               # the schema oracle; shares a pid-only socket path, keep one thread
cargo test  -p komorebi -p komorebic -p komorebi-client -p komorebi-hotkeys    # daemon-binary, CLI and client tests (tests/linux_*.rs)

A single test file: cargo test -p komorebi-linux --test NAME (the files are in komorebi-linux/tests). The -p komorebi --lib that older notes use is the thin binary package now: the unit tests are in komorebi-linux.

Run tools/kde-closure-check (see tools/README.md) after any dependency change in the KDE crates or the crates they use: the Linux source takes only the crates listed in nix/linux/root-crates.json.

KDE nix checks (no VM), prefixed linux-:

nix build -L --no-link .#checks.x86_64-linux.linux-clippy
nix build -L --no-link .#checks.x86_64-linux.linux-nextest
# also linux-{fmt,toml-fmt,deny,doc,bridge-js,schema-fresh,nix-options-validation,nixos-module-eval,
# keybindings-fixtures,plasma-guests-eval}
nix build -L .#komorebi .#komorebic            # the native packages of the Linux system

just check runs cargo test --workspace, which would build the Windows crates on Linux. Use the commands above; just vm NAME and just nixgen-linux are fine.

KDE VM suites

Each suite under nix/linux/tests/vm/suites/NAME boots NixOS with Plasma and KWin; they need KVM (nested is enough under WSL2; nix run .#wsl2-probe measures it).

just vm NAME                                              # = nix build -L .#legacyPackages.x86_64-linux.vm.NAME
just vm-all                                               # every suite in the order of the flake
nix build -L .#legacyPackages.x86_64-linux.vm.NAME      # the same suite as a test with a `driver`
# the names of each tier as JSON (ran; CI reads it)
nix eval --json .#legacyPackages.x86_64-linux.vmTiers

Tiers (the tier in each suite's default.nix; CI runs fast on every pull request, slow on master):

  • fast: check hotplug commands kwin-restart kwin-events scrolling workspace-rules core-e2e kwin-contract kwin workspace-switch stacks module placement user-maximize run-kde
  • slow: client-geometry restart-survival keys-whkd core-lock keys-sxhkd render-smoke drag-resize rdp features focus-follows-mouse latency keys-engine live-resize lock-sleep look keys-skhd keys-static wallpaper
  • vm-lib (a check, not a suite) runs the unit tests of the VM library; no VM boots.

To run only some steps of a suite: E2E_ONLY=stacks,monocle nix build --impure .#legacyPackages.x86_64-linux.vm.core-e2e -L (a substring of the printed module.function; KFDE_ONLY is the old name). To record a run: KOMOREBI_RECORDER=$(nix build ~/komorebi-recorder#komorebi-recorder --no-link --print-out-paths) nix build --impure .#legacyPackages.x86_64-linux.vm.core-lock -L (the recorder's repository is private; core-e2e and core-lock keep recording-NAME.tar.gz). Details, the library and how to add a suite: docs/linux/dev/vm-tests.md. The suites use a daemon built once with the constant stamp, so a new commit does not rebuild it.

3. macOS

On a Mac (aarch64-darwin), from the repository root (a .git checkout, or COMMIT_HASH=dev in the environment). These are the commands for the Mac Mini; none has been run on a Mac against wip-cand4 unless macos-handcheck.md says so:

cargo build --locked -p komorebi -p komorebic -p komorebi-bar
cargo clippy --locked -p komorebi -p komorebi-macos -p komorebic -p komorebi-client -p komorebi-bar -p komorebi-bar-core --all-targets -- -D warnings
cargo test  --locked -p komorebi-macos -p komorebic -p komorebi-client -p komorebi-bar-core -p komorebi-bar
cargo build --locked --features deadlock_detection -p komorebi          # the feature is forwarded
target/debug/komorebi --version                                          # komorebi 0.1.0 (the macOS version crate)
target/debug/komorebic --help; target/debug/komorebic docgen --output /tmp/docs-mac
target/debug/komorebi-bar --schema | cmp - schemas/macos/schema.bar.json

Never -p komorebic-macos together with -p komorebic (the shims komorebic-macos, komorebi-client-macos and komorebi-bar-macos still build alone). Before any change that touches macOS code, run the unit tests on the Mac first: nothing else can run them. After that walk macos-handcheck.md.

On Linux, macOS can only be type-checked, through a fake C compiler and the target aarch64-apple-darwin: tools/mac-check.sh does it unconditionally, tools/fast-check when macOS files changed (fake compiler: tools/cc-fake.sh); it cannot link or run:

tools/mac-check.sh     # = COMMIT_HASH=dev cargo check --target aarch64-apple-darwin ... --all-targets, CC set to tools/cc-fake.sh

Nix, on a Mac: the macos-* checks (macos-{clippy,fmt,toml-fmt,deny,nextest}, macos-nix-options-validation, macos-darwin-module-validation) and the packages komorebi, komorebic, komorebi-bar of aarch64-darwin. From Linux they can be evaluated only (nix flake check --no-build --all-systems, nix eval), which proves nothing builds.

4. Windows e2e (QEMU guest)

Full text: e2e/platforms/qemu_windows/README.md (building the golden image, every variable). Short form:

E2E_GOLDEN=golden nix run .#e2e-windows -- OUT SCENARIO...      # e.g. OUT tiling focus commands
E2E_GOLDEN=golden KOMOREBI_E2E_SCALE=1.5 nix run .#e2e-windows -- OUT bar   # the komorebi-bar scenario

The app uses this checkout's binaries, built with the constant stamp e2e (so a docs-only commit reuses them); the commit under test is KOMOREBI_E2E_COMMIT (default: the flake revision). To test another commit: build-ref.sh REF bins then KOMOREBI_E2E_BINS=bins ... (bins needs komorebi-bar.exe for bar).

Variable Effect
E2E_ONLY=word,word run only the steps whose printed name contains a word (a rerun of one step)
KOMOREBI_E2E_LOG_LEVEL=trace the daemon's log level (debug, trace)
KOMOREBI_E2E_RECORDER=DIR record with komorebi-recorder (a folder with komorebi-recorder.exe); comes back as recording.zip
KOMOREBI_E2E_KEEP_GUEST=1 keep the guest's run directory (overlay, TPM state) instead of deleting it
KOMOREBI_E2E_SCALE=1.5 every wait is 1.5 times as long, for a busy host
KOMOREBI_E2E_STATE=DIR restore guests from a saved state (3 s instead of 50-90 s start)
KOMOREBI_E2E_CAPTURE=DIR save raw komorebic state fixtures
SWEEP_TWO_DISPLAYS=1 commands adds a second display

Keep output and run directories on a short path (unix socket paths are limited to about 108 bytes). Each scenario gets its own guest (about 4 vCPU and 6 GB). Results are in OUT/<scenario>/result.json; trust it over the printed line. docs/dev/bar-e2e.md describes the bar scenario.

A change to the Windows daemon or bar needs these before it is considered landed (commit types BEHAVIOUR): commands, plus the scenario of the cluster named in the revision body (see backend-switch.md for the table).

5. What runs where (summary)

Change touches Run
crates/* (not bar/komorebic) section 1 native crate tests, then Windows clippy (section 1), KDE (section 2) and macOS type-check (section 3)
komorebi-windows/ (Windows daemon) Windows clippy and nextest, then e2e (section 4)
komorebi-linux/, komorebi-hotkeys/ section 2 cargo, then KDE checks, VM fast tier
komorebi-macos/ macOS type-check on Linux; build and tests on a Mac
komorebi-bar/, komorebi-bar-core Windows clippy, cargo test -p komorebi-bar-core, macOS type-check, e2e bar
komorebic*, komorebic-core cargo test -p komorebic-core (CLI doc oracle), all three platforms' checks
flake.nix, nix/**, flake.lock nix flake check --no-build --all-systems, then the checks of the platform edited
docs only nothing, unless under a platform tree (see section 0)

6. Known flakes

Policy: on any e2e or VM failure, check this list by check name and by log signature first; do not soak to re-prove a known flake. Write rates as failures/runs with the commit and host load. A known flake needs baseline-seen evidence (it occurred before the consolidation) or at least 3 occurrences with the same signature. A name-only match gets one rerun on a calm host at trace with logs kept; no match gets one calm rerun, and a second failure is a regression candidate to bisect by revision. A soak is only for a candidate that failed twice or a flake whose rate looks more than 2x higher with at least 3 failures. Passing under load stays a pass; failing under high load is not evidence of a regression. A full commands sweep takes 4 to 6 minutes, so the E2E_ONLY runs come first.

Check Platform What is seen Rate (from a measured set)
commands, daemon stops answering komorebic state Windows the daemon logs nothing from any thread for 3 to 3.6 s after answering State; the reply write hits a closed socket (os error 10054); border manager: stuck for ~3000 ms in locking the window manager; could not acquire window manager lock. Cause not found (host I/O stalls are a candidate) 1/10 sweeps before the consolidation, 1/12 after; probe 0.35% vs 0.39% of calls
lifecycle_hidden (monocle after crash) Windows no signature captured (capture at trace next time) 1/10 before, 2/12 after
resize (drag checks win2:bottomleft, win3:top) Windows drag checks fail, pass on rerun; documented as flaky 1 failure in the first run, passed twice
daemon does not start (failed call to AllowSetForegroundWindow after 5 retries) Windows the scenario prints "did not run, counted as 1 failed", no result.json; only seen at load 6.6-8 candidate, 4/~45 starts at that load vs 0/~150 at load 3-5
hotplug with the recorder on (AgentLost ... during exec tasklist) Windows after the display unplug, in the recorder collection step; the rerun passed candidate, 1 occurrence
maximizing.user, placement (integer case), unknown_monitor (2) Windows not flakes: the same 4 checks fail on every commit (stale known-failure markers) fix or re-mark them
focus_follows_mouse "did not run" Windows reporting quirk of the runner, result.json says 15/0 ignore the line
vm-commands, vm-core-e2e KDE commands.py (guest D-Bus stops replying, BrokenPipe), handover.py ("win3 is inside the work area and not on a tile"), lifecycle_hidden.py, manage_rules.py (window never appeared, 30 s), core_e2e.py (KWin script never reported in) 0 green in 6 runs before the consolidation at host load 25 to 190; load-dependent is plausible, not shown; no gate decision until one calm-host run exists
golden test of komorebi-protocol native "5 passed; 1 failed" once, six reruns passed, text not captured 1 occurrence; keep the text if it recurs
KDE tests/schemas.rs native shares a pid-only socket path keep --test-threads=1

Observed rates are consistent with a wide range: 1 failure in 10 runs fits anything from about 0.3% to 45% per run. Quote the counts, not "flaky". The source registry of the consolidation runs (with commits and logs) is kept by whoever runs the gates; add new occurrences there and update this table when a rate changes.