Workspace Artifacts keeps stale, dead-link entries after files are moved or deleted
#6,867 opened on Aug 9, 2026
Repository metrics
- Stars
- (17,368 stars)
- PR merge metrics
- (Avg merge 14h 31m) (314 merged PRs in 30d)
Description
Report
The Workspace Artifacts tab can retain an obsolete path after files are updated or moved. The stale row remains clickable and ends in the generic “file not found” / file_open_failed state even though the file exists at its current location. Switching to another session and back rebuilds the list correctly.
Reported from exp-v0.52.158-dirty-a9b7cc19; the lifecycle gap is still present on master at 614b5c9f485d33de0f35f0c2b5b95e4090ef3af3 (exp-v0.52.186).
Investigation
The canonical artifact data updates, but one settled-session recovery path does not project that new data into the already-rendered Artifacts DOM:
collectSessionArtifacts()derives the current rows fromS.toolCallsand structured message metadata.renderSessionArtifacts()is what materializes that state into the panel; the DOM is not otherwise reactive.- Normal live paths do refresh the panel:
tool/tool_completeschedule an artifact render, and the normaldonepath renders after applying the settled session. _restoreSettledSession()replacesS.session,S.messages, andS.toolCallsfrom the canonical persisted session after stream-end/SSE recovery, then calls onlysyncTopbar()andrenderMessages(). It never callsrenderSessionArtifacts()orscheduleRenderSessionArtifacts().- The reported self-heal matches the other lifecycle exactly:
loadSession()explicitly callsrenderSessionArtifacts()after loading the session. Switching away and back therefore projects the already-correct canonical artifact state and removes the stale row. openArtifactPath()then explains the visible failure: clicking the retained old DOM row performs an existence check and emitsfile_open_failed.
I executed the real current-head collector and renderer against the relevant state transition:
{
"initialDom": ["old/path.md"],
"canonicalAfterRestore": ["new/path.md"],
"domAfterRestoreWithoutProjection": ["old/path.md"],
"domAfterSessionLoadProjection": ["new/path.md"]
}
This isolates the bug: canonical state is already correct after recovery; only the Artifacts DOM remains stale until the session-load render runs.
Reproduction shape
- Keep the Artifacts tab/panel mounted while a live turn changes the session artifact set.
- Let the turn settle through the
stream_end/ settled-session recovery path rather than the ordinarydoneprojection. - Observe that the transcript and canonical
S.toolCallssettle, but the Artifacts DOM retains its previous row. - Click that obsolete row and observe
file_open_failed. - Switch to another session and back; the Artifacts list now reflects the canonical path.
Expected behavior
Every path that installs canonical session messages/tool metadata for the actively viewed session should refresh all dependent projections, including Workspace Artifacts. Users should not need to switch sessions to reconcile the panel.
Fix shape and acceptance criteria
- After
_restoreSettledSession()installs canonicalS.messages/S.toolCalls, refresh Workspace Artifacts for the active viewed session. - Prefer a shared post-session-state projection helper used by normal
done, settled-session recovery, andloadSession()so these dependent views cannot drift again. - Preserve
openArtifactPath()'s existence check as a safety boundary; prevent the obsolete row rather than weakening file-not-found handling. - Add a deterministic regression test using the real collector and renderer: render an old path, apply a settled snapshot containing a replacement path, run the recovery projection, and assert that the new path is visible without a session switch and the old row is absent.
- Ensure recovery for a non-viewed/foreign session cannot repaint the currently viewed panel.
Distinct from existing issues
- #5747 and PRs #5752/#6691 cover stale content in an already-open file preview, not stale rows in the Artifacts list.
- #6205 / #6207 / #6469 concern durable turn-owned artifact references and explicitly leave the existing Artifacts-tab reconstruction unchanged.
- #6593 / #6694 add artifact categories; they do not cover settled-session DOM invalidation.
- #3329 fixed structured tool metadata and absolute-path opening. The current bug has correct canonical metadata but a stale rendered row.
- #3885 is related lifecycle history: it added settled-session recovery for a missing transcript after
stream_end, but did not refresh Workspace Artifacts.