diff --git a/docs/IMPLEMENTATION_MASTERPLAN.md b/docs/IMPLEMENTATION_MASTERPLAN.md index 9e5e0f294..8d37a8eb8 100644 --- a/docs/IMPLEMENTATION_MASTERPLAN.md +++ b/docs/IMPLEMENTATION_MASTERPLAN.md @@ -597,6 +597,18 @@ Delivered in the latest cycle: - board metrics accuracy verification tests (`#718`/`#749`): 61 tests (51 service + 10 controller) for throughput, cycle time, WIP, blocked cards, done-column heuristic - notification delivery integration tests (`#719`/`#746`): 36 tests covering all 5 notification types, deduplication, preference filtering, cross-user isolation, batch operations - wave progress: 15 of 22 `#721` issues now delivered (~886 new tests total); 7 issues remain open +128. Post-adversarial-review hardening and test expansion (PRs `#741`–`#756`, 2026-04-04): + - 9 issues from `#721` tracker plus product telemetry taxonomy, two bug fixes, and six frontend regression test additions + - product telemetry taxonomy delivered (`#341`/`#741`): `docs/product/TELEMETRY_TAXONOMY.md` with 35+ named events, privacy-first bucketing, and R1/R2/R3 launch gate anchors; opt-in, not yet implemented + - board header presence label bug fixed (`#683`/`#744`): username/email flip resolved with `normalizePresenceMembers()` in `BoardView.vue`; adversarial review confirmed no edge cases; 3 new tests + - manual card provenance empty state fixed (`#680`/`#754`): 3 bugs caught and fixed by adversarial review (overly broad 404 swallow, global Axios log regression, empty-state flash); `CardModal.vue` now shows "No capture provenance available." correctly; 4 new tests + - WIP-limit toast dedup regression tests (`#686`/`#745`): 7 tests in `boardStore.wipLimit.spec.ts` for `createCard` and `moveCard` + - auth-flow toast lifecycle tests (`#685`/`#742`): 20 tests in `sessionStore.authToast.spec.ts`; adversarial review fixed timer leak, mock isolation, inverted assertion + - router auth guard + workspace stability tests (`#687`/`#748`): `authGuard.spec.ts` and `workspaceRouteStability.spec.ts` with 16-case exhaustive guard table; pre-existing `AuthControllerEdgeCaseTests.cs` compile error fixed + - inbox triage action visibility tests (`#688`/`#743`): 21 new tests in `InboxView.spec.ts` for single-item triage and bulk action bar visibility + - webhook HMAC verification tests (`#726`/`#750`): 11 tests in `OutboundWebhookHmacDeliveryTests.cs` for header format, round-trip, wrong-key, secret rotation, timing-safe comparison + - webhook delivery reliability + SSRF boundary tests (`#710`/`#756`): 78 total webhook tests across 9 files; SSRF coverage via `OutboundWebhookEndpointGuardTests` for private IP ranges; retry/backoff/dead-letter reliability; `HttpClient` resource leak fixed in tests + - TST-32–TST-57 wave progress updated: 17 of 25 issues now delivered; remaining open: `#705`, `#711`, `#712`, `#716`, `#717`, `#720`, `#723`, `#725`; frontend suite at 1592 passing (up from 1496) ## Current Planning Pivot (2026-03-07) diff --git a/docs/MANUAL_TEST_CHECKLIST.md b/docs/MANUAL_TEST_CHECKLIST.md index 576935327..1ad9800f7 100644 --- a/docs/MANUAL_TEST_CHECKLIST.md +++ b/docs/MANUAL_TEST_CHECKLIST.md @@ -105,6 +105,16 @@ Manual-only checks (non-automatable in generic local script): 9. Logout from top bar. - Expected: token/session cleared, redirected to `/login`. +**Auth-flow toast regression (PR #742):** +- Attempt login with wrong password. + - Expected: error toast appears with the server-provided reason (e.g. "Invalid credentials"). +- Attempt registration with a duplicate email. + - Expected: error toast appears with guidance about the duplicate account. +- Login successfully after a failed attempt. + - Expected: error toast from the failed attempt does not persist; success toast "Logged in successfully" appears. +- Sign in with GitHub OAuth (if configured). + - Expected: success toast "Signed in with GitHub" appears; error toast appears on OAuth failure. + ## B. Boards, Columns, Cards, Labels 1. Create board from workspace boards page. @@ -130,10 +140,25 @@ Manual-only checks (non-automatable in generic local script): - Expected: operation blocked with visible error feedback. - WIP limit enforcement bug (`#517`) has been resolved; verify regression. +**WIP-limit toast deduplication regression (PR #745):** +- Set a WIP limit of 1 on a column, add a card, then try to add a second card. + - Expected: exactly ONE error toast appears. No duplicate toasts. +- Try to move a card into the same WIP-limit-reached column. + - Expected: exactly ONE error toast. No duplicate toasts. + 9. Create card inline. - Expected: card appears in target column. 10. Open card modal (`Enter` on selected card or click). - Expected: modal opens with current values. + +**Manual card provenance empty state (PR #754):** +- Open a card that was created manually (not via capture/inbox). + - Expected: card detail shows "No capture provenance available." in the provenance area. No error shown. No blank/broken provenance section. +- Open a card created via the capture/inbox flow. + - Expected: card detail shows full capture provenance (source, timestamp, original capture text). The "No capture provenance available." message does NOT appear for captured cards. +- For captured cards, verify the provenance empty state does not flash during the initial load of the captured card's modal. + - Expected: empty state is only shown after load completes and provenance is confirmed absent. + 11. Edit title/description, set due date, block with reason, assign labels. - Expected: updates persist and render in lane. 12. Move card to another column via drag/drop using the `Drag Card` handle. @@ -147,6 +172,12 @@ Manual-only checks (non-automatable in generic local script): - Expected: label manager modal uses dark workspace theme (design tokens) — no jarring light-theme styling. - Bug fixed (`#684`/`#692`): modal migrated from hardcoded light-theme classes to design-token-driven dark theme. +**Board header presence label format (PR #744):** +- Open a board with at least one other presence member (or open the same board in two browser tabs with the same user). + - Expected: the current user's presence indicator shows their **username** (e.g. "alice"), NOT their email (e.g. "alice@example.com"). + - Expected: when you open a card for editing, the presence label stays as username — it does not switch to email. + - Expected: presence indicators for OTHER users show whatever name the server provides (unaffected by the fix). + ## C. Filters and Keyboard Workflow 1. Toggle filter panel with `f`. @@ -202,6 +233,25 @@ Manual-only checks (non-automatable in generic local script): - Expected: proposals that expire while the page is open transition to expired state reactively (60-second clock). - Bug fixed (`#678`+`#690`/`#696`): expired proposals no longer appear actionable; dismiss action now available. +## D2. Router Auth Guard and Workspace State (PR #748) + +1. Workspace routes require authentication. + - Navigate to `/workspace/boards` while logged out. + - Expected: redirected to `/login?redirect=%2Fworkspace%2Fboards`. + - Log in. Expected: redirected back to `/workspace/boards`. + +2. Expired token cleanup. + - Manually set an expired JWT in localStorage (`taskdeck_token` key with an `exp` in the past), then navigate to any `/workspace/` route. + - Expected: token is cleared from localStorage, user redirected to `/login`. + +3. Workspace mode persistence across navigation. + - Switch workspace mode (if applicable) on Home, then navigate to Inbox, then back. + - Expected: workspace mode is unchanged after navigation within the workspace. + +4. Logout clears workspace state. + - Log in, navigate into a board, then logout from the top bar. + - Expected: after logging back in, workspace state is fresh (no stale board context from previous session). + ## E. Inbox and Notifications Continuity 1. Open `/workspace/inbox?boardId={boardId}` after creating a board-scoped capture. diff --git a/docs/STATUS.md b/docs/STATUS.md index 4607144bf..83a4bae7d 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -1,6 +1,6 @@ # Taskdeck Status (Source of Truth) -Last Updated: 2026-04-04 (wave 2) +Last Updated: 2026-04-04
Status Owner: Repository maintainers Authoritative Scope: Current implementation, verified test execution, and active phase progress @@ -78,6 +78,16 @@ Current constraints are mostly hardening and consistency: - **Proposal lifecycle edge cases** (`#708`/`#736`): 74 tests (42 domain + 25 application + 7 api) covering expiry timing boundaries, double-apply prevention, comprehensive state machine violations, dismissal edge cases, operation mutation guards, batch expiry, worker-vs-manual race conditions; adversarial review fixed clock-resolution flakiness and added 5 new edge case tests - **OAuth/auth edge case tests** (`#707`/`#737`): 44 tests covering login/registration edge cases, token validation (malformed/expired/wrong-key/missing-claims), OAuth code exchange, open redirect prevention, middleware enforcement; **found and fixed production bug**: `ExternalLoginAsync` `Substring(0, 50)` overflow for short usernames - **MCP full resource and tool inventory** (`#653`/`#739`): 9 resources under `taskdeck://` URI scheme + 11 tools (2 read + 6 write + 3 proposal management); all write tools produce proposals per GP-06; `approve_proposal` intentionally excluded; 42 MCP-specific tests; **adversarial review found and fixed user-scoping gap** on proposal resources/tools +- Post-adversarial-review hardening and test expansion wave (2026-04-04, PRs `#741`–`#756`, 9 issues): + - **Product telemetry taxonomy** (`#341`/`#741`): `docs/product/TELEMETRY_TAXONOMY.md` defines 35+ named events across 7 categories (Capture, Proposal/Review, Board, Auth, Navigation, Agent, Error) with `noun.verb` naming convention, universal envelope, privacy guardrails (bucketed counts, no PII), and R1/R2/R3 launch gate anchors; telemetry is opt-in and not yet implemented + - **Board header presence label fixed** (`#683`/`#744`): `normalizePresenceMembers()` in `BoardView.vue` now replaces current user's SignalR `displayName` with locally-known username, eliminating email/username flip on card open; 3 new tests + - **Manual card provenance empty state** (`#680`/`#754`): `cardsApi.getCardProvenance()` now returns null only for "Capture provenance not found" 404s (not all 404s); CardModal shows "No capture provenance available." with `loadedCaptureProvenanceCardId` guard against flash; 4 new tests; adversarial review caught and fixed 3 bugs (overly broad 404 catch, global Axios log-level regression, empty-state flash) + - **WIP-limit duplicate toast regression** (`#686`/`#745`): 7 regression tests in `boardStore.wipLimit.spec.ts` guard against future double-toast on WIP limit violations for createCard and moveCard + - **Auth-flow toast regression coverage** (`#685`/`#742`): 20 tests in `sessionStore.authToast.spec.ts` covering login/register/OAuth failure and success toast lifecycle, isolation, and auto-removal; adversarial review fixed timer leak, mock isolation, and inverted assertion + - **Route and workspace-state stability** (`#687`/`#748`): `authGuard.spec.ts` (auth guard decision table) and `workspaceRouteStability.spec.ts` (mode persistence, hydration drift, resetForLogout) with 16-case exhaustive guard table; also fixed pre-existing `AuthControllerEdgeCaseTests.cs` compile error + - **Inbox triage action visibility** (`#688`/`#743`): 21 new tests in `InboxView.spec.ts` covering single-item triage action states and bulk action bar visibility with DOM-level assertions + - **Webhook HMAC signature verification** (`#726`/`#750`): 11 tests in `OutboundWebhookHmacDeliveryTests.cs` covering header format, HMAC round-trip, wrong-key rejection, secret rotation, large payload, and timing-safe comparison; adversarial review fixed rotation test and replaced BCL-testing stubs with real domain property tests + - **Webhook delivery reliability and SSRF boundary** (`#710`/`#756`): 78 webhook tests across 9 files (endpoint guard, service, signature, delivery worker, HMAC delivery, API, repository, domain delivery, domain subscription); SSRF coverage via `OutboundWebhookEndpointGuardTests` includes private IPv4/IPv6 ranges; delivery reliability covers retry/backoff, dead-letter, concurrent delivery, HMAC at worker boundary; `HttpClient` resource leak fixed in tests Target experience metrics for the capture direction: - capture action to saved artifact should feel under 10 seconds in normal use diff --git a/docs/TESTING_GUIDE.md b/docs/TESTING_GUIDE.md index 571836dfc..0fd2ef156 100644 --- a/docs/TESTING_GUIDE.md +++ b/docs/TESTING_GUIDE.md @@ -12,21 +12,22 @@ Companion Active Docs: ## Current Verified Totals (2026-04-04) -- Backend: ~2950+ passing (estimated based on ~300 new tests from PRs `#732`–`#739` + ~586 new tests from PRs `#740`–`#755`) +- Backend: ~2990+ passing (estimated based on ~300 new tests from PRs `#732`–`#739` + ~586 new tests from PRs `#740`–`#755` + ~78 webhook tests from PRs `#750`/`#756`) - Domain: ~620+ (174 new entity state machine tests + 45 archive lifecycle domain tests) - Application: ~1500+ (101 LLM edge cases + 64 export/import + 51 metrics accuracy tests) - - API integration: ~770+ (5 ChangePassword + 38 data isolation + 24 worker + 67 controller + 44 auth + 7 golden-path + 42 MCP + 19 SignalR + 57 error contract + 29 archive lifecycle + 10 metrics controller + 36 notification tests) + - API integration: ~810+ (5 ChangePassword + 38 data isolation + 24 worker + 67 controller + 44 auth + 7 golden-path + 42 MCP + 19 SignalR + 57 error contract + 29 archive lifecycle + 10 metrics controller + 36 notification tests + 11 webhook HMAC + 22 webhook SSRF/delivery/repository) - CLI contract: 4 - Architecture boundaries: 8 -- Frontend unit: 1496/1496 passing (134 test files) +- Frontend unit: 1592/1592 passing (~125 test files) - Frontend E2E (smoke + automation/ops + capture loop + starter-pack fixtures + concurrency harness): default required lane passing -- Combined automated total: ~4450+ passing (backend ~2950+ + frontend unit 1496 + E2E) +- Combined automated total: ~4600+ passing (backend ~2990+ + frontend unit 1592 + E2E) Verification note: -- backend totals are estimated after two 2026-04-04 waves; wave 1 (`#732`–`#739`, ~300 new tests) and wave 2 (`#740`–`#755`, ~586 new tests with adversarial review); each PR verified green individually; full-suite recertification needed -- frontend unit totals were re-verified on 2026-04-02 via `npx vitest --run` +- backend totals are estimated after three 2026-04-04 waves; wave 1 (`#732`–`#739`, ~300 new tests), wave 2 (`#740`–`#755`, ~586 new tests with adversarial review), and wave 3 (`#750`/`#756`, ~50+ net new webhook tests: 11 HMAC + endpoint guard extensions + service/signature/worker/domain tests); each PR verified green individually; full-suite recertification needed +- frontend unit totals: **1592 passing** as of 2026-04-04 post-wave 3 (up from 1496 pre-wave); verified via `npx vitest --run` after adversarial review fixes - significant test growth in 2026-04-04 wave 1: ChangePassword fix (5 tests), golden-path integration (7), cross-user isolation (38), worker integration (24), controller HTTP (67), proposal lifecycle (74), OAuth/auth edge cases (44), MCP full inventory (42) - significant test growth in 2026-04-04 wave 2: domain state machines (174), SignalR integration (19), LLM tool-calling edge cases (101), export/import round-trip (64), API error contract (57), archive lifecycle (74), board metrics accuracy (61), notification delivery (36); all 8 PRs received two rounds of adversarial review with 47 review-fix commits addressing false-positive tests, weak assertions, and missing edge cases +- significant test growth in 2026-04-04 wave 3 (PRs `#741`–`#756`, 9 issues): webhook HMAC verification (11 backend tests, `#726`/`#750`), webhook SSRF/delivery reliability (78 total webhook tests across 9 files including pre-existing, `#710`/`#756`), frontend regression suite expansion (+96 tests: `#744` +3, `#754` +4, `#745` +7, `#742` +20, `#748` +route/workspace tests, `#743` +21) ## Product-Coherence Testing Priorities (2026-03-07) @@ -50,8 +51,8 @@ High-signal additions and delivered guardrails: Telemetry and release-gate follow-through from the expanded blueprint: -- product telemetry/event taxonomy remains tracked in `#341` with reuse of `#77`, while `#328` now provides the delivered first-run guardrail baseline -- keep event names privacy-safe and product-shaped (for example `home_loaded`, `today_loaded`, `capture_created`, `proposal_opened`, `proposal_approved`, `board_action_capture_here_clicked`, `workspace_mode_changed`, `agent_run_started`, `agent_run_completed`, `agent_run_failed`) +- product telemetry/event taxonomy delivered in `#341`/`#741` — see `docs/product/TELEMETRY_TAXONOMY.md`; reuses `#77` as baseline; `#328` provides the delivered first-run guardrail +- keep event names privacy-safe and product-shaped using the canonical `noun.verb` format from `docs/product/TELEMETRY_TAXONOMY.md` (for example `capture.modal_opened`, `capture.submitted`, `proposal.approved`, `proposal.dismissed`, `card.created`, `board.loaded`, `auth_session.started`, `agent_run.completed`, `agent_run.failed`) - treat launch framing as evidence gates, not marketing labels: - `R1` novice-first beta -> coherent `Home -> capture -> review -> execute -> board` path - `R2` agent foundation alpha -> inspectable runs, policies, and bounded templates @@ -134,17 +135,17 @@ Security finding during audit: `#722` (SEC-20) — `ChangePassword` endpoint doe |----------|--------|-------|--------| | I | ~~`#703`~~ | Capture → triage → proposal → review → board end-to-end golden path | **Delivered** (`#735`) | | II | ~~`#699`~~, ~~`#700`~~, ~~`#702`~~, ~~`#704`~~, `#705`, ~~`#707`~~, `#723`, `#725` | Infrastructure repos, worker, controller gaps, data isolation, concurrency, auth, OAuth, frontend HTTP interceptor | **5 of 8 delivered** | -| III | ~~`#701`~~, ~~`#706`~~, ~~`#708`~~, ~~`#709`~~, `#710`, `#711`, `#712`, ~~`#713`~~, ~~`#714`~~, ~~`#715`~~, `#716`, ~~`#718`~~, ~~`#719`~~, `#720`, `#726` | Domain state machines, SignalR, proposal lifecycle, LLM tool-calling, webhooks, frontend stores/views, export/import, error contracts, archive, metrics, notifications, resilience | **9 of 15 delivered** | +| III | ~~`#701`~~, ~~`#706`~~, ~~`#708`~~, ~~`#709`~~, ~~`#710`~~, `#711`, `#712`, ~~`#713`~~, ~~`#714`~~, ~~`#715`~~, `#716`, ~~`#718`~~, ~~`#719`~~, `#720`, ~~`#726`~~ | Domain state machines, SignalR, proposal lifecycle, LLM tool-calling, webhooks, frontend stores/views, export/import, error contracts, archive, metrics, notifications, resilience | **11 of 15 delivered** | | IV | `#717` | Property-based and adversarial input tests (extends `#89`) | Open | -**Wave progress**: 15 of 22 issues delivered (plus SEC-20 fix). ~886 new tests across two delivery waves. 7 issues remain open. +**Wave progress**: 17 of 25 issues delivered (plus SEC-20 fix). ~960+ new tests across three delivery waves. 8 issues remain open: `#705`, `#711`, `#712`, `#716`, `#717`, `#720`, `#723`, `#725`. ### Key Gaps Identified (updated 2026-04-04) - ~~**Infrastructure repositories**~~: 7 classes now have 77 integration tests (`#699`/`#730`); remaining repositories still untested - ~~**`LlmQueueToProposalWorker`**~~: **RESOLVED** — 24 integration tests delivered (`#700`/`#734`) covering happy path, error/retry, cancellation, fair-batch, and capture triage paths - ~~**Cross-user data isolation**~~: **RESOLVED** — 38 integration tests delivered (`#704`/`#733`) covering all major API boundaries; 3 false-positive tests caught and fixed in adversarial review -- **Frontend HTTP interceptor and router auth guard**: crossed by every request, zero test coverage (`#725` open) +- **Frontend HTTP interceptor and router auth guard**: crossed by every request, zero test coverage (`#725` open); note — router auth guard now has unit tests from `#748` but interceptor remains untested - ~~**Golden path**~~: **RESOLVED** — 7 integration tests delivered (`#703`/`#735`) proving full capture → triage → proposal → review → board pipeline - ~~**Domain entity state machines**~~: **RESOLVED** — 174 exhaustive tests delivered (`#701`/`#740`) covering CommandRun, ArchiveItem, ChatSession, UserPreference, NotificationPreference, CardLabel, CardCommentMention - ~~**SignalR hub integration**~~: **RESOLVED** — 19 integration tests delivered (`#706`/`#751`) covering auth, presence, multi-user, authorization, and edge cases @@ -154,6 +155,8 @@ Security finding during audit: `#722` (SEC-20) — `ChangePassword` endpoint doe - ~~**Archive lifecycle**~~: **RESOLVED** — 74 tests delivered (`#715`/`#755`): 45 domain state machine + 29 API integration covering cross-user isolation, conflict detection, audit trail - ~~**Board metrics accuracy**~~: **RESOLVED** — 61 tests delivered (`#718`/`#749`): 51 service + 10 controller covering throughput, cycle time, WIP, blocked cards, done-column heuristic - ~~**Notification delivery**~~: **RESOLVED** — 36 tests delivered (`#719`/`#746`) covering all 5 types, deduplication, preference filtering, cross-user isolation, batch operations +- ~~**Webhook HMAC signature verification**~~: **RESOLVED** — 11 tests delivered (`#726`/`#750`) covering header format, HMAC round-trip, wrong-key rejection, secret rotation, timing-safe comparison +- ~~**Webhook delivery reliability and SSRF**~~: **RESOLVED** — 78 webhook tests across 9 files delivered (`#710`/`#756`) covering retry/backoff, dead-letter, SSRF boundary conditions (private IPv4/IPv6 ranges via `OutboundWebhookEndpointGuardTests`) ### Relationship to Existing Test Issues @@ -876,3 +879,44 @@ For local development only, authorization bypass can be enabled via: Safety boundary: - Sandbox bypass is forced off outside Development environment. - Validation and data integrity rules still apply. + +## Webhook HMAC Signature Verification Coverage (PR #750, delivered 2026-04-04) + +Tracking issue: `#726` + +New test coverage: +- `OutboundWebhookHmacDeliveryTests` (11 tests): header format verification (`sha256=<64-hex>`), HMAC round-trip receiver recompute and match, wrong-key rejection, secret rotation produces different signature, body/content-type matching, large payload (100 kB), timing-safe comparison via `CryptographicOperations.FixedTimeEquals`, determinism, key-differ properties + +Key adversarial review findings fixed: secret rotation test was testing different subscriptions (not actual rotation on same subscription); BCL-testing assertions replaced with real domain property tests. + +## Webhook Delivery Reliability and SSRF Coverage (PR #756, delivered 2026-04-04) + +Tracking issue: `#710` + +New test coverage across webhook test suite (78 tests total across 9 files): +- `OutboundWebhookEndpointGuardTests` (Application.Tests): SSRF guard cases covering private IPv4 ranges and endpoint validation +- `OutboundWebhookServiceTests` (Application.Tests, 19 tests): service-level webhook subscription and delivery orchestration +- `OutboundWebhookSignatureTests` (Application.Tests, 8 tests): HMAC signature computation and verification +- `OutboundWebhookDeliveryWorkerTests` (Api.Tests, 8 tests): worker-level delivery scheduling and retry logic +- `OutboundWebhookHmacDeliveryTests` (Api.Tests, 11 tests): end-to-end HMAC delivery including header format, round-trip, wrong-key rejection +- `OutboundWebhooksApiTests` (Api.Tests, 10 tests): API endpoint contract for webhook subscription management +- `OutboundWebhookDeliveryRepositoryTests` (Api.Tests, 3 tests): repository-level delivery persistence +- `OutboundWebhookDeliveryTests` (Domain.Tests, 8 tests): domain entity state and transitions +- `OutboundWebhookSubscriptionTests` (Domain.Tests, 7 tests): subscription domain entity + +Key adversarial review fix: `HttpClient` resource leaks across 9 test methods. + +Manual validation recommended: configure a webhook endpoint with a known secret and verify that (a) the `X-Taskdeck-Webhook-Signature` header (alongside `X-Taskdeck-Webhook-Timestamp`) is present and verifiable with HMAC-SHA256, and (b) a webhook targeting `http://localhost/` or `http://10.0.0.1/` is rejected at the SSRF guard. + +## Frontend Regression Test Wave (PRs #742–#745, #748, #743, #744, #754, delivered 2026-04-04) + +Tracking issues: `#683`, `#680`, `#685`, `#686`, `#687`, `#688` + +New test files: +- `boardStore.wipLimit.spec.ts` (7 tests): WIP-limit toast deduplication regression for `createCard` and `moveCard`; guards against future double-toast introduction +- `sessionStore.authToast.spec.ts` (20 tests): auth-flow toast lifecycle — login/register/OAuth failure and success toasts, cross-flow isolation, auto-removal independence; uses real `toastStore` backed by fresh Pinia +- `router/authGuard.spec.ts` (new): auth guard decision table — unauthenticated redirect, expired-token cleanup, authenticated pass-through, deflection from /login when authenticated, demo mode, 12-route exhaustive table +- `router/workspaceRouteStability.spec.ts` (new): workspace mode persistence across simulated reloads, hydration drift prevention, `resetForLogout` cleanup +- `InboxView.spec.ts` (+21 tests): single-item triage action states (per status variant), bulk action bar visibility and count, batchBusy disabled state, select-all behavior; all assertions on DOM state + +Frontend suite total after this wave: **1592 passing** (up from 1496 pre-wave).