# RevHero QA Run — scheduled-20261011T135455 **Started:** 2026-10-11T13:55:02.879Z **Finished:** 2026-10-11T13:59:35.328Z ## Summary | | Count | |---|---| | Total | 494 | | PASS | 481 | | FAIL | 3 | | SKIP | 0 | | NOT_EXEC | 10 | ## Results | ID | Status | Duration | Description | |---|---|---|---| | `ANALYTICS-001` | PASS | 873.6992220000002ms | Unauth GET /v1/dashboard/health rejected | | `ANALYTICS-002` | PASS | 6375.019993ms | Authed GET /v1/dashboard/health does not fail closed (service up) | | `ANALYTICS-003` | PASS | 420.85308199999963ms | Bogus sibling path 404s distinctly from the real route's 401 (route-exists sanity) | | `FE-ACT-001` | PASS | 2.147860000000037ms | Outbound SMS produces 'SMS Sent' activity (smoke) | | `FE-ACT-002` | PASS | 0.4728629999999612ms | Inbound SMS produces 'SMS Received' activity (smoke) | | `FE-ACT-003` | PASS | 0.28898000000026514ms | Email sent produces 'Email Sent' activity (smoke) | | `FE-ACT-004` | PASS | 0.22515100000009625ms | Email received produces 'Email Received' activity (smoke) | | `FE-ACT-005` | PASS | 0.2860239999999976ms | A2P brand approved produces activity (smoke) | | `FE-ACT-006` | PASS | 0.25090899999986505ms | Phone purchase produces 'Phone Number Purchased' (smoke) | | `FE-ACT-007` | PASS | 0.24361399999997957ms | Toky import produces 'Phone Number Imported' (smoke) | | `FE-ACT-008` | PASS | 0.177831999999853ms | Deal-loss negative-sentiment activity (smoke) | | `FE-ACT-009` | PASS | 0.24687100000028295ms | Stage processing failure activity (smoke) | | `FE-ACT-010` | PASS | 5366.880036ms | Activities mark-read endpoints respond | | `FE-ACT-011` | PASS | 0.44507100000009814ms | Activity feed scoped to current account_id (smoke) | | `FE-ACT-AIC-001` | PASS | 5586.422825ms | POST /v1/stages/:id/actions/ai-call endpoint exists | | `FE-ACT-AIC-002` | PASS | 4.26195799999914ms | PUT updates AI-call action (smoke) | | `FE-ACT-AIC-003` | PASS | 0.308324999999968ms | DELETE removes action (smoke) | | `FE-ACT-AIC-004` | PASS | 0.22725399999944784ms | Trigger requests AI call (smoke) | | `FE-ACT-AIC-005` | PASS | 0.22548099999949045ms | Empty prompt_template → validation error (smoke) | | `FE-ACT-BBS-001` | PASS | 7366.673849999999ms | Endpoint exists | | `FE-ACT-BBS-002` | PASS | 0.4713290000036068ms | CRUD verified (smoke) | | `FE-ACT-BBS-003` | PASS | 0.1923289999976987ms | Trigger dispatches request (smoke) | | `FE-ACT-PD-001` | PASS | 5957.631129999998ms | Endpoint exists | | `FE-ACT-PD-002` | PASS | 0.47236200000043027ms | Editor lists folders/templates (smoke) | | `FE-ACT-PD-003` | PASS | 0.19050599999900442ms | CRUD verified (smoke) | | `FE-ACT-PD-004` | PASS | 2.359615000001213ms | Trigger creates + emails doc (smoke) | | `FE-ACT-PD-005` | PASS | 0.1934320000000298ms | Invalid template_id → graceful failure (smoke) | | `FE-ACT-S2C-001` | PASS | 4411.117547000002ms | Endpoint exists | | `FE-ACT-S2C-002` | PASS | 0.4832119999991846ms | Editor lists user's campaigns + stages (smoke) | | `FE-ACT-S2C-003` | PASS | 0.22312599999713711ms | Trigger moves deal across campaigns (smoke) | | `FE-ACT-S2C-004` | PASS | 0.2096910000036587ms | Cycle prevention at save time (smoke) | | `FE-ACT-SF-001` | PASS | 5525.568407999999ms | Endpoint exists | | `FE-ACT-SF-002` | PASS | 11.426645999999892ms | CRUD verified (smoke) | | `FE-ACT-SF-003` | PASS | 0.5336370000004536ms | Invalid API key at save → friendly error (smoke) | | `FE-ACT-SF-004` | PASS | 0.19706800000130897ms | Trigger logs activity (smoke) | | `FE-ACT-VM-001` | PASS | 7619.574175ms | POST /v1/stages/:id/actions/voicemail endpoint exists | | `FE-ACT-VM-002` | PASS | 1.4151330000004236ms | Voicemail editor accepts audio upload (smoke) | | `FE-ACT-VM-003` | PASS | 4.640534000000116ms | PUT updates voicemail action (smoke) | | `FE-ACT-VM-004` | PASS | 0.5852130000002944ms | DELETE removes action (smoke) | | `FE-ACT-VM-005` | PASS | 0.2670589999997901ms | Trigger dispatches voicemail (smoke) | | `FE-ACT-VM-006` | PASS | 0.4069899999994959ms | Reject wrong file type with friendly error (smoke) | | `FE-ACT-VM-007` | PASS | 0.23259500000131084ms | Reject oversized audio with friendly error (smoke) | | `FE-ADM-001` | PASS | 6634.081222ms | /admin/dashboard renders without crashing | | `FE-ADM-002` | PASS | 0.6572670000023209ms | Sidebar shows Billing/Dashboard/Pricing/Campaigns (smoke) | | `FE-ADM-003` | PASS | 9390.50868ms | /admin/billing renders without crashing | | `FE-ADM-004` | PASS | 8013.952206000002ms | /admin/billing/clients renders without crashing | | `FE-ADM-005` | PASS | 5227.095670999999ms | /admin/billing/payments renders without crashing | | `FE-ADM-006` | PASS | 5740.2883900000015ms | /admin/campaigns renders without crashing | | `FE-ADM-007` | PASS | 5443.473867000001ms | /admin/campaigns/analytics renders without crashing | | `FE-ADM-008` | PASS | 7402.303139000003ms | /admin/campaigns/templates renders without crashing | | `FE-ADM-012` | PASS | 7684.620861999996ms | /admin/pricing/plans renders without crashing | | `FE-ADM-013` | PASS | 6783.580378999999ms | /admin/pricing/plans/create renders without crashing | | `FE-ADM-014` | PASS | 3769.088168000002ms | /admin/pricing/promo-codes renders without crashing | | `FE-ADM-015` | PASS | 9322.076014999999ms | /admin/pricing/addons renders without crashing | | `FE-ADM-016` | PASS | 6167.7984099999885ms | /admin/user-settings renders without crashing | | `FE-ADM-017` | PASS | 4922.543107999998ms | MEMBER role hits /admin/dashboard → 403 or redirect | | `FE-ADM-018` | PASS | 0.479114000001573ms | /admin/* on prod hostname → redirected (skip on staging) | | `FE-ADM-ADDON-001` | PASS | 3539.7717279999924ms | Add-ons list renders | | `FE-ADM-ADDON-002` | PASS | 0.6641109999909531ms | Create requires name/price/scope (smoke) | | `FE-ADM-ADDON-003` | PASS | 0.17219199999817647ms | Created add-on appears in public list (smoke) | | `FE-ADM-ADDON-004` | PASS | 0.2691729999933159ms | Update price reflects on /settings/manage-plans (smoke) | | `FE-ADM-ADDON-005` | PASS | 0.9655119999952149ms | Delete blocked when subs active (smoke) | | `FE-ADM-PLAN-001` | PASS | 5137.351051999998ms | Plans list renders | | `FE-ADM-PLAN-002` | PASS | 0.5021879999985686ms | Create form validates required fields (smoke) | | `FE-ADM-PLAN-003` | PASS | 3.0229549999930896ms | POST /v1/admin/plans creates plan (smoke) | | `FE-ADM-PLAN-004` | PASS | 0.5065950000134762ms | PUT updates plan, public endpoint reflects (smoke) | | `FE-ADM-PLAN-005` | PASS | 0.25818200000503566ms | Delete with active subs → friendly block (smoke) | | `FE-ADM-PLAN-006` | PASS | 1.0186720000056084ms | Delete unused plan succeeds (smoke) | | `FE-ADM-PROMO-001` | PASS | 4252.266404000009ms | Promo list shows discount/expiry/usage | | `FE-ADM-PROMO-002` | PASS | 1.8041900000098394ms | Create 100% code applies on signup (smoke) | | `FE-ADM-PROMO-003` | PASS | 0.3050999999977648ms | Past-expiry code returns expired (smoke) | | `FE-ADM-PROMO-004` | PASS | 0.6807709999993676ms | Usage cap enforced (smoke) | | `FE-ADM-PROMO-005` | PASS | 0.22931799999787472ms | Delete cleanly removes (smoke) | | `FE-AH-001` | PASS | 0.7632149999990361ms | PUT /v1/active-hours/:id saves schedule (smoke) | | `FE-AH-002` | PASS | 0.7471850000001723ms | Stage actions defer outside active window (smoke) | | `FE-AH-003` | PASS | 0.2547550000017509ms | Saturday outside window → defer to Monday (smoke) | | `FE-AH-004` | PASS | 0.22356800000125077ms | PUT /v1/active-hours-preferences globally disables (smoke) | | `FE-AI-001` | PASS | 8108.526553ms | /automation-campaign/[id] shows AI personalization toggle | | `FE-AI-002` | PASS | 5.959467000000586ms | Toggle ON opens cost modal + persists (smoke) | | `FE-AI-003` | PASS | 0.5196599999999307ms | Toggle OFF flips back, banner disappears (smoke) | | `FE-AI-004` | PASS | 0.28380900000047404ms | Test-Email button disabled when AI flag OFF (smoke) | | `FE-AI-005` | PASS | 0.30931799999962095ms | Personalised stage email differs from template (smoke) | | `FE-AI-006` | PASS | 10.426319000000149ms | AI flag OFF sends literal template (smoke) | | `FE-AI-007` | PASS | 0.3195269999996526ms | AI ON + empty goal → fallback to template (smoke) | | `FE-AI-008` | PASS | 0.3345850000005157ms | AI ON + empty offering → fallback (smoke) | | `FE-AI-009` | PASS | 0.3876040000013745ms | Stage SMS with AI ON personalises body (smoke) | | `FE-AI-010` | PASS | 5.261856000000989ms | AI runs before merge-tag rendering (smoke) | | `FE-AI-011` | PASS | 4.540999000000738ms | generate_ai_variants switch hidden in prod (smoke) | | `FE-AI-012` | PASS | 1540.9390650000005ms | ai-agent /health endpoint reports OpenAI connectivity | | `FE-AI-013` | PASS | 0.5272650000006252ms | Inbound sentiment runs regardless of AI flag (smoke) | | `FE-AI-014` | PASS | 0.3056699999997363ms | Heuristic infers NEGATIVE on 'unsubscribe' fast (smoke) | | `FE-AI-015` | PASS | 0.18513699999857636ms | Heuristic falls through to OpenAI (smoke) | | `FE-AI-016` | PASS | 0.24664100000154576ms | OpenAI failure retries 5 times → sentiment NONE (smoke) | | `FE-AI-017` | PASS | 410.58866599999965ms | sentiment-webhook from public internet must require auth | | `FE-AI-018` | PASS | 25.98306699999921ms | Credit balance drops by AI rate after personalised send (smoke) | | `FE-AI-019` | PASS | 0.4823500000002241ms | Toky + AI charges AI credits, not phone (smoke) | | `FE-AI-020` | PASS | 471.86143599999923ms | cleanup-old-prompts endpoint exists at both legacy and /v1 paths | | `FE-AUTH-001` | PASS | 6801.263094ms | /login page renders with email + password + Forgot Password + Login + Register link | | `FE-AUTH-002` | PASS | 8663.256771ms | Login with valid credentials → redirect to /automation-campaign | | `FE-AUTH-003` | PASS | 360.2070300000014ms | Login with wrong password → friendly error, no stack trace | | `FE-AUTH-004` | PASS | 212.0819760000013ms | Login with non-existent email → generic friendly error (no enumeration) | | `FE-AUTH-005` | PASS | 4327.795563ms | Login with empty fields → form validation errors | | `FE-AUTH-006` | PASS | 1701.9669880000001ms | Eye icon on password field toggles show/hide | | `FE-AUTH-007` | PASS | 2684.052674999999ms | Forgot Password link → /forgot-password page renders | | `FE-AUTH-008` | PASS | 293.7337100000004ms | Submit forgot password form with valid email → success message | | `FE-AUTH-009` | PASS | 593.272058999999ms | Submit forgot password with non-existent email → generic success (anti-enumeration) | | `FE-AUTH-010` | PASS | 126.41557699999976ms | /auth-reset-password?token=invalid → friendly invalid token error | | `FE-AUTH-011` | PASS | 293.60845600000175ms | /auth-reset-password validates min length and match | | `FE-AUTH-012` | PASS | 39766.919956ms | Sign Out clears cookies and redirects to /login | | `FE-AUTH-013` | PASS | 6118.350049999994ms | Hard refresh of authenticated page → session restores, no console errors | | `FE-AUTH-014` | PASS | 2763.472828999991ms | Direct nav to authenticated route while logged out → redirects to /login with ?redirect= | | `FE-AUTH-015` | PASS | 152.57680600001186ms | JWT expires mid-session → next API call triggers refresh; refresh fail → logout | | `FE-AUTH-016` | PASS | 4311.290368000002ms | Login on staging hits staging BFF, NOT prod (FE-BUG-002 regression) | | `FE-AUTH-017` | PASS | 4923.788832999999ms | BFF auth cookies have HttpOnly + Secure + SameSite flags | | `FE-AUTH-018` | PASS | 19376.06745599999ms | Open redirect — ?redirect=https://evil.com after login → blocked | | `FE-AUTH-019` | PASS | 4142.136065999992ms | Login button shows loading spinner while authenticating | | `FE-AUTH-020` | PASS | 2508.3813149999914ms | Rate limiting on /login — rapid wrong-password attempts trigger 429 | | `FE-AUTH-021` | NOT_EXEC | 0ms | rapid wrong-password attempts on a unique email return 429 within budget | | `FE-AUTH-022` | NOT_EXEC | 0ms | 429 response carries a friendly message + retry hint, no internals leaked | | `FE-AUTH-023` | NOT_EXEC | 0ms | rate limit is scoped per-email (different fakes don't share budget) | | `FE-CAMP-001` | PASS | 23216.303069999998ms | /automation-campaign lists campaigns or shows empty state | | `FE-CAMP-002` | PASS | 9951.358896999998ms | Tabs Active / Inactive / All switch correctly | | `FE-CAMP-003` | PASS | 11799.76803ms | Search Campaigns input filters list | | `FE-CAMP-004` | PASS | 6115.0493859999915ms | Pagination Next/Prev (where present) is sane | | `FE-CAMP-005` | PASS | 4548.930015999998ms | PULSE / SWARM tabs at top (SWARM dev-only on staging) | | `FE-CAMP-006` | PASS | 23648.95984099999ms | /automation-campaign/create renders builder | | `FE-CAMP-007` | PASS | 6507.570965999999ms | Builder header shows 'Untitled' (FE-BUG-08 fix — not literal 'undefined') | | `FE-CAMP-008` | PASS | 9486.112326999995ms | Builder canvas shows 'Add Stage +' button | | `FE-CAMP-009` | PASS | 5002.446155999991ms | Click Add Stage opens stage type modal | | `FE-CAMP-010` | PASS | 8828.04080100001ms | Stage settings modal validates required fields (sanity check) | | `FE-CAMP-011` | FAIL | 4989.782217ms | Builder name area exists (route smoke) | | `FE-CAMP-012` | PASS | 6414.9638039999845ms | Save Campaign with no stages → friendly error or warning | | `FE-CAMP-013` | PASS | 7033.392867999995ms | Active toggle persists after save (visual presence) | | `FE-CAMP-014` | PASS | 6681.903182999988ms | Click 'Import campaign from CRM' opens import modal | | `FE-CAMP-015` | PASS | 0.5100020000245422ms | Import campaign validates CRM connection state (smoke) | | `FE-CAMP-016` | PASS | 4724.428555999999ms | /automation-campaign/[id] for non-existent ID → 404 or friendly error | | `FE-CAMP-017` | PASS | 5795.705738999997ms | /automation-campaign/[id]/deals lists campaign deals | | `FE-CAMP-018` | PASS | 6189.089188000013ms | Deals table renders without crashing (smoke) | | `FE-CAMP-019` | PASS | 7430.388926999993ms | Pull CRM State button triggers sync (button present) | | `FE-CAMP-020` | PASS | 8950.425019999995ms | Stage drag-and-drop reorders without crashes (page renders) | | `FE-CAMP-021` | PASS | 8866.333406999998ms | Deals search page renders with filter components | | `FE-CAMP-022` | PASS | 7011.859499999999ms | Search filter updates URL params when typed + submitted | | `FE-CAMP-023` | PASS | 7720.279283ms | Status filter (when present) updates URL state | | `FE-CAMP-024` | PASS | 5990.338060999999ms | Pagination controls (when present) navigate without crash | | `FE-CRED-001` | PASS | 5523.685750000001ms | Header credit balance widget reflects /v1/credit | | `FE-CRED-002` | PASS | 3.4869210000006206ms | Top-up via card increases balance (smoke @paid) | | `FE-CRED-003` | PASS | 0.2929180000000997ms | Twilio SMS decrements balance by 1 (smoke) | | `FE-CRED-004` | PASS | 3.672037000000273ms | Twilio failure releases reserved credits (smoke) | | `FE-CRED-005` | PASS | 0.463474999999562ms | Toky SMS leaves balance unchanged (smoke) | | `FE-CRED-006` | PASS | 2.1488319999998566ms | Personalised stage send charges AI unit not phone (smoke) | | `FE-CRED-007` | PASS | 0.43540200000006735ms | Failed AI personalization → AI credit not committed (smoke) | | `FE-CRED-008` | PASS | 0.26188899999942805ms | Hit balance=0 → friendly out-of-credits modal (smoke) | | `FE-CRED-009` | PASS | 3.7119309999998222ms | Add-on activation increases credit allowance (smoke) | | `FE-CRED-010` | PASS | 4.314886999999544ms | Cancel add-on at end of period → next month reverts (smoke) | | `FE-CRM-001` | PASS | 4398.350316ms | Pipedrive verify-api-key endpoint exists | | `FE-CRM-002` | PASS | 4.285160999999789ms | Invalid Pipedrive API key → friendly error (smoke) | | `FE-CRM-003` | PASS | 3.9461389999996754ms | Map Pipedrive user to RevHero account (smoke) | | `FE-CRM-004` | PASS | 0.536961999999221ms | Enable CRM sync on campaign pulls existing deals (smoke) | | `FE-CRM-005` | PASS | 0.622653000000355ms | Force-pull from CRM enqueues sweeper candidates (smoke) | | `FE-CRM-006` | PASS | 8.202174999999443ms | Disable CRM sync stops auto-pulls (smoke) | | `FE-CRM-007` | PASS | 0.47447699999975157ms | Stage move with CRM connected → Pipedrive note + stage update (smoke) | | `FE-CRM-008` | PASS | 6.660036000000218ms | Pipedrive webhook updates RevHero deal record (smoke) | | `FE-CRM-009` | PASS | 6.150174000000334ms | Pipedrive outage → CRM goroutine fails silently, move proceeds (smoke) | | `FE-CRM-010` | PASS | 2949.4564729999993ms | HubSpot verify-api-key endpoint exists | | `FE-CROSS-001` | PASS | 9455.549019000006ms | All staging API calls go to *.test.revhero.io (FE-BUG-002 regression) | | `FE-CROSS-002` | PASS | 0.8424219999942579ms | Cloud-document uploads go to staging cloud-documents (smoke) | | `FE-CROSS-003` | PASS | 6586.197048000002ms | Dev-only routes accessible on staging (proxy.ts hostname check) | | `FE-CROSS-004` | PASS | 0.369460000001709ms | Same routes redirect to /automation-campaign on prod (skip on staging) | | `FE-CROSS-005` | PASS | 0.2808729999960633ms | Free Plan signup completes without payment form (FE-BUG-001 regression) | | `FE-CROSS-006` | PASS | 0.375411000000895ms | Plan-feature labels render numbers with thousands separators (smoke) | | `FE-CROSS-007` | PASS | 5.639670999997179ms | Settings right-rail items don't truncate (smoke) | | `FE-CROSS-008` | PASS | 0.564342999998189ms | Currency values show 2 decimals consistently (smoke) | | `FE-CROSS-009` | PASS | 0.2580119999984163ms | Campaign create header shows 'Untitled campaign' (FE-BUG-08 regression) | | `FE-CROSS-010` | PASS | 0.25695899999846006ms | Phone /sms doesn't get stuck on skeleton (FE-BUG-04 regression) | | `FE-CSV-001` | PASS | 4559.934621ms | GET /v1/csv-imports/template returns CSV template | | `FE-CSV-002` | PASS | 0.7377470000001267ms | POST /v1/stages/:id/csv-imports creates pending job (smoke) | | `FE-CSV-003` | PASS | 2.778758999999809ms | Job advances pending → processing → completed (smoke) | | `FE-CSV-004` | PASS | 2.8463550000005853ms | Missing required columns → per-row error report (smoke) | | `FE-CSV-005` | PASS | 2.840143999999782ms | Malformed phones skipped, valid rows ingested (smoke) | | `FE-CSV-006` | PASS | 0.6108400000002803ms | Duplicate emails skipped or merged (smoke) | | `FE-CSV-007` | PASS | 0.20706600000085018ms | Reprocess endpoint idempotent (smoke) | | `FE-CSV-008` | PASS | 0.19403199999942444ms | GET /v1/stages/:id/csv-imports lists jobs (smoke) | | `FE-CSV-009` | PASS | 1.1750449999999546ms | suppress-import-actions flag toggles trigger behavior (smoke) | | `FE-CSV-010` | PASS | 0.8874070000001666ms | Oversized CSV handled gracefully (smoke) | | `FE-CSV-011` | PASS | 273.7727869999999ms | lead_ingestion_analytics table exists in deals-actions DB | | `FE-CSV-012` | PASS | 0.5560190000001057ms | lead-ingestion event contract has v1 (smoke) | | `FE-CSV-013` | PASS | 0.35662500000034925ms | OAuth2 token acquisition + refresh via leadingestion/auth.go (smoke) | | `FE-CSV-014` | PASS | 0.32967599999983577ms | analytics record carries success / partial / failed status (smoke) | | `FE-DEAL-001` | PASS | 238.95036599999958ms | Sweep endpoint returns jobs_scheduled count | | `FE-DEAL-002` | PASS | 0.8095619999999144ms | Sweep moves a deal forward (smoke — needs seeded campaign) | | `FE-DEAL-003` | PASS | 9.095813999999791ms | Inactive campaign skips sweep (smoke) | | `FE-DEAL-004` | PASS | 0.3146969999997964ms | Inactive user's stages skipped (smoke) | | `FE-DEAL-005` | PASS | 0.25836200000003373ms | max_deals_to_move quota respected (smoke) | | `FE-DEAL-006` | PASS | 0.2757440000000315ms | Worker pops job within 5s (smoke) | | `FE-DEAL-007` | PASS | 0.26838199999974677ms | Worker triggers email/SMS action (smoke) | | `FE-DEAL-008` | PASS | 0.1970269999997072ms | Action returns 425 → deal rolled back (smoke) | | `FE-DEAL-009` | PASS | 0.3029660000001968ms | Action 5xx → exponential backoff retry (smoke) | | `FE-DEAL-010` | PASS | 9.457510000000184ms | Successful move appears in BFF /v1/deals/filter (smoke) | | `FE-DEAL-011` | PASS | 0.4070090000000164ms | Successful move does NOT create activity row (smoke) | | `FE-DEAL-012` | PASS | 0.19473500000003696ms | CRM sync goroutine fires after move (smoke) | | `FE-DEAL-013` | PASS | 420.1498569999999ms | /v1/stages/scheduled endpoint reachable | | `FE-DEAL-014` | PASS | 124.51011999999992ms | /v1/stages/moved endpoint reachable | | `FE-DEAL-015` | PASS | 0.7420759999999973ms | Redis isolation between staging and prod (smoke) | | `FE-DEAL-016` | PASS | 15.20135399999981ms | Super-admin sweeper button (smoke) | | `FE-DEAL-017` | PASS | 1.314734000000044ms | next_move_date NULL → deal NOT picked up (smoke) | | `FE-DEAL-SEARCH-001` | FAIL | 8817.808667ms | Type email into Search Deals input → table filters by email | | `FE-DEAL-SEARCH-002` | PASS | 6745.9696220000005ms | Type partial first name → filter applies | | `FE-DEAL-SEARCH-003` | PASS | 6270.308942ms | Press Enter in search submits without page reload | | `FE-DEAL-SEARCH-004` | PASS | 7251.941180000002ms | Clear input → full deal list returns | | `FE-DEAL-SEARCH-005` | PASS | 2.695593000000372ms | Search persists across pagination | | `FE-DEAL-SEARCH-006` | PASS | 9019.020568ms | Include lost deals toggle ON/OFF persists | | `FE-E2E-001` | PASS | 5.815510000000131ms | Signup → Onboarding → First campaign → First deal email sent (smoke) | | `FE-E2E-002` | PASS | 0.5336769999998978ms | Inbound reply NEGATIVE → deal auto-Lost (smoke) | | `FE-E2E-003` | PASS | 0.3630479999999352ms | Toky BYOC end-to-end SMS round-trip (smoke) | | `FE-E2E-004` | PASS | 0.3801100000000588ms | Multi-stage campaign with wait + actions (smoke) | | `FE-E2E-005` | PASS | 0.5191800000000057ms | Quota cap respected (smoke) | | `FE-E2E-006` | PASS | 0.5733099999999922ms | Inactive user pause-billing edge case (smoke) | | `FE-E2E-007` | PASS | 0.336819000000105ms | Free-plan SMS via Toky succeeds, via Twilio rejected (smoke) | | `FE-E2E-008` | PASS | 0.24540799999999763ms | JWT expiry mid-flow auto-refreshes (smoke) | | `FE-E2E-009` | PASS | 0.3123430000000553ms | Multi-tenant isolation across mailboxes/Toky/deals (smoke) | | `FE-E2E-010` | PASS | 0.2511489999999412ms | Webhook-only services not exposed (smoke — covered by WEBHOOK-AUTH) | | `FE-EMAIL-001` | PASS | 6596.359541999999ms | /email-system/email lists messages or empty state | | `FE-EMAIL-002` | PASS | 6743.971958999999ms | 'Mailbox not connected' empty state with Connect Mailbox CTA | | `FE-EMAIL-003` | PASS | 6589.2760050000015ms | Connect Mailbox button opens OAuth flow (button presence) | | `FE-EMAIL-004` | PASS | 6000.830192000001ms | Email filters work (filter UI exists) | | `FE-EMAIL-005` | PASS | 8466.510140000002ms | Search Emails input filters list | | `FE-EMAIL-006` | PASS | 6093.411466999998ms | '+' button opens compose / add modal | | `FE-EMAIL-007` | FAIL | 5486.560332999994ms | /email-system/email/add page renders without crashing | | `FE-EMAIL-008` | PASS | 6958.483098000004ms | Compose form requires recipient + subject + body | | `FE-EMAIL-009` | PASS | 0.9940459999997984ms | Send email triggers BFF call (network observation) | | `FE-EMAIL-010` | PASS | 7761.963813000002ms | /email-system/email/[id] shows email detail (route accessible) | | `FE-EMAIL-011` | PASS | 6087.758560999995ms | Email categories sidebar navigates | | `FE-EMAIL-012` | PASS | 0.4141420000087237ms | Pagination at top right (X of Y) updates with results | | `FE-EMAIL-IN-001` | PASS | 7.972396000000117ms | Reply appears in FE thread within ~30s (smoke) | | `FE-EMAIL-IN-002` | PASS | 2.7024860000001354ms | email row has sentiment after scoring (smoke) | | `FE-EMAIL-IN-003` | PASS | 0.5261829999999463ms | 'unsubscribe' triggers NEGATIVE heuristic + deal-loss (smoke) | | `FE-EMAIL-IN-004` | PASS | 0.27623599999969883ms | OOO autoresponder → NEUTRAL + date extraction (smoke) | | `FE-EMAIL-IN-005` | PASS | 3.022161999999753ms | Self-reply skips sentiment (smoke) | | `FE-EMAIL-IN-006` | PASS | 0.4838439999998627ms | Inbound XSS subject escapes on render (smoke) | | `FE-EMAIL-IN-007` | PASS | 0.26272100000005594ms | Bounce notification flags original send (smoke) | | `FE-EMAIL-IN-008` | PASS | 447.98427100000026ms | POST /v1/emails/sentiment-webhook from public internet — must return 401/403/404 | | `FE-EMAIL-IN-009` | PASS | 1.0054159999999683ms | Mark inbound email Read/Unread/Favourite/Archive (smoke) | | `FE-EMAIL-IN-010` | PASS | 0.4355729999997493ms | Conversation history merges sent + received chronologically (smoke) | | `FE-EMAIL-IN-011` | PASS | 0.2785309999999299ms | Cross-tenant email isolation (smoke) | | `FE-EMAIL-IN-012` | PASS | 1051.1360760000002ms | bounce-webhook endpoint requires internal-services auth | | `FE-EMAIL-IN-013` | PASS | 145.8105029999997ms | duplicate bounces within debounce window are absorbed (smoke) | | `FE-EMAIL-IN-014` | PASS | 0.777201999999761ms | bounced address propagates to the blocklist (smoke) | | `FE-EMAIL-OUT-001` | PASS | 6722.569068000001ms | Connect Gmail mailbox via OAuth (external-blocked) — assert URL request returns redirec... | | `FE-EMAIL-OUT-002` | PASS | 5264.0359260000005ms | Connect Microsoft mailbox same flow (external-blocked) | | `FE-EMAIL-OUT-003` | PASS | 0.9654430000009597ms | Disconnect mailbox via POST /v1/user-mailboxes/:id/disconnect (smoke) | | `FE-EMAIL-OUT-004` | PASS | 5586.913684000001ms | Test Email (rate-limited 5/hr) endpoint exists | | `FE-EMAIL-OUT-005` | PASS | 2.4309590000011667ms | Test-Email button disabled when ai_personalization_enabled=false (FE check) | | `FE-EMAIL-OUT-006` | PASS | 5.1178450000006706ms | 6 test emails in 1 hour → 429 | | `FE-EMAIL-OUT-007` | PASS | 7487.181855999999ms | Send manual email with merge tags (composer renders) | | `FE-EMAIL-OUT-008` | PASS | 0.6005609999992885ms | Manual email to deal contact creates sent_email row (smoke) | | `FE-EMAIL-OUT-009` | PASS | 1.1980770000009215ms | Email signature appended to outbound (smoke) | | `FE-EMAIL-OUT-010` | PASS | 6634.863979999998ms | Empty subject → form validation rejects | | `FE-EMAIL-OUT-011` | PASS | 0.9701910000003409ms | Long body (>50 KB) handled (smoke — no 500) | | `FE-EMAIL-OUT-012` | PASS | 0.31513799999811454ms | XSS in subject + body sanitised (smoke — no script execution) | | `FE-EMAIL-OUT-013` | PASS | 1134.645187ms | POST /v1/templates/render endpoint exists on email-ingress | | `FE-EMAIL-OUT-014` | PASS | 75.20258000000013ms | invalid deal_id is rejected (no panic) | | `FE-EMAIL-OUT-015` | PASS | 76.59162500000002ms | missing required field returns 400 | | `FE-HELP-001` | PASS | 8783.770342000002ms | /help renders FAQ section (dev-only on staging) | | `FE-HELP-002` | PASS | 0.5090600000003178ms | Search articles input filters FAQ | | `FE-HELP-003` | PASS | 0.2042010000004666ms | Help category cards render | | `FE-HELP-004` | PASS | 0.23150199999872711ms | Contact Support button opens email/chat | | `FE-HELP-005` | PASS | 4735.0287750000025ms | /getting-started checklist progress bar updates | | `FE-HELP-006` | PASS | 0.4191819999978179ms | Watch Video opens modal | | `FE-HELP-007` | PASS | 0.20761700000002747ms | Add Signature redirects to email signature settings | | `FE-HELP-008` | PASS | 0.19421300000249175ms | Start Guided Walkthrough triggers tour | | `FE-LAY-001` | PASS | 5586.571054ms | Sidebar visible on every authenticated dashboard page | | `FE-LAY-002` | PASS | 15524.834361999998ms | Sidebar shows Dashboard / Campaign / Phone / Email / Settings (smoke) | | `FE-LAY-003` | PASS | 12011.419716999997ms | Header shows credit balance, notification bell, sign out | | `FE-LAY-004` | PASS | 0.812486999995599ms | Active sidebar item highlighted in primary color (smoke) | | `FE-LAY-005` | PASS | 0.3861810000016703ms | Click sidebar item navigates without full page reload (smoke) | | `FE-LAY-006` | PASS | 4.629584000002069ms | Mobile nav (<768px) collapses sidebar to hamburger (smoke) | | `FE-LAY-007` | PASS | 3.670663999997487ms | Layout no CLS when notifications appear/dismiss (smoke) | | `FE-LAY-008` | PASS | 4.087231999998039ms | Layout no CLS when modals open/close (smoke) | | `FE-MISC-001` | PASS | 0.19144799999776296ms | Wrong current password → friendly error not 500 (smoke) | | `FE-MISC-002` | PASS | 0.2141300000002957ms | Same-as-old password blocked (smoke) | | `FE-MISC-003` | PASS | 0.1749160000035772ms | Password change success → next login uses new (smoke) | | `FE-MISC-004` | PASS | 0.2492950000014389ms | Driver License upload accepts JPG/PNG/PDF (smoke) | | `FE-MISC-005` | PASS | 0.16992800000298303ms | Driver License rejects >5 MB (smoke) | | `FE-MISC-006` | PASS | 7976.088896000001ms | GET /v1/user/driver-license returns previously uploaded | | `FE-MISC-007` | PASS | 0.6058120000016061ms | Add invalid card → friendly inline error (smoke) | | `FE-MISC-008` | PASS | 0.15944799999851966ms | Delete only payment method blocked (smoke) | | `FE-MISC-009` | PASS | 0.14581199999520322ms | Set default payment method updates (smoke) | | `FE-MISC-010` | PASS | 1.6318559999999707ms | AI Customized Templates editor saves + renders (smoke) | | `FE-NOTIF-001` | PASS | 7603.453004999999ms | /notifications renders list with All / Read / Unread tabs | | `FE-NOTIF-002` | PASS | 0.6161310000006779ms | Tabs filter notifications | | `FE-NOTIF-003` | PASS | 21.909239999999045ms | Sub-tabs Email/SMS/LinkedIn/System filter by type | | `FE-NOTIF-004` | PASS | 16.512220999999045ms | Mark all as read clears unread | | `FE-NOTIF-005` | PASS | 0.7393000000010943ms | Per-row 'Mark as Read' updates row (smoke) | | `FE-NOTIF-006` | PASS | 0.3397850000001199ms | Notifications scoped to current account_id (smoke) | | `FE-NOTIF-007` | PASS | 0.22641399999884015ms | Bell icon shows unread badge (smoke) | | `FE-NOTIF-008` | PASS | 11.701469999999972ms | Relative timestamps update (smoke) | | `FE-PERF-001` | PASS | 8656.393248ms | /automation-campaign reaches DOMContentLoaded under 15000ms (warn >5000ms) | | `FE-PERF-002` | PASS | 6189.656045ms | /dashboard reaches DOMContentLoaded under 15000ms (warn >5000ms) | | `FE-PERF-003` | PASS | 8313.345497999999ms | /email-system/email reaches DOMContentLoaded under 15000ms (warn >5000ms) | | `FE-PERF-004` | PASS | 6092.714070000002ms | /phone-system/sms reaches DOMContentLoaded under 15000ms (warn >5000ms) | | `FE-PERF-005` | PASS | 7135.593506999998ms | /notifications reaches DOMContentLoaded under 15000ms (warn >5000ms) | | `FE-PERF-006` | PASS | 6118.517007999995ms | /settings/general reaches DOMContentLoaded under 15000ms (warn >5000ms) | | `FE-PERF-007` | PASS | 5905.579303000006ms | /admin/dashboard reaches DOMContentLoaded under 15000ms (warn >5000ms) | | `FE-PERF-008` | PASS | 14876.390664999999ms | axe-core /automation-campaign zero serious violations | | `FE-PERF-009` | PASS | 7663.388160999995ms | axe-core /settings/general zero serious violations | | `FE-PERF-010` | PASS | 9413.842046999998ms | Form inputs have associated labels (axe label rule) | | `FE-PERF-011` | PASS | 9941.963594ms | Color contrast meets WCAG AA (axe color-contrast rule) | | `FE-PERF-012` | PASS | 0.6229929999972228ms | Tab order through forms is logical (smoke) | | `FE-PERF-013` | PASS | 9361.037660000002ms | Images have alt text (axe image-alt rule) | | `FE-PERF-014` | PASS | 0.4652080000087153ms | Page titles match content (smoke) | | `FE-PERF-015` | PASS | 5165.753668999998ms | No 404s on static assets (smoke — checked via network observer) | | `FE-PHONE-001` | PASS | 7326.943977999999ms | /phone-system redirects to /phone-system/sms | | `FE-PHONE-002` | PASS | 11995.558138999999ms | /phone-system/sms renders empty state (FE-BUG-04 fix — no permanent skeleton) | | `FE-PHONE-003` | PASS | 4794.228544000001ms | Empty state shows 'Go to Phone System Settings' CTA (best-effort) | | `FE-PHONE-004` | PASS | 3056.0419729999994ms | /phone-system/voicemails lists voicemails or empty state | | `FE-PHONE-005` | PASS | 0.581506000002264ms | Brand registration flow accessible from phone system | | `FE-PHONE-006` | PASS | 1.1143510000001697ms | A2P status badge displays correct color/text (smoke) | | `FE-PHONE-007` | PASS | 0.4963659999993979ms | Phone Number purchase flow renders available numbers (smoke) | | `FE-PHONE-008` | PASS | 0.4450619999988703ms | Buy phone number button triggers purchase API call (smoke) | | `FE-PHONE-009` | PASS | 1.4088919999994687ms | Send SMS modal validates recipient + body (smoke) | | `FE-PUR-001` | PASS | 9071.36391ms | /purchase-lists renders (dev-only on staging) | | `FE-PUR-002` | PASS | 3.7692580000002636ms | Search by Name filters list (smoke) | | `FE-PUR-003` | PASS | 1.9318969999949331ms | Status badges In Progress / Success render correct colors (smoke) | | `FE-PUR-004` | PASS | 4.245948000003409ms | Download Leads icon enabled only on Success (smoke) | | `FE-PUR-005` | PASS | 6536.502918999999ms | /purchase-lists/create renders form | | `FE-PUR-006` | PASS | 7.449479000002611ms | Create requires name + filters (smoke) | | `FE-PUR-007` | PASS | 0.41288100000383565ms | Pagination Rows-per-page selector (smoke) | | `FE-PUR-008` | PASS | 0.2684510000035516ms | Targeting eye-icon opens detail modal (smoke) | | `FE-REG-001` | PASS | 9598.067971ms | /signup step 1 renders register form (name, email, password, phone) | | `FE-REG-002` | PASS | 5859.078776000002ms | Submit empty form → field validation errors | | `FE-REG-003` | PASS | 5737.62888ms | Submit with invalid email format → validation error | | `FE-REG-004` | PASS | 4387.228121ms | Submit with weak password → strength meter + rejection | | `FE-REG-005` | PASS | 749.1142020000007ms | Submit with duplicate email → friendly 'email already registered' | | `FE-REG-006` | PASS | 24886.550325ms | Submit valid form → advances to step 2 (Select Plan) | | `FE-REG-007` | PASS | 3924.5257189999975ms | Step 2 shows Pulse Free + Pulse Pro side-by-side | | `FE-REG-008` | PASS | 1940.0044319999943ms | Toggle Monthly / Annually switches plan prices | | `FE-REG-009` | PASS | 2044.9285699999964ms | Click Free Plan → advances to step 4 (Order Information), skipping step 3 | | `FE-REG-010` | PASS | 1221.5304719999986ms | Click Pulse Pro → advances to step 3 (Add-ons) | | `FE-REG-011` | PASS | 3172.484181ms | Step 4 (Free Plan) — Total Due $0.00, 'Continue' button (NOT 'Continue to Payment') | | `FE-REG-012` | PASS | 1059.4499400000059ms | Step 4 (Free Plan) — promo code field hidden (FE-BUG-001 fix) | | `FE-REG-013` | PASS | 731.8267420000047ms | Step 4 (Free Plan) — clicking Continue skips payment form | | `FE-REG-014` | NOT_EXEC | 0ms | Step 4 (Paid plan) — Payment Information form shows card fields @paid | | `FE-REG-015` | NOT_EXEC | 0ms | Step 4 — apply promo code BETAOFFER → 100% discount → label changes @paid | | `FE-REG-016` | NOT_EXEC | 0ms | Step 4 — invalid promo code → friendly error @paid | | `FE-REG-017` | NOT_EXEC | 0ms | Step 4 — expired promo code → friendly error @paid | | `FE-REG-018` | NOT_EXEC | 0ms | Step 4 — payment form rejects invalid card number @paid | | `FE-REG-019` | NOT_EXEC | 0ms | Step 4 — payment form rejects expired card @paid | | `FE-REG-020` | NOT_EXEC | 0ms | Step 4 — payment form requires all billing address fields @paid | | `FE-REG-021` | PASS | 3174.7717919999996ms | Browser back button mid-wizard preserves form state | | `FE-REG-022` | PASS | 3229.576365000001ms | Direct nav to ?step=4 without completing 1-3 → redirects | | `FE-REG-023` | PASS | 6013.553999999989ms | Already-authenticated user navigating to /signup → redirects to dashboard | | `FE-REG-024` | PASS | 2656.5024209999974ms | Wizard step indicator updates correctly per step | | `FE-ROLE-001` | PASS | 4734.7036769999995ms | MEMBER login lands on dashboard | | `FE-ROLE-002` | PASS | 6851.129237999998ms | MEMBER /admin/dashboard redirected or 403 | | `FE-ROLE-003` | PASS | 0.42775800000163144ms | MEMBER PUT /v1/admin/plans/:id → 403 (smoke) | | `FE-ROLE-004` | PASS | 0.1763100000025588ms | MEMBER scoped to own account_id (smoke) | | `FE-ROLE-005` | PASS | 6.824051999999938ms | MEMBER admin-only actions hidden from UI (smoke) | | `FE-ROLE-006` | PASS | 4.7821900000017195ms | MEMBER edits own profile, can't delete account (smoke) | | `FE-SEAT-001` | PASS | 14264.116592999999ms | Sub-User Invite form requires valid email + role | | `FE-SEAT-002` | PASS | 0.70776300000216ms | Invite creates pending seat row (smoke) | | `FE-SEAT-003` | PASS | 0.2957719999976689ms | Recipient receives /invite/[id] email (smoke) | | `FE-SEAT-004` | PASS | 14776.576107000004ms | /invite/[id] shows account + inviter + Accept | | `FE-SEAT-005` | PASS | 0.6739390000002459ms | Accept invite from new email creates account (smoke) | | `FE-SEAT-006` | PASS | 0.8665079999991576ms | Reuse accepted invite shows already-accepted (smoke) | | `FE-SEAT-007` | PASS | 0.23016099999949802ms | Expired invite shows expired-link (smoke) | | `FE-SEAT-008` | PASS | 0.29041200000210665ms | Admin revokes seat → MEMBER session invalidated (smoke) | | `FE-SEAT-009` | PASS | 6803.637975999998ms | GET /v1/user/seats returns seat count | | `FE-SEC-001` | PASS | 1528.686765ms | Direct API call to BFF without token → 401 | | `FE-SEC-002` | PASS | 515.999613ms | Manipulated JWT → 401, FE redirects to login | | `FE-SEC-003` | PASS | 9.694672000000537ms | XSS via campaign name escaped on render (smoke) | | `FE-SEC-004` | PASS | 2.1318710000005012ms | XSS via email signature escaped (smoke) | | `FE-SEC-005` | PASS | 0.9567770000003293ms | XSS via business profile description escaped (smoke) | | `FE-SEC-006` | PASS | 1.112938000000213ms | SQL injection via search inputs safe (smoke — Prisma parameterised) | | `FE-SEC-007` | PASS | 7718.694102ms | Direct nav to /admin/* as non-admin blocked | | `FE-SEC-008` | PASS | 4.361924999999246ms | IDOR /automation-campaign/[id] foreign id → 403/404 (smoke) | | `FE-SEC-009` | PASS | 9.210057000000234ms | IDOR /admin/billing/clients/[id] foreign id → 403/404 (smoke) | | `FE-SEC-010` | PASS | 2.363814000000275ms | File upload wrong type rejected (smoke) | | `FE-SEC-011` | PASS | 6.088218000000779ms | File upload oversized rejected (smoke) | | `FE-SEC-012` | PASS | 0.30662300000039977ms | File upload uses staging cloud-documents URL (regression) | | `FE-SEC-013` | PASS | 0.2164649999995163ms | CSP blocks third-party scripts not in allowlist (smoke) | | `FE-SEC-014` | PASS | 1045.1412810000002ms | Frames-ancestors blocks iframe embedding (smoke) | | `FE-SEC-015` | PASS | 0.8244290000002366ms | Logout invalidates session token (smoke) | | `FE-SET-G-001` | PASS | 15231.787098ms | /settings/general renders Billing section by default | | `FE-SET-G-002` | PASS | 10654.848065000002ms | Right sidebar nav items show full text (fe-ui-01 regression) | | `FE-SET-G-003` | PASS | 0.7790349999995669ms | Right sidebar nav items list (smoke) | | `FE-SET-G-004` | PASS | 0.3233730000029027ms | Switching nav items updates panel without reload (smoke) | | `FE-SET-G-005` | PASS | 0.28897999999753665ms | Current Plan card shows plan name + price (smoke) | | `FE-SET-G-006` | PASS | 5653.219895000002ms | Plan features show numbers with thousands separators (fe-ui-02 regression) | | `FE-SET-G-007` | PASS | 0.6385420000005979ms | Promo code card shows discount + expiry + COPY (smoke) | | `FE-SET-G-008` | PASS | 7.128721000000951ms | Manage Add-ons button opens manage-plans page (smoke) | | `FE-SET-G-009` | PASS | 2.2096269999965443ms | CRM API tab shows connected CRM with masked key (smoke) | | `FE-SET-G-010` | PASS | 0.7018000000025495ms | Sub-User Management lists invited users (smoke) | | `FE-SET-G-011` | PASS | 0.3225419999944279ms | Sub-User Invite form validates email (smoke) | | `FE-SET-G-012` | PASS | 0.26134799999999814ms | Active Hours tab allows setting weekly schedule (smoke) | | `FE-SET-G-013` | PASS | 0.19176700000389246ms | Email Signatures tab renders editor + preview (smoke) | | `FE-SET-G-014` | PASS | 0.4941929999986314ms | Book Link tab persists URL (smoke) | | `FE-SET-G-015` | PASS | 0.21485100000427337ms | AI Customized Templates tab lists templates (smoke) | | `FE-SET-G-016` | PASS | 7044.02947ms | /settings/general AI Chat Response tab renders | | `FE-SET-G-017` | PASS | 8351.077998ms | Selecting a campaign reveals channel configuration toggles | | `FE-SET-G-018` | PASS | 7917.3317019999995ms | AI chat config persists in LocalStorage across reload | | `FE-SET-M-001` | PASS | 7709.465969000004ms | /settings/manage-plans renders manage add-ons section | | `FE-SET-M-002` | PASS | 0.48085700000228826ms | Existing add-ons list (smoke) | | `FE-SET-M-003` | PASS | 0.17716199999995297ms | Empty state friendly message (smoke) | | `FE-SET-M-004` | PASS | 0.14992899999924703ms | Available add-ons list (smoke) | | `FE-SET-M-005` | PASS | 0.276307000000088ms | Add new add-on triggers checkout flow (smoke) | | `FE-SET-M-006` | PASS | 0.22661299999890616ms | Cancel add-on triggers confirmation modal (smoke) | | `FE-SET-S-001` | PASS | 9807.680485999997ms | /settings/system renders Brand Status + Phone Settings | | `FE-SET-S-002` | PASS | 8.129318999999668ms | Right sidebar Phone / Email Settings (smoke) | | `FE-SET-S-003` | PASS | 0.4906660000051488ms | Brand Status badge color matches status (smoke) | | `FE-SET-S-004` | PASS | 10.442428999995172ms | Register Brand button opens modal (smoke) | | `FE-SET-S-005` | PASS | 0.4578639999963343ms | Phone Number Settings shows empty state (smoke) | | `FE-SET-S-006` | PASS | 0.21489099999598693ms | Email Settings shows OAuth connection state (smoke) | | `FE-SET-S-007` | PASS | 0.813399999999092ms | Save Route button persists route preferences (smoke) | | `FE-SETUP-001` | PASS | 7964.115400999999ms | /setup page renders for newly-signed-up users | | `FE-SETUP-002` | PASS | 1652.0041669999991ms | Setup wizard captures business profile info (form renders) | | `FE-SETUP-003` | PASS | 6869.273567ms | Skip onboarding via 'Skip for now' → dashboard with welcome modal (skip CTA exists) | | `FE-SETUP-004` | PASS | 7233.775118999998ms | /getting-started shows checklist with at least one step | | `FE-SETUP-005` | PASS | 7177.5065410000025ms | Welcome greeting renders user's first name | | `FE-SETUP-006` | PASS | 236.64834800000244ms | setup_finished flag persists in DB for the test admin | | `FE-SETUP-007` | PASS | 5530.790682000006ms | /getting-started accessible even when setup_finished is true (onboarding route exception) | | `FE-SIG-001` | PASS | 0.3372190000009141ms | Save email signature persists across reload (smoke) | | `FE-SIG-002` | PASS | 0.8758650000017951ms | Outbound email shows signature appended (smoke) | | `FE-SIG-003` | PASS | 0.2661660000012489ms | Save booking link persists (smoke) | | `FE-SIG-004` | PASS | 0.21244600000500213ms | {{sender_booking_link}} merge tag rendered (smoke) | | `FE-SIG-005` | PASS | 0.22853700000268873ms | Empty signature → no trailing artifact (smoke) | | `FE-SMS-TOKY-001` | PASS | 6.949697000000015ms | BYOC card lists Toky in /settings/system (smoke) | | `FE-SMS-TOKY-002` | PASS | 2.7280130000003737ms | Save bogus Toky API key → red error (smoke) | | `FE-SMS-TOKY-003` | PASS | 0.6385529999997743ms | Save real test API key creates carrier_credentials row (smoke) | | `FE-SMS-TOKY-004` | PASS | 0.3371490000004087ms | Save handshake registers webhook on Toky side (smoke) | | `FE-SMS-TOKY-005` | PASS | 0.28932999999960884ms | Re-save credential clears existing webhook auth (smoke) | | `FE-SMS-TOKY-006` | PASS | 0.27290999999968335ms | Add Toky Number lists user inventory (smoke) | | `FE-SMS-TOKY-007` | PASS | 0.28578299999981027ms | Import test number creates phonenumbers row (smoke) | | `FE-SMS-TOKY-008` | PASS | 0.24662999999964086ms | Send SMS via Toky doesn't decrement credits (smoke) | | `FE-SMS-TOKY-009` | PASS | 0.33618799999976545ms | Reply lands inbound within 10s (smoke) | | `FE-SMS-TOKY-010` | PASS | 1141.82319ms | Toky inbound webhook validates HTTP Basic auth | | `FE-SMS-TOKY-011` | PASS | 0.48741000000018175ms | Toky payload is JSON array (smoke) | | `FE-SMS-TOKY-012` | PASS | 0.24181199999975433ms | Toky inbound NEGATIVE sentiment marks deal LOST (smoke) | | `FE-SMS-TOKY-013` | PASS | 0.2786999999998443ms | Replay same payload twice → idempotent (smoke) | | `FE-SMS-TOKY-014` | PASS | 3.518029000000297ms | Disconnect Toky credential revokes webhook (smoke) | | `FE-SMS-TOKY-015` | PASS | 0.5676210000001447ms | Twilio + Toky number coexistence (smoke) | | `FE-SMS-TOKY-016` | PASS | 0.22774499999968612ms | AI personalization charges AI credits but not phone (smoke) | | `FE-SMS-TOKY-017` | PASS | 0.20685599999978876ms | Twilio regression after Toky enabled (smoke) | | `FE-SMS-TOKY-018` | PASS | 0.2395080000001144ms | Legacy provider=NULL treated as 'twilio' (smoke) | | `FE-SMS-TOKY-019` | PASS | 0.22187399999984336ms | Toky API key with zero numbers → empty inventory (smoke) | | `FE-SMS-TOKY-020` | PASS | 0.29759500000000116ms | Webhook dedup respects DRF pagination shape (smoke) | | `FE-SMS-TW-001` | PASS | 6.252013000000261ms | A2P brand registration starts from /settings/system (smoke) | | `FE-SMS-TW-002` | PASS | 0.6622059999999692ms | Phone-number purchase blocked when A2P != brand_approved | | `FE-SMS-TW-003` | PASS | 0.34034499999961554ms | Phone-number purchase succeeds when approved | | `FE-SMS-TW-004` | PASS | 0.2986670000000231ms | Send SMS from /phone-system/sms (smoke) | | `FE-SMS-TW-005` | PASS | 1.0324579999996786ms | Send SMS with merge tag rendered correctly | | `FE-SMS-TW-006` | PASS | 0.4346930000001521ms | Send SMS with no credits → 402 / out-of-credits | | `FE-SMS-TW-007` | PASS | 0.34993300000041927ms | Twilio API failure releases reserved credits | | `FE-SMS-TW-008` | PASS | 0.2828479999998308ms | Send SMS exceeds rate limit → 429 | | `FE-SMS-TW-009` | PASS | 0.809900999999627ms | Inbound SMS appears in FE thread (smoke) | | `FE-SMS-TW-010` | PASS | 0.38076099999943835ms | Inbound negative sentiment marks deal LOST (smoke) | | `FE-SMS-TW-011` | PASS | 273.97960500000045ms | Twilio webhook with wrong bears_key → 401 | | `FE-SMS-TW-012` | PASS | 1.0400719999997818ms | Twilio status callback updates messages.status (smoke) | | `FE-USER-001` | PASS | 10719.256589999997ms | /user renders profile fields | | `FE-USER-002` | PASS | 5997.320900000006ms | Created date renders correctly (NOT 'Invalid Date') | | `FE-USER-003` | PASS | 0.3687989999889396ms | Change Password button opens modal (smoke) | | `FE-USER-004` | PASS | 0.17358500001137145ms | Password modal validates fields (smoke) | | `FE-USER-005` | PASS | 3.8173380000080215ms | Wrong current password → friendly error (smoke) | | `FE-USER-006` | PASS | 0.33086899999761954ms | Password change success closes modal + toast (smoke) | | `FE-VM-001` | PASS | 3524.988045ms | /phone-system/voicemails lists records or empty state | | `FE-VM-002` | PASS | 0.6325509999996939ms | Each row shows recipient/duration/status/timestamp (smoke) | | `FE-VM-003` | PASS | 0.3213400000004185ms | Play affordance plays audio inline (smoke) | | `FE-VM-004` | PASS | 0.34245000000009895ms | Filter by status works (smoke) | | `FE-VM-005` | PASS | 1.2763020000002143ms | Pagination works at boundaries (smoke) | | `FE-VM-006` | PASS | 0.42605600000024424ms | Voicemail audio URL is signed/scoped (smoke) | | `JUDY-001` | PASS | 655.9577160000003ms | Unauth GET /v1/judy/conversations rejected | | `JUDY-002` | PASS | 6757.9741269999995ms | Authed GET /v1/judy/conversations does not 5xx (service up) | | `JUDY-003` | PASS | 100.63380700000016ms | Bogus sibling path 404s distinctly from the real route's 401 (route-exists sanity) | | `OPT-001` | PASS | 1256.8645610000003ms | Unauth GET /v1/optimization/signoffs rejected | | `OPT-002` | PASS | 8627.236864ms | Authed GET /v1/optimization/signoffs does not 5xx (service up) | | `OPT-003` | PASS | 370.854883ms | Bogus sibling path 404s distinctly from the real route's 401 (route-exists sanity) | | `UNKNOWN-0qcv15` | PASS | 0.35567500000024665ms | false when the token cookie expires inside the required margin | | `UNKNOWN-2itzcs` | PASS | 1.5583890000002611ms | falls back to exponential backoff with jitter when no Retry-After is given | | `UNKNOWN-a4y2fh` | PASS | 6.019480000000385ms | honors Retry-After across repeated 429s, then succeeds | | `UNKNOWN-ada1e5` | PASS | 0.8001339999999573ms | keeps going after an early role fails (e.g. 429 budget exhausted) | | `UNKNOWN-d9198d` | PASS | 18.139091000000008ms | false for malformed state | | `UNKNOWN-djb09v` | PASS | 4.383976000000075ms | respects QA_LOGIN_PREWARM_BUDGET_MS when no explicit budgetMs is given | | `UNKNOWN-eca4ue` | PASS | 0.7366360000000896ms | true when the token cookie has well over the required margin left | | `UNKNOWN-g6j5hl` | PASS | 0.8455380000000332ms | does NOT skip when the cached session exists but isFresh says no | | `UNKNOWN-hovbau` | PASS | 3.560748999999987ms | skips a role with no configured credentials instead of aborting the suite (2026-10-02 r... | | `UNKNOWN-lb77c5` | PASS | 3582.4543400000002ms | WITH the lock, exactly one process logs in per role | | `UNKNOWN-mp9fqc` | PASS | 4031.055242ms | WITHOUT the lock, concurrent processes each log in independently (>1) | | `UNKNOWN-mttqol` | PASS | 3.584563999999773ms | fails with a clear role + rate-limit error after the budget is exhausted | | `UNKNOWN-w7oibu` | PASS | 0.3652820000002066ms | false when the token cookie is already expired | | `UNKNOWN-yd04dn` | PASS | 0.32659000000012384ms | false when there is no token cookie | | `UNKNOWN-z3qzbn` | PASS | 10.66725800000006ms | warms every role, serially and in order, when all succeed | | `UNKNOWN-ztoet1` | PASS | 1.9813399999998182ms | skips the login entirely when a fresh cached session already exists | | `WEBHOOK-AUTH-001` | PASS | 482.2633390000001ms | email-ingress sentiment-webhook rejects without auth | | `WEBHOOK-AUTH-002` | PASS | 88.30490600000007ms | sms-service sentiment-webhook rejects without auth | | `WEBHOOK-AUTH-003` | PASS | 156.12997099999984ms | deal-mover sweeper rejects without auth | ## Failures ### FE-CAMP-011 — Builder name area exists (route smoke) ``` Expected some name-edit affordance on the builder: expected false to be true // Object.is equality ``` ### FE-DEAL-SEARCH-001 — Type email into Search Deals input → table filters by email ``` Expected a search input on /deals/search: expected false to be true // Object.is equality ``` ### FE-EMAIL-007 — /email-system/email/add page renders without crashing ``` Expected at least one input/editor on /email/add: expected 0 to be greater than 0 ```