fix(archive): keep dismissed confirmations closed across delayed responses - #3010
Conversation
…e receipts Refs #2996. Add deferred-response component regressions and an explicit verification handoff.
|
Exact-head qualification update for |
…ive-request-ownership # Conflicts: # frontend/taskdeck-web/src/components/board/CardArchiveAction.vue
…uite evidence The draft's qualification note recorded the repair as unqualified and listed the frontend commands as NOT RUN, because the authoring environment had no installed frontend dependencies. Both statements are now false: the eight regression cases, the existing archive specs, the consumer specs, typecheck and build all ran on the merged head. Also records what the cases are actually worth: reverted to main's component, five of the eight fail and three pass, so three of them pin invariants rather than reproducing the defect. Real-browser and screen-reader journeys stay marked NOT RUN.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Review round 1 — dispositionCodex connector did not review this head. Its only comment is an informational notice that the account's code-review usage limit is reached; that is a non-finding, not a clean outcome, so under global law 2g the review gate is carried by one fresh-context independent adversarial pass instead. That pass ran against the merged head Result: nothing at CRITICAL or HIGH. One MEDIUM, four LOWs, one vacuous test. All non-blocking under law 2a; tracked in #3033 rather than fixed here, so the reviewed head is the merged head. Confirmed sound
Declined here, tracked in #3033
Evidence at this headHosted Frontend Unit passed on both ubuntu-latest and windows-latest — that is the broad frontend evidence the local box cannot produce. Backend Unit (both platforms), Backend Architecture, Docs Governance, Migration Validation, SAST, Container Images and Smart CI Required Gate all passed. Locally on the merged head: the three archive specs 18/18, the three consumer specs 75/75, typecheck clean, build clean, docs governance and doc links clean — with the eight new cases' regression value measured by reverting the component (5 of 8 fail, 3 pin invariants), stated plainly in the body rather than presented as eight reproducers. |
Summary
Closes #2996.
CardArchiveAction.refreshChildrencheckedconfirmingonly on entry and never re-checked after itsawait. Dismiss the confirmation (Escape/backdrop) while an in-dialog child refresh is in flight and the late response reopened the dialog the user closed, cleared the retained error, and pulled focus back into the modal. The mirror case overwrote the page-level message and stole focus after the user had moved on.nextTick, not only when it is scheduled, so dismissed work cannot pull keyboard focus back.busy.setCardArchivedfor the same card still emitschanged, a failed one still raises the page-level error without stealing focus. Escape stays unconditional — a request that never settles must not trap a keyboard user.Rebase onto current main
The original draft was based on
4c479a7ffand went DIRTY when #3015 (GH-2969) landed thearchivedprop override in the same component. Merged withmainat5396fb6cc; the ownership model is re-applied on top of main's component, not the other way round. Both conflicts were additive and resolved keeping main's semantics intact:change()sends!archived.value(main's settled-state override), then the context guard runs.requestChange()keeps main'sif (archived.value) return change()entry.git diff origin/main...HEADtouches exactly three files; no other file in main's version of the component is altered.Verification actually executed
Real Vitest on the merged head — the draft's dependency-free Node probe is superseded and is not evidence for this change.
frontend/taskdeck-web)npx vitest --run --maxWorkers=2 src/tests/components/CardArchiveAction.requestOwnership.spec.ts src/tests/components/CardArchiveAction.spec.ts src/tests/components/BoardCardArchive.spec.ts--reporter=verbose)npx vitest --run --maxWorkers=2 src/tests/components/CardModal.spec.ts src/tests/components/CardModalAssignmentSave.spec.ts src/tests/views/paper/PaperBoardCard.spec.tsnpm run typechecknpm run buildnode scripts/check-docs-governance.mjs/node scripts/check-doc-links.mjs(repo root)Regression value measured, not assumed. With the component reverted to
main's version and the spec untouched, 5 of the 8 fail: both late-refresh-after-Escape cases, the late write failure after Escape, and both card-switch cases. The other three — late write success after Escape, same-card prop replacement, and unmount before the write settles — pass against the unfixed component too, so they pin invariants the repair must not break rather than reproducing the reported defect. Said plainly here and in the note rather than presented as eight reproducers.NOT verified
Scope
CardArchiveAction.vue, its new spec, anddocs/analysis/2026-09-11-archive-request-ownership.md(rewritten: the draft's note claimed the frontend commands were NOT RUN, which is no longer true). No endpoint, payload, permission rule, expected-state token, retry behaviour or confirmation wording changes. No CardModal, BoardCardArchive or CI control-path edits. STATUS/MASTERPLAN unchanged — a bounded defect repair inside one already-shipped control, the same basis on which #3015 landed.#2969 (newer unsaved draft disposal) and #2997 (assignment-save close paths) remain separate. #3023 (kept-draft notice residuals from #3015's review) is untouched by this PR.
Review focus
Escape during a deferred refresh/write in both success and failure; the interaction between the new
onBeforeUnmountinvalidation andCardModal's:key="card.updatedAt"remount of this control; same-ID prop replacement during a write; context switches with overlapping reads; and the shared control in both Paper and Legacy hosts.