deepline 0.3.482 → 0.3.484

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  2. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-dead-letter.ts +100 -9
  3. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/ambiguous-modal-create-state.ts +21 -0
  4. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/compute-billing-job-state.ts +23 -0
  5. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-retirement-state.ts +25 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-retirement.ts +15 -1
  7. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/outbox-repair-operation-state.ts +30 -0
  8. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +95 -33
  9. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +9 -1
  10. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/sandbox-cleanup-job-state.ts +23 -0
  11. package/dist/bundling-sources/shared_libs/product-notifications/destination-state.ts +93 -0
  12. package/dist/cli/{auth-R5GFDAMI.mjs → auth-EBFOTF7X.mjs} +5 -5
  13. package/dist/cli/auth-L5CSV3UO.js +43 -0
  14. package/dist/cli/{billing-SO5SFQFC.mjs → billing-2ZOIMW5V.mjs} +6 -6
  15. package/dist/cli/{billing-DXKVQPTC.js → billing-G2G3EF3I.js} +79 -79
  16. package/dist/cli/{chunk-Y4Y2QUFL.js → chunk-2AWYJXBX.js} +5 -5
  17. package/dist/cli/{chunk-OVSSKTXG.js → chunk-3XQIVEAT.js} +3 -3
  18. package/dist/cli/{chunk-RLG2MNXH.mjs → chunk-4OEOM6GP.mjs} +4 -4
  19. package/dist/cli/{chunk-LVOEZVDW.mjs → chunk-4OVHIWE7.mjs} +2 -2
  20. package/dist/cli/{chunk-G7N2DYQL.mjs → chunk-4SFC2XUF.mjs} +5 -5
  21. package/dist/cli/chunk-5AEDYVB6.mjs +6 -0
  22. package/dist/cli/{chunk-2KC3MJP5.mjs → chunk-5GOG5ZGC.mjs} +2 -2
  23. package/dist/cli/chunk-5K5CAND4.mjs +200 -0
  24. package/dist/cli/{chunk-AEMPAR6L.js → chunk-5KNRQWHE.js} +3 -3
  25. package/dist/cli/chunk-6GRZEYSG.js +200 -0
  26. package/dist/cli/{chunk-FQFAWIRK.mjs → chunk-6NPWXE32.mjs} +1 -1
  27. package/dist/cli/{chunk-AZRG5NWV.mjs → chunk-7K5CWKKZ.mjs} +2 -2
  28. package/dist/cli/{chunk-LMLN7R7X.mjs → chunk-AF7MOUZP.mjs} +2 -2
  29. package/dist/cli/{chunk-UVU4OCYO.js → chunk-C62NI2X6.js} +5 -5
  30. package/dist/cli/{chunk-BHID34HA.js → chunk-CYWBAV5H.js} +16 -16
  31. package/dist/cli/chunk-D3BCSAN7.js +6 -0
  32. package/dist/cli/{chunk-M6B2OZGA.js → chunk-DBJ62RAO.js} +3 -3
  33. package/dist/cli/{chunk-JLI7SK55.mjs → chunk-DEXSQGXB.mjs} +5 -5
  34. package/dist/cli/{chunk-Y6OKWGAM.mjs → chunk-EACX7QXO.mjs} +2 -2
  35. package/dist/cli/{chunk-3EN2BLAS.js → chunk-FQK7BULS.js} +1 -1
  36. package/dist/cli/{chunk-6NF7S5WY.js → chunk-FRD5WFT4.js} +6 -6
  37. package/dist/cli/{chunk-KDJZXX7I.mjs → chunk-HEI3BWIV.mjs} +1 -1
  38. package/dist/cli/{chunk-RLYJ4O6Q.js → chunk-IXWQOVNW.js} +53 -53
  39. package/dist/cli/{chunk-4V34YMLU.js → chunk-KA2LNIUP.js} +6 -6
  40. package/dist/cli/{chunk-VU2PUAEH.js → chunk-KGOC6HGI.js} +53 -53
  41. package/dist/cli/{chunk-AJT436SK.mjs → chunk-LTZXLYKE.mjs} +1 -1
  42. package/dist/cli/{chunk-ETJSPSOQ.js → chunk-M4PG7FGC.js} +2 -2
  43. package/dist/cli/{chunk-YT6GV6RP.js → chunk-NW4QJE54.js} +2 -2
  44. package/dist/cli/{chunk-MFNEJOQG.js → chunk-OHKKDPA5.js} +10 -10
  45. package/dist/cli/{chunk-7SZUHFJ6.mjs → chunk-PU52JXKA.mjs} +2 -2
  46. package/dist/cli/{chunk-2ZIUCN5I.js → chunk-QIDDTIVZ.js} +93 -93
  47. package/dist/cli/{chunk-DZRHML3J.js → chunk-RLLEH2SP.js} +26 -26
  48. package/dist/cli/{chunk-RCWBWM5J.mjs → chunk-TIRSKEZH.mjs} +1 -1
  49. package/dist/cli/{chunk-QCIG6V26.mjs → chunk-TN2GW57M.mjs} +1 -1
  50. package/dist/cli/{chunk-5MHCTVMM.mjs → chunk-TRLDJNVE.mjs} +1 -1
  51. package/dist/cli/{chunk-OO6HA5OT.js → chunk-U7IJAGWB.js} +7 -7
  52. package/dist/cli/{chunk-AZUDSDZX.js → chunk-UKM74PAA.js} +37 -37
  53. package/dist/cli/{chunk-NXTZ4UNI.js → chunk-UT4YMA2N.js} +4 -4
  54. package/dist/cli/{chunk-LKFQERA6.js → chunk-UWOY74RU.js} +21 -21
  55. package/dist/cli/{chunk-EC2QPBSZ.mjs → chunk-V7JCMBLU.mjs} +4 -4
  56. package/dist/cli/{chunk-SFZCKYTD.js → chunk-VEVGM6B5.js} +9 -9
  57. package/dist/cli/{chunk-DYHBKFCW.mjs → chunk-WXRM3UC6.mjs} +3 -3
  58. package/dist/cli/{chunk-BK3XMHPF.mjs → chunk-WYUCDLVR.mjs} +1 -1
  59. package/dist/cli/{chunk-SKBXTN5F.mjs → chunk-XZXIWPT3.mjs} +1 -1
  60. package/dist/cli/{chunk-DM7APZWK.mjs → chunk-YGN77QA5.mjs} +2 -2
  61. package/dist/cli/{chunk-FKGA7VKL.mjs → chunk-YHA3EV3I.mjs} +4 -4
  62. package/dist/cli/{chunk-HYS35M6H.mjs → chunk-YWC5AN26.mjs} +10 -10
  63. package/dist/cli/{chunk-FUVJPW7O.js → chunk-ZOKM7DVA.js} +8 -8
  64. package/dist/cli/{csv-IC3XJ4PV.mjs → csv-NLWVWD3H.mjs} +4 -4
  65. package/dist/cli/{csv-UWFQLI3K.js → csv-S3CHUKI6.js} +13 -13
  66. package/dist/cli/{db-RIPJQYF3.mjs → db-OGRPAEEM.mjs} +6 -6
  67. package/dist/cli/{db-PT73YDEP.js → db-WBSKMMOH.js} +27 -27
  68. package/dist/cli/{describe-GHI2MTDW.mjs → describe-FAD3Z7LN.mjs} +18 -17
  69. package/dist/cli/describe-UIAYCHWW.js +49 -0
  70. package/dist/cli/{executions-XUJBZF5H.mjs → executions-LYCL344R.mjs} +6 -6
  71. package/dist/cli/{executions-QUOWVXCU.js → executions-SOAZHCY4.js} +8 -8
  72. package/dist/cli/{feedback-JOZ7QNGH.mjs → feedback-AVF6V7SV.mjs} +4 -4
  73. package/dist/cli/{feedback-UDZ7BFB3.js → feedback-OROUPUNJ.js} +8 -8
  74. package/dist/cli/git-ATMWC27D.js +25 -0
  75. package/dist/cli/{git-O67OED4L.mjs → git-J5N5M57H.mjs} +5 -5
  76. package/dist/cli/index.js +138 -138
  77. package/dist/cli/index.mjs +42 -42
  78. package/dist/cli/{legacy-noops-T2G2TKO2.mjs → legacy-noops-ENRRM7BL.mjs} +5 -5
  79. package/dist/cli/{legacy-noops-ZFD6Z2ID.js → legacy-noops-QAQMZMEG.js} +8 -8
  80. package/dist/cli/{monitors-WSH4I37O.mjs → monitors-CKQ65WRL.mjs} +7 -7
  81. package/dist/cli/{monitors-QPWEWJW7.js → monitors-SFMQ5LFR.js} +91 -91
  82. package/dist/cli/{org-PZOFC4P3.js → org-3UNTDLT2.js} +72 -72
  83. package/dist/cli/{org-FVM465Q4.mjs → org-K4UIEU5P.mjs} +6 -6
  84. package/dist/cli/{pages-A5SLKL6L.mjs → pages-6GPGBIAH.mjs} +6 -6
  85. package/dist/cli/{pages-UMDOU2WF.js → pages-NKZTGB4C.js} +17 -17
  86. package/dist/cli/{play-XKJLIZQE.mjs → play-62BEE7IX.mjs} +26 -22
  87. package/dist/cli/{play-AFGL5D7B.js → play-BDEADESI.js} +495 -491
  88. package/dist/cli/{providers-CQDRM62K.js → providers-SXGP44GH.js} +9 -9
  89. package/dist/cli/{providers-A2EIHS3P.mjs → providers-X3CUWMFP.mjs} +6 -6
  90. package/dist/cli/{quickstart-BJ2XCUVV.mjs → quickstart-7LN22BKX.mjs} +4 -4
  91. package/dist/cli/{quickstart-NMJLH7T6.js → quickstart-XQ4426M4.js} +6 -6
  92. package/dist/cli/{run-S4XTJADQ.js → run-PBJ4ZJ4W.js} +37 -36
  93. package/dist/cli/{run-63I5M3ID.mjs → run-XXSN3B5A.mjs} +26 -25
  94. package/dist/cli/search-IGHLRLBD.js +32 -0
  95. package/dist/cli/{search-DUIWWZ56.mjs → search-M75VMADD.mjs} +8 -8
  96. package/dist/cli/{chunk-UXQZLXHZ.js → search-output-F6HCFYEI.js} +14 -194
  97. package/dist/cli/{chunk-EDBQIPMG.mjs → search-output-NUQAKWDM.mjs} +14 -194
  98. package/dist/cli/{secrets-FK4PQJ6U.mjs → secrets-J2H6V33R.mjs} +6 -6
  99. package/dist/cli/{secrets-Q6QEWCAT.js → secrets-LRYY4QPE.js} +15 -15
  100. package/dist/cli/{sessions-QJSN6AUL.mjs → sessions-IMT336UV.mjs} +5 -5
  101. package/dist/cli/{sessions-KF6JPKFK.js → sessions-YPF62CZE.js} +6 -6
  102. package/dist/cli/{settings-PIKGA5PF.js → settings-35YYC5WA.js} +78 -78
  103. package/dist/cli/{settings-UIQP5ERC.mjs → settings-PDWVQIGH.mjs} +11 -11
  104. package/dist/cli/{setup-4CALCNAA.mjs → setup-DG5DISSE.mjs} +9 -9
  105. package/dist/cli/{setup-ROKA4M5X.js → setup-UR7GOR7H.js} +47 -47
  106. package/dist/cli/skills-4U5WC4MJ.js +33 -0
  107. package/dist/cli/{skills-SQKRC7W4.mjs → skills-U6NJD5J7.mjs} +7 -7
  108. package/dist/cli/{tools-B6J53QS2.mjs → tools-2HGEOELR.mjs} +17 -16
  109. package/dist/cli/tools-PYJTQVVS.js +56 -0
  110. package/dist/cli/update-344OTRFM.js +33 -0
  111. package/dist/cli/{update-MVKCAJJV.mjs → update-FRAYBAHK.mjs} +9 -9
  112. package/dist/cli/{workflow-3BO5WPZO.mjs → workflow-DDKVTF36.mjs} +7 -7
  113. package/dist/cli/{workflow-VH2H4VS3.js → workflow-JKKLOMBX.js} +17 -17
  114. package/dist/index.js +10 -10
  115. package/dist/index.mjs +10 -10
  116. package/dist/install-integrity.json +106 -96
  117. package/dist/plays/bundle-play-file.mjs +6 -6
  118. package/dist/release.d.mts +1 -1
  119. package/dist/release.d.ts +1 -1
  120. package/dist/release.js +2 -2
  121. package/dist/release.mjs +1 -1
  122. package/dist/server.js +5 -5
  123. package/dist/server.mjs +3 -3
  124. package/package.json +1 -1
  125. package/dist/cli/auth-Q5VRDGL4.js +0 -43
  126. package/dist/cli/describe-72RFB7RS.js +0 -48
  127. package/dist/cli/git-A6SU7ITW.js +0 -25
  128. package/dist/cli/search-ACCI4VYH.js +0 -32
  129. package/dist/cli/skills-GZQSDPZX.js +0 -33
  130. package/dist/cli/tools-5C7ZVTDG.js +0 -55
  131. package/dist/cli/update-PR4QP7JN.js +0 -33
@@ -205,7 +205,7 @@ export const SDK_RELEASE = {
205
205
  // getters keep their established compatibility behavior.
206
206
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
207
207
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
208
- version: '0.3.482',
208
+ version: '0.3.484',
209
209
  updateSummary: {
210
210
  introducedIn: '0.3.90',
211
211
  summary:
@@ -22,6 +22,72 @@ export type InboundPgClient = {
22
22
 
23
23
  export type InboundFailureClass = 'transient' | 'permanent';
24
24
 
25
+ /** Persisted states for `dl_meta.signal_radar_inbound_dead_letter`. */
26
+ export const SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS = {
27
+ open: 'open',
28
+ replaying: 'replaying',
29
+ replayed: 'replayed',
30
+ discarded: 'discarded',
31
+ } as const;
32
+
33
+ export type SignalRadarInboundDeadLetterStatus =
34
+ (typeof SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS)[keyof typeof SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS];
35
+
36
+ export type ClaimableSignalRadarInboundDeadLetterStatus = Extract<
37
+ SignalRadarInboundDeadLetterStatus,
38
+ 'open' | 'replaying'
39
+ >;
40
+
41
+ /** Durable transition edges. Database predicates remain the atomic fences. */
42
+ export type SignalRadarInboundDeadLetterTransition =
43
+ | { event: 'claim'; from: 'open'; to: 'replaying' }
44
+ | { event: 'stale_claim_reclaimed'; from: 'replaying'; to: 'replaying' }
45
+ | { event: 'enqueue_failed'; from: 'replaying'; to: 'open' }
46
+ | { event: 'worker_unprocessed'; from: 'replaying'; to: 'open' }
47
+ | {
48
+ event: 'worker_processed';
49
+ from: 'open' | 'replaying';
50
+ to: 'replayed';
51
+ }
52
+ | { event: 'malformed_payload'; from: 'replaying'; to: 'discarded' }
53
+ | {
54
+ event: 'dead_letter_recorded';
55
+ from: 'open' | 'replaying' | 'replayed';
56
+ to: 'open';
57
+ }
58
+ | { event: 'dead_letter_recorded'; from: 'discarded'; to: 'discarded' };
59
+
60
+ /** Parse a value read from persisted storage; unknown future values fail closed. */
61
+ export function parseSignalRadarInboundDeadLetterStatus(
62
+ value: unknown,
63
+ ): SignalRadarInboundDeadLetterStatus | null {
64
+ switch (value) {
65
+ case SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS.open:
66
+ case SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS.replaying:
67
+ case SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS.replayed:
68
+ case SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS.discarded:
69
+ return value;
70
+ default:
71
+ return null;
72
+ }
73
+ }
74
+
75
+ /** A failed redrive returns an in-flight/completed delivery to review. */
76
+ export function transitionSignalRadarInboundDeadLetterStatus(
77
+ value: unknown,
78
+ event: 'dead_letter_recorded',
79
+ ): SignalRadarInboundDeadLetterStatus {
80
+ const current = parseSignalRadarInboundDeadLetterStatus(value);
81
+ if (!current) {
82
+ throw new Error(
83
+ `Unknown signal radar dead-letter status '${String(value)}'.`,
84
+ );
85
+ }
86
+ return current === SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS.discarded
87
+ ? SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS.discarded
88
+ : SIGNAL_RADAR_INBOUND_DEAD_LETTER_STATUS.open;
89
+ }
90
+
25
91
  function errorMessage(error: unknown): string {
26
92
  if (error instanceof Error && error.message.trim()) return error.message;
27
93
  if (typeof error === 'string' && error.trim()) return error;
@@ -211,17 +277,42 @@ export async function recordSignalRadarDeadLetter(input: {
211
277
  };
212
278
 
213
279
  if (message.deadLetterId) {
214
- const reopened = await client.query(
215
- `UPDATE dl_meta.signal_radar_inbound_dead_letter
216
- SET status = CASE WHEN status = 'discarded' THEN status ELSE 'open' END,
217
- attempts = attempts + $2,
218
- last_error = $3,
219
- updated_at = now()
280
+ const prior = await client.query(
281
+ `SELECT status
282
+ FROM dl_meta.signal_radar_inbound_dead_letter
220
283
  WHERE dead_letter_id = $1
221
- RETURNING dead_letter_id`,
222
- [message.deadLetterId, input.attempts, lastError.slice(0, 8000)],
284
+ FOR UPDATE`,
285
+ [message.deadLetterId],
223
286
  );
224
- if ((reopened.rows ?? []).length > 0) {
287
+ const existing = (prior.rows ?? [])[0] as
288
+ | { status?: unknown }
289
+ | undefined;
290
+ if (existing) {
291
+ const nextStatus = transitionSignalRadarInboundDeadLetterStatus(
292
+ existing.status,
293
+ 'dead_letter_recorded',
294
+ );
295
+ const reopened = await client.query(
296
+ `UPDATE dl_meta.signal_radar_inbound_dead_letter
297
+ SET status = $2,
298
+ attempts = attempts + $3,
299
+ last_error = $4,
300
+ updated_at = now()
301
+ WHERE dead_letter_id = $1 AND status = $5
302
+ RETURNING dead_letter_id`,
303
+ [
304
+ message.deadLetterId,
305
+ nextStatus,
306
+ input.attempts,
307
+ lastError.slice(0, 8000),
308
+ existing.status,
309
+ ],
310
+ );
311
+ if ((reopened.rows ?? []).length === 0) {
312
+ throw new Error(
313
+ 'Signal radar dead-letter status changed while recording a failure.',
314
+ );
315
+ }
225
316
  if (eventIdempotencyKey) {
226
317
  await markCapturedRawWriteFailed(
227
318
  client,
@@ -0,0 +1,21 @@
1
+ /** Persisted in ambiguous_modal_creates.status. */
2
+ export const AmbiguousModalCreateStatus = {
3
+ Pending: 'pending',
4
+ Resolved: 'resolved',
5
+ } as const;
6
+
7
+ export type AmbiguousModalCreateStatus =
8
+ (typeof AmbiguousModalCreateStatus)[keyof typeof AmbiguousModalCreateStatus];
9
+
10
+ /** Decode database text at the scheduler boundary; unknown states fail closed. */
11
+ export function readAmbiguousModalCreateStatus(
12
+ value: unknown,
13
+ ): AmbiguousModalCreateStatus {
14
+ if (
15
+ value === AmbiguousModalCreateStatus.Pending ||
16
+ value === AmbiguousModalCreateStatus.Resolved
17
+ ) {
18
+ return value;
19
+ }
20
+ throw new Error(`Unknown ambiguous Modal create status: ${String(value)}.`);
21
+ }
@@ -0,0 +1,23 @@
1
+ /** Persisted in compute_billing_jobs_v2.status. */
2
+ export const ComputeBillingJobStatus = {
3
+ Pending: 'pending',
4
+ Settling: 'settling',
5
+ Settled: 'settled',
6
+ } as const;
7
+
8
+ export type ComputeBillingJobStatus =
9
+ (typeof ComputeBillingJobStatus)[keyof typeof ComputeBillingJobStatus];
10
+
11
+ /** Decode database text at the scheduler boundary; unknown states fail closed. */
12
+ export function readComputeBillingJobStatus(
13
+ value: unknown,
14
+ ): ComputeBillingJobStatus {
15
+ if (
16
+ value === ComputeBillingJobStatus.Pending ||
17
+ value === ComputeBillingJobStatus.Settling ||
18
+ value === ComputeBillingJobStatus.Settled
19
+ ) {
20
+ return value;
21
+ }
22
+ throw new Error(`Unknown compute billing job status: ${String(value)}.`);
23
+ }
@@ -0,0 +1,25 @@
1
+ /** Persisted in runtime_integration_operation_value_retirements.state. */
2
+ export const IntegrationOperationValueRetirementState = {
3
+ Pending: 'pending',
4
+ Deleting: 'deleting',
5
+ Deleted: 'deleted',
6
+ Cancelled: 'cancelled',
7
+ } as const;
8
+
9
+ export type IntegrationOperationValueRetirementState =
10
+ (typeof IntegrationOperationValueRetirementState)[keyof typeof IntegrationOperationValueRetirementState];
11
+
12
+ /** Decode database text at the scheduler boundary; unknown states fail closed. */
13
+ export function readIntegrationOperationValueRetirementState(
14
+ value: unknown,
15
+ ): IntegrationOperationValueRetirementState {
16
+ if (
17
+ value === IntegrationOperationValueRetirementState.Pending ||
18
+ value === IntegrationOperationValueRetirementState.Deleting ||
19
+ value === IntegrationOperationValueRetirementState.Deleted ||
20
+ value === IntegrationOperationValueRetirementState.Cancelled
21
+ ) {
22
+ return value;
23
+ }
24
+ throw new Error(`Unknown Integration Operation value retirement state: ${String(value)}.`);
25
+ }
@@ -4,6 +4,10 @@ import {
4
4
  isIntegrationOperationValueReference,
5
5
  type IntegrationOperationValueReference,
6
6
  } from './integration-operation-value-reference';
7
+ import {
8
+ IntegrationOperationValueRetirementState,
9
+ readIntegrationOperationValueRetirementState,
10
+ } from './integration-operation-value-retirement-state';
7
11
 
8
12
  /**
9
13
  * The value-retirement journal needs only the scheduler client's query
@@ -50,6 +54,7 @@ type RetirementRow = {
50
54
  object_digest: string;
51
55
  reference_json: unknown;
52
56
  claim_token: string;
57
+ state: unknown;
53
58
  };
54
59
 
55
60
  export type ClaimedIntegrationOperationValueRetirement = {
@@ -59,6 +64,7 @@ export type ClaimedIntegrationOperationValueRetirement = {
59
64
  objectDigest: string;
60
65
  reference: IntegrationOperationValueReference;
61
66
  claimToken: string;
67
+ state: typeof IntegrationOperationValueRetirementState.Deleting;
62
68
  };
63
69
 
64
70
  /**
@@ -102,7 +108,8 @@ export async function claimPostgresIntegrationOperationValueRetirements(input: {
102
108
  WHERE retirements.ctid = candidates.ctid
103
109
  RETURNING retirements.org_id, retirements.operation_key,
104
110
  retirements.object_key, retirements.object_digest,
105
- retirements.reference_json, retirements.claim_token`,
111
+ retirements.reference_json, retirements.claim_token,
112
+ retirements.state`,
106
113
  [limit(input.limit), claimToken],
107
114
  );
108
115
  return claimed.rows.map((row) => {
@@ -119,6 +126,12 @@ export async function claimPostgresIntegrationOperationValueRetirements(input: {
119
126
  `Integration Operation value retirement ${row.object_key} does not match its immutable reference.`,
120
127
  );
121
128
  }
129
+ const state = readIntegrationOperationValueRetirementState(row.state);
130
+ if (state !== IntegrationOperationValueRetirementState.Deleting) {
131
+ throw new Error(
132
+ `Integration Operation value retirement ${row.object_key} was claimed in ${state} state.`,
133
+ );
134
+ }
122
135
  return {
123
136
  orgId: row.org_id,
124
137
  operationKey: row.operation_key,
@@ -126,6 +139,7 @@ export async function claimPostgresIntegrationOperationValueRetirements(input: {
126
139
  objectDigest: row.object_digest,
127
140
  reference: row.reference_json,
128
141
  claimToken: row.claim_token,
142
+ state,
129
143
  };
130
144
  });
131
145
  }
@@ -0,0 +1,30 @@
1
+ /** Persisted in outbox_repair_operations.state. */
2
+ export const OutboxRepairOperationState = {
3
+ Planned: 'planned',
4
+ Applied: 'applied',
5
+ } as const;
6
+
7
+ export type OutboxRepairOperationState =
8
+ (typeof OutboxRepairOperationState)[keyof typeof OutboxRepairOperationState];
9
+
10
+ /** Decode database text at the scheduler boundary; unknown states fail closed. */
11
+ export function readOutboxRepairOperationState(
12
+ value: unknown,
13
+ ): OutboxRepairOperationState {
14
+ if (
15
+ value === OutboxRepairOperationState.Planned ||
16
+ value === OutboxRepairOperationState.Applied
17
+ ) {
18
+ return value;
19
+ }
20
+ throw new Error(`Unknown outbox repair operation state: ${String(value)}.`);
21
+ }
22
+
23
+ /** A repair is planned once, then durably applied; applied is terminal. */
24
+ export function canTransitionOutboxRepairOperation(
25
+ from: OutboxRepairOperationState,
26
+ to: OutboxRepairOperationState,
27
+ ): boolean {
28
+ return from === OutboxRepairOperationState.Planned &&
29
+ to === OutboxRepairOperationState.Applied;
30
+ }
@@ -59,6 +59,24 @@ import {
59
59
  type RuntimeSandboxProvider,
60
60
  runtimeSandboxProviderForResourceKind,
61
61
  } from './runtime-sandbox-operation';
62
+ import {
63
+ AmbiguousModalCreateStatus,
64
+ readAmbiguousModalCreateStatus,
65
+ } from './ambiguous-modal-create-state';
66
+ import {
67
+ ComputeBillingJobStatus,
68
+ readComputeBillingJobStatus,
69
+ } from './compute-billing-job-state';
70
+ import {
71
+ SandboxCleanupJobStatus,
72
+ readSandboxCleanupJobStatus,
73
+ } from './sandbox-cleanup-job-state';
74
+ export {
75
+ OutboxRepairOperationState,
76
+ canTransitionOutboxRepairOperation,
77
+ readOutboxRepairOperationState,
78
+ } from './outbox-repair-operation-state';
79
+ export type { OutboxRepairOperationState as OutboxRepairOperationStateType } from './outbox-repair-operation-state';
62
80
  import {
63
81
  TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
64
82
  type ToolExecutionErrorSchemaVersion,
@@ -10245,7 +10263,7 @@ export async function recordPostgresSchedulerAmbiguousModalCreateIntent(
10245
10263
  },
10246
10264
  options?: Pick<PostgresSchedulerOptions, 'schema'>,
10247
10265
  ): Promise<boolean> {
10248
- const recorded = await client.query<{ run_id: string }>(
10266
+ const recorded = await client.query<{ run_id: string; status: unknown }>(
10249
10267
  `
10250
10268
  INSERT INTO ${tableName('ambiguous_modal_creates', options)} (
10251
10269
  run_id, attempt, modal_app_id, environment, tags_json, sandbox_capacity_lease_id
@@ -10263,7 +10281,7 @@ export async function recordPostgresSchedulerAmbiguousModalCreateIntent(
10263
10281
  sandbox_capacity_lease_id = EXCLUDED.sandbox_capacity_lease_id,
10264
10282
  status = 'pending',
10265
10283
  resolved_at = NULL
10266
- RETURNING run_id
10284
+ RETURNING run_id, status
10267
10285
  `,
10268
10286
  [
10269
10287
  input.runId,
@@ -10275,6 +10293,14 @@ export async function recordPostgresSchedulerAmbiguousModalCreateIntent(
10275
10293
  input.sandboxCapacityLeaseId?.trim() || null,
10276
10294
  ],
10277
10295
  );
10296
+ for (const row of recorded.rows) {
10297
+ if (
10298
+ readAmbiguousModalCreateStatus(row.status) !==
10299
+ AmbiguousModalCreateStatus.Pending
10300
+ ) {
10301
+ throw new Error('Recorded ambiguous Modal create intent was not pending.');
10302
+ }
10303
+ }
10278
10304
  return recorded.rows.length > 0;
10279
10305
  }
10280
10306
 
@@ -10302,6 +10328,7 @@ export async function resolvePostgresSchedulerAmbiguousModalCreateIntent(
10302
10328
  }
10303
10329
 
10304
10330
  export type PostgresSchedulerAmbiguousModalCreateIntent = {
10331
+ status: typeof AmbiguousModalCreateStatus.Pending;
10305
10332
  runId: string;
10306
10333
  attempt: number;
10307
10334
  modalAppId: string;
@@ -10329,6 +10356,7 @@ export async function listPostgresSchedulerAmbiguousModalCreateIntents(
10329
10356
  const minimumAgeMs = Math.max(0, Math.floor(input.minimumAgeMs));
10330
10357
  const rows = await client.query<{
10331
10358
  run_id: string;
10359
+ status: unknown;
10332
10360
  attempt: number;
10333
10361
  modal_app_id: string;
10334
10362
  environment: 'preview' | 'production';
@@ -10337,7 +10365,7 @@ export async function listPostgresSchedulerAmbiguousModalCreateIntents(
10337
10365
  created_at_ms: number;
10338
10366
  }>(
10339
10367
  `
10340
- SELECT run_id, attempt, modal_app_id, environment, tags_json, sandbox_capacity_lease_id,
10368
+ SELECT run_id, status, attempt, modal_app_id, environment, tags_json, sandbox_capacity_lease_id,
10341
10369
  floor(extract(epoch FROM created_at) * 1000)::bigint AS created_at_ms
10342
10370
  FROM ${tableName('ambiguous_modal_creates', options)}
10343
10371
  WHERE status = 'pending'
@@ -10348,15 +10376,24 @@ export async function listPostgresSchedulerAmbiguousModalCreateIntents(
10348
10376
  `,
10349
10377
  [input.environment, minimumAgeMs, limit],
10350
10378
  );
10351
- return rows.rows.map((row) => ({
10352
- runId: row.run_id,
10353
- attempt: Number(row.attempt),
10354
- modalAppId: row.modal_app_id,
10355
- environment: row.environment,
10356
- tags: row.tags_json,
10357
- sandboxCapacityLeaseId: row.sandbox_capacity_lease_id,
10358
- createdAtMs: Number(row.created_at_ms),
10359
- }));
10379
+ return rows.rows.map((row) => {
10380
+ const status = readAmbiguousModalCreateStatus(row.status);
10381
+ if (status !== AmbiguousModalCreateStatus.Pending) {
10382
+ throw new Error(
10383
+ `Ambiguous Modal create intent ${row.run_id} was listed in ${status} state.`,
10384
+ );
10385
+ }
10386
+ return {
10387
+ status,
10388
+ runId: row.run_id,
10389
+ attempt: Number(row.attempt),
10390
+ modalAppId: row.modal_app_id,
10391
+ environment: row.environment,
10392
+ tags: row.tags_json,
10393
+ sandboxCapacityLeaseId: row.sandbox_capacity_lease_id,
10394
+ createdAtMs: Number(row.created_at_ms),
10395
+ };
10396
+ });
10360
10397
  }
10361
10398
 
10362
10399
  /** Provider-confirmed absence is terminal for one pre-create selector. */
@@ -11743,6 +11780,7 @@ export async function directCompletePostgresSchedulerRunnerTerminal(
11743
11780
  }
11744
11781
 
11745
11782
  export type PostgresSchedulerComputeBillingJob = {
11783
+ status: typeof ComputeBillingJobStatus.Settling;
11746
11784
  runId: string;
11747
11785
  attemptCount: number;
11748
11786
  failureCount: number;
@@ -11994,6 +12032,7 @@ export async function claimPostgresSchedulerComputeBillingJobs(
11994
12032
  );
11995
12033
  const claimed = await client.query<{
11996
12034
  run_id: string;
12035
+ status: unknown;
11997
12036
  attempt_count: number;
11998
12037
  failure_count: number;
11999
12038
  run_status: string;
@@ -12045,6 +12084,7 @@ export async function claimPostgresSchedulerComputeBillingJobs(
12045
12084
  WHERE job.run_id = candidates.run_id
12046
12085
  RETURNING
12047
12086
  job.run_id,
12087
+ job.status,
12048
12088
  job.attempt_count,
12049
12089
  job.failure_count,
12050
12090
  job.session_bootstrap_approved_at,
@@ -12052,6 +12092,7 @@ export async function claimPostgresSchedulerComputeBillingJobs(
12052
12092
  )
12053
12093
  SELECT
12054
12094
  claimed.run_id,
12095
+ claimed.status,
12055
12096
  claimed.attempt_count,
12056
12097
  claimed.failure_count,
12057
12098
  claimed.session_bootstrap_approved_at,
@@ -12063,15 +12104,24 @@ export async function claimPostgresSchedulerComputeBillingJobs(
12063
12104
  `,
12064
12105
  [input.leaseOwner, limit, leaseSeconds],
12065
12106
  );
12066
- return claimed.rows.map((row) => ({
12067
- runId: row.run_id,
12068
- attemptCount: row.attempt_count,
12069
- failureCount: row.failure_count,
12070
- success: row.run_status === 'completed',
12071
- bootstrapSessionPending:
12072
- row.session_bootstrap_approved_at !== null &&
12073
- row.session_bootstrap_completed_at === null,
12074
- }));
12107
+ return claimed.rows.map((row) => {
12108
+ const status = readComputeBillingJobStatus(row.status);
12109
+ if (status !== ComputeBillingJobStatus.Settling) {
12110
+ throw new Error(
12111
+ `Compute billing job ${row.run_id} was claimed in ${status} state.`,
12112
+ );
12113
+ }
12114
+ return {
12115
+ status,
12116
+ runId: row.run_id,
12117
+ attemptCount: row.attempt_count,
12118
+ failureCount: row.failure_count,
12119
+ success: row.run_status === 'completed',
12120
+ bootstrapSessionPending:
12121
+ row.session_bootstrap_approved_at !== null &&
12122
+ row.session_bootstrap_completed_at === null,
12123
+ };
12124
+ });
12075
12125
  }
12076
12126
 
12077
12127
  /**
@@ -12476,6 +12526,7 @@ function protectedDetachedResourceSql(
12476
12526
  }
12477
12527
 
12478
12528
  export type PostgresSchedulerSandboxCleanupJob = {
12529
+ status: typeof SandboxCleanupJobStatus.Deleting;
12479
12530
  provider: 'daytona' | 'modal';
12480
12531
  sandboxId: string;
12481
12532
  runId: string;
@@ -12951,6 +13002,7 @@ export async function claimPostgresSchedulerSandboxCleanupJobs(
12951
13002
  if (!adoptionWork.rows[0].pending && !adoptionWork.rows[0].claimable)
12952
13003
  return [];
12953
13004
  const claimed = await client.query<{
13005
+ status: unknown;
12954
13006
  provider: 'daytona' | 'modal';
12955
13007
  sandbox_id: string;
12956
13008
  run_id: string;
@@ -13031,6 +13083,7 @@ export async function claimPostgresSchedulerSandboxCleanupJobs(
13031
13083
  target.run_id,
13032
13084
  target.attempt,
13033
13085
  target.environment,
13086
+ target.status,
13034
13087
  target.routing_domain,
13035
13088
  target.attempt_count,
13036
13089
  target.failure_count,
@@ -13108,18 +13161,27 @@ export async function claimPostgresSchedulerSandboxCleanupJobs(
13108
13161
  input.throughAttempt ?? null,
13109
13162
  ],
13110
13163
  );
13111
- return claimed.rows.map((row) => ({
13112
- provider: row.provider,
13113
- sandboxId: row.sandbox_id,
13114
- runId: row.run_id,
13115
- attempt: row.attempt,
13116
- environment: row.environment,
13117
- routingDomain: row.routing_domain,
13118
- attemptCount: row.attempt_count,
13119
- failureCount: row.failure_count,
13120
- runStatusAtClaim: row.terminal_status,
13121
- diagnostic: row.diagnostic_json,
13122
- }));
13164
+ return claimed.rows.map((row) => {
13165
+ const status = readSandboxCleanupJobStatus(row.status);
13166
+ if (status !== SandboxCleanupJobStatus.Deleting) {
13167
+ throw new Error(
13168
+ `Sandbox cleanup job ${row.sandbox_id} was claimed in ${status} state.`,
13169
+ );
13170
+ }
13171
+ return {
13172
+ status,
13173
+ provider: row.provider,
13174
+ sandboxId: row.sandbox_id,
13175
+ runId: row.run_id,
13176
+ attempt: row.attempt,
13177
+ environment: row.environment,
13178
+ routingDomain: row.routing_domain,
13179
+ attemptCount: row.attempt_count,
13180
+ failureCount: row.failure_count,
13181
+ runStatusAtClaim: row.terminal_status,
13182
+ diagnostic: row.diagnostic_json,
13183
+ };
13184
+ });
13123
13185
  }
13124
13186
 
13125
13187
  /**
@@ -13,6 +13,8 @@ import {
13
13
  RuntimeSandboxOperationState,
14
14
  RuntimeSandboxProvider,
15
15
  } from './runtime-sandbox-operation';
16
+ import type { ComputeBillingJobStatus } from './compute-billing-job-state';
17
+ import { readComputeBillingJobStatus } from './compute-billing-job-state';
16
18
 
17
19
  /**
18
20
  * The baseline when an organization has no current override. It sits above
@@ -1437,7 +1439,7 @@ export type RuntimeSandboxCapacityTestEvidence = {
1437
1439
  cleanupJobs: number;
1438
1440
  confirmedCleanupJobs: number;
1439
1441
  pendingCleanup: number;
1440
- computeJobStatus: string | null;
1442
+ computeJobStatus: ComputeBillingJobStatus | null;
1441
1443
  hasComputeIntent: boolean;
1442
1444
  recordedResources: number;
1443
1445
  firstAcquiredAtMs: number | null;
@@ -1544,5 +1546,11 @@ export async function readRuntimeSandboxCapacityTestEvidence(
1544
1546
  const evidence = result.rows[0]?.evidence;
1545
1547
  if (!evidence)
1546
1548
  throw new Error('Sandbox capacity evidence query returned no snapshot.');
1549
+ if (evidence.run) {
1550
+ evidence.run.computeJobStatus =
1551
+ evidence.run.computeJobStatus === null
1552
+ ? null
1553
+ : readComputeBillingJobStatus(evidence.run.computeJobStatus);
1554
+ }
1547
1555
  return input.runId && evidence.run === null ? null : evidence;
1548
1556
  }
@@ -0,0 +1,23 @@
1
+ /** Persisted in sandbox_cleanup_jobs_v2.status. */
2
+ export const SandboxCleanupJobStatus = {
3
+ Pending: 'pending',
4
+ Deleting: 'deleting',
5
+ Deleted: 'deleted',
6
+ } as const;
7
+
8
+ export type SandboxCleanupJobStatus =
9
+ (typeof SandboxCleanupJobStatus)[keyof typeof SandboxCleanupJobStatus];
10
+
11
+ /** Decode database text at the scheduler boundary; unknown states fail closed. */
12
+ export function readSandboxCleanupJobStatus(
13
+ value: unknown,
14
+ ): SandboxCleanupJobStatus {
15
+ if (
16
+ value === SandboxCleanupJobStatus.Pending ||
17
+ value === SandboxCleanupJobStatus.Deleting ||
18
+ value === SandboxCleanupJobStatus.Deleted
19
+ ) {
20
+ return value;
21
+ }
22
+ throw new Error(`Unknown sandbox cleanup job status: ${String(value)}.`);
23
+ }
@@ -0,0 +1,93 @@
1
+ /** Persisted product notification destination lifecycle. */
2
+ export const PRODUCT_NOTIFICATION_DESTINATION_STATUS = {
3
+ pendingVerification: 'pending_verification',
4
+ active: 'active',
5
+ disabled: 'disabled',
6
+ needsAttention: 'needs_attention',
7
+ } as const;
8
+
9
+ export type ProductNotificationDestinationStatus =
10
+ (typeof PRODUCT_NOTIFICATION_DESTINATION_STATUS)[keyof typeof PRODUCT_NOTIFICATION_DESTINATION_STATUS];
11
+
12
+ export const PRODUCT_NOTIFICATION_DESTINATION_TRANSITIONS = {
13
+ pending_verification: ['active', 'disabled', 'needs_attention'],
14
+ active: ['pending_verification', 'disabled', 'needs_attention'],
15
+ disabled: ['pending_verification', 'active'],
16
+ needs_attention: ['pending_verification', 'active', 'disabled'],
17
+ } as const satisfies Record<
18
+ ProductNotificationDestinationStatus,
19
+ readonly ProductNotificationDestinationStatus[]
20
+ >;
21
+
22
+ export type StoredProductNotificationDestinationStatus =
23
+ | { kind: 'known'; status: ProductNotificationDestinationStatus }
24
+ | { kind: 'unknown'; value: string };
25
+
26
+ export function readProductNotificationDestinationStatus(
27
+ value: string,
28
+ ): StoredProductNotificationDestinationStatus {
29
+ switch (value) {
30
+ case PRODUCT_NOTIFICATION_DESTINATION_STATUS.pendingVerification:
31
+ case PRODUCT_NOTIFICATION_DESTINATION_STATUS.active:
32
+ case PRODUCT_NOTIFICATION_DESTINATION_STATUS.disabled:
33
+ case PRODUCT_NOTIFICATION_DESTINATION_STATUS.needsAttention:
34
+ return { kind: 'known', status: value };
35
+ default:
36
+ return { kind: 'unknown', value };
37
+ }
38
+ }
39
+
40
+ export function requireProductNotificationDestinationStatus(
41
+ value: string,
42
+ ): ProductNotificationDestinationStatus {
43
+ const stored = readProductNotificationDestinationStatus(value);
44
+ if (stored.kind === 'unknown') {
45
+ throw new Error(
46
+ `Unsupported product notification destination status: ${stored.value}`,
47
+ );
48
+ }
49
+ return stored.status;
50
+ }
51
+
52
+ export function isProductNotificationDestinationDeliverable(
53
+ value: string,
54
+ ): boolean {
55
+ return (
56
+ readProductNotificationDestinationStatus(value).kind === 'known' &&
57
+ value === PRODUCT_NOTIFICATION_DESTINATION_STATUS.active
58
+ );
59
+ }
60
+
61
+ export function canTransitionProductNotificationDestination(
62
+ current: string,
63
+ next: ProductNotificationDestinationStatus,
64
+ ): boolean {
65
+ const stored = readProductNotificationDestinationStatus(current);
66
+ return (
67
+ stored.kind === 'known' &&
68
+ (
69
+ PRODUCT_NOTIFICATION_DESTINATION_TRANSITIONS[
70
+ stored.status
71
+ ] as readonly string[]
72
+ ).includes(next)
73
+ );
74
+ }
75
+
76
+ /** Validate a destination lifecycle write without narrowing persisted schema. */
77
+ export function nextProductNotificationDestinationStatus(
78
+ current: string,
79
+ next: ProductNotificationDestinationStatus,
80
+ ): ProductNotificationDestinationStatus {
81
+ const stored = readProductNotificationDestinationStatus(current);
82
+ if (stored.kind === 'unknown') {
83
+ throw new Error(
84
+ `Cannot transition product notification destination from unknown status: ${stored.value}`,
85
+ );
86
+ }
87
+ if (!canTransitionProductNotificationDestination(current, next)) {
88
+ throw new Error(
89
+ `Invalid product notification destination transition: ${current} -> ${next}`,
90
+ );
91
+ }
92
+ return next;
93
+ }