feat(desktop): surface config diff in restart-required badge - #3637
Merged
Conversation
wpfleger96
force-pushed
the
hayt/restart-diff-ui
branch
from
July 31, 2026 14:48
7715d7e to
551bbe1
Compare
kalvinnchau
previously approved these changes
Jul 31, 2026
wpfleger96
force-pushed
the
hayt/restart-diff-ui
branch
2 times, most recently
from
August 3, 2026 16:06
c67f3ed to
27420b4
Compare
When a running managed agent's config drifts from what it was spawned with, the UI now surfaces the specific before/after diff — field names, old values, new values — rather than a bare "Restart required" badge. Rust (desktop/src-tauri): - New spawn_snapshot module: captures the effective config at spawn time as a structured snapshot (command, args, env, relay URL, system prompt, team instructions, session title, parallelism). The same structure feeds both the hash comparison (no behaviour change) and a field-level diff for the UI. - spawn_snapshot/diff.rs: produces RestartDiffEntry vec from two snapshots. Policy-driven masking: env keys on is_safe_to_reveal() allowlist (BUZZ_AGENT_THINKING_EFFORT, BUZZ_AGENT_PROVIDER, BUZZ_AGENT_MODEL, DATABRICKS_HOST/MODEL) render plain; all other env keys are masked (key name visible, value shows last-4 chars). Big values (system prompt, team instructions) are summarised as char counts. Secrets are never leaked. - Hoist is_safe_to_reveal() from commands/agent_config.rs to managed_agents/env_vars.rs as pub(crate) — single allowlist authority for both baked-env display and the diff masking policy. - ManagedAgentSummary gains restart_diff: Vec<RestartDiffEntry> (empty when no drift or no stamp). Adopted PID-only agents have no stamp and always produce an empty diff — same invariant as the existing hash behaviour. - Adapter-availability drift (codex) continues to set needs_restart; diff vec stays empty for that case. - Tests: snapshot round-trips, diff field coverage, allowlisted / non-allowlisted masking, case-insensitivity, empty-key / dotted-key fail-closed, unstamped-agent invariant. TypeScript / UI: - New RestartDiffEntry / RestartChange / JsonValue types in restartDiff.ts; re-exported from tauri.ts and types.ts. - fromRawManagedAgent maps restart_diff → restartDiff (omission → []). - RestartDiffBadge: hover tooltip capped at 6 entries + "and N more"; asChild span trigger — never nested inside a <button>. Shows auto-restart blurb (on/off variant) below the diff list. - RestartDiffList: uncapped display for the Runtime-tab banner. - Hero badge in UserProfilePanelSections is self-center (was self-start). - AUTO_RESTART_ON_BLURB / AUTO_RESTART_OFF_BLURB exported constants shared by the badge tooltip and the Runtime banner; both surfaces import the same strings so they cannot drift. - All four badge call sites (ManagedAgentRow, UnifiedAgentsSection ×2, UserProfilePanelSections hero) pass autoRestartEnabled. - e2e: needs-restart-screenshots.spec.ts covers all badge sites, tooltip hover + keyboard focus, no-button-ancestor assertion, 6+1 truncation, full uncapped Runtime list, unknown-field humanisation, side-panel badge on default Info tab. - types.rs doc comments trimmed to stay under the 1000-line ratchet. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
force-pushed
the
hayt/restart-diff-ui
branch
2 times, most recently
from
August 4, 2026 15:48
27420b4 to
c611630
Compare
wpfleger96
pushed a commit
that referenced
this pull request
Aug 4, 2026
…-links-fixes * origin/main: feat(desktop): surface config diff in restart-required badge (#3637) Polish sidebar unread hierarchy (#4573) fix(desktop): show cached display names on startup (#3317) docs(acp): explain per-channel session model in base prompt (#4729) docs(nip-am): normative amendment — cache SHOULD/MUST + pricingIdentity + consumer cost guidance (#4632) Remove blur from Welcome composer guidance (#4691) Refine desktop timeline activity presentation (#4582) Defer desktop media uploads until send (#4522) fix(desktop): stop clipping focus ring on channel intro action cards (#2392) (#4374) Signed-off-by: npub1g8493u0xfsjrvflg4n08ezd7vec99mnwzlv0qgwpr9d7gvjwhuzqx59rhw <41ea58f1e64c243627e8acde7c89be667052ee6e17d8f021c1195be4324ebf04@buzz.block.builderlab.xyz>
tellaho
pushed a commit
that referenced
this pull request
Aug 4, 2026
…theme-config * origin/main: feat(desktop): persist sidebar observed-unread across webview reload (#3976) feat(desktop): surface config diff in restart-required badge (#3637) Polish sidebar unread hierarchy (#4573) fix(desktop): show cached display names on startup (#3317) docs(acp): explain per-channel session model in base prompt (#4729) docs(nip-am): normative amendment — cache SHOULD/MUST + pricingIdentity + consumer cost guidance (#4632) Remove blur from Welcome composer guidance (#4691) Refine desktop timeline activity presentation (#4582) Defer desktop media uploads until send (#4522) fix(desktop): stop clipping focus ring on channel intro action cards (#2392) (#4374) Polish mobile inbox and media flows (#4512) feat: ship Buzz Term (#4347) Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
tellaho
pushed a commit
that referenced
this pull request
Aug 4, 2026
…onfig * origin/main: feat(desktop): persist sidebar observed-unread across webview reload (#3976) feat(desktop): surface config diff in restart-required badge (#3637) Polish sidebar unread hierarchy (#4573) fix(desktop): show cached display names on startup (#3317) docs(acp): explain per-channel session model in base prompt (#4729) docs(nip-am): normative amendment — cache SHOULD/MUST + pricingIdentity + consumer cost guidance (#4632) Remove blur from Welcome composer guidance (#4691) Refine desktop timeline activity presentation (#4582) Defer desktop media uploads until send (#4522) fix(desktop): stop clipping focus ring on channel intro action cards (#2392) (#4374) Polish mobile inbox and media flows (#4512) feat: ship Buzz Term (#4347) Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
wpfleger96
pushed a commit
that referenced
this pull request
Aug 4, 2026
…-phase2-integration * origin/main: (23 commits) Refine community invite links (#4734) feat(desktop): persist sidebar observed-unread across webview reload (#3976) feat(desktop): surface config diff in restart-required badge (#3637) Polish sidebar unread hierarchy (#4573) fix(desktop): show cached display names on startup (#3317) docs(acp): explain per-channel session model in base prompt (#4729) docs(nip-am): normative amendment — cache SHOULD/MUST + pricingIdentity + consumer cost guidance (#4632) Remove blur from Welcome composer guidance (#4691) Refine desktop timeline activity presentation (#4582) Defer desktop media uploads until send (#4522) fix(desktop): stop clipping focus ring on channel intro action cards (#2392) (#4374) Polish mobile inbox and media flows (#4512) feat: ship Buzz Term (#4347) feat(mobile): sync per-group channel sorting (#4231) feat(mobile): add channel scroll navigation (#4239) feat(desktop): redesign the Huddle experience (#4281) feat(mobile): bring channel menus to desktop parity (#3940) feat(agents): model-tuning parity in global Agent Defaults editor (#4578) Polish Share Compute settings (#3735) fix(reactions): wrap long popover names (#3834) ...
wpfleger96
added a commit
that referenced
this pull request
Aug 4, 2026
…opagation, tests True git rebase onto bc9e652 (current origin/main). Conflict resolution preserves #3637 (spawn_snapshot, restart-diff) and #4522 (media_raw, deferred uploads) alongside all B1 content. Fix 3b (hash-verified file recovery): - schema.rs: add agents_content_hash / teams_content_hash columns to file_commit_phases (schema v3 with ALTER TABLE migration for existing DBs). - txn.rs: compute SHA-256 of staged payloads and record them in the intent row. - Recovery now verifies canonical file hash against recorded hash before treating absent stage files as 'already completed'. All three missing-stage branches (intent/both-absent, intent/teams-absent, first_renamed/teams-absent) fail closed unless canonical matches. Only hash-verified canonicals advance to committed. Fix 4 (tombstone/archive propagation): - agents.rs: tombstone_managed_agent_pending and archive_managed_agent_pending use .map_err(|e| ...)? — failures surface in the delete command's Result. - personas/mod.rs: same pattern for cascaded agent tombstones and persona tombstone. - teams.rs: tombstone_team_pending and cascaded persona tombstones propagate. - agents_retain.rs: retain_managed_agent_pending keeps its outer log-and-swallow with an explicit comment documenting the boot-reconcile-recoverable contract (Thufir accepted this distinction for updates vs deletes). Tests: - store_journal_fix_tests.rs (5 new tests): - test_file_recovery_rename_done_phase_not_updated_succeeds: both stages absent, canonicals match hashes → advance to committed. - test_file_recovery_hash_mismatch_fails_closed: hash mismatch → uncommitted. - test_file_recovery_first_renamed_teams_done_hash_verified: teams hash verified. - test_file_recovery_first_renamed_teams_absent_no_hash_fails_closed: fail closed. - test_boot_recovery_inserts_into_supplied_retention_path_not_flat: scoped path. - storage_tests.rs (2 new tests): keyring round-trip (Fix 2 coverage). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
added a commit
that referenced
this pull request
Aug 4, 2026
…opagation, tests True git rebase onto bc9e652 (current origin/main). Conflict resolution preserves #3637 (spawn_snapshot, restart-diff) and #4522 (media_raw, deferred uploads) alongside all B1 content. Fix 3b (hash-verified file recovery): - schema.rs: add agents_content_hash / teams_content_hash columns to file_commit_phases (schema v3 with ALTER TABLE migration for existing DBs). - txn.rs: compute SHA-256 of staged payloads and record them in the intent row. - Recovery now verifies canonical file hash against recorded hash before treating absent stage files as 'already completed'. All three missing-stage branches (intent/both-absent, intent/teams-absent, first_renamed/teams-absent) fail closed unless canonical matches. Only hash-verified canonicals advance to committed. Fix 4 (tombstone/archive propagation): - agents.rs: tombstone_managed_agent_pending and archive_managed_agent_pending use .map_err(|e| ...)? — failures surface in the delete command's Result. - personas/mod.rs: same pattern for cascaded agent tombstones and persona tombstone. - teams.rs: tombstone_team_pending and cascaded persona tombstones propagate. - agents_retain.rs: retain_managed_agent_pending keeps its outer log-and-swallow with an explicit comment documenting the boot-reconcile-recoverable contract (Thufir accepted this distinction for updates vs deletes). Tests: - store_journal_fix_tests.rs (5 new tests): - test_file_recovery_rename_done_phase_not_updated_succeeds: both stages absent, canonicals match hashes → advance to committed. - test_file_recovery_hash_mismatch_fails_closed: hash mismatch → uncommitted. - test_file_recovery_first_renamed_teams_done_hash_verified: teams hash verified. - test_file_recovery_first_renamed_teams_absent_no_hash_fails_closed: fail closed. - test_boot_recovery_inserts_into_supplied_retention_path_not_flat: scoped path. - storage_tests.rs (2 new tests): keyring round-trip (Fix 2 coverage). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
added a commit
that referenced
this pull request
Aug 4, 2026
* commit 'ce3cf3cd2': (76 commits) Polish Huddle voice controls (#4694) fix(local-archive): default both archive settings to enabled (#4750) fix(mobile): stop oversized read-state retry loop (#4595) fix(desktop): close reconnect gaps that previously required CMD+R (#4737) Dock Buzz Term within channel workspace (#4724) perf(relay): index channel-id lookups and skip trace-only reads (#4647) fix(agents): canonicalize stale persona harness pins (#4631) Refine community invite links (#4734) feat(desktop): persist sidebar observed-unread across webview reload (#3976) feat(desktop): surface config diff in restart-required badge (#3637) Polish sidebar unread hierarchy (#4573) fix(desktop): show cached display names on startup (#3317) docs(acp): explain per-channel session model in base prompt (#4729) docs(nip-am): normative amendment — cache SHOULD/MUST + pricingIdentity + consumer cost guidance (#4632) Remove blur from Welcome composer guidance (#4691) Refine desktop timeline activity presentation (#4582) Defer desktop media uploads until send (#4522) fix(desktop): stop clipping focus ring on channel intro action cards (#2392) (#4374) Polish mobile inbox and media flows (#4512) feat: ship Buzz Term (#4347) ... Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
shellz-n-stuff
added a commit
to shellz-n-stuff/buzz
that referenced
this pull request
Aug 4, 2026
…gent-instructions * origin/main: (30 commits) feat: Buzz entity links — rich preview cards + in-app navigation for repos, PRs, and issues (block#4695) fix(desktop): serialize tray channel actions for frontend (block#4762) chore(release): release Buzz Desktop version 0.5.5 (block#4788) feat(projects): support multiple repositories (block#4671) fix(ci): make desktop cache test version agnostic (block#4791) fix(desktop): widen post-Enter timeouts in empty-edit-delete spec (block#4792) fix(desktop): wait for terminal frame before splash (block#4781) fix(desktop): integer-align custom reaction emoji (block#4779) Polish Huddle voice controls (block#4694) fix(local-archive): default both archive settings to enabled (block#4750) fix(mobile): stop oversized read-state retry loop (block#4595) fix(desktop): close reconnect gaps that previously required CMD+R (block#4737) Dock Buzz Term within channel workspace (block#4724) perf(relay): index channel-id lookups and skip trace-only reads (block#4647) fix(agents): canonicalize stale persona harness pins (block#4631) Refine community invite links (block#4734) feat(desktop): persist sidebar observed-unread across webview reload (block#3976) feat(desktop): surface config diff in restart-required badge (block#3637) Polish sidebar unread hierarchy (block#4573) fix(desktop): show cached display names on startup (block#3317) ... Signed-off-by: Alex Rosenzweig <arosenzweig@squareup.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The "Restart required" badge reports that an agent's running config has drifted from its spawn-time config, but never says what changed. This ships the full feature: a typed Rust diff engine and a TS/UI layer that renders it at every badge site.
Rust core (spawn-snapshot diff engine)
Replaces the lossy
u64spawn_config_hashwith a typedSpawnConfigSnapshot. The snapshot is stamped from the already-resolved command/env/config values immediately beforespawn(), closing the race window where a mid-spawn config edit would suppress the badge.SpawnConfigSnapshot::canonical()is the single JSON projection shared by the badge and the diff. Drift isto_value(stamped) != to_value(current); the diff is a generic leaf walk over those same two values, so badge-on and diff-non-empty are structurally guaranteed. Adding a snapshot field reaches the UI with no code change to the diff engine —mutation_table_covers_every_serialized_fieldfails CI if a new field arrives without a mutation row.eligible_restart_diff(persona_orphaned, Option<TrackedSpawnState>)returns the final vector — snapshot walk entries plus a syntheticadapter_availabilityentry. It returns empty for an orphaned instance (spawning one would fail) and for agents with no tracked spawn state (never stamped, can never have drifted).needs_restart = !restart_diff.is_empty()derives from that vector and nothing else.Redaction policy (
policy_for(path)) is shared by the wire diff and the snapshot's manualDebugviais_safe_to_reveal()frommanaged_agents::env_varsas the single authority for env-key masking:Textsystem_prompt,team_instructionsMaskedBareargs,relay_url••••, no suffixMaskedSuffixenv.*••••+ last 4 chars when longer than 8Plainenv.*(BUZZ_AGENT_THINKING_EFFORT,BUZZ_AGENT_PROVIDER,BUZZ_AGENT_MODEL,DATABRICKS_HOST/MODEL) and everything elseDefault-deny: every env key not in the explicit allowlist stays masked.
is_safe_to_reveal()is the single allowlist authority for both the baked-env display and the diff.restart_diffis omitted from the wire when empty (skip_serializing_if).TypeScript / UI layer
New
restartDiff.tsmodule definesRestartDiffEntry,RestartChange,JsonValue;tauri.tsandtypes.tsre-export and addrestart_diff/restartDifffields (Rust omission →restartDiff: []).RestartDiffBadge— hover tooltip capped at 6 entries + "and N more",asChildspan trigger (never inside a<button>), auto-restart blurb below the diff list (on/off variant fromautoRestartEnabledprop; sameAUTO_RESTART_ON_BLURB/AUTO_RESTART_OFF_BLURBconstants shared with the Runtime-tab banner).RestartDiffListrenders the full uncapped list for the Runtime-tab banner withtooltip/inlinepresentation variants for correct foreground in both surfaces.ManagedAgentRowB4 fix — badge moved to a siblingdivof the row expansion button; tooltip trigger has nobuttonancestor.UnifiedAgentsSection— both badge sites render<RestartDiffBadge>instead of a raw<Badge>, withautoRestartEnabledthreaded fromagent.autoRestartOnConfigChange.Side-panel fix —
RestartDiffBadgerendered tab-independently in theProfileSummaryViewhero area (was Runtime-tab only — root cause of the ~50% inconsistency Will reported). Hero badge isself-centerin the flex column.ProfileRuntimeTabContentearly-return checksneedsRestartso the banner is never dropped when all other content is empty. Auto-restart blurb in the Runtime-tab banner uses the shared constants.Wire shape
added/removedoccur only for dynamic-map keys; nullable struct fields always serialize asnull; arrays are atomic leaves (args, neverargs.0).Tests
Rust — 1902 passing: snapshot mutation coverage, diff entry serialization, allowlist-aware env masking (
allowlisted_env_key_shows_plain_value,allowlisted_env_key_is_case_insensitive,non_allowlisted_env_key_stays_masked),unstamped_agent_yields_no_badge_and_no_entries(both orphan values),summary_without_drift_omits_restart_diff_from_the_wire,unstamped_availability_is_not_drift. Clippy clean, fmt clean.TypeScript —
needs-restart-screenshots.spec.ts: 11 E2E cases registered in the smoke project — all three badge sites, tooltip + keyboard focus, DOM no-button-ancestor assertion, 6+1 truncation, uncapped Runtime list, unknown field humanisation, side-panel badge on default Info tab, inactive/friendly-error Runtime opening path.Consolidates #3652