Two rankings of the propflowai unit tests, both read from CI's own logs: what turned main red this past week, and how long each test file takes on average.
Measured Oct 1, 2026 · 656 failed CI runs, Sep 23 – Oct 1 · 25 full-suite runs on Oct 1 · companion to CI/CD architecture and CI Factory
Failures are mostly one break that stays red for hours, not flaky tests. 70 of the 82 failing test files broke main exactly once and failed every run until someone fixed it. Only 12 files broke main more than once, and four of those check live ElevenLabs settings. Time is spread out: the slowest 10 files are 12% of test time, and 6,830 of 7,585 files finish in under a second.
| File | Runs | Breaks |
|---|---|---|
| collections-chase-activity.test.ts | 71 | once |
| send-leasing-team-tour-update.test.ts | 70 | once |
| onboarding-wizard-steps.test.tsx | 70 | once |
| workspace-loading-shell-status-marker.test.tsx | 70 | once |
| renewal-ntv-email-regression.test.ts | 61 | once |
| File | Average |
|---|---|
| appfolio-client.test.ts | 67.7s |
| household-matrix.test.ts | 44.9s |
| mutation-control-invocation.test.ts | 43.9s |
| guards-for-paths.test.ts | 43.1s |
| review-verdict-watchdog-pages-surgically.test.ts | 42.8s |
Broke main more than once (the real flaky-test candidates): user-route-inventory.drift.test.ts ×6, specialist-prompt-drift.test.ts ×5, live-agent-roster.drift.test.ts ×4, specialist-transfers-drift.test.ts ×3, renewal-letter-mms-retry-route.test.ts ×3.
Open a section below for the full rankings. Each fix is a row on the Test Speed Tracker.
Fede's page lists a flaky-test ranking as "done, list in session". That list was never published, so this page rebuilds it from the logs. It is consistent with his 34-run sample: drift pins, led by the route inventory, are the repeat offenders here too, and maintenance-comms-activities from his list shows up here as well.
How to read the count. Main runs CI on every merge, about 180 times a day. When a test breaks on main it fails every run until a fix lands. So "failed 70 times" usually means "stayed broken for 4 hours", not "fails at random". The last column shows which kind it is. A one break needs a faster fix-forward. A repeat is a quarantine candidate.
| # | Test file · test that failed most | Failed runs | Red for | First seen | Suggestion |
|---|---|---|---|---|---|
| 1 | src/__tests__/collections-chase-activity.test.tssendCollectionsChase — legality gate (ADR-0117 deterministic half) > route-to-human (REAL property) with NO existing conversation: creates the thread, then esca | 71 | one break 3.9 h, once | Sep 30 | Fix forward faster |
| 2 | src/__tests__/send-leasing-team-tour-update.test.tssendLeasingTeamTourUpdate — the text leg > someone opted in → email AND a text to them, with the tour reference | 70 | one break 4.2 h, once | Sep 30 | Fix forward faster |
| 3 | src/__tests__/onboarding-wizard-steps.test.tsxthe wizard route list > keeps the steps Fede kept | 70 | one break 4.2 h, once | Sep 30 | Fix forward faster |
| 4 | src/__tests__/workspace-loading-shell-status-marker.test.tsxevery workspace route loading shell carries role="status" (p11-x-skeleton-everywhere) > src/app/(workspace)/onboarding-guide/leasing/hours-contact/loading.tsx r | 70 | one break 4.2 h, once | Sep 30 | Fix forward faster |
| 5 | src/__tests__/renewal-ntv-email-regression.test.tstenant NTV email is recorded on the renewal thread > 🔴 month-to-month + a date written in words + stopped for review → fires the firm notice AND lands the email | 61 | one break 3.3 h, once | Sep 30 | Fix forward faster |
| 6 | agents/clara/lib/messaging/__tests__/handle-tenant-email-capture.test.tshandleTenantEmailCapture > appends both the inbound text and the outbound ack through the conversation-writer machinery | 61 | one break 3.3 h, once | Sep 30 | Fix forward faster |
| 7 | src/__tests__/message-blocked-draft-marker.test.tsagent-loop sweep — no guard can park a draft without the marker > anomaly_review_gate parks its draft through the shared seam | 61 | one break 3.3 h, once | Sep 30 | Fix forward faster |
| 8 | src/__tests__/user-route-inventory.drift.test.tsuser-route inventory — the pin matches the tree > MUTATION CONTROL: a route that gains a raw company equality is SCOPE moved and MISREAD | 51 | repeat 6 separate breaks over 7.1 days | Sep 23 | Auto-update pinThe hand-kept route pin goes stale when routes are added; the mutation control also edits the real collections route by string-match and needs it pinned 'selection'. Fix: Generate the pin from a script, and run the mutation control on a fixture route instead of a real one. |
| 9 | src/lib/domain/escalation/__tests__/escalation-owner-readers.drift.test.tsescalation.owner readers · the real tree > matches the pin EXACTLY — no unpinned reader, no stale pin, no count moved | 50 | one break 2.6 h, once | Sep 30 | Fix forward faster |
| 10 | src/__tests__/apply-tour-intent-slot-hold.test.tsthe slot hold at applyTourIntent (listed buildings only) > CONFIRM of a tour that already has an event does not book the slot when the provider write did not la | 39 | one break 2.0 h, once | Sep 30 | Fix forward faster |
| 11 | src/__tests__/entity-conversation-routes.test.tsxwork order — /maintenance/work-orders/[displayId]/conversation > offers NO copy-link when the thread has no person, rather than a url built from undefined | 32 | repeat 2 separate breaks over 3.6 days | Sep 24 | KeepNot a flake: a module-level 30s memo cache (#13169) leaked between tests, and #13168 changed firstChunk; shard debounce-skips hid the red. Fix: Reset every module-level TtlCache memo in a global vitest setup, and run full shards for route changes. |
| 12 | src/__tests__/live-agent-roster.drift.test.tslive-agent roster — live ElevenLabs vs this repo > every live agent is declared by the repo or listed as expected-unmanaged | 28 | repeat 4 separate breaks over 3.0 days | Sep 26 | Move to nightlyCalls the live ElevenLabs API and fails whenever a throwaway agent is left in the workspace or a declared agent is deleted. Those are drifts no PR makes. Fix: Run the live roster comparison nightly with an alert; keep only the no-network shape describe in the merge gate. |
| 13 | src/lib/domain/portfolio/knowledge/__tests__/effective-sections.test.tsnobody bypasses the door — the one-hop guard, under a title it can keep > no module outside this directory names it — every reader goes through the door | 28 | one break 1.1 h, once | Sep 30 | Fix forward faster |
| 14 | src/__tests__/process-inbound-message-zillow-thread-reply.test.tsD11: a renter reply inside a Zillow thread keeps its forwarding address as the prospect address > [CONTROL] a shared aggregator mailbox is never the prospect ad | 26 | one break 1.1 h, once | Oct 1 | Fix forward faster |
| 15 | src/__tests__/active-thread-invariant.test.tsactive-thread invariant — the Jasper Mockley drop (2026-08-02) > [CONTROL] the same aggregator lead with NO open thread still parks | 26 | one break 1.1 h, once | Oct 1 | Fix forward faster |
| 16 | src/lib/domain/scope/__tests__/stored-pick-is-bootstrap-only.test.tstwo devices, one login — the row answers a device once, at bootstrap > the pin writes NO row — it is a pin, not a pick | 26 | one break 1.0 h, once | Sep 30 | Fix forward faster |
| 17 | src/__tests__/text-send-module-fence.test.ts'none' is closed to new sites — the shrink-only ratchet > no production file declares more 'none' than the ratchet allows, and no new file declares any | 24 | one break 2.3 h, once | Sep 28 | Share the scanWalks the source tree with readdirSync and parses every file with the TypeScript compiler to resolve imports of the Twilio and text-send modules. Fix: Read import edges from a shared once-per-run codebase index instead of re-walking and re-parsing the tree. |
| 18 | src/lib/domain/leasing/__tests__/email-lead-name-home-match.test.tsforwarding-only lead from a renter we already have at this home > reuses the existing person and inquiry: note on her card, no second first email | 23 | one break 42 min, once | Sep 30 | Fix forward faster |
| 19 | src/__tests__/import-guards-read-the-syntax-tree.drift.test.tsimport guards read the syntax tree (shrink-only ratchet) > no NEW test file decides an import by searching source text | 17 | repeat 2 separate breaks over 2.2 days | Sep 29 | Auto-update pinIt compares the whole test tree against a hand-kept TEXT_SEARCH_IMPORT_GUARDS list. A PR adding a flagged test isn't selected by the affected lane, so main breaks. Fix: Always run this scan on PRs that add test files, so the new offender fails its own PR. |
| 20 | src/__tests__/maintenance-comms-activities.test.tsforwardAnswerToTechActivity > a dispatcher skip is BENIGN — no throw, no stamp, and the F-2 marker still clears | 17 | one break 1.9 h, once | Sep 29 | Fix forward faster |
| 21 | scripts/voice-harness/clone-checklist/__tests__/gate-classes.test.tsthe real voice path is fully classified > EVERY gate on the voice path is in one of the two lists | 16 | repeat 2 separate breaks over 6 h | Sep 24 | Auto-update pinNew voice-path gates land without an entry in the hand-kept SAFETY_ONLY/CALLER_AUDIBLE lists, so main breaks after merge. Fix: Make PRs touching the walked voice directories run this test, so the PR that adds a gate fails. |
| 22 | src/__tests__/conversation-link-ratchet.drift.test.tsno NEW producer of the retiring /conversations/<id> route > every emitter is on the allowlist — a new one fails here | 15 | one break 36 min, once | Sep 30 | Fix forward faster |
| 23 | src/__tests__/tour-slot-offer-cap-windows-precedence.test.tstour slot offer cap defers to the windows footer — the footer itself (tour-time-windows eval g-voice-on bug) > the windows footer tells the model to offer windo | 15 | one break 48 min, once | Sep 30 | Fix forward faster |
| 24 | src/lib/domain/leasing/__tests__/email-lead-engine-edge-cases.replay.test.tsemail-lead engine — edge-case replay (Graph + SES lanes, hermetic) > quoted-chain-no-in-reply-to — quoted-reply chain with no In-Reply-To header [known: N4] | 14 | one break 48 min, once | Oct 1 | Fix forward faster |
| 25 | src/lib/domain/escalation/__tests__/bake-gate.test.tsapproveEscalationHold — source 'clara_prospect_email' (review mode) > a HELD FIRST TOUCH whose classification signal throws still applies the approve, but repor | 14 | one break 36 min, once | Sep 24 | Fix forward faster |
| # | Test file · test that failed most | Failed runs | Red for | First seen | Suggestion |
|---|---|---|---|---|---|
| 26 | src/__tests__/admin-scope-inventory.drift.test.tsadmin family — the COMPLETE p10-core-contract inventory (A + B1 + B2) > every route matches its pinned gate, scope input and read family | 13 | repeat 2 separate breaks over 2.5 days | Sep 24 | Auto-update pinA hand-written INVENTORY of all 150 admin routes (scripts/lib/admin-scope-inventory.ts) must be edited whenever an admin route or gate changes, and roughly 15 PRs touched it this week. Fix: Generate the inventory rows from source, and always run this test on PRs touching src/app/api/admin or middleware. |
| 27 | src/__tests__/smoke-wo-bugs.test.tsBug 1: No specialist quotes when handyman auto-assigned > plumbing/medium WO with handyman → NO specialist quote emails or Telegram | 13 | one break 1.0 h, once | Oct 1 | Fix forward faster |
| 28 | src/__tests__/list-my-assigned-work-orders.test.tshandleListMyAssignedWorkOrders — the identity walk fails CLOSED on a text line > NO SCOPE, NO READ — a conversation with no property never asks the walk at all | 12 | one break 48 min, once | Oct 1 | Fix forward faster |
| 29 | scripts/__tests__/ci-merge-group-on-demand.drift.test.tsci.yml routes merge_group to on-demand machines > every runs-on in ci.yml routes merge_group to spot=false | 11 | one break 30 min, once | Sep 30 | Fix forward faster |
| 30 | src/__tests__/ci-cost-routing.test.tsRunsOn production label — pinned, no dead override arms > finds exactly one CI_RUNS_ON-gated runs-on: line per switched job | 11 | one break 30 min, once | Sep 30 | Fix forward faster |
| 31 | src/__tests__/legacy-field-elimination.drift.test.tsPhase 5a — total legacy elimination drift guard > no production reference to "'user.email'" survives outside the audit allowlist | 10 | repeat 2 separate breaks over 6.9 days | Sep 24 | Auto-update pinRuns git grep for 'user.email' against a hand-kept path allowlist, so separately green PRs that add new reads break main once merged. Fix: Run the grep only on the PR diff's added lines so the adding PR fails, not main afterwards. |
| 32 | src/lib/domain/leasing/__tests__/clara-guest-card-first-touch-mailbox-gate.test.tsClara's first guest-card touch at a property with a connected mailbox > still honors the master claraLive gate at the send door — suppressed is a hold, not a se | 10 | one break 30 min, once | Oct 1 | Fix forward faster |
| 33 | src/lib/domain/escalation/__tests__/held-draft-staleness.test.tsapproveEscalationHold — a stale prospect draft > the SECOND approve sends the fresh draft — a rewrite is not stale again | 10 | one break 30 min, once | Oct 1 | Fix forward faster |
| 34 | src/lib/data/dynamo/__tests__/onboarding-attempt-no-pii.test.tscompany-connect route — the started-row write never logs or carries secret/token material > every log call on the started-write path logs only non-secret identi | 10 | one break 42 min, once | Sep 28 | Fix forward faster |
| 35 | src/__tests__/promptfoo-corpus.drift.test.tspromptfoo corpus manifest > is current with the catalog and the configs on disk | 9 | one break 48 min, once | Sep 30 | Fix forward faster |
| 36 | src/__tests__/customer-identifier-fence.drift.test.tsmulti-tenancy fence — customer identifiers never compile into shared source > no fixture introduces a customer identifier the baseline has not already recorded | 9 | one break 42 min, once | Sep 30 | Fix forward faster |
| 37 | src/__tests__/property-scope-surface-registry.drift.test.tsroutes that read a caller-supplied propertyId (query, body or path) > are all classified in the registry | 9 | one break 42 min, once | Sep 29 | Fix forward faster |
| 38 | src/lib/domain/leasing/__tests__/guest-card-engine-turn.test.tscomposeClaraFirstTouchViaEngine > falls back to the inquiry row's own unit and the property name when the card names neither | 9 | one break 18 min, once | Sep 24 | Fix forward faster |
| 39 | src/__tests__/conversation-org-stamp-dark.drift.test.tsConversation.organizationId — declared reader set (P6 step 5a) > has NO reader outside the DECLARED set | 8 | one break 24 min, once | Sep 30 | Fix forward faster |
| 40 | src/lib/domain/renewals/__tests__/external-reconcile-sweep.read-ledger.test.tsthe external-reconcile sweep reads each shared index once, not once per building > NEGATIVE CONTROL — with the bound dropped (origin/main's call), every buildin | 8 | one break 30 min, once | Sep 28 | Fix forward faster |
| 41 | src/__tests__/voice-stress-imports.test.tsvoice-stress orchestrator tool loader > getVoiceTools resolves a non-empty tool array | 7 | repeat 2 separate breaks over 9 h | Sep 28 | Move to nightlygetVoiceTools cold-loads the tools-leasing graph (~10.7k lines). On a busy CI shard this hit the 60s limit, so it only guards the nightly voice-stress script. Fix: Run the getVoiceTools check as a preflight step in the nightly voice-stress job, alerting on failure. |
| 42 | src/__tests__/conversation-single-writer.drift.test.tsF10 — dynamo/conversation.ts export surface is pinned (the post-F7 door) > every module-level export is pinned with a reason | 7 | one break 18 min, once | Sep 30 | Fix forward faster |
| 43 | src/__tests__/d1-confirm-table-guard.drift.test.tsD1 confirm-table guard — drift > every confirm-table-gated script is classified GUARDED or EXEMPT | 7 | one break 12 min, once | Sep 25 | Fix forward faster |
| 44 | src/__tests__/specialist-prompt-drift.test.tsspecialist prompt parity — shared fleet (live ElevenLabs vs what is deployed) > Clara — Leasing prompt + first_message match voice-agents/leasing.ts | 6 | repeat 5 separate breaks over 1.8 days | Sep 28 | Move to nightlyCompares live ElevenLabs agent prompts with the repo; breaks when on-merge sync fails or someone edits an agent in the dashboard. Fix: Take it out of the merge gate; run it on a nightly or after-sync cron that alerts #alerts. |
| 45 | src/__tests__/guard-pin-kinds.drift.test.tsguard pin kinds > mutation controls > an unsure bookkeeping entry goes red | 6 | one break 6 min, once | Sep 30 | Fix forward faster |
| 46 | src/lib/integrations/email/__tests__/company-live-gate-one-seam.test.tsthe one-seam invariant > a voice dial site or a text-only send site declares, and is deliberately OUT OF SCOPE for the email map | 6 | one break 36 min, once | Sep 29 | Fix forward faster |
| 47 | src/__tests__/get-tenants-passthrough.drift.test.tsget-tenants-passthrough.drift (ADR-0035 Phase F Slice 3b) > every bare getTenants() caller is on the ALL-tenants allowlist | 6 | one break 12 min, once | Sep 24 | Fix forward faster |
| 48 | src/lib/domain/settings/__tests__/settings-search-index.drift.test.tssettings search index > every anchor exists as an id on its own level's page source | 5 | one break 6 min, once | Sep 24 | Fix forward faster |
| 49 | src/__tests__/process-inbound-message-thread-bypass.test.tsprocessInboundEmailMessage — thread-context bypass wiring > reply bridge — an inbound email stops a running outreach cadence > non-bypass in-thread reply signal | 4 | one break 36 min, once | Oct 1 | Fix forward faster |
| 50 | src/__tests__/detail-back-href-canonical.test.tsdetail back href — one constant, no hand-rolled copies > no entity detail file hand-rolls its own "Back to …" destination | 4 | one break 30 min, once | Sep 28 | Fix forward faster |
| 51 | src/app/api/leasing/stats/__tests__/route.multi-org.test.tsa two-org selection is ANSWERED, not refused > is no longer a 400 — the refusal this leg replaced | 4 | one break 24 min, once | Sep 26 | Fix forward faster |
| 52 | src/app/api/leasing/stats/__tests__/route.selection.test.tstwo orgs is LOADED PER ORG, never unioned and never refused (ST-136) > names no single building on either leg | 4 | one break 24 min, once | Sep 26 | Fix forward faster |
| 53 | src/app/api/leasing/pipeline-members/__tests__/route.badge-drawer-agreement.test.tsone URL, one answer — the badge and the drawer agree on the building set > MANY-ORGS: the two routes fold the SAME building set, one leg per company | 4 | one break 24 min, once | Sep 26 | Fix forward faster |
| 54 | src/__tests__/specialist-transfers-drift.test.tsspecialist transfers — repo vs live drift > live unknown_caller_agent agent transfers MATCH the repo config (no drift) | 3 | repeat 3 separate breaks over 1.1 days | Sep 30 | Move to nightlyIt calls the live ElevenLabs API and compares live agent transfers to repo config, so main goes red whenever the live agents and main drift apart. Fix: Run the live repo-vs-ElevenLabs comparison nightly or after the sync deploy, with an alert; keep only the offline tests in CI. |
| 55 | src/__tests__/renewal-letter-mms-retry-route.test.tsPOST /api/leasing/renewals/[leaseId]/letter-mms-retry > PM double-click within the same minute produces the same eventId (workflow + activity dedup) | 3 | repeat 3 separate breaks over 2.6 days | Sep 24 | Fake the clockThe double-click test calls POST twice on the real clock and expects the same minute-bucketed eventId, so it flakes when a minute boundary falls between calls. Fix: Call vi.useFakeTimers() and vi.setSystemTime() to a fixed mid-minute instant in that test. |
| 56 | src/__tests__/decide-deploy-queue-stuck.test.tsdeploy-queue-watchdog.yml coverage > watches exactly the workflows whose queue one stuck run can freeze | 3 | one break 12 min, once | Oct 1 | Fix forward faster |
| 57 | src/__tests__/lib-data-mock-shape.drift.test.ts@/lib/data mock-shape drift guard (PR #1762) > every @/lib/data mock spreads importOriginal/importActual (or is allowlisted) | 3 | one break 18 min, once | Sep 30 | Fix forward faster |
| 58 | src/__tests__/audit-prod-invariants-signatures.test.tsaudit-prod-invariants — invariant call signatures > audit-prod-invariants.ts loads RenewalSaga entities (regression guard for nightly-2026-05-25) | 3 | one break 30 min, once | Sep 30 | Fix forward faster |
| 59 | src/app/api/admin/modules/buildings/__tests__/route.test.tsGET /api/admin/modules/buildings > lists each building's state next to the company's own switch | 3 | one break 18 min, once | Sep 29 | Fix forward faster |
| 60 | scripts/eval/__tests__/module-send-gate-declarations.test.tsderiveDeclaredCells — the real tree (the drift pin) > so the NOT APPLICABLE set is exactly email × collections, voice × prospects, voice × collections | 3 | one break 18 min, once | Sep 29 | Share the scanreadProductionSources walks the whole tree and parses every file with the TypeScript compiler; fixtures also build a ts.createProgram each. Fix: Use a shared once-per-run parsed-source index for the real-tree drift pin. |
| 61 | src/__tests__/leasing.test.tsGET /api/leasing/stats > computes leasing Metrics | 3 | one break 36 min, once | Sep 26 | Fix forward faster |
| 62 | src/lib/domain/agentflow/__tests__/smith-sessions.phase-sweep.test.tsgetSmithSessions — the phase sweep is off the read path > a status() query that never answers does not hold the read: it returns before any timer runs, phase un | 3 | one break 18 min, once | Sep 26 | Fix forward faster |
| 63 | src/__tests__/self-review-unresolvable-range.test.tsself-review: an unresolvable range is UNKNOWN, never a pass > a range that RESOLVES and is empty passes, and says which of the two it is | 3 | one break 18 min, once | Sep 25 | Slim it downEach test spawns the real scripts/self-review.sh, and two tests run the identical bad-base invocation separately. Fix: Run the bad-base invocation once in beforeAll and share its output across both tests. |
| 64 | src/__tests__/live-equals-main.drift.test.tslive == main — turn config (live ElevenLabs vs repo TURN exports) > Clara — Escalation Answer Callback (Outbound) turn config matches main | 2 | repeat 2 separate breaks over 8 h | Sep 30 | Move to nightlyFetches live ElevenLabs agent configs. It fails whenever a merged TURN change isn't synced to the fleet within 24h, e.g. the Escalation Callback agent. Fix: Run it as a nightly check that alerts and re-runs sync-specialists, not as a merge gate. |
| 65 | src/__tests__/tool-handlers.test.tshandleCreateWorkOrder > does NOT auto-approve an EXTERNAL-vendor WO with no estimate — unknown spend fails closed | 2 | one break 12 min, once | Sep 25 | Fix forward faster |
| 66 | src/__tests__/sms-review-gate-e2e.test.tsAnomaly Review Gate — SMS/email agent loop (#5131) > CONTROL: the turn actually reaches the fatal failure | 2 | one break 12 min, once | Sep 25 | Fix forward faster |
| 67 | src/__tests__/duplicate-wo-race.test.tsDuplicate WO race condition (Sean bug 2026-03-14) > allows WO creation for different conversations | 2 | one break 12 min, once | Sep 25 | Fix forward faster |
| 68 | src/__tests__/thread-context-bypass.test.tscheckThreadContextBypass — negative cases (must NOT bypass) > does NOT bypass when person has conversations only at OTHER properties (cross-property guard) | 2 | one break 12 min, once | Sep 25 | Fix forward faster |
| 69 | src/__tests__/handyman-create-wo.test.ts#41 handyman create — falls through to tenant path > ENDED membership → router outputs flag=false → gate skips (primary path, review #1736 F2) | 2 | one break 12 min, once | Sep 25 | Fix forward faster |
| 70 | agents/clara/lib/agent/__tests__/conversation-read-dedup.test.tsschedule_tour — conversation read is deduped > loads the conversation exactly once (property default + phone read share the row) | 2 | one break 12 min, once | Sep 25 | Fix forward faster |
| 71 | src/__tests__/create-wo-report-backstamp.test.tshandleCreateWorkOrder back-stamps the report segment > FIRST-TYPE-WINS: a maestro renewal row inside the segment keeps its type through the create-time backstam | 2 | one break 6 min, once | Sep 24 | Fix forward faster |
| 72 | src/__tests__/specialist-voice-sound-drift.test.tsspecialist voice sound parity (live ElevenLabs) > live Clara — Leasing agent sound MATCHES the repo config (no drift) | 1 | one break 0 min, once | Oct 1 | Fix forward faster |
| 73 | src/__tests__/specialist-tool-drift.test.tsSpecialist tool drift (catalog ⇄ live ElevenLabs) > no catalog-claimed tool name is bound twice to the SAME agent | 1 | one break 0 min, once | Oct 1 | Fix forward faster |
| 74 | src/__tests__/live-state-discipline.drift.test.tsrepo-wide guards that read outside state declare how they stay fair > CONTROL — the detector finds BOTH known instances of the class | 1 | one break 0 min, once | Sep 30 | Fix forward faster |
| 75 | scripts/__tests__/workflow-grep-marker-ratchet.drift.test.tsthe live workflows: every grep is annotated or already on the baseline > no new unannotated grep | 1 | one break 0 min, once | Sep 30 | Fix forward faster |
| 76 | src/__tests__/apply-tour-intent.test.tsapplyTourIntent > self-guided lockbox-code ask wiring (propose/confirm/reschedule) > SELF-GUIDED TOUR: autoConfirmed propose fires the lockbox-code ask; an in_p | 1 | one break 0 min, once | Sep 29 | Fix forward faster |
| 77 | lambda/stage-replicator/__tests__/spine-throttle-retry.test.tsan exhausted spine-index throttle hands the whole batch back once > THE HEADLINE: a 100-record batch builds the dictionary ONCE and reports only the first recor | 1 | one break 0 min, once | Sep 28 | Fix forward faster |
| 78 | src/lib/domain/properties/__tests__/property-directory-refresh-read-path.test.tsthe directory read touches only the AppFolio Reporting API > reads property_directory over the Reports API — no robot, no warm-up, no Redis | 1 | one break 0 min, once | Sep 26 | Fix forward faster |
| 79 | src/__tests__/outlook-webhook-extraction-lifecycle.test.tsextraction lifecycle — needs_review tenant-rescue arm > rescued-extraction rejection → flow still resolves cleanly, error logged under the rescue tag, bookkeepi | 1 | one break 0 min, once | Sep 24 | Fix forward faster |
| 80 | src/lib/domain/pms/mirror/__tests__/guest-card-mirror-per-inquiry-emit.test.tsmirrorGuestCards — one lead.received per inquiry (#11097) > this home's tick never emits another home's inquiry | 1 | one break 0 min, once | Sep 24 | Fix forward faster |
| 81 | src/lib/integrations/voice/store.test.tsresolveVoiceConversationId — fan-out regression guard > reuses the already-loaded meta set for the phone fallback instead of a second read | 1 | one break 0 min, once | Sep 23 | Fix forward faster |
| 82 | src/__tests__/dangerous-diff-label-in-ci.drift.test.tsthe single glob source > `globs` is byte-identical to auto-merge-all.yml rule 3 (until that file is deleted) | 1 | one break 0 min, once | Oct 1 | Fix forward faster |
These are the ones a flaky-test quarantine would actually catch. A break is counted again when the test fails after more than 3 hours of passing.
| Test file · test | Breaks | Failed runs | Suggestion |
|---|---|---|---|
| src/__tests__/user-route-inventory.drift.test.tsuser-route inventory — the pin matches the tree > MUTATION CONTROL: a route that gains a raw company equality is SCOPE moved and MISREAD | 6 | 51 | Auto-update pinThe hand-kept route pin goes stale when routes are added; the mutation control also edits the real collections route by string-match and needs it pinned 'selection'. Fix: Generate the pin from a script, and run the mutation control on a fixture route instead of a real one. |
| src/__tests__/specialist-prompt-drift.test.tsspecialist prompt parity — shared fleet (live ElevenLabs vs what is deployed) > Clara — Leasing prompt + first_message match voice-agents/leasing.ts | 5 | 6 | Move to nightlyCompares live ElevenLabs agent prompts with the repo; breaks when on-merge sync fails or someone edits an agent in the dashboard. Fix: Take it out of the merge gate; run it on a nightly or after-sync cron that alerts #alerts. |
| src/__tests__/live-agent-roster.drift.test.tslive-agent roster — live ElevenLabs vs this repo > every live agent is declared by the repo or listed as expected-unmanaged | 4 | 28 | Move to nightlyCalls the live ElevenLabs API and fails whenever a throwaway agent is left in the workspace or a declared agent is deleted. Those are drifts no PR makes. Fix: Run the live roster comparison nightly with an alert; keep only the no-network shape describe in the merge gate. |
| src/__tests__/specialist-transfers-drift.test.tsspecialist transfers — repo vs live drift > live unknown_caller_agent agent transfers MATCH the repo config (no drift) | 3 | 3 | Move to nightlyIt calls the live ElevenLabs API and compares live agent transfers to repo config, so main goes red whenever the live agents and main drift apart. Fix: Run the live repo-vs-ElevenLabs comparison nightly or after the sync deploy, with an alert; keep only the offline tests in CI. |
| src/__tests__/renewal-letter-mms-retry-route.test.tsPOST /api/leasing/renewals/[leaseId]/letter-mms-retry > PM double-click within the same minute produces the same eventId (workflow + activity dedup) | 3 | 3 | Fake the clockThe double-click test calls POST twice on the real clock and expects the same minute-bucketed eventId, so it flakes when a minute boundary falls between calls. Fix: Call vi.useFakeTimers() and vi.setSystemTime() to a fixed mid-minute instant in that test. |
| src/__tests__/entity-conversation-routes.test.tsxwork order — /maintenance/work-orders/[displayId]/conversation > offers NO copy-link when the thread has no person, rather than a url built from undefined | 2 | 32 | KeepNot a flake: a module-level 30s memo cache (#13169) leaked between tests, and #13168 changed firstChunk; shard debounce-skips hid the red. Fix: Reset every module-level TtlCache memo in a global vitest setup, and run full shards for route changes. |
| src/__tests__/import-guards-read-the-syntax-tree.drift.test.tsimport guards read the syntax tree (shrink-only ratchet) > no NEW test file decides an import by searching source text | 2 | 17 | Auto-update pinIt compares the whole test tree against a hand-kept TEXT_SEARCH_IMPORT_GUARDS list. A PR adding a flagged test isn't selected by the affected lane, so main breaks. Fix: Always run this scan on PRs that add test files, so the new offender fails its own PR. |
| scripts/voice-harness/clone-checklist/__tests__/gate-classes.test.tsthe real voice path is fully classified > EVERY gate on the voice path is in one of the two lists | 2 | 16 | Auto-update pinNew voice-path gates land without an entry in the hand-kept SAFETY_ONLY/CALLER_AUDIBLE lists, so main breaks after merge. Fix: Make PRs touching the walked voice directories run this test, so the PR that adds a gate fails. |
| src/__tests__/admin-scope-inventory.drift.test.tsadmin family — the COMPLETE p10-core-contract inventory (A + B1 + B2) > every route matches its pinned gate, scope input and read family | 2 | 13 | Auto-update pinA hand-written INVENTORY of all 150 admin routes (scripts/lib/admin-scope-inventory.ts) must be edited whenever an admin route or gate changes, and roughly 15 PRs touched it this week. Fix: Generate the inventory rows from source, and always run this test on PRs touching src/app/api/admin or middleware. |
| src/__tests__/legacy-field-elimination.drift.test.tsPhase 5a — total legacy elimination drift guard > no production reference to "'user.email'" survives outside the audit allowlist | 2 | 10 | Auto-update pinRuns git grep for 'user.email' against a hand-kept path allowlist, so separately green PRs that add new reads break main once merged. Fix: Run the grep only on the PR diff's added lines so the adding PR fails, not main afterwards. |
| src/__tests__/voice-stress-imports.test.tsvoice-stress orchestrator tool loader > getVoiceTools resolves a non-empty tool array | 2 | 7 | Move to nightlygetVoiceTools cold-loads the tools-leasing graph (~10.7k lines). On a busy CI shard this hit the 60s limit, so it only guards the nightly voice-stress script. Fix: Run the getVoiceTools check as a preflight step in the nightly voice-stress job, alerting on failure. |
| src/__tests__/live-equals-main.drift.test.tslive == main — turn config (live ElevenLabs vs repo TURN exports) > Clara — Escalation Answer Callback (Outbound) turn config matches main | 2 | 2 | Move to nightlyFetches live ElevenLabs agent configs. It fails whenever a merged TURN change isn't synced to the fleet within 24h, e.g. the Escalation Callback agent. Fix: Run it as a nightly check that alerts and re-runs sync-specialists, not as a merge gate. |
Four of these call live ElevenLabs and compare it to the repo (specialist-prompt-drift, live-agent-roster, specialist-transfers-drift, live-equals-main). They go red whenever someone edits an agent in ElevenLabs, whatever the code says. That makes them better suited to a nightly alert than a merge gate. user-route-inventory is the single worst offender: 6 breaks in 7 days, because every new page route has to be added to its pin.
Average is the mean across 25 complete runs on Oct 1. Per test is the file's average divided by its number of tests: a high value means a few heavy tests, not a big file.
| # | Test file | Average | Median | Slowest | Tests | Per test | Suggestion |
|---|---|---|---|---|---|---|---|
| 1 | src/__tests__/appfolio-client.test.ts | 67.7s | 67.8s | 72.6s | 25 | 2.7s | Fake the clockThe '5xx via appfolioPolicy' test uses real timers and waits through the whole retry/backoff ladder (120s timeout); the other 429 tests already fake time. Fix: Use vi.useFakeTimers in the 5xx test and step through the backoff with advanceTimersByTimeAsync. |
| 2 | src/__tests__/household-harness/household-matrix.test.ts | 44.9s | 40.6s | 53.4s | 33 | 1.4s | Slim it downEvery invariant test loops all scenarios and re-runs projectHouseholds/runHouseholdSync (the sync runs twice) on the real JSON file store, with the same rows over and over. Fix: Compute each scenario's baseline projection once in beforeAll and reuse it in the invariant tests. |
| 3 | scripts/__tests__/mutation-control-invocation.test.ts | 43.9s | 43.8s | 51.6s | 11 | 4.0s | Move to nightlyThree tests spawn `npx tsx check-mutation-control.ts`, one running a fixture-git-repo control; each spawn cold-starts tsx (≈44s total). Fix: Move the three CLI-spawning exit-code tests to a nightly lane; keep the in-process parser and selection tests gating. |
| 4 | scripts/__tests__/guards-for-paths.test.ts | 43.1s | 40.2s | 48.9s | 12 | 3.6s | Share the scanEach of 12 tests spawns `node guards-for-paths.mjs`, which re-lists and re-greps ~850 candidate guard files from scratch. Fix: Import the selector in-process and build the candidate index once in beforeAll, shared by all cases. |
| 5 | src/__tests__/review-verdict-watchdog-pages-surgically.test.ts | 42.8s | 42.8s | 43.6s | 32 | 1.3s | Move to nightlyEach of about 32 cases writes stub gh/curl into a temp dir and spawns bash to run the real workflow sweep script. Fix: Run it only on PRs that touch the watchdog workflow, plus nightly. |
| 6 | src/__tests__/convention-files-phosphor-server-safe.drift.test.ts | 39.2s | 36.4s | 45.4s | 318 | 0.1s | Share the scanIt globs every route convention file and, for each of about 318, walks its import graph from scratch with readFileSync/existsSync, re-reading shared modules every time. Fix: Build one import-graph index per run, cached across entries, and query it for each convention file. |
| 7 | src/lib/data/dynamo/__tests__/batch-get-callers-reread.test.ts | 34.2s | 34.2s | 34.4s | 9 | 3.8s | Fake the clockThe header says 'Real timers — one exhausted retry budget is ~3s', and every case runs a five-attempt batchGet backoff on the real clock. Fix: Use vi.useFakeTimers() with runAllTimersAsync, or inject a zero backoff delay into the batchGet retry helper. |
| 8 | lambda/appfolio-sync/__tests__/onboarding-import-runner.test.ts | 27.5s | 27.5s | 27.6s | 78 | 0.4s | KeepCould not pin it down. Every failing-stage test already injects a no-op sleep, so the cost seems to be 78 real stage-chain runs. Fix: No cheap fix found; profile per-test durations before changing anything. |
| 9 | scripts/eval/__tests__/module-send-gate-declarations.test.ts | 25.8s | 22.8s | 33.6s | 116 | 0.2s | Share the scanreadProductionSources walks the whole tree and parses every file with the TypeScript compiler; fixtures also build a ts.createProgram each. Fix: Use a shared once-per-run parsed-source index for the real-tree drift pin. |
| 10 | src/__tests__/roster-gate-call-sites.drift.test.ts | 23.7s | 21.8s | 28.6s | 10 | 2.4s | Share the scanreadFirstPartySources walks all of src/agents/lambda/scripts five times: once for the main scan, then again for each P0b missing-root case through symlinks. Fix: Use a shared cached source index, and test the missing-root check on a tiny fixture tree. |
| 11 | src/__tests__/text-send-module-fence.test.ts | 23.6s | 24.1s | 30.6s | 28 | 0.8s | Share the scanWalks the source tree with readdirSync and parses every file with the TypeScript compiler to resolve imports of the Twilio and text-send modules. Fix: Read import edges from a shared once-per-run codebase index instead of re-walking and re-parsing the tree. |
| 12 | src/__tests__/schedule-tour-volunteered-email.test.ts | 22.2s | 21.1s | 25.5s | 25 | 0.9s | Slim it downbeforeEach calls vi.resetModules, so every one of 25 tests re-imports tools-leasing and its leasing domain graph, plus a data/seed copy. Fix: Import tools-leasing once in beforeAll and swap mock return values per test, without resetModules. |
| 13 | src/__tests__/lambda-eager-ai-client.drift.test.ts | 21.1s | 19.4s | 24.9s | 7 | 3.0s | Move to nightlySpawns `npx tsx lambda/<name>/build.ts` (a full esbuild bundle) for each of 7 candidate lambdas to read their metafiles. Fix: Run only when lambda/ or its imports change, plus nightly, or reuse CI's existing lambda build metafiles. |
| 14 | src/__tests__/calendar-stub-fence.drift.test.ts | 18.4s | 17.9s | 26.2s | 8 | 2.3s | Share the scanimporters() runs `git ls-files` over four roots and reads every tracked file on each call, and multiple tests call it. Fix: Compute importers() once in beforeAll, or read it from a shared once-per-run codebase index. |
| 15 | src/lib/domain/conversations/__tests__/turn-score.test.ts | 18.1s | 18.1s | 22.4s | 72 | 0.3s | Fake the clockThe ECONNRESET tests go through the real scoringClaudePolicy retry, which sleeps 2s/4s/8s (≈14s) before giving up. Fix: Use fake timers in the vendor-failure tests, or inject a zero-delay retry policy into scoreConversationTurns. |
| 16 | src/__tests__/turn-checks-route-fence.drift.test.ts | 17.0s | 15.3s | 20.7s | 5 | 3.4s | Share the scanIt walks every file under src/app with readdirSync and follows each file's import chain by reading source files. Fix: Read import edges from a shared once-per-run import-graph index instead of its own readdirSync walk. |
| 17 | src/lib/domain/conversations/__tests__/trajectory-review-llm.test.ts | 16.4s | 16.7s | 19.5s | 33 | 0.5s | Fake the clockThe two 'network blip' transport-error tests go through the real scoringClaudePolicy retry, waiting out its real backoff. Fix: Fake timers in the transport-error tests, or inject a no-delay retry policy. |
| 18 | scripts/__tests__/scope-parity-replay-pair-coverage.drift.test.ts | 16.3s | 14.6s | 21.4s | 16 | 1.0s | Share the scancheckPairCoverage(root) scans the real tree three times, and scanFieldReaders reads more than 1000 product files on top of that. Fix: Scan the real tree once in beforeAll and run the without-owed-list variants against that cached result. |
| 19 | src/__tests__/audit-channels.test.ts | 15.6s | 14.9s | 18.1s | 32 | 0.5s | Slim it downEach describe calls vi.resetModules() before every test, then re-imports heavy modules (Twilio webhook route, dispatcher, voice personalization route) per test across 32 tests. Fix: Import each route or module once per describe in beforeAll; reset the mock state, not the module graph. |
| 20 | src/app/(workspace)/(operations)/agents/__tests__/page.decision-queue.test.tsx | 15.6s | 14.9s | 18.6s | 94 | 0.2s | Slim it down94 tests each mount the full AgentsPageClient in jsdom with a stubbed fetch, and 8 call settleUrl, which waits a real 500ms. Fix: Share one mount per describe block where possible and fake timers for the 400ms URL write delay. |
| 21 | src/lib/domain/scope/__tests__/operator-authority-seam.drift.test.ts | 15.5s | 14.4s | 18.7s | 4 | 3.9s | Share the scanWalks all of src/ with readdirSync/statSync and reads and comment-strips every .ts/.tsx file to regex-match writer shapes. Fix: Read files from a shared once-per-run comment-stripped source index instead of its own walk. |
| 22 | evals/replay-harness/guest-card-corpus/__tests__/judge-row-resilience.test.ts | 15.5s | 15.5s | 15.6s | 11 | 1.4s | Fake the clockjudgeOne really sleeps 500ms×attempt between retries on bad JSON (judge.ts:2540), and judgeRowResilient retries it, so each failing case waits several seconds. Fix: Use vi.useFakeTimers with runAllTimersAsync, or inject a zero retry delay into judgeOne. |
| 23 | src/app/(workspace)/(operations)/leasing/prospects/ProspectsClient.stage-insight.test.tsx | 14.4s | 14.2s | 15.1s | 9 | 1.6s | Fake the clockswitchTab, clickFigure and the deep-link test each sleep a real 600ms setTimeout, repeated across 9 tests. Fix: Use vi.useFakeTimers() and advanceTimersByTimeAsync(600) instead of real sleeps. |
| 24 | src/__tests__/send-application-link.test.ts | 14.4s | 12.9s | 17.9s | 92 | 0.2s | Slim it downbeforeEach runs vi.resetModules, then 73 separate dynamic imports reload send-application-link and its dependency graph for each of 92 tests. Fix: Import the module once at file scope and reset mock state per test, not modules. |
| 25 | src/__tests__/self-review-unresolvable-range.test.ts | 14.3s | 13.8s | 16.4s | 5 | 2.9s | Slim it downEach test spawns the real scripts/self-review.sh, and two tests run the identical bad-base invocation separately. Fix: Run the bad-base invocation once in beforeAll and share its output across both tests. |
| 26 | src/__tests__/outlook-webhook-fetch-retry.test.ts | 14.2s | 14.3s | 15.8s | 10 | 1.4s | Fake the clockIt runs the real graphMail retry policy (500ms initial, 5s max backoff, Retry-After up to 10s) with real timers through repeated 503/throttle cases. Fix: Use vi.useFakeTimers and advance timers instead of waiting out the real backoff. |
| 27 | src/__tests__/schedule-tour-failure-reaches-review-gate.test.ts | 14.1s | 12.7s | 17.6s | 26 | 0.5s | Slim it downbeforeEach runs vi.resetModules(), so each of 26 tests re-imports the heavy tools-leasing and voice-review-gate module graph under many importOriginal mocks. Fix: Import tools-leasing and the gate modules once in beforeAll; reset mocks and breaker state between tests instead. |
| 28 | src/lib/domain/leasing/__tests__/listing-geocode.test.ts | 14.0s | 14.0s | 14.0s | 26 | 0.5s | Fake the clockThe real geocoder enforces a 1s Nominatim gap between calls and retries 3 times, so tests wait on real setTimeout sleeps. Fix: Use vi.useFakeTimers or inject the sleep and gap so retries resolve instantly. |
| 29 | src/__tests__/conversation-partition-fanout-pinned.drift.test.ts | 13.2s | 12.2s | 17.3s | 3 | 4.4s | Share the scanRuns `git ls-files` and parses every tracked non-test TS file with the TypeScript compiler to find partition fan-out call sites. Fix: Use a shared once-per-run parsed-AST index of tracked sources. |
| 30 | src/lib/data/dynamo/__tests__/batch-get-reports-given-up-keys.test.ts | 13.1s | 13.1s | 13.2s | 9 | 1.5s | Fake the clockThe wire throttles keys through all five batchGet attempts plus the re-read, and the helper's real retry backoff runs with real timers (no fake timers in the file). Fix: Use vi.useFakeTimers and runAllTimersAsync, like tour-calendar-window's throttle tests already do. |
| # | Test file | Average | Median | Slowest | Tests | Per test | Suggestion |
|---|---|---|---|---|---|---|---|
| 31 | src/__tests__/ci-guard-pin-coverage.drift.test.ts | 12.7s | 11.9s | 14.3s | 16 | 0.8s | Slim it downSpawns node for the union script twice and the selector at least twice (each scans the repo), plus git ls-files and a git init temp repo. Fix: Run the union and selector scripts once each in beforeAll and reuse their output across all assertions. |
| 32 | src/__tests__/d1-guard-import-order.drift.test.ts | 12.6s | 11.2s | 16.0s | 6 | 2.1s | Share the scanIt walks the scripts tree with readdirSync and parses each file with ts.createSourceFile to resolve import closures; it once ran over 60s. Fix: Resolve import closures from a shared once-per-run TypeScript import-graph index. |
| 33 | src/__tests__/lib-coverage-gaps.test.ts | 12.6s | 12.6s | 13.4s | 17 | 0.7s | Slim it downSeveral describe blocks call vi.resetModules in beforeEach and re-import big modules (store, quotes generator, elevenlabs client) for each test. Fix: Import each module once per describe in beforeAll; reset only the mocks per test. |
| 34 | src/lib/data/dynamo/__tests__/tour-calendar-window.test.ts | 12.4s | 12.4s | 12.6s | 17 | 0.7s | Fake the clockThe dropped-key tests for undated tours and the month read use real timers, so the batchGet retry backoff runs at real speed; only two other tests fake the clock. Fix: Turn on fake timers in beforeEach and await runAllTimersAsync in every test that drops a key. |
| 35 | scripts/__tests__/table-default-drift.test.ts | 12.4s | 11.6s | 13.7s | 28 | 0.4s | Slim it downThree tests each spawn `npx tsx` on the check CLI, though the in-process scanTree tests already cover the same detection logic. Fix: Keep one CLI spawn that checks both exit codes; cover the empty and missing-root cases through scanTree in-process. |
| 36 | src/app/(workspace)/(operations)/leasing/prospects/ProspectsClient.date-window.test.tsx | 11.8s | 11.9s | 12.3s | 18 | 0.7s | Fake the clockAbout 22 date-range picks each wait a real 500ms for the URL write delay, roughly 11s of the 11.8s total. Fix: Use vi.useFakeTimers and advanceTimersByTime(500) instead of real setTimeout waits. |
| 37 | src/__tests__/guard-union-kind-filter.test.ts | 11.4s | 11.5s | 12.8s | 5 | 2.3s | Slim it downbeforeAll spawns node guard-union-files.mjs three times (default, all, fence); each run builds the full 900+ pin union. Fix: Spawn once; get the fence list with the pure filterPinsByKind function, keeping one env-path spawn. |
| 38 | src/__tests__/speakable-tour-availability.test.ts | 11.2s | 10.6s | 14.1s | 25 | 0.4s | Slim it downbeforeEach calls vi.resetModules, so every test re-imports heavy modules (tools-leasing, @/lib/data, calendar) dynamically from scratch. Fix: Drop the per-test resetModules, import the modules once at the top, and reset state through mocks. |
| 39 | src/__tests__/line-coverage-no-dashboard-writer.drift.test.ts | 11.1s | 10.0s | 13.9s | 8 | 1.4s | Share the scanWalks production roots with readdirSync and resolves import reachability (reachesSymbols, client-import-graph) across the whole tree. Fix: Answer the reachability query from a shared once-per-run import graph index instead of walking per test file. |
| 40 | src/__tests__/tour-booking-reads-every-calendar.test.ts | 10.5s | 9.3s | 13.2s | 17 | 0.6s | Slim it downbeforeEach calls vi.resetModules, then re-imports tools-leasing and its leasing graph, plus a data/seed copy, for each of 17 tests. Fix: Import tools-leasing once in beforeAll and change the calendar fakes per test, without resetModules. |
| 41 | src/lib/domain/portfolio/context/__tests__/raw-store-importers.drift.test.ts | 10.2s | 9.2s | 12.7s | 10 | 1.0s | not reviewed |
| 42 | src/lib/integrations/appfolio/__tests__/balances-portfolio.test.ts | 10.2s | 10.3s | 11.0s | 10 | 1.0s | not reviewed |
| 43 | scripts/email-stress/__tests__/wait-for-reply.test.ts | 10.0s | 10.0s | 10.0s | 6 | 1.7s | not reviewed |
| 44 | evals/replay-harness/guest-card-corpus/__tests__/bound-home-concessions.test.ts | 9.8s | 8.8s | 12.3s | 18 | 0.5s | not reviewed |
| 45 | src/__tests__/turnover-client.test.ts | 9.7s | 9.4s | 11.8s | 9 | 1.1s | not reviewed |
| 46 | src/__tests__/wo-displayid-drift-guards.test.ts | 9.6s | 9.1s | 11.1s | 12 | 0.8s | not reviewed |
| 47 | src/lib/data/dynamo/__tests__/calendar-day-window.prefilter.test.ts | 9.4s | 9.4s | 9.5s | 5 | 1.9s | not reviewed |
| 48 | src/lib/data/dynamo/__tests__/conversation-home-read.test.ts | 9.3s | 9.3s | 9.4s | 6 | 1.6s | not reviewed |
| 49 | scripts/__tests__/find-culprit.test.ts | 9.3s | 9.8s | 12.5s | 16 | 0.6s | not reviewed |
| 50 | src/__tests__/specialist-system-tool-binding.drift.test.ts | 9.2s | 6.0s | 39.5s | 37 | 0.2s | not reviewed |
| 51 | src/app/(workspace)/(operations)/leasing/prospects/ProspectsClient.funnel.test.tsx | 9.2s | 9.1s | 9.8s | 16 | 0.6s | not reviewed |
| 52 | src/__tests__/workspace-loading-shell-honest-values.drift.test.tsx | 9.1s | 8.6s | 10.9s | 120 | 0.1s | not reviewed |
| 53 | src/__tests__/quote-parser-resilience.test.ts | 9.1s | 9.1s | 9.1s | 40 | 0.2s | not reviewed |
| 54 | src/lib/domain/vendors/__tests__/pick-vendor.parity.test.ts | 9.0s | 8.3s | 11.1s | 90 | 0.1s | not reviewed |
| 55 | scripts/__tests__/check-deleted-file-importers.test.ts | 8.7s | 8.2s | 10.2s | 10 | 0.9s | not reviewed |
| 56 | src/__tests__/post-checkout-provision-lock.test.ts | 8.6s | 8.8s | 9.1s | 16 | 0.5s | not reviewed |
| 57 | src/__tests__/tour-booking-refusal-is-not-availability.test.ts | 8.6s | 8.1s | 10.7s | 14 | 0.6s | not reviewed |
| 58 | scripts/__tests__/self-review-eslint-verdict.test.ts | 8.5s | 8.0s | 10.1s | 7 | 1.2s | not reviewed |
| 59 | src/__tests__/specialist-turn-drift.test.ts | 8.5s | 7.7s | 25.6s | 169 | 0.1s | not reviewed |
| 60 | src/__tests__/dashboard-home.test.ts | 8.4s | 8.2s | 10.3s | 16 | 0.5s | not reviewed |
| 61 | src/__tests__/legacy-field-elimination.drift.test.ts | 8.3s | 8.9s | 9.4s | 52 | 0.2s | Auto-update pinRuns git grep for 'user.email' against a hand-kept path allowlist, so separately green PRs that add new reads break main once merged. Fix: Run the grep only on the PR diff's added lines so the adding PR fails, not main afterwards. |
| 62 | src/__tests__/vercel-promote-await.test.ts | 8.3s | 8.5s | 8.7s | 11 | 0.8s | not reviewed |
| 63 | agents/clara/lib/agent/tools/renewal/__tests__/renewal-email-suppression.test.ts | 8.2s | 8.3s | 9.0s | 24 | 0.3s | not reviewed |
| 64 | src/__tests__/renewal-policy-single-home.drift.test.ts | 8.2s | 7.6s | 9.1s | 12 | 0.7s | not reviewed |
| 65 | src/__tests__/af-vendor-stamp.drift.test.ts | 8.1s | 7.4s | 9.2s | 7 | 1.2s | not reviewed |
| 66 | src/lib/temporal/activities/__tests__/remediate-turnover-strands-activity.test.ts | 7.8s | 7.8s | 8.6s | 25 | 0.3s | not reviewed |
| 67 | src/__tests__/store-conditional.test.ts | 7.7s | 7.7s | 8.1s | 16 | 0.5s | not reviewed |
| 68 | src/__tests__/merge-evidence-decision.test.ts | 7.7s | 8.2s | 9.3s | 71 | 0.1s | not reviewed |
| 69 | scripts/overnight/run.test.ts | 7.3s | 7.0s | 9.0s | 11 | 0.7s | not reviewed |
| 70 | src/lib/domain/leasing/__tests__/google-maps-failure-loud.test.ts | 7.0s | 7.0s | 7.0s | 7 | 1.0s | not reviewed |
| 71 | src/lib/integrations/appfolio/__tests__/report-snapshot-cache.test.ts | 7.0s | 7.0s | 8.0s | 10 | 0.7s | not reviewed |
| 72 | src/__tests__/twilio-webhook.test.ts | 7.0s | 7.2s | 7.9s | 71 | 0.1s | not reviewed |
| 73 | src/__tests__/conversation-manager.test.ts | 6.8s | 6.9s | 8.0s | 447 | 0.0s | not reviewed |
| 74 | scripts/voice-fastlane/__tests__/reachability.test.ts | 6.7s | 6.1s | 8.2s | 23 | 0.3s | not reviewed |
| 75 | src/__tests__/conversation-org-stamp-dark.drift.test.ts | 6.7s | 6.1s | 7.6s | 7 | 1.0s | not reviewed |
| 76 | src/__tests__/workspace-loading-shell-status-marker.test.tsx | 6.6s | 6.2s | 7.7s | 119 | 0.1s | not reviewed |
| 77 | scripts/__tests__/sync-specialist-prompts-agent-id.test.ts | 6.6s | 5.8s | 8.0s | 30 | 0.2s | not reviewed |
| 78 | src/__tests__/maintenance-action-gate.test.ts | 6.5s | 6.1s | 8.1s | 26 | 0.3s | not reviewed |
| 79 | src/__tests__/inbound-org-scope.drift.test.ts | 6.5s | 5.9s | 7.8s | 20 | 0.3s | not reviewed |
| 80 | src/__tests__/scripts-import-resolution.drift.test.ts | 6.4s | 5.7s | 8.4s | 2 | 3.2s | not reviewed |
| 81 | src/lib/domain/tenants/__tests__/load-tenants-list.contact-reads.test.ts | 6.4s | 6.4s | 6.5s | 7 | 0.9s | not reviewed |
| 82 | src/__tests__/vendor-card-write-paths.drift.test.ts | 6.4s | 5.6s | 7.4s | 7 | 0.9s | not reviewed |
| 83 | src/__tests__/auto-merge-guard-decision.test.ts | 6.3s | 5.8s | 8.0s | 158 | 0.0s | not reviewed |
| 84 | src/__tests__/tour-day-policy.test.ts | 6.3s | 6.5s | 8.1s | 45 | 0.1s | not reviewed |
| 85 | src/__tests__/leasing-settings-write-only-fields.drift.test.ts | 6.3s | 5.7s | 7.9s | 54 | 0.1s | not reviewed |
| 86 | src/__tests__/property-owner-id-retired.drift.test.ts | 6.3s | 5.9s | 7.5s | 15 | 0.4s | not reviewed |
| 87 | src/lib/integrations/email/__tests__/company-live-gate-one-seam.test.ts | 6.2s | 6.0s | 7.2s | 33 | 0.2s | not reviewed |
| 88 | src/__tests__/client-bundle-no-temporal-leak.drift.test.ts | 6.2s | 5.8s | 7.5s | 11 | 0.6s | not reviewed |
| 89 | src/__tests__/tech-sms-dispatch.test.ts | 5.9s | 6.0s | 6.7s | 35 | 0.2s | not reviewed |
| 90 | src/app/(workspace)/(operations)/agents/_components/__tests__/pane-terminal-no-passive-resize.test.tsx | 5.8s | 5.8s | 5.9s | 5 | 1.2s | not reviewed |
| 91 | src/__tests__/conversation-detail-page-ssr-seed.test.ts | 5.8s | 5.5s | 7.2s | 8 | 0.7s | not reviewed |
| 92 | src/lib/domain/pms/__tests__/guest-card-outbox-drain-runner.test.ts | 5.8s | 5.3s | 7.0s | 54 | 0.1s | not reviewed |
| 93 | src/__tests__/leasing-tools.test.ts | 5.7s | 5.6s | 6.6s | 474 | 0.0s | not reviewed |
| 94 | scripts/__tests__/main-lane-red-alert.test.ts | 5.6s | 5.6s | 6.9s | 55 | 0.1s | not reviewed |
| 95 | scripts/__tests__/test-affected-invocation-shapes.test.ts | 5.6s | 5.4s | 6.2s | 4 | 1.4s | not reviewed |
| 96 | src/__tests__/alerts-emitters-transmit-marker.test.ts | 5.5s | 5.5s | 5.9s | 49 | 0.1s | not reviewed |
| 97 | src/__tests__/api-routes-voice.test.ts | 5.5s | 5.7s | 6.5s | 488 | 0.0s | not reviewed |
| 98 | scripts/__tests__/eval-judge-oauth-gate.drift.test.ts | 5.5s | 4.8s | 7.0s | 4 | 1.4s | not reviewed |
| 99 | src/__tests__/review-fallback-submission.test.ts | 5.4s | 4.9s | 6.8s | 111 | 0.0s | not reviewed |
| 100 | src/__tests__/touch-budget-hold-crosses-the-door.test.ts | 5.4s | 5.4s | 5.9s | 12 | 0.5s | not reviewed |
| 101 | src/app/(workspace)/(operations)/leasing/prospects/ProspectsClient.card-filter.test.tsx | 5.4s | 5.4s | 5.7s | 6 | 0.9s | not reviewed |
| 102 | src/__tests__/external-clients.test.ts | 5.4s | 5.1s | 6.3s | 47 | 0.1s | not reviewed |
| 103 | src/__tests__/outlook-webhook-attachment-metadata.test.ts | 5.3s | 5.4s | 6.1s | 12 | 0.4s | not reviewed |
| 104 | src/__tests__/tour-email-actions.test.ts | 5.3s | 5.1s | 6.4s | 19 | 0.3s | not reviewed |
| 105 | src/__tests__/set-free-month-applies-to-args.test.ts | 5.3s | 5.1s | 6.5s | 5 | 1.1s | not reviewed |
| 106 | lambda/inbound-processor/__tests__/inbox-email-pms-door.test.ts | 5.3s | 5.3s | 6.2s | 15 | 0.4s | not reviewed |
| 107 | src/app/(workspace)/(operations)/agents/__tests__/page.decision-poll-keeps-answer.test.tsx | 5.1s | 5.1s | 5.5s | 6 | 0.9s | not reviewed |
| 108 | src/__tests__/renewal-payload-canary.test.ts | 5.1s | 5.1s | 5.9s | 11 | 0.5s | not reviewed |
| 109 | src/lib/integrations/appfolio/__tests__/occupancies-portfolio.test.ts | 4.9s | 5.0s | 5.9s | 8 | 0.6s | not reviewed |
| 110 | src/__tests__/clara-bundle-dynamic-export.drift.test.ts | 4.9s | 4.6s | 5.7s | 4 | 1.2s | not reviewed |
| 111 | agents/clara/lib/agent/tools/renewal/__tests__/handlers-skipped-send.test.ts | 4.9s | 5.0s | 5.5s | 19 | 0.3s | not reviewed |
| 112 | src/__tests__/renewal-auto-start.test.ts | 4.9s | 4.9s | 5.7s | 177 | 0.0s | not reviewed |
| 113 | src/app/(workspace)/(operations)/review/page.star-selection.test.tsx | 4.8s | 4.7s | 5.4s | 15 | 0.3s | not reviewed |
| 114 | src/__tests__/specialist-tool-drift.test.ts | 4.8s | 2.3s | 48.1s | 9 | 0.5s | not reviewed |
| 115 | src/__tests__/temporal-failure-modes.test.ts | 4.8s | 4.8s | 5.5s | 59 | 0.1s | not reviewed |
| 116 | src/__tests__/staff-booking-tentative-calendar.test.ts | 4.8s | 4.7s | 5.8s | 6 | 0.8s | not reviewed |
| 117 | scripts/__tests__/sync-specialist-turn-agent-id.test.ts | 4.8s | 4.8s | 6.9s | 31 | 0.2s | not reviewed |
| 118 | src/lib/platform/__tests__/session-cache-signout.test.tsx | 4.6s | 4.1s | 5.7s | 31 | 0.1s | not reviewed |
| 119 | src/__tests__/agents-auth-gate.drift.test.ts | 4.6s | 4.3s | 5.7s | 14 | 0.3s | not reviewed |
| 120 | agents/clara/lib/agent/tools/renewal/__tests__/change-renewal-term.test.ts | 4.5s | 4.6s | 5.5s | 10 | 0.5s | not reviewed |
| 121 | lambda/inbound-processor/__tests__/inbox-email-company-mailbox-reply.test.ts | 4.5s | 4.5s | 5.4s | 13 | 0.3s | not reviewed |
| 122 | src/__tests__/smoke-live-api.test.ts | 4.5s | 4.4s | 5.5s | 9 | 0.5s | not reviewed |
| 123 | src/__tests__/tour-workflow-replay-corpus.test.ts | 4.5s | 4.1s | 5.4s | 5 | 0.9s | not reviewed |
| 124 | src/__tests__/deploy-digest.test.ts | 4.5s | 4.1s | 5.3s | 15 | 0.3s | not reviewed |
| 125 | src/__tests__/timeline-rail-inheritance.test.tsx | 4.4s | 4.4s | 5.4s | 60 | 0.1s | not reviewed |
| 126 | src/lib/integrations/email/__tests__/send-email-outcome.test.ts | 4.4s | 3.9s | 5.5s | 46 | 0.1s | not reviewed |
| 127 | agents/clara/lib/agent/tools/renewal/__tests__/decline-migrated-saga.test.ts | 4.4s | 4.3s | 5.2s | 10 | 0.4s | not reviewed |
| 128 | src/__tests__/contact-import.test.ts | 4.4s | 3.9s | 5.4s | 34 | 0.1s | not reviewed |
| 129 | src/__tests__/no-emoji-ui-chrome.drift.test.ts | 4.3s | 3.8s | 5.3s | 5 | 0.9s | not reviewed |
| 130 | src/__tests__/turnover-walk-replay.test.ts | 4.3s | 4.3s | 5.2s | 99 | 0.0s | not reviewed |
| 131 | src/__tests__/protected-classes-single-list.drift.test.ts | 4.3s | 4.0s | 5.0s | 53 | 0.1s | not reviewed |
| 132 | src/__tests__/tour-cancel-outcome-at-the-socket.test.ts | 4.3s | 4.2s | 5.1s | 13 | 0.3s | not reviewed |
| 133 | src/__tests__/middleware.test.ts | 4.3s | 4.3s | 4.8s | 268 | 0.0s | not reviewed |
| 134 | src/__tests__/live-equals-main.drift.test.ts | 4.3s | 3.2s | 17.6s | 40 | 0.1s | Move to nightlyFetches live ElevenLabs agent configs. It fails whenever a merged TURN change isn't synced to the fleet within 24h, e.g. the Escalation Callback agent. Fix: Run it as a nightly check that alerts and re-runs sync-specialists, not as a merge gate. |
| 135 | src/__tests__/user-route-inventory.drift.test.ts | 4.3s | 3.8s | 5.2s | 17 | 0.3s | Auto-update pinThe hand-kept route pin goes stale when routes are added; the mutation control also edits the real collections route by string-match and needs it pinned 'selection'. Fix: Generate the pin from a script, and run the mutation control on a fixture route instead of a real one. |
| 136 | src/__tests__/auth-server-hooks.test.ts | 4.2s | 3.8s | 5.5s | 21 | 0.2s | not reviewed |
| 137 | src/__tests__/work-order-conversation-error.test.tsx | 4.2s | 3.9s | 5.2s | 3 | 1.4s | not reviewed |
| 138 | src/app/(workspace)/(operations)/leasing/renewals/board/_components/__tests__/BoardV2.test.tsx | 4.2s | 3.9s | 5.3s | 96 | 0.0s | not reviewed |
| 139 | src/lib/domain/escalation/__tests__/bake-gate.test.ts | 4.2s | 3.8s | 5.3s | 108 | 0.0s | not reviewed |
| 140 | src/__tests__/org-scope-callers-read-the-authoritative-row.test.ts | 4.2s | 3.9s | 5.2s | 7 | 0.6s | not reviewed |
| 141 | src/lib/domain/agentflow/__tests__/read-only.test.ts | 4.2s | 3.9s | 5.2s | 28 | 0.1s | not reviewed |
| 142 | src/__tests__/turnover-r3-e2e.test.ts | 4.2s | 4.2s | 5.1s | 41 | 0.1s | not reviewed |
| 143 | src/__tests__/ask-clara-boot-wiring.test.tsx | 4.2s | 3.8s | 5.2s | 5 | 0.8s | not reviewed |
| 144 | src/__tests__/work-order-pipeline-dispatch.test.ts | 4.1s | 4.1s | 5.2s | 43 | 0.1s | not reviewed |
| 145 | src/lib/integrations/appfolio/__tests__/renewals-portfolio.test.ts | 4.1s | 4.2s | 4.6s | 7 | 0.6s | not reviewed |
| 146 | src/__tests__/forward-to-pm.test.ts | 4.0s | 4.0s | 4.9s | 35 | 0.1s | not reviewed |
| 147 | src/__tests__/scraper.test.ts | 4.0s | 4.0s | 4.0s | 15 | 0.3s | not reviewed |
| 148 | src/__tests__/turnover-wo-turnoverid-stamp.test.ts | 4.0s | 4.0s | 4.6s | 6 | 0.7s | not reviewed |
| 149 | lambda/inbound-processor/__tests__/inbox-email-inquiry-outbound-hold.test.ts | 4.0s | 4.0s | 4.7s | 8 | 0.5s | not reviewed |
| 150 | src/__tests__/renewal-workflow-signal-routes.test.ts | 4.0s | 3.9s | 4.6s | 19 | 0.2s | not reviewed |
| 151 | src/__tests__/work-order-pipeline-persist.test.ts | 4.0s | 3.9s | 4.4s | 23 | 0.2s | not reviewed |
| 152 | src/__tests__/prospect-conversation-error.test.tsx | 4.0s | 3.7s | 4.9s | 3 | 1.3s | not reviewed |
| 153 | agents/clara/lib/agent/__tests__/autonomous-handoff.test.ts | 3.9s | 3.9s | 5.1s | 53 | 0.1s | not reviewed |
| 154 | src/__tests__/packages-ui-build.drift.test.ts | 3.9s | 3.4s | 4.9s | 4 | 1.0s | not reviewed |
| 155 | lambda/inbound-processor/__tests__/inbox-email-review-hold.test.ts | 3.9s | 4.0s | 4.6s | 8 | 0.5s | not reviewed |
| 156 | src/__tests__/initiate-renewal-call.test.ts | 3.9s | 4.0s | 4.7s | 12 | 0.3s | not reviewed |
| 157 | src/__tests__/voice-initiation-ledger.test.ts | 3.9s | 3.9s | 4.3s | 19 | 0.2s | not reviewed |
| 158 | src/__tests__/set-my-quiet-hours.test.ts | 3.9s | 3.8s | 4.5s | 28 | 0.1s | not reviewed |
| 159 | src/__tests__/appfolio-renewal-summary-adapter.test.ts | 3.9s | 3.9s | 5.1s | 32 | 0.1s | not reviewed |
| 160 | src/lib/domain/leasing/reporting-digest/__tests__/run-digest.test.ts | 3.9s | 3.9s | 4.7s | 38 | 0.1s | not reviewed |
| 161 | src/__tests__/advisory-tests-off-pr-lane.drift.test.ts | 3.9s | 3.7s | 4.4s | 7 | 0.6s | not reviewed |
| 162 | src/lib/domain/scope/__tests__/mint-selection-cookie-never-widens.test.ts | 3.8s | 3.7s | 4.8s | 10 | 0.4s | not reviewed |
| 163 | src/__tests__/work-order-pipeline-gather.test.ts | 3.8s | 3.8s | 4.5s | 41 | 0.1s | not reviewed |
| 164 | src/__tests__/renewal-workflow-replay-corpus.test.ts | 3.8s | 3.5s | 4.5s | 4 | 1.0s | not reviewed |
| 165 | src/__tests__/tour-move-outcome-at-the-socket.test.ts | 3.8s | 3.8s | 4.4s | 8 | 0.5s | not reviewed |
| 166 | src/__tests__/audit-ai-core.test.ts | 3.8s | 3.4s | 4.9s | 31 | 0.1s | not reviewed |
| 167 | src/__tests__/scoped-list-cache-read-isolation.test.tsx | 3.8s | 3.4s | 4.8s | 69 | 0.1s | not reviewed |
| 168 | src/__tests__/run-outbound-takeover-release.test.ts | 3.7s | 3.8s | 4.6s | 31 | 0.1s | not reviewed |
| 169 | src/__tests__/sync-tour-write-retry.test.ts | 3.7s | 3.8s | 4.6s | 6 | 0.6s | not reviewed |
| 170 | src/__tests__/guard-pin-kinds.drift.test.ts | 3.7s | 3.6s | 4.3s | 10 | 0.4s | not reviewed |
| 171 | src/__tests__/schedule-tour-company-tour-length.test.ts | 3.7s | 3.5s | 4.5s | 2 | 1.8s | not reviewed |
| 172 | src/__tests__/smoke-results-api.test.ts | 3.7s | 3.3s | 4.7s | 8 | 0.5s | not reviewed |
| 173 | src/__tests__/turnover-tool-dispatcher.test.ts | 3.7s | 3.6s | 4.3s | 80 | 0.0s | not reviewed |
| 174 | src/__tests__/prospect-outreach-workflow-replay-corpus.test.ts | 3.7s | 4.0s | 4.4s | 4 | 0.9s | not reviewed |
| 175 | src/__tests__/api-routes.test.ts | 3.7s | 3.7s | 4.2s | 79 | 0.0s | not reviewed |
| 176 | src/__tests__/work-order-pipeline-orchestrator.test.ts | 3.6s | 3.7s | 4.3s | 10 | 0.4s | not reviewed |
| 177 | src/__tests__/appfolio-unit-vacancy-adapter.test.ts | 3.6s | 3.6s | 4.2s | 25 | 0.1s | not reviewed |
| 178 | src/__tests__/turnover-mangled-walk-corpus.test.ts | 3.6s | 3.5s | 4.1s | 245 | 0.0s | not reviewed |
| 179 | src/__tests__/json-conditional-twin.drift.test.ts | 3.6s | 3.3s | 4.3s | 5 | 0.7s | not reviewed |
| 180 | agents/clara/lib/agent/tools/renewal/__tests__/change-renewal-term.contract.test.ts | 3.6s | 3.5s | 4.1s | 4 | 0.9s | not reviewed |
| 181 | src/__tests__/terminology-capability-senses.drift.test.ts | 3.6s | 3.6s | 3.9s | 7 | 0.5s | not reviewed |
| 182 | src/app/(workspace)/(operations)/agents/__tests__/session-page.overview-seed.test.ts | 3.5s | 3.5s | 3.6s | 13 | 0.3s | not reviewed |
| 183 | lambda/inbound-processor/__tests__/inbox-email-ingestion-record.test.ts | 3.5s | 3.4s | 4.2s | 6 | 0.6s | not reviewed |
| 184 | src/__tests__/classify-zero-selection.test.ts | 3.5s | 3.6s | 3.8s | 61 | 0.1s | not reviewed |
| 185 | src/__tests__/lint-step-names-its-failure.drift.test.ts | 3.5s | 2.7s | 26.8s | 26 | 0.1s | not reviewed |
| 186 | src/__tests__/handyman-create-wo.test.ts | 3.4s | 3.4s | 4.0s | 14 | 0.2s | not reviewed |
| 187 | src/__tests__/turnover-api.test.ts | 3.4s | 3.5s | 4.1s | 77 | 0.0s | not reviewed |
| 188 | src/__tests__/conversation-view-whole-history.test.tsx | 3.4s | 3.4s | 3.9s | 16 | 0.2s | not reviewed |
| 189 | src/__tests__/demo-appfolio-sync.test.ts | 3.4s | 3.3s | 3.5s | 11 | 0.3s | not reviewed |
| 190 | src/__tests__/conversation-container-resolver.drift.test.ts | 3.4s | 3.1s | 3.9s | 16 | 0.2s | not reviewed |
| 191 | src/__tests__/tool-handlers.test.ts | 3.3s | 3.4s | 3.7s | 165 | 0.0s | not reviewed |
| 192 | src/__tests__/conversation-org-stamp-birth-discriminator.test.ts | 3.3s | 3.3s | 3.9s | 14 | 0.2s | not reviewed |
| 193 | src/lib/domain/agentflow/__tests__/pane-stream-contract.test.ts | 3.3s | 3.3s | 4.0s | 5 | 0.7s | not reviewed |
| 194 | src/lib/domain/dashboard/stats/__tests__/leasing-fold-largest-first.test.ts | 3.3s | 3.1s | 4.0s | 2 | 1.7s | not reviewed |
| 195 | scripts/__tests__/lambda-deploy-gate.test.ts | 3.3s | 3.0s | 3.9s | 124 | 0.0s | not reviewed |
| 196 | src/lib/domain/maintenance/__tests__/tech-sms-dispatch-flow.test.ts | 3.3s | 3.3s | 3.9s | 23 | 0.1s | not reviewed |
| 197 | src/__tests__/send-renewal-letter-mms.test.ts | 3.3s | 3.3s | 4.0s | 11 | 0.3s | not reviewed |
| 198 | src/lib/domain/leasing/__tests__/email-lead-engine-stress.replay.test.ts | 3.2s | 3.3s | 3.9s | 18 | 0.2s | not reviewed |
| 199 | agents/clara/lib/agent/tools/renewal/__tests__/handlers-spine-name.test.ts | 3.2s | 3.2s | 3.8s | 4 | 0.8s | not reviewed |
| 200 | src/__tests__/vendor-completion.test.ts | 3.2s | 3.2s | 3.6s | 55 | 0.1s | not reviewed |
The slowest individual tests are mostly waiting, not working. The top one is the whole of appfolio-client.test.ts's 68 seconds: it waits through real retry delays instead of a fake clock.
| # | Test | Average |
|---|---|---|
| 1 | AppfolioClient > surfaces failure when the server keeps returning 5xx (via appfolioPolicy) | 67.6s |
| 2 | the roster gate is reached from a known set of places > P2 · every declared entry point is called from exactly its declared files | 22.5s |
| 3 | deriveDeclaredCells — every way a caller reaches a hop > a hop graph too wide to converge FAILS CLOSED (MAX_HOPS) | 16.8s |
| 4 | the CLI survives the environment a git hook hands it > a poisoned GIT_DIR is scrubbed before a fixture-repo control runs, and that control passes | 16.5s |
| 5 | scoreConversationTurns — voice is graded PER UTTERANCE from the transcript rows, never as one call > through the REAL policy gate (only the vendor edge faked): the prefilter decides which utterances reach the judge, and | 16.4s |
| 6 | the CLI cannot be answered with a pass for controls it did not run > exits non-zero when --controls names an id the registry does not have | 15.8s |
| 7 | the addressed-write gate's operator premise > no production file under `src/` writes a `managed_by` row or calls the writer | 15.5s |
| 8 | household harness — rule 5: name text is never an input > rewriting every announced visitor name to garbage changes no household outcome | 11.7s |
| 9 | the conversation partition walk stays a closed set (board row p6-fanouts) > walks every building partition for CONV# rows in exactly the pinned places (leg 1) | 11.3s |
| 10 | every workflow that calls this script passes flags it honours > the one-call-one-email lane still names a control that exists | 10.9s |
| 11 | the text fence — no file reaches the carrier without declaring a module > the importers of the carrier are exactly the sanctioned set | 10.3s |
| 12 | resolve-table retrofit — an IMPORTED script must not resolve at module scope > no script that another file imports resolves its table at module scope | 9.8s |
| 13 | turn-checks route fence — no Next.js entry reaches the Cerebrus bridge > no file under src/app (route, page, layout, loading, error, …), middleware or instrumentation reaches grading/cerebrus, turn-checks, or quality-gat | 9.7s |
| 14 | household harness — rule 5: name text is never an input > rewriting every display name to garbage changes no household outcome | 9.6s |
| 15 | the stub calendar provider is fenced off from production > detects the real importer — the POSITIVE CONTROL for the finder itself | 9.3s |
vitest only prints a single test's time when it is slow, so this table is the slow tail, not every test.
Every file in the 52 reviewed (the 40 slowest plus every repeat failer) had its code read and was given one suggestion. Files further down the list say not reviewed. Seconds are each label's share of the average running time.
| Suggestion | What it means | Files | Seconds |
|---|---|---|---|
| Fake the clock | It sits through real retry delays or sleeps. A fake clock makes it take milliseconds. | 12 | 233.5s |
| Share the scan | It re-reads or re-parses the codebase itself. Build that once per run and share it. | 12 | 259.7s |
| Slim it down | Real work, but repetitive: near-duplicate cases or heavy setup repeated per test. | 13 | 211.7s |
| Move to nightly | Calls a live outside service or starts other programs. Run nightly with an alert, not on every merge. | 8 | 114.8s |
| Auto-update pin | Compares the code to a hand-kept list that goes stale whenever someone adds something. | 5 | 13.0s |
| Fix forward faster | The test is fine; it caught a real break once. The fix is reverting the breaking PR sooner. | 67 | |
| Keep | The cost is justified and there is no cheap fix. | 2 | 29.3s |
| Delete? | Duplicates another test or checks nothing meaningful. Read it before deleting. |
Re-run the same measurement after the fixes land and compare against these.
| Measure | Today | Basis |
|---|---|---|
| Full suite, start to finish (both halves) | 20.3 min | median of 25 runs |
| One half of the suite, whole job (setup + install + tests) | 16.7 min | median of 50 jobs; slowest 21.1 min |
| Inside one half: vitest wall clock | 14.6 min | median of 16 halves |
| Inside one half: loading test files (summed over workers) | 62.3 min | the biggest single cost |
| Inside one half: running tests (summed over workers) | 24.0 min | what the rankings on this page measure |
| All test files, running time added up | 53 min | both halves, 7,585 files |
60791eee54e)| Same machine type (m8g.2xlarge) | Half 1, Oct 1 baseline | Half 1, Oct 3 | Change | Half 2, Oct 1 baseline | Half 2, Oct 3 | Change |
|---|---|---|---|---|---|---|
| CI job, start to finish | 15.1 min | 9.8 min | −35% | 15.4 min | 9.5 min | −39% |
| vitest wall clock | 866 s | 535 s | −38% | 886 s | 516 s | −42% |
| Loading test files (summed over workers) | 3,646 s | 1,897 s | −48% | 3,869 s | 1,889 s | −51% |
| Running tests (summed over workers) | 1,496 s | 952 s | −36% | 1,357 s | 816 s | −40% |
| Test files in the half | about 3,770 | 3,994 | about +6% | about 3,770 | 3,994 | about +6% |
Each baseline figure is the median of the Oct 1 runs on this machine type (4 runs for half 1, 5 for half 2). Across their whole range the change is −34% to −37% (half 1 job), −37% to −41% (half 2 job), −47% to −54% (loading) and −35% to −42% (running).
What row 82 actually saved (vitest's own per-module import self time, both halves, the throwaway reporter: Oct 2 run 37027978394 on m7g.2xlarge, Oct 3 run 37133264469 on m8g.2xlarge). The two machines differ, so Oct 3 is also shown at m7g speed. Across 14 heavily loaded modules nobody changed in between, m8g took 0.73 times as long per load (middle half 0.68 to 0.77).
| Module | Oct 2 (m7g) | Oct 3 (m8g) | Oct 3 at m7g speed | Why |
|---|---|---|---|---|
src/lib/utils/explicit-year-day.ts | 646 s over 3,011 loads | under 1.4 s | about 0 | row 82 part 1: plain arithmetic, no date-fns (now below the reporter's top-250 cut) |
src/lib/domain/leasing/renewal-rent.ts | 320 s over 3,002 | 88 s over 3,121 | 120 s | row 82 part 2: lightFormat instead of format |
src/lib/domain/leasing/lease-terms/dates.ts | 36 s over 485 | 112 s over 513 | 153 s | cost moved here: it imports date-fns/format and now loads it first |
src/lib/domain/vendors/vendor-calendar.ts | 5 s over 277 | 33 s over 296 | 44 s | cost moved here: it imports date-fns/parse |
| All four | 1,006 s | 233 s | 317 s | about −690 s per full run at m7g speed (−660 to −700), about −500 s on m8g; the estimate was about 600 s |
All first-party module self time: 4,159 s on Oct 2 (m7g), 2,688 s on Oct 3 (m8g), which is about 3,670 s at m7g speed (−12%).
What is left, biggest first. src/lib/platform/auth/server.ts 519 s over 1,208 test-file loads on m8g (about 710 s at m7g speed; it was 660 s over 1,011 on Oct 2, because more files reach it every day). Trimming it is an auth change, so it needs its owner. src/lib/domain/leasing/lease-terms/dates.ts 112 s, now the first loader of date-fns/format; the same lightFormat change would likely remove most of it, unless the cost moves again. src/lib/domain/vendors/vendor-calendar.ts 33 s, the first loader of date-fns/parse.
Basis and limits. Timing: run 37133262569 (ci.yml dispatched on main at 60791eee54e), both halves on m8g.2xlarge, 3,994 + 3,994 test files, all passing (3 + 6 skipped). Baseline: this page's Oct 1 runs on m8g.2xlarge (half 1: 36829783241, 36882040216, 36875447902, 36870896634; half 2: the same four plus 36872698236). The Oct 1 file count is that day's 3,769 per half. One timing run, so the yardstick for noise is the baseline's own spread (886 to 926 s for half 1's job). Breakdown: run 37133264469, the same tree plus the throwaway reporter on a branch deleted afterwards. One test, self-review-unresolvable-range, failed only in that run; the plain run had none. Row 40 (the watchdog test leaving the per-PR lane, about 43 s of one worker) is too small to see in a half's wall clock, and rows 83 and 84 only add mocks.
16206803b2a)| Half 1 of the suite, same machine type (m7g.2xlarge) | Oct 1 baseline | Oct 2 final (two runs) | Change |
|---|---|---|---|
| CI job, start to finish | 20.4 min | 12.7–13.3 min | −35% to −38% |
| vitest wall clock | 1,181 s | 723–756 s | −36% to −39% |
| Loading test files (summed over workers) | 5,170 s | 2,694–2,825 s | −45% to −48% |
| Running tests (summed over workers) | 1,847 s | 1,184–1,233 s | −33% to −36% |
| Every vitest phase, summed over workers | 7,647 s | 4,521–4,729 s | −38% to −41% |
| Test files in the half | 3,769 | 3,888 | +3.2% |
Against the Oct 1 medians above (mixed machines, mostly the faster Graviton4), today's runs on the slower Graviton3 still come in under every one: one half's whole job 16.7 → 12.5–13.3 min, vitest wall clock 14.6 → 11.8–12.6 min, loading 62.3 → 44–47 worker-minutes, running 24.0 → 18–21 worker-minutes. Half 2 today: 12.5–12.7 min job, 709–719 s vitest; its Oct 1 runs were all on Graviton4 (842–933 s), so there is no same-type pair for it.
Where the loading went (vitest's own per-module import self time, both halves, two runs with the throwaway reporter, both on m7g.2xlarge: Oct 2 01:40 UTC run 36949936682 against the final tree, run 37027978394):
| Module | Before | Final | Fixed by |
|---|---|---|---|
src/lib/data/statuses/renewals.ts | 4,073 s | 44 s | row 78: date-fns per function |
packages/ui/src/FilterBar.tsx | 1,326 s | 15 s | row 79: Phosphor per icon |
src/lib/utils/format.ts | 816 s | 113 s | row 78 |
| Twilio client and webhook validator | 116 s | 14 s | row 80: SDKs load on first use |
src/lib/integrations/email/client.ts | 55 s | 27 s | row 80 |
src/lib/temporal/pm-action-reminder-client.ts | 53 s | 0 (no longer loaded) | row 80 |
| All first-party modules | 9,498 s | 4,159 s | −56% |
What is left, biggest first. src/lib/platform/auth/server.ts 660 s over 1,011 test-file loads (it was 305 s over 475: new auth code today doubled the files that reach it); trimming it is an auth change, so it needs its owner. src/lib/utils/explicit-year-day.ts 646 s and src/lib/domain/leasing/renewal-rent.ts 320 s: the date-fns barrel is gone, but date-fns/parse (about 190 ms cold) and date-fns/format (about 113 ms, it brings the locale) still reach about 3,000 test files through them (row 82).
Basis and limits. Final: run 37027723475 (ci.yml dispatched on main at 16206803b2a) and run 37028316163 (an empty commit on the same tree, row 79’s change run), every half on m7g.2xlarge, 3,885 + 3,882 test files all passing in both. A third run on the same tree with the throwaway reporter (37027978394) fell inside that range: 725 / 720 s. Baseline: run 36872698236 half 1, the only Oct 1 baseline half on m7g. The gain is the whole effort since the baseline (every merged row on the tracker), not only the loading rows. One Oct 1 half on this machine type is a small sample, and the same tree varied by up to 5% from run to run today, which is why the table gives ranges.
4d1921089)| Measure (one half, summed over workers unless noted) | Baseline, same machine type | Interim | Change |
|---|---|---|---|
| Running tests, same 3,757 files (half 1, Graviton3 m7g) | 1,841 s | 1,584 s | −14.0% |
| Running tests, same 3,748 files (half 2, Graviton4 r8gn) | 1,355 s | 1,170 s | −13.6% |
| Loading test files (half 1, m7g) | 5,170 s | 5,385 s | +4.2% |
| Loading test files (half 2, r8gn) | 3,804 s | 3,940 s | +3.6% |
| vitest wall clock (half 1, m7g) | 19.7 min | 19.7 min | +0.2% |
| vitest wall clock (half 2, r8gn) | 14.6 min | 14.5 min | −0.1% |
Basis and limits. Interim: run 36941383284 (dispatched on main; 6 + 3 test files failed from main's own reds, which does not change the timing). Each baseline row is the one baseline run on that machine type (36872698236 half 1 on m7g, 36865074180 half 2 on r8gn), so loading and wall clock within about ±8% are noise. The running-time drop is the same in both halves on two different machine types, and it is measured on the files present in both runs (the suite gained 121 test files and lost 65 since the baseline). Rows still open when this ran (20, 21, 24, 28–41, 44, 49, 75 and others) are not in it. The final re-measure comes after they land.
ci.yml run with conclusion failure on push-to-main, merge_group and schedule, created Sep 24 UTC onward. For each run, the log of every failed Unit Tests (affected) / Unit Tests (full N/2) job was read for vitest's FAIL lines. Blind spot: tests that run in the Guard pins jobs, and the database-safety check in CI Checks, are not read; see the correction in section 1. A test counts once per run. Pull-request runs are left out on purpose: a red PR is usually the PR's own bug.Unit Tests (full 1/2) and (full 2/2); 24 on main plus 1 nightly). Per-file times are vitest's own (one line per file in the log). The two halves split the suite with no overlap, and the per-file times add up exactly to each log's own total.