fix: prune stale attached_workspaces when anchor paths become invalid#2032
Merged
Conversation
…#2030) Add prune_stale_attached_workspaces() to RuntimeHandle that lazily removes stale workspace IDs from attached_workspaces. An entry is stale when its ID is absent from the workspace registry or when the anchor path no longer exists on disk. Called from the agent_state HTTP handler before building the summary, so stale entries are cleaned on every state read. Active workspace and AgentHome are always preserved. Each pruned ID emits a workspace_detached audit event with reason "stale_workspace_anchor". Closes #2030
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
jolestar
commented
Jun 27, 2026
jolestar
left a comment
Collaborator
Author
There was a problem hiding this comment.
Review: PR #2032 — prune stale attached_workspaces when anchor paths become invalid
Verdict: ✅ LGTM — ready to merge after CI passes.
Analysis
- Scope: 3 files, +232 lines — adds
prune_stale_attached_workspaces()toRuntimeHandle, calls it from theagent_stateHTTP handler, and includes 5 unit tests. - Correctness: Logic is clean — stale = absent from registry OR anchor not a directory. Active workspace and AgentHome are correctly protected from pruning.
- Audit trail: Each pruned ID emits a
workspace_detachedevent withreason: "stale_workspace_anchor"— good observability. - Persistence: State is properly persisted after pruning.
- Test coverage: 5 tests cover all key scenarios (missing registry entry, deleted anchor, active workspace protection, valid workspace preservation, audit events).
Non-blocking notes
- Lock granularity: The method acquires the agent lock 3 times (agent_id, active_workspace_id, attached_workspaces). Could be consolidated into one acquisition, but not a correctness issue given the HTTP handler call site.
- Error propagation:
bridge.workspace_entry_by_id()uses?which aborts the entire prune on a single registry error. Since the caller uses.ok(), amatchwithcontinueon error could be more resilient — but this is a minor robustness improvement.
Overall: clean, well-tested fix for a real accumulation bug. ✅
…n prune_stale_attached_workspaces Address non-blocking review feedback on PR #2032: - Consolidate 3 separate agent lock reads into a single acquisition - Use match+continue instead of ? for per-entry registry errors
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.
Problem
When a workspace's anchor path becomes invalid (worktree deleted, directory moved/deleted), the workspace ID remains in the agent's
attached_workspaceslist forever. Onlydetach_workspaceremoves entries; all other worktree cleanup paths (cleanup_task_owned_worktree_in_detail,discard_managed_worktree,exit_worktree) delete the physical worktree but never clean up the agent state.This causes stale workspace entries to accumulate in the UI (workspace IDs with no path shown, not browsable).
Closes #2030.
Solution
Add
prune_stale_attached_workspaces()toRuntimeHandlethat lazily removes stale workspace IDs fromattached_workspaces. An entry is stale when:The prune runs from the
agent_stateHTTP handler before building the summary, so stale entries are cleaned on every state API read — the primary read path for the UI.Design choice: runtime-layer cleanup vs. projection-only
The issue proposed doing the cleanup inside
state_workspace_snapshot(a pure projection function). Instead, the cleanup lives at the runtime layer (RuntimeHandle::prune_stale_attached_workspaces) because:state_workspace_snapshotshould not mutate agent state.workspace_detachedaudit event withreason: "stale_workspace_anchor".Safety guarantees
agent_homeandagent_home:{agent_id}) is never pruned — it is a virtual workspace that may not be in the registry.Changes
src/runtime/lifecycle.rsprune_stale_attached_workspaces()methodsrc/http/state.rsagent_summary()inagent_statehandlersrc/runtime/tests/workspace.rsTest plan
prune_removes_workspace_id_missing_from_registry— stale ID not in registry gets prunedprune_removes_workspace_with_deleted_anchor— registry entry with deleted anchor dir gets prunedprune_preserves_active_workspace_even_when_stale— active workspace is never prunedprune_preserves_valid_workspaces— valid workspaces are preservedprune_emits_audit_events_for_removed_workspaces— audit events with correct reasoncargo fmt --all -- --checkpassesRUSTFLAGS="-D warnings" cargo check --all-targetspasses