From 2719088822107646ada8a8de37ba9566e78db2ea Mon Sep 17 00:00:00 2001 From: Sami Date: Fri, 7 Aug 2026 14:35:21 -0400 Subject: [PATCH] test(desktop): guard that every export resolver folds the 30179 overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The behavioural tests added with the export/card overlay fold model the resolution by calling `resolved_records` / `resolve_from_lists` directly. They cannot reach the production call sites: all three live inside `#[tauri::command]` bodies needing a live `AppHandle` + `State`. Measured on the parent commit, one full-workspace run per mutant: delete the snapshot.rs fold -> SURVIVED (2283 passed, 0 failed) delete the card precheck fold -> SURVIVED (2283 passed, 0 failed) delete the card mint fold -> SURVIVED (2283 passed, 0 failed) revert the respond_to fallback -> killed (3 tests) mix definition mode + inst. list -> killed (1 test) So all three production folds were deletable with a green suite. The fallback and the mode/list-atomicity invariant were genuinely covered; only the wiring was not. Add an `include_str!` source guard with EXACT per-file call counts (snapshot.rs: 1, card.rs: 2) — same remedy as `write_site_resolve_guard` in private_config_overlay.rs. Exact rather than a lower bound: `>= 1` per file would not notice one card site losing its fold while the other gained a second one. A second test strips the searched string and asserts zero matches remain, so a typo in the pattern cannot make the guard pass vacuously. Re-ran all three mutants against the guard, deleting each fold statement outright so the mutant compiles: all three fail, each naming its own file, with the unmutated control passing and both sources restored byte-identical after each arm. The guard lives in a sibling `tests_export_resolver_guard.rs` rather than in `snapshot/tests.rs`, following the convention `tests_locked.rs` documents: `snapshot/tests.rs` is already over the 1000-line desktop ratchet, so a file already above the limit may not grow. This commit adds 3 lines to snapshot.rs (528 total) and one new 67-line file, so it clears the ratchet on its own; the two pre-existing ratchet rows on this branch are unchanged by it. Verified: cargo test --workspace in desktop/src-tauri — 2285 passed, 0 failed, 14 ignored; cargo clippy --workspace --all-targets -D warnings clean; cargo fmt --all --check clean. All at parent 692fdafa with `git rev-parse HEAD` checked in the same shell. Co-authored-by: Tyler Longwell Signed-off-by: Tyler Longwell --- .../src/commands/personas/snapshot.rs | 3 + .../snapshot/tests_export_resolver_guard.rs | 67 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 desktop/src-tauri/src/commands/personas/snapshot/tests_export_resolver_guard.rs diff --git a/desktop/src-tauri/src/commands/personas/snapshot.rs b/desktop/src-tauri/src/commands/personas/snapshot.rs index 6d03f45a08..13a58caed1 100644 --- a/desktop/src-tauri/src/commands/personas/snapshot.rs +++ b/desktop/src-tauri/src/commands/personas/snapshot.rs @@ -455,6 +455,9 @@ pub async fn encode_agent_snapshot_for_send( }) } +#[cfg(test)] +#[path = "snapshot/tests_export_resolver_guard.rs"] +mod export_resolver_guard; #[cfg(test)] mod fidelity_tests; #[cfg(test)] diff --git a/desktop/src-tauri/src/commands/personas/snapshot/tests_export_resolver_guard.rs b/desktop/src-tauri/src/commands/personas/snapshot/tests_export_resolver_guard.rs new file mode 100644 index 0000000000..0150e91cfe --- /dev/null +++ b/desktop/src-tauri/src/commands/personas/snapshot/tests_export_resolver_guard.rs @@ -0,0 +1,67 @@ +//! Source guard: every export resolver folds the private-config overlay. +//! +//! Kept in a sibling file so `snapshot/tests.rs` stays under the 1000-line +//! gate; `#[path]`-included from there as a child module. +//! +//! The behavioural tests in `tests.rs` model the fold by calling +//! `resolved_records` / `resolve_from_lists` directly. They CANNOT reach the +//! production call sites: all three live inside `#[tauri::command]` bodies +//! needing a live `AppHandle` + `State`. Measured on the parent +//! commit — deleting any one of the three production folds leaves the full +//! workspace suite green (2283 passed, 0 failed). +//! +//! Same weakness, same remedy, as `write_site_resolve_guard` in +//! `private_config_overlay.rs`: assert the call exists at each site. + +/// The fold call every export resolver must make. A resolver that reads raw +/// disk instead fails with "agent not found" for a relay-only agent that has +/// never started on this device, and bakes stale disk values into the +/// exported manifest on a follower device. +const FOLD_CALL: &str = ".resolved_records(&instances)"; + +/// `(file, source, expected_fold_calls)` — every export resolver that turns +/// an id into a record destined for a snapshot manifest or a card. +fn sites() -> Vec<(&'static str, &'static str, usize)> { + vec![ + // `materialize_snapshot_bytes` — JSON + PNG + send-to-channel. + ( + "commands/personas/snapshot.rs", + include_str!("../snapshot.rs"), + 1, + ), + // Card precheck (`card_mint_key_status`) + mint resolver + // (`mint_agent_card`). Exact, not `>= 1`: a lower bound would not + // notice one site losing its fold while the other gained a second. + ("commands/personas/card.rs", include_str!("../card.rs"), 2), + ] +} + +#[test] +fn every_export_resolver_folds_the_private_config_overlay() { + for (file, source, expected) in sites() { + let found = source.matches(FOLD_CALL).count(); + assert_eq!( + found, expected, + "{file}: expected {expected} `{FOLD_CALL}` call(s), found {found}. \ + An export resolver that reads raw disk fails with \"agent not found\" \ + for a relay-only agent that has never started on this device, and \ + bakes stale disk values into the exported manifest on a follower." + ); + } +} + +/// The guard above is a substring count, so prove it can FAIL: a source with +/// the fold removed must not satisfy it. Without this, a typo in `FOLD_CALL` +/// would make every row pass vacuously. +#[test] +fn guard_detects_a_missing_overlay_fold() { + for (file, source, expected) in sites() { + let stripped = source.replace(FOLD_CALL, ".REMOVED(&instances)"); + assert_eq!( + stripped.matches(FOLD_CALL).count(), + 0, + "{file}: guard string never matched, so its {expected} expected \ + call(s) passed vacuously" + ); + } +}