Commit e9499ca
refactor(api): extract InvestigationLease table, fix review issues
Migrates lease state from the InvestigationRun.leaseOwner/leaseExpiresAt
fields (nullable, representable-invalid) into a separate InvestigationLease
table where the row's *existence* represents "this investigation is PROCESSING
with a live lease holder". This eliminates the invalid states that the old
schema permitted (leaseOwner without leaseExpiresAt, PENDING/COMPLETE
investigations with orphan lease fields, etc.) and removes the now-redundant
InvestigationRun model entirely.
Key design changes:
- InvestigationLease row existence ↔ PROCESSING status structural invariant
- progressClaims moves to InvestigationLease (auto-cleaned on row delete)
- attemptCount, queuedAt, retryAfter promoted to Investigation directly
- Retry backoff now application-managed (not graphile-worker maxAttempts):
TRANSIENT failures reclaim to PENDING + re-enqueue with exponential delay
(10s × 2^(attempt-1)); NON_RETRYABLE failures mark FAILED immediately
- Per-investigation jobKey (investigate:${id}) deduplicate concurrent enqueues
Review fixes included in this commit:
- Bug: duplicate no-op assertion in interim-source-selection test replaced
with an explicit InvestigationLease DB query (the original assertion was
checking the same already-verified variable twice, losing coverage)
- Coverage: extract markInvestigationFailedInTx and releaseLeaseToRetryInTx
from attempt-audit.ts so all three terminal/reclaim helpers can be unit
tested with mock tx clients, not just persistCompletedInvestigation
- Coverage: add invariant-violation throw tests for all three tx helpers
(lease deleted but status not PROCESSING → throw rolls back lease deletion)
- Coverage: add investigation-lease.test.ts pinning the retry backoff schedule
(BASE_BACKOFF_MS, formula, concrete per-attempt values per spec §3.7)
- Fix: TypeScript narrowing bug in investigation-lifecycle.ts (investigation
variable closure capture in $transaction callback)
- Clean: remove redundant seedInvestigationWithLeaseFields calls in lifecycle
fuzz test (startedAt/heartbeatAt are not asserted and were already set by
seedInvestigation)
- Docs: document in tryClaimLease that retryAfter is intentionally not gated
there; investigateNow bypassing the backoff window is by design
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>1 parent ec1b158 commit e9499ca
28 files changed
Lines changed: 1412 additions & 1179 deletions
File tree
- src/typescript/api
- prisma
- migrations/0023_extract_investigation_lease
- src/lib
- services
- trpc/routes
- post
- test
- integration
- helpers
- unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
980 | 980 | | |
981 | 981 | | |
982 | 982 | | |
983 | | - | |
984 | | - | |
985 | | - | |
986 | | - | |
987 | | - | |
988 | | - | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
989 | 993 | | |
990 | 994 | | |
991 | 995 | | |
| |||
1010 | 1014 | | |
1011 | 1015 | | |
1012 | 1016 | | |
1013 | | - | |
1014 | | - | |
1015 | | - | |
1016 | | - | |
1017 | | - | |
1018 | | - | |
1019 | | - | |
1020 | | - | |
1021 | | - | |
1022 | | - | |
1023 | | - | |
1024 | | - | |
1025 | | - | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
1026 | 1032 | | |
1027 | 1033 | | |
1028 | | - | |
1029 | 1034 | | |
1030 | 1035 | | |
1031 | 1036 | | |
1032 | | - | |
1033 | | - | |
1034 | | - | |
1035 | | - | |
1036 | | - | |
1037 | | - | |
1038 | | - | |
1039 | | - | |
1040 | | - | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
1041 | 1046 | | |
1042 | 1047 | | |
1043 | 1048 | | |
| |||
1597 | 1602 | | |
1598 | 1603 | | |
1599 | 1604 | | |
1600 | | - | |
1601 | | - | |
1602 | | - | |
1603 | | - | |
1604 | | - | |
| 1605 | + | |
1605 | 1606 | | |
1606 | 1607 | | |
1607 | 1608 | | |
1608 | 1609 | | |
1609 | | - | |
| 1610 | + | |
1610 | 1611 | | |
1611 | 1612 | | |
1612 | 1613 | | |
1613 | | - | |
1614 | | - | |
| 1614 | + | |
| 1615 | + | |
| 1616 | + | |
1615 | 1617 | | |
1616 | 1618 | | |
1617 | 1619 | | |
| |||
1622 | 1624 | | |
1623 | 1625 | | |
1624 | 1626 | | |
1625 | | - | |
| 1627 | + | |
1626 | 1628 | | |
1627 | | - | |
| 1629 | + | |
| 1630 | + | |
| 1631 | + | |
| 1632 | + | |
| 1633 | + | |
| 1634 | + | |
| 1635 | + | |
1628 | 1636 | | |
1629 | 1637 | | |
1630 | 1638 | | |
1631 | 1639 | | |
1632 | 1640 | | |
1633 | | - | |
| 1641 | + | |
1634 | 1642 | | |
1635 | | - | |
| 1643 | + | |
1636 | 1644 | | |
1637 | 1645 | | |
| 1646 | + | |
| 1647 | + | |
| 1648 | + | |
| 1649 | + | |
| 1650 | + | |
1638 | 1651 | | |
1639 | | - | |
| 1652 | + | |
1640 | 1653 | | |
1641 | 1654 | | |
1642 | 1655 | | |
| |||
1645 | 1658 | | |
1646 | 1659 | | |
1647 | 1660 | | |
1648 | | - | |
1649 | | - | |
| 1661 | + | |
| 1662 | + | |
| 1663 | + | |
1650 | 1664 | | |
1651 | 1665 | | |
1652 | 1666 | | |
| |||
1985 | 1999 | | |
1986 | 2000 | | |
1987 | 2001 | | |
1988 | | - | |
| 2002 | + | |
1989 | 2003 | | |
1990 | 2004 | | |
1991 | 2005 | | |
1992 | | - | |
| 2006 | + | |
1993 | 2007 | | |
1994 | 2008 | | |
1995 | 2009 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
57 | | - | |
58 | | - | |
59 | | - | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
| |||
87 | 88 | | |
88 | 89 | | |
89 | 90 | | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
95 | 98 | | |
96 | 99 | | |
97 | 100 | | |
| |||
Lines changed: 108 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
0 commit comments