mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Relay-primary managed-agent config (kind:30179) delivered config for exactly
one launch and could overwrite a newer device's config with an audit-clean
event. Three defects, each measured with a probe before being fixed.
Overlay boot rehydration. `PrivateConfigOverlay` was in-memory only and its
single writer fired only when an inbound 30179 was strictly newer than the
retained row. On every second-and-later launch the backfill re-delivered the
same event, retention deduped it to Skipped, and the overlay stayed empty for
the whole session, so every read silently fell back to stale disk. Rebuild the
overlay from the retained rows on the `run_event_sync` boot seam, which already
runs post-identity-resolution with the resolved owner keys and scoped db path.
Adds `get_retained_events_of_kind` (nothing read rows back by kind before).
Boot publication on default keyring builds. `reconcile_agents_in_dir_at` read
`managed-agents.json` raw, so on a default `system-keyring` build the nsec was
keyring-resident and `retain_private_agent_record`'s empty-nsec skip fired for
every untouched agent: zero 30179s published on first boot. Hydrate keys in the
reconcile path. The doc comment asserted the bug ("keys are never needed here")
and is corrected, so the next reader is not re-licensed to reintroduce it.
Stale-disk republish at three write sites. `private_payload_from_record`
serializes every config field, so retaining a disk-derived record on a device
following a newer relay head republished the other fields from stale disk;
`monotonic_created_at` then floored the write at head+1, so it won LWW, bumped
the generation, and chained `prev` to the head it destroyed — a validly-chained
successor indistinguishable from a legitimate edit. Resolve the overlay before
the local mutation at `agent_models.rs` (edit), `personas/update.rs` (persona
rename) and `agents.rs` (pair-start snapshot re-apply).
Ordering is the fix at each site, and it differs per site, which is why this is
not centralized in `retain_managed_agent_pending`:
- edit: resolve before the user's patch, or the patch is discarded
- rename: resolve for the payload only; the `name != old_display_name` gate must
keep reading disk state, and name/display_name are re-applied after
- pair-start: resolve before `apply_persona_snapshot`, so the definition quad
stays definition-authoritative
Tests. Regression coverage for all three defects plus three probes that pin the
wrong fixes (centralized resolve discards edits; resolve-before-gate skips the
rename; swapped pair-start ordering lets the overlay clobber the persona quad),
each with positive and negative controls.
`write_site_resolve_guard` is a source-level assertion, added because the
behavioural tests cannot see the production wiring: every write site is inside a
`#[tauri::command]` needing a live `AppHandle`, so the tests call
`retain_agent_record` directly and stayed green with the production resolve
deleted (measured: 2261 passed / 0 failed). The guard fails when a site loses
its resolve or a new site is added without one, and carries its own vacuity
control.
File-size ratchet. `agent_models.rs` sat at the 1000-line cap before this
change (1024 lines), so the ratchet allows it zero growth, and
`reconcile/tests.rs` crossed the cap. Two verbatim moves, following the seams
each file already uses: `normalize_agent_models` to
`agent_models_normalize.rs` (`#[path]` submodule, like the databricks/
openrouter/discovery helpers) and the stale-republish test family to
`reconcile/tests/stale_republish_tests.rs` (like
`personas/update/name_propagation_tests.rs`). Both moved blocks are
byte-identical to their pre-move bytes apart from one visibility line
(`pub(super)` -> `pub(crate)`, required by E0364 on the re-export), and the
write-site guard's deletion mutant was re-run after the move: still dead.
Item 3 from the review (collapsing the 27-field `PrivateConfigPatch` mirror,
~169 deletable lines) is deliberately not in this commit; it is an overlay
refactor and lands separately.
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>