## Review findings **P0: None.** ### P1 - **Partial settlement confirmation asks users to acknowledge information that is never displayed.** `frontend/src/pages/HouseholdReviewPage.vue:126-130` renders the incomplete mapping and a checkbox stating that the “next step” was reviewed, but neither the frontend contract nor the dialog displays the backend’s `next_step` instruction from `src/jarvis_finance/services/household_review_corrections.py:348-351`. A user can therefore confirm a partial settlement without seeing the required remediation. Add `next_step` to `HouseholdReviewItemActionPreview`, render it prominently, and bind acknowledgement to that visible instruction. - **The settlement action can be offered where the API will always reject it.** `frontend/src/pages/HouseholdReviewPage.vue:268` identifies eligible settlements solely through the localized `special_hint === 'Gegenbuchung fehlt'`. The backend assigns that hint to both payment and counterpost classifications (`src/jarvis_finance/services/household_import.py:2443-2446`), while confirmation accepts only AKB/Raiffeisen bank sources (`src/jarvis_finance/services/household_review_corrections.py:272-279`). VISA/card-side counterposts therefore receive an inert action ending in 409. Eligibility should be an explicit API action capability, not inferred from display copy. - **The shared transaction dialog does not maintain modal focus semantics.** `frontend/src/components/household/TransactionDetailDrawer.vue:85-95` waits for both requests to finish before focusing the dialog and making the application inert. During loading—and permanently on an error—the `aria-modal` dialog is visible while focus and interaction remain in the background. Closing also never restores focus to the opener (`:114-115`). Make the background inert and focus the dialog immediately on opening, retain modal behavior on errors, and restore the captured opener on close. - **Required drawer workflows are not keyboard-equivalent or 44px-compliant across 390/1440 layouts.** Mobile expense cards are click-only (`frontend/src/pages/BudgetTransactionsPage.vue:50-55`); the desktop merchant opener is an un-sized inline button (`:64`); desktop budget-status rows are mouse-only (`frontend/src/pages/BudgetStatusPage.vue:17-18`); and the category detail itself lacks dialog semantics/focus containment (`:21-27`). Consequently keyboard users cannot reliably reach the transaction drawer on required views, and the desktop inline opener is not guaranteed to meet 44×44px. Use semantic buttons/links with Enter/Space behavior, minimum 44×44 targets, and proper modal focus handling. ### P2 - **Category Assignment still has no 820px card/reflow treatment and exposes undersized controls.** Both five-/four-column tables remain unconditional at `frontend/src/pages/BudgetCategoryAssignmentPage.vue:25-35`, with no responsive card layout or overflow containment. The candidate checkboxes at `:29` retain their native small hit areas, and confirmed-transaction rows at `:34` have `tabindex` but no button role or Space activation. At 390px, long descriptions and headers can force horizontal table overflow. Add the required ≤820px card layout and semantic 44×44 controls. - **The duplicate-original picker exposes choices broader than the API contract.** `frontend/src/pages/HouseholdReviewPage.vue:280-288` fetches a capped page and filters only by date, amount, and currency, while the backend additionally requires an exact normalized merchant match (`src/jarvis_finance/services/household_review_corrections.py:148-166`). Users can select unrelated same-value transactions and receive a 409, while a valid original beyond the first page may be omitted. Return eligible originals from the review contract or mirror the complete compatibility and pagination rules. ## Verification - Frontend focused tests: **45 passed** - Frontend typecheck: **passed** - Frontend production build: **passed** - Backend correction tests: **8 passed** - `git diff --check`: **passed** - **Files modified by reviewer:** none - **Issues encountered:** initial Vitest command used repository-relative paths instead of frontend-relative paths; rerun succeeded.