Repository navigation
fix(ai-workspace): a write whose status save fails is reported as done, with a warning - #1416
Conversation
c4fb5e7 to
462a2e2
Compare
|
Process gate q107 (W1). History rebuilt, force-pushed over my own |
…e-specific advice (review a) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Disposition for review a (head
|
…DIR/EROFS advice (review b) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Disposition for review b (head
|
…e (review c nits) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Disposition for review c (MERGE-READY at
|
…ate write (verification b) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Disposition for verification b (head
|
|
READY (W1). Head |
Fixes #1285.
Plan:
docs/plans/2026-09-27-ai-workspace-write-status-warning.md, the first commit on the branch.Problem
ai-workspaces.json.invalid-<digest>.json.writeFilereplaces the user's file on disk, then refreshes the entry status, which saves state, which must make the owed copy first. That step fails.{ ok: false, error: "is a directory" }although the file was written. The editor (or an agent) told "failed" retries, or reports a failure that did not happen.Change
AiWorkspaceRegistry.writeFile. A failed status refresh after a successful write no longer fails the write. It returnsok: truewith an optionalwarning: new onAiWorkspaceWriteFileResult's success branch, documented as "the file IS written; do not retry". It logs the error, and still emitsfile-writtento every workspace holding the file. The owed-copy invariant is unchanged: state is still never saved while a copy is owed.preserveOwedCopy. A copy failure now says what is wrong and how to unblock it, keeping only the errno code: "AI Workspace storage needs attention: N unreadable row(s) must be copied aside before saving, and the copy could not be written (EISDIR). "Review a (
589d42a9):storageWarningfrom Save and Overwrite, shown through the file list's existing alert and cleared by the next clean write.AI_WORKSPACE_STATUS_NOT_SAVED), never a raw filesystem message.changedemits are guarded, so a throwing listener cannot fail a landed write or starve other workspaces.Review b (
d8f1eae6):getreturns a runtime-onlystorageWarningwhile an owed copy cannot be written, and the editor reads it on every load, so a workspace switch or remount shows it again.Verification b (
5ea05e1d):getalso reportsAI_WORKSPACE_STATUS_NOT_SAVEDwhile the last state save failed, even when the owed copy itself succeeded, until a later save succeeds.Tests (
AiWorkspaceRegistry.test.ts)The input is the real recorded registry state,
testing/fixtures/ai-workspace/real-workspaces-2026-09-25.json(two workspaces from the owner's file). Its paths are redacted, so one real entry is pointed at a temp file. One real workspace is made malformed so a copy is owed, as the #1260 tests do. The copy path is blocked with a directory.writeFileputsv2on disk, returnsok: truewith a warning that the file was saved but the status was not, and leaves the state file unchanged.{ ok: false, error: 'is a directory' }.createis refused with the actionable message.ok: true; a missing folder gets ENOENT advice. The always-warn, unguarded-emit and wrong-advice mutations each fail.getreports the blocked storage, clears it once the copy is written, and never persists it. The refusal carries no raw error text. A file shared by two workspaces notifies both, even when a listener throws.getkeeps reporting the unsaved status, and a successful save clears it.Verification
npx tsc -bclean.src/main/aiWorkspace: 23 tests, run with--testTimeout 60000under a machine load of about 60.🤖 Generated with Claude Code