4.2 KiB
Recovery diagnostic publication correction
Frozen local source 554cfbd9fe6fd64f0eb3012bcbb3efd7a95f7424, parent 92ff99eb54b75a67c6320cad93d11790413bbd8d, clean .local/tu, branch codex/text-union-956atf-20260913. Parent owns independent review, integration and compiler/native acceptance. Other worktrees, root, dependencies and targets unchanged.
The confirmed source defect was SourceRecovered filtering pending_save and unconditionally stamping every remaining diagnostic with the current source key. A warning retained across a workspace-key departure could thereby acquire fresh action/annotation authority even though recovery had neither recomputed it nor replaced the retained drafts.
Only crates/oa-desktop/src/app.rs and crates/oa-desktop/src/app/text_workspace/lifecycle_tests.rs changed: +166/-7. The production change captures publication/source-key equality before filtering. It removes the recovery notice in all matching successful recovery receipts, but republishes the remainder only if they were current beforehand. A previously stale publication remains stale (or absent stays absent). Current warnings get a new generation, so queued old primary/related actions cannot replay. The subsequent existing successful-reload/unapplied-workspace, applied-draft-retention and reload-error branches remain unchanged. This follows the existing reset_source_navigation_session freshness guard; no new publication/cache framework or source navigation policy was added.
Exact source manifest, SHA256 b90d42d23601ab415afb5dde1406d66f6ae1c2af0a2076184a870bddb12e741b, binds both committed blobs, sizes and SHA256s. Exact source diff, SHA256 35b5b224a50aa7e3e7e1b535388e5e7239669719c0fcba8fcacae5323e80442c.
Two new test declarations, both UNCOMPILED/UNRUN:
app::text_workspace::lifecycle_tests::recovery_retains_current_warning_authority_with_drafts_and_reload_failureapp::text_workspace::lifecycle_tests::recovery_does_not_republish_stale_warnings_after_workspace_key_departure
Each runs a successful-load and reload-error receipt arm. The fixture saves a real private temporary source project, writes the established recovery journal format, derives pending-save diagnostics/target through load_project/recovery_target, dispatches normal SourceRecover, calls the actual recover_snapshot worker and delivers the matching SourceRecovered receipt. Returned App tasks are deliberately not polled, following the existing deterministic lifecycle harness. The error arm explicitly injects receipt.disk = Err(...) after successful real journal recovery; it does not claim to provoke an OS reload failure. Tests themselves have not run, so no journal execution/result is claimed by this handoff.
Both cases retain newer applied-workspace drafts. The positive publishes its warning after the draft edit and requires a current annotation snapshot and fresh primary/related navigation. The negative publishes before Workspace::edit advances the source key, preserves the old warning vector while lint is outstanding, and requires no fresh diagnostic message or annotation snapshot afterward. Both require removal of pending_save, consumed recovery ownership, unchanged source key/editor cursor/drawer visit/full raw bundle/accepted Project Arc/revision/Undo-Redo state, exact restored disk bytes, and rejection of captured pre-recovery primary/related actions before source interaction/reveal changes. The negative directly fails the unconditional 92ff republish predicate; the positive prevents a blanket diagnostic-clear workaround. Existing chooser/passive/retention tests and source branches are untouched.
Completed: standalone rustfmt (edition 2024, skip_children=true) for both owned files; git diff --check; exact two-file scope check; clean status after commit. No Cargo, rustc, build, tests, GUI, target changes or Gitea operations. No test names removed, no ignores added. Parent/fresh critic should inspect this source and run these two cases plus retained lifecycle/diagnostic and root recovery cases when the compiler lease permits. The broader Text union and public release remain unaccepted pending their gates.