ADR-0022: OS/shell/UI boundaries must use testable seams + behavioral tests
Date: 2026-06-15 / Status: Adopted
Decision
Code that touches the OS, shell, processes, file I/O, or UI events must go through an injectable seam (an interface, or an internal core with paths/dependencies passed as arguments), and must come with tests that verify its behavior via dotnet test / cargo test. Do not ship with only pure helpers or argument construction tested while "actual behavior is unverified."
Canonical patterns: app/FindMyFiles/Engine/IEngineClient.cs (Fake/Ffi/Pipe), Services/IDispatcher.cs, Services/IProcessRunner.cs / Services/IRevealApi.cs, the path-parameterized core of Services/FileLog.cs. On the engine side, engine/crates/fmf-core/.../seams.rs (SnapshotStore / JournalSource; the two-seam cap is ADR-0018).
Rationale
- "Open folder and select file" (reveal) was broken from day one: the actual behavior of
ShellOps.Reveal(SHOpenFolderAndSelectItems) was never tested; only the pure helperBuildOpenStartInfowas green, and CI kept passing. The tests did not guarantee quality. - Root-cause type: if the runtime/OS boundary stays
static+ direct P/Invoke, behavior cannot be swapped with a fake and behavioral verification cannot be written. Argument/structure tests do not make "passes = not broken" hold. - The C# coverage gate being
Threshold=15(nominal only) also allowed unverified code to ship.
Consequences
- New boundary code is required at review to have "seam + behavioral test" (construction-only tests are deemed insufficient).
- C# live UI automation assumes a PowerShell script (
ui-tests.ps1), which is disabled by execution policy on this machine and not adopted by operating policy. Therefore UI-adjacent logic is pushed into ViewModels / core and verified viadotnet test(no dependence on live UI automation). - Mutation testing is used to detect vacuous tests (those that pass even when broken): Rust =
just mutants(cargo-mutants), C# =just stryker(Stryker.NET). Informational for now; gated incrementally. - The C# coverage gate is raised incrementally from 15% (ratchet).
Re-examination triggers
- If live UI automation becomes adoptable without PowerShell dependence (e.g., integrating FlaUI into
dotnet test) → re-evaluate direct testing of UI flows. - Signs that seam proliferation distorts the design (the engine side keeps the two-seam cap = ADR-0018).