Skip to content

feat(desktop): restart-required badge from spawn-time config hash#1602

Merged
wesbillman merged 2 commits into
mainfrom
pinky/restart-badge
Jul 7, 2026
Merged

feat(desktop): restart-required badge from spawn-time config hash#1602
wesbillman merged 2 commits into
mainfrom
pinky/restart-badge

Conversation

@wesbillman

Copy link
Copy Markdown
Collaborator

Summary

Adds a "Restart required" badge for running managed agents whose effective spawn configuration has drifted since they were started — the detection layer for the upcoming auto-restart policy (Chunk F).

  • New pure fn spawn_config_hash(record, personas) -> u64 (managed_agents/spawn_hash.rs): hashes exactly what spawn consumes — effective_agent_command (live-persona-resolved), normalized args, effective MCP config, resolve_effective_agent_env output, and the record fields the env writes read. DefaultHasher over BTreeMaps; the hash never crosses a process/persistence boundary.
  • Semantics (encoded in the module doc and pinned by tests): badge = "a restart would change what runs"; personaOutOfDate = "a respawn would." Persona prompt/model/provider edits do NOT trip the badge (spawn reads the pinned record snapshot — restart wouldn't apply them); persona runtime/harness edits DO (resolved live at spawn). Record-level prompt edits trip it (spawn input via BUZZ_ACP_SYSTEM_PROMPT).
  • Stamped at spawn on ManagedAgentProcess (Unix struct literal + Windows finish_spawn); build_managed_agent_summary recomputes vs the current record+personas → needs_restartneedsRestart badge + hint in ManagedAgentRow. Stopped/adopted-via-runtime_pid agents have no runtimes entry, so they stay honestly badge-off.
  • Drive-by required by the file-size guard: tauri.ts crossed its limit, so this does the queued split (start/stopManagedAgenttauriManagedAgents.ts) and ratchets the guard 1388 → 1380 rather than bumping it.

Testing

  • 7 new unit tests, including the semantic boundary pair (persona_runtime_edit_changes_hash / persona_prompt_edit_does_not_change_hash) and non_spawn_bookkeeping_fields_do_not_change_hash.
  • just desktop-tauri-test 1016 passed / 0 failed; just desktop-check, just desktop-test (2029 passed), just desktop-typecheck, both fmt-checks, workspace just clippy all green.

Stamp a digest of the effective spawn config (live-persona-resolved
harness command + derived args/mcp, layered effective env, and the
record fields the spawn env writes read) on ManagedAgentProcess at
launch. build_managed_agent_summary recomputes the hash from current
disk state and flags needs_restart on mismatch, surfaced as a
"Restart required" badge on the agent row.

Semantics: the badge means "a restart would change what runs";
persona_out_of_date keeps meaning "a respawn would." Persona
prompt/model/provider edits are snapshot-pinned at spawn and so are
excluded; persona runtime edits resolve live and are included. Channel
membership is not an input — agents pick up channel changes live
(#1468). The hash is runtime-only state, never persisted; agents
adopted via a persisted runtime_pid have no stamped hash and stay
unbadged.

Also starts the queued tauri.ts split (start/stopManagedAgent →
tauriManagedAgents.ts) and ratchets its file-size limit 1388 → 1380.

Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dedicated review of the restart-required badge, re-verified at source before posting. The UI/API plumbing is coherent, Unix and Windows stamp the same computed spawn_config_hash, stopped/adopted-via-runtime_pid agents correctly stay badge-off, and the tauri.ts split is real (1375 lines against the ratcheted 1380 override, not a bump in disguise).

Requesting changes on two correctness gaps where the badge stays OFF even though a plain restart would change what runs — the dangerous false-negative direction for this feature. Both verified against the actual start/spawn paths. Inline comments below; the 🟢 is optional.

//! command (persona runtime edits DO propagate on restart), its derived
//! args/mcp command, the effective env layering, and the record fields the
//! spawn env writes read.
//! - Persona prompt/model/provider edits are EXCLUDED: spawn reads the pinned

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False-negative: persona prompt/model/provider edits are excluded, but the restart path DOES apply them. This scope rule assumes spawn reads the pinned record snapshot, so a persona prompt/model/provider edit wouldn't survive a restart. That's not what the start path does anymore: start_local_agent_with_preflight re-snapshots the linked persona's system_prompt/model/provider/env_vars onto the record immediately before spawning (desktop/src-tauri/src/commands/agents.rs:263:284), and restore does the same on launch. So a running persona-backed agent can have its persona prompt edited, this hash stays unchanged (it digests the stored record fields, not the prospective re-snapshot), the badge stays off — and then a stop/start changes what runs.

Fix: compute the comparison hash from the same prospective re-snapshotted record that start/restore will actually spawn (resolve the persona into a scratch record before hashing), OR drop the pre-spawn re-snapshot if pinned-until-delete is the intended product behavior. Whichever way it lands, persona_prompt_edit_does_not_change_hash (spawn_hash/tests.rs:112) needs to flip to assert_ne! if the re-snapshot stays.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed at source and fixed in dcd5cee — you're right, start_local_agent_with_preflight and restore_managed_agents_on_launch both re-snapshot the persona onto the record before spawning, so those edits DO apply on restart. spawn_config_hash now applies the same prospective re-snapshot (persona_snapshot_with_agent_config_fallback with the record's model/provider fallbacks) to a scratch record before hashing prompt/model/provider/env, so the hash covers exactly what a restart would run. The re-snapshot is idempotent, so the spawn-time stamp and later recomputes agree when nothing changed. Flipped persona_prompt_edit_does_not_change_hash to persona_prompt_edit_changes_hash (assert_ne).

effective.env.hash(&mut hasher);

// Record fields the spawn env writes read directly.
record.relay_url.hash(&mut hasher);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False-negative: blank record relay hashes the raw empty string, but spawn resolves the workspace relay. spawn_agent_child sets BUZZ_RELAY_URL from effective_agent_relay_url(&record.relay_url, relay_ws_url_with_override(state)) (runtime.rs:1553–1560), which falls back to the active workspace relay when record.relay_url is empty (relay.rs:65–72). Create intentionally stores relay_url: "" when the user leaves it unset (agents.rs:582–587). So if the workspace relay changes while a blank-relay agent is running, a restart would change both BUZZ_RELAY_URL and the relay-scoped git credential-helper URL — but this hashes "" vs "" and keeps the badge off.

Fix: hash the resolved effective relay URL (pass the workspace/effective relay into the helper) rather than the raw record field. Add a regression test for blank record relay + changed workspace relay.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in dcd5cee: the relay is now hashed in resolved form — spawn_config_hash takes a workspace_relay param (keeping it pure, no AppHandle) and hashes effective_agent_relay_url(&record.relay_url, workspace_relay). The summary builder passes relay_ws_url_with_override; the spawn stamp reuses the already-resolved effective_relay_url (resolution is idempotent). Added regression tests: blank record relay + workspace change trips the hash; pinned record relay + workspace change does not.

effective.env.hash(&mut hasher);

// Record fields the spawn env writes read directly.
record.relay_url.hash(&mut hasher);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit (optional, opposite direction — false positive): a few record fields are hashed in raw shape where spawn normalizes or drops them, which can trip the badge when a restart would change nothing — respond_to_allowlist when mode isn't allowlist, mcp_toolsets: None vs the default toolset string, max_turn_duration_seconds: None vs an explicit default. Not blocking, but worth tightening once the false-negatives above are fixed if the contract is strictly "badge only when a restart changes behavior."

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed these are real but benign (worst case a spurious badge that a restart clears, and each requires an unusual edit sequence). Deferring to keep this fix focused on the two false-negatives — happy to normalize respond_to_allowlist/mcp_toolsets/max_turn_duration in a follow-up if you'd like it tracked.

…lves it

Review feedback on #1602: the restart badge hash had two false-negatives.

1. Persona prompt/model/provider/env edits were excluded, but start/restore
   re-snapshot the linked persona onto the record right before spawning, so
   those edits DO apply on a plain restart. spawn_config_hash now applies the
   same prospective re-snapshot (persona_snapshot_with_agent_config_fallback)
   before hashing, so the badge trips when a restart would pick up the edit.

2. A blank record relay_url resolves to the active workspace relay at spawn,
   but the raw "" was hashed — a workspace relay change never badged. The
   relay is now hashed in resolved form (effective_agent_relay_url) with the
   workspace relay threaded from both call sites, keeping the hash pure.

Flipped persona_prompt_edit test to assert_ne and added blank-relay /
pinned-relay workspace-change regression tests.

Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman wesbillman merged commit cc42a49 into main Jul 7, 2026
45 of 47 checks passed
@wesbillman wesbillman deleted the pinky/restart-badge branch July 7, 2026 20:54
tellaho added a commit that referenced this pull request Jul 7, 2026
…ivity

* origin/main:
  feat(desktop): restart-required badge from spawn-time config hash (#1602)
  feat(desktop): boot-time reconcile of managed agents to relay events (#1601)
  feat(desktop): canonical <PubKey> component — hover to view/copy full keys, owner "you" labels (#1589)

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
tlongwell-block pushed a commit that referenced this pull request Jul 7, 2026
* origin/main:
  docs(readme): add Getting started section routing install paths (#1606)
  fix(desktop): restrict shared-agent sync to dev data dirs (#1597)
  feat(desktop): restart-required badge from spawn-time config hash (#1602)
  feat(desktop): boot-time reconcile of managed agents to relay events (#1601)
  feat(desktop): canonical <PubKey> component — hover to view/copy full keys, owner "you" labels (#1589)
  fix(desktop): hydrate reactions for Inbox context messages (#1596)
  fix: cleanup old screenshots that my agents committed (#1598)
  chore(release): release Buzz Desktop version 0.3.46 (#1585)
  fix(desktop): preserve agent model/provider when persona snapshot fields are blank (#1583)
  feat(acp,desktop): identify and reap stale agent harness processes (#1582)
  feat(desktop): active-draft badge, send-from-drafts confirm dialog, thread-deleted state (#1581)
  fix(desktop): treat baked build env vars as satisfying required agent config (#1580)
  feat(desktop): add "Copy image" to image right-click context menu (#1579)
  fix(nest): use buzz-dev symlink name for dev builds (#1587)
  fix(composer): address image-editor follow-up nits on #1491 (#1565)
  fix(desktop): render black static boot screen (#1570)
  feat(agents): group activity tool bursts (#1571)
  feat(desktop): aggregated overview rail, commit detail page, and full breadcrumbs (#1573)
  fix(desktop): fetch profiles for reaction actors and thread-reply authors (#1550)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants