Pre-release Harn is pre-1.0 — the language, standard library, and CLI may change between releases. See the release notes

Windows test coverage

This page tracks the disposition of every workspace test module that opts out of Windows via #![cfg(unix)] (or per-test #[cfg(unix)]). It exists so that a new contributor can tell at a glance whether a gate is load-bearing (POSIX semantics under test) or simply lazy (the test does not exercise anything OS-specific and could run on Windows with minor care).

The Windows nightly nextest matrix in .github/workflows/windows-nightly.yml runs the workspace test surface on windows-latest, so any test that is not gated below is expected to pass on Windows.

Inventory

Test moduleDispositionRationale
crates/harn-hostlib/tests/harn_hostlib/process_tools.rsKeep #![cfg(unix)] — POSIX-boundEvery fixture spawns bash -c "<script>" to exercise argv / cwd / env / stdin / timeout plumbing. Bash and the shell-script vocabulary used here (echo, pwd, 1>&2, for i in $(seq 1 N), printenv, $, etc.) are POSIX-only. Porting to Windows would require rewriting every fixture against cmd.exe / PowerShell, with subtle quoting and exit-code semantics that would no longer test the same plumbing on both sides.
crates/harn-cli/tests/harn_cli_e2e/orchestrator_cli.rsKeep #![cfg(unix)] — POSIX-boundEvery test sends SIGTERM to the orchestrator child and asserts on the resulting drain (graceful shutdown complete log line, successful exit code, lifecycle event ordering). Windows has no portable signal-delivery mechanism for an arbitrary console child without taking over the parent's console group, so the orchestrator cannot be drained the same way under test.
crates/harn-cli/tests/harn_cli_fast/orchestrator_http.rsKeep #![cfg(unix)] — POSIX-boundSame as orchestrator_cli.rs: every test asserts on graceful shutdown after SIGTERM. Some tests additionally assert on in-flight HTTP request drain, which is also a POSIX-signal-driven flow today.
crates/harn-cli/tests/harn_cli_e2e/orchestrator_inbox_dedupe.rsKeep #![cfg(unix)] — POSIX-boundSame as above: SIGTERM + clean drain are part of the assertion.
crates/harn-cli/tests/harn_cli_e2e/acp_server_cli.rsUngate — fully portableDrives harn serve acp over piped stdio; child shutdown is via stdin EOF, not signals. Runs on Unix and Windows.
crates/harn-cli/tests/harn_cli_e2e/mcp_server_cli.rsUngate — fully portableDrives harn mcp serve over piped stdio; child shutdown is via std::process::Child::kill (TerminateProcess on Windows, SIGKILL on Unix).
crates/harn-cli/tests/harn_cli_e2e/harn_serve_mcp_cli.rsUngate — fully portableDrives harn serve mcp; child shutdown is via stdin EOF or Child::kill. No POSIX signals, no shellouts to kill.

The rest of the workspace either has no module-level #![cfg(unix)] (individual #[cfg(unix)] items remain — typically for skill paths, symlink helpers, or tokio signal streams that already have a #[cfg(not(unix))] Windows fallback nearby) or is a Unix-only implementation file (crates/harn-vm/src/stdlib/sandbox.rs, crates/harn-cli/src/package/registry.rs::symlink_path_dependency, etc.) that genuinely cannot be implemented on Windows the same way.

Adding new POSIX-bound tests

If a new test module needs POSIX semantics (signals, fork, real shell), gate it #![cfg(unix)] and add a row to the table above so the gate remains discoverable. The header comment in the test file should explain why the gate exists; this page is for cross-cutting visibility.

Adding new portable tests

Default to not gating. The Windows nightly matrix will catch hidden Unix assumptions (/-only paths, \n-only line endings, missing .exe suffix, etc.) and you can either fix them in place or add a per-test #[cfg(unix)] annotation if a single case turns out to be POSIX-bound.

Cross-platform child shutdown helpers

crates/harn-cli/tests/test_util/timing.rs::ChildExitWatcher exposes terminate() and kill() that work on both platforms:

  • Unix: shells out to kill -TERM / kill -KILL.
  • Windows: shells out to taskkill /F (which calls TerminateProcess underneath). Both terminate() and kill() collapse to the same forceful path; there is no graceful-shutdown drain on Windows.

Tests that depend on the orchestrator running its drain logic must therefore stay #![cfg(unix)] regardless of which helper they call. This is documented in the doc-comment on ChildExitWatcher::terminate.