fix(reports): discard the fetched report when the use case changes (#1943) - #1945
Conversation
…1943) Changing the use case left `report` and `sourceId` intact, and step 2's Next button is gated only on `sourceId` — so a user could pick a use case, pick a source, go back, pick a DIFFERENT use case, and click straight through to step 3 still holding a report fetched under the previous use case. Post-#1930 this was no longer just a stale-figures cosmetic bug: a budget-overview -> claim switch along that route could carry quotation-tier documents into an exported claim PDF handed to a bank, defeating #1930's AC2 via a route it doesn't cover. The reset clears `report`, `reportStatus`, `sourceId`, and both invoice/line exclusion sets — inside the existing `guardedUpdate` discard-confirmation callback, so unsaved edits or AI-generated content still prompt for confirmation first and only clear once confirmed. A one-shot `deepLinkAppliedRef` stops the `?sourceId=` deep-link effect (keyed on `!report`) from re-arming once `report` is cleared and silently re-selecting the original query-string source under the new use case. Notes for the record: - AC4 (a report exported under use case X is identical to one from a clean start under X, in both directions and for every use-case pair) is satisfied structurally by this fix — both paths converge on the same `handleSourceChange` call under the current `useCase` closure — but is not independently tested here. The deeper determinism claim belongs to `getSourceReport`, already covered by #1930/#1942's own suite. A cross-direction diff test is a nice-to-have follow-up. - The new E2E scenarios (13/14) have never been executed locally — Playwright's Chromium is network-policy-blocked in this sandbox (no browser binary present at all), so CI is their first real run. Fixes #1943 Co-Authored-By: Claude dev-team-lead <noreply@anthropic.com> Co-Authored-By: Claude frontend-developer <noreply@anthropic.com> Co-Authored-By: Claude qa-integration-tester <noreply@anthropic.com> Co-Authored-By: Claude e2e-test-engineer <noreply@anthropic.com>
|
[product-architect] Architecture / test-coverage / code-quality review of PR #1945 (#1943). Verdict: APPROVED — no critical or high findings. Three medium and two low findings below are non-blocking follow-ups; one of them (M1) I'd like filed and fixed inside this Bank Report Wizard cluster before the What I verified
Answers to the three questions raised on handback1. Is AC4's "structural corollary" reasoning sound? — Mostly, but there is one real gapThe reasoning is correct for the deterministic path: after the fix, step 3 is reachable only via a But AC4 says always identical, and two history-dependent inputs survive:
So: the reasoning is sound about why the fetch is right; it is not sufficient to establish AC4 as literally stated. That is an AC-precision issue plus M1, not a defect in this change. 2. Does
|
…1943) M1 from product-architect's review of PR #1945: `handleSourceChange` had no abort and no staleness token, so an in-flight `getSourceReport` fetch from the PREVIOUS use case could still resolve after a later fetch for the same source. Out-of-order resolution — the `budget-overview` fetch settling AFTER the `claim` fetch — let the stale response win the final `setReport`/`setReportStatus` write, reaching step 3 with a report from the wrong use case even though the prior reset (this PR's first commit) had already cleared it. That is #1943's exact end state (quotation-tier documents in a claim export), reached via a race #1943's own AC1 ("no report fetched under a different use case survives the change") does not yet cover. Fixed with a monotonic request token (`reportRequestRef`): bumped on every use-case change and on every source (re-)selection, and checked in both the `.then` and `.catch` of `getSourceReport` before writing any state. A response that isn't from the most recently started fetch is discarded outright — including a stale REJECTION, which would otherwise flip `reportStatus` to `'error'` over an already-succeeded newer report. This also closes a pre-existing symmetric variant: rapidly picking source A then source B on step 2 (no use-case change involved) had the same unguarded race. Independent of `deepLinkAppliedRef` (added in the first commit on this branch) — that guard stops the deep-link effect from re-*firing*; this token stops an already-in-flight response from *writing*. The two address orthogonal failure modes and don't interact. Two new deterministic unit tests use manually-resolved deferred promises to force the settle order explicitly (out-of-order success, and a stale rejection arriving after a newer success) rather than relying on timing. Verified both fail without the token logic and pass with it restored. Co-Authored-By: Claude dev-team-lead <noreply@anthropic.com> Co-Authored-By: Claude frontend-developer <noreply@anthropic.com> Co-Authored-By: Claude qa-integration-tester <noreply@anthropic.com>
Product-owner notes from the PR #1945 review round: the M1 in-PR fix rationale, the AC4 rewording, the completed AC5 enumeration, and the recurring pattern where an acceptance criterion misdescribes what is being built and would fail a correct implementation at UAT. Co-Authored-By: Claude product-owner <noreply@anthropic.com>
|
🎉 This PR is included in version 2.13.0-beta.45 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
reportandsourceIdintact, and step 2's Next button is gated only onsourceId— so a user could pick a use case, pick a source, go back to step 1, pick a different use case, and click straight through to step 3 still holding a report fetched under the previous use case.report,reportStatus,sourceId, and both invoice/line exclusion sets — inside the existingguardedUpdatediscard-confirmation callback, so unsaved edits or AI-generated content still prompt for confirmation first and only clear once confirmed.deepLinkAppliedRefstops the?sourceId=deep-link effect (keyed on!report) from re-arming oncereportis cleared and silently re-selecting the original query-string source under the new use case.Fixes #1943
Notes for the record
handleSourceChangecall under the currentuseCaseclosure — but is not independently tested here. The deeper determinism claim belongs togetSourceReport, already covered by Attachment tier rules per report type (quotation -> deposit -> invoice) replace per-invoice stage matching #1930/feat(reports): filter report attachments by document tier per report type (#1930) #1942's own suite. A cross-direction diff test would be a nice-to-have follow-up.Test plan
ReportWizardPage.test.tsx, 26/26 inReportWizardPage.aiGeneration.test.tsx— unaffected/no regression)Co-Authored-By: Claude dev-team-lead noreply@anthropic.com
Co-Authored-By: Claude frontend-developer noreply@anthropic.com
Co-Authored-By: Claude qa-integration-tester noreply@anthropic.com
Co-Authored-By: Claude e2e-test-engineer noreply@anthropic.com