From a3f68c9bd67635dd74d7c5f83e549b6e1f3477ca Mon Sep 17 00:00:00 2001 From: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz> Date: Tue, 25 Aug 2026 14:08:59 -0400 Subject: [PATCH] test(managed-agents): cover the boot-reconcile continue-on-error arm 66995b1fc made empty relay_url valid in the same commit that hardened the boot loop, so its regression test never reaches the `Err` arm: both records take `Ok(true)`, and restoring `?` would leave it green. Add a three-record test with a genuinely unpublishable middle record (nsec that does not derive its pubkey): reconcile must return Ok(2), the first and last records get 30177 + 30179, and the bad coordinate gets neither. Verified red with `?` restored in reconcile.rs, green with the `match`. Co-authored-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz> Signed-off-by: Meli <5aaa86bce934fc3445fc254aab560a40923f10252f92107e665073dede0e04d3@buzz.block.builderlab.xyz> --- .../src/managed_agents/reconcile/tests.rs | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/desktop/src-tauri/src/managed_agents/reconcile/tests.rs b/desktop/src-tauri/src/managed_agents/reconcile/tests.rs index e1e84f0a41..17e648ca66 100644 --- a/desktop/src-tauri/src/managed_agents/reconcile/tests.rs +++ b/desktop/src-tauri/src/managed_agents/reconcile/tests.rs @@ -303,6 +303,60 @@ fn empty_relay_url_pin_does_not_abort_boot_reconcile() { } } +/// A record that genuinely cannot be published (here: an nsec that does not +/// derive its pubkey) is logged and skipped; the records before and after it +/// in file order still get both heads, and the bad coordinate gets neither. +#[test] +fn unpublishable_record_does_not_abort_boot_reconcile() { + use nostr::ToBech32; + + let owner_keys = nostr::Keys::generate(); + let first_keys = nostr::Keys::generate(); + let bad_keys = nostr::Keys::generate(); + let last_keys = nostr::Keys::generate(); + let mut first = sample_record(&first_keys.public_key().to_hex(), "first"); + first.private_key_nsec = first_keys.secret_key().to_bech32().unwrap(); + let mut bad = sample_record(&bad_keys.public_key().to_hex(), "bad"); + bad.private_key_nsec = nostr::Keys::generate().secret_key().to_bech32().unwrap(); + let mut last = sample_record(&last_keys.public_key().to_hex(), "last"); + last.private_key_nsec = last_keys.secret_key().to_bech32().unwrap(); + + let dir = TempDir::new().unwrap(); + write_store(&dir, &[first, bad, last]); + let db_path = dir.path().join("retention.db"); + let reconciled = reconcile_agents_in_dir_with( + dir.path(), + &owner_keys, + &db_path, + None::<&crate::secret_store::SecretStore>, + ) + .unwrap(); + assert_eq!(reconciled, 2); + + let conn = open_retention_db(&db_path).unwrap(); + let owner = owner_keys.public_key().to_hex(); + for keys in [&first_keys, &last_keys] { + let agent = keys.public_key().to_hex(); + for kind in [KIND_MANAGED_AGENT, KIND_PRIVATE_MANAGED_AGENT] { + assert!( + get_retained_event(&conn, kind, &owner, &agent) + .unwrap() + .is_some(), + "{kind} for {agent}" + ); + } + } + let bad_agent = bad_keys.public_key().to_hex(); + for kind in [KIND_MANAGED_AGENT, KIND_PRIVATE_MANAGED_AGENT] { + assert!( + get_retained_event(&conn, kind, &owner, &bad_agent) + .unwrap() + .is_none(), + "{kind} must not be retained for the unpublishable record" + ); + } +} + #[test] fn fresh_record_is_retained_pending() { let dir = TempDir::new().unwrap();