fix: let a slow add-source wizard finish instead of failing with a phantom disk error - #291
Merged
Merged
Conversation
…antom disk error Root cause (diagnosed from a user diag bundle): add_source resolved the local folder from a single-use dialog token with a 5-minute TTL, consumed the token before validating anything, and mapped every token failure to local.io_error. A wizard session that outlives the TTL (big-tree exclusion preview + destination browsing) therefore failed at Finish with 'Driven hit a disk error reading a file' - and because the take consumed the token even on failure, every retry in the same session failed the same way. No disk error ever occurred, and none of the six rejected add_source calls left any trace in the logs. - add_source now PEEKs the token up front and spends it only at commit (the restore command's R3-P2-1 pattern), so a failed validation leaves the token intact - DIALOG_TOKEN_TTL raised 5min -> 60min to cover a real wizard session; binding stores its expiry instant so tests can force expiry - new stable code internal.stale_dialog_token (SPEC s24 + en-US copy 'pick the folder again') replaces the local.io_error mapping for unknown/spent/expired tokens across add_source, exclusion previews, restore, and the diagnostic export; the dialog-cancel sentinel is untouched - every CommandError is now logged (warn) as it serialises across the IPC boundary, so rejected commands appear in the rolling log and diagnostic bundles - the add-source and setup wizards render a muted technical-detail line (stable code + redacted backend message) under the localized error, so same-code failures are distinguishable on screen Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LRMdu3VkuhL6Ny6hRcnFpU
… too Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LRMdu3VkuhL6Ny6hRcnFpU
Contributor
Coverage
Gate: passed - no coverage regression (epsilon 0.1 pp). |
pmaxhogan
added a commit
that referenced
this pull request
Aug 15, 2026
🤖 I have created a release *beep* *boop* --- ## [2.11.0](v2.10.1...v2.11.0) (2026-08-14) ### Features * **ui:** live disk/network throughput graphs + visible upload recovery ([#290](#290)) ([4fe156c](4fe156c)) ### Bug Fixes * **core:** exempt Zone.Identifier from the ads_skipped warning ([#288](#288)) ([f37ff68](f37ff68)) * let a slow add-source wizard finish instead of failing with a phantom disk error ([#291](#291)) ([1fbba98](1fbba98)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
pmaxhogan
added a commit
that referenced
this pull request
Aug 15, 2026
…d fix (#292) The #291 wizard fix changed the step-2 error layout (+40px) but never got a baseline pass - the visual suite only runs at the release gate, which is exactly how the v2.11.0 release run went red (2 failed snapshots, both `setup-wizard/step2-error`). Regenerated via `just visual-update` on current main; all 102 visual tests pass locally in the same Docker harness. Baseline-only change; after merge the v2.11.0 tag will be re-cut so the release pipeline can pass. README checked, no changes needed (test-only). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01A7q3CvJzL4zZmDA9CbXyQQ
pmaxhogan
added a commit
that referenced
this pull request
Aug 15, 2026
The v2.11.0 tag's release pipeline failed at the visual-regression gate (setup-wizard baselines predating #291) before publishing any artifacts, so no 2.11.0 build ever shipped. The baselines were regenerated in #292; this empty commit gives release-please a releasable change so 2.11.1 carries the full 2.11.0 payload (#288, #290, #291) through a green pipeline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A7q3CvJzL4zZmDA9CbXyQQ
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 bug (diagnosed from a user diagnostic bundle)
Creating a backup source failed every time with "Driven hit a disk error reading a file" — with zero real disk errors anywhere and zero trace of the six failed
add_sourcecalls in the logs. Root cause chain:add_sourceresolved the local folder from a single-use dialog token with a 5-minute TTL. A real wizard session (big-tree exclusion preview + Drive destination browsing + thinking) outlives that, so Finish always failed.take_dialog_tokenconsumed the token before any validation, so the first failed Finish destroyed it and every retry in the same session failed too.local.io_error, whose copy tells the user their disk is failing.The fix
add_sourcepeeks up front and spends the token only at commit (the same R3-P2-1 pattern the restore command already uses), so failed validation leaves the token intact.DIALOG_TOKEN_TTL5 min → 60 min; the binding now stores its expiry instant (testable withoutInstantunderflow).internal.stale_dialog_token(SPEC §24 + en-US copy "pick the folder again") replaces thelocal.io_errormapping for unknown/spent/expired tokens acrossadd_source, exclusion previews, restore, and the diagnostic export. The dialog-cancel sentinel is untouched.CommandErroris now logged (WARN) as it serialises across the IPC boundary — the single seam every rejection passes through — so failures land in the rolling log and diagnostic bundles. Known trade-off: a UI polling loop against a persistently failing command writes one WARN per poll; accepted for diagnosability.R8-P2-1 said backend English must never render. This PR narrows that: the localized
t(errors.${code}.long)string remains the only primary error, but a dedicated muted detail element may carry the stable code + backendmessage. Rationale: two failures sharing one code (expired token vs. genuinely unreadable folder) were indistinguishable on screen, which is how a token expiry masqueraded as a disk error. Therecovery-reveal-error-i18ntest is updated to enforce the new shape (primary line exactly localized; backend text only inside*-error-detail).Tests
cargo check --workspace --all-targetsclean;cargo fmt --checkclean (dockerized); driven-core 555 + driven-app 417 lib tests + ipc_path_validation passexpired_dialog_token_is_rejected_by_peek_and_take), stale-token i18n copy test, detail-line rendering assertionsREADME checked, no changes needed (no stale claims; behavior-level fix below the feature list).
🤖 Generated with Claude Code
https://claude.ai/code/session_01LRMdu3VkuhL6Ny6hRcnFpU