@opengeni/worker-bundle 1.0.0-canary.1 → 1.0.0

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 (244) hide show
  1. package/dist/activities/agent-run-admission.d.ts +3 -1
  2. package/dist/activities/agent-turn/admission.d.ts +24 -3
  3. package/dist/activities/agent-turn/agent-build.d.ts +4 -0
  4. package/dist/activities/agent-turn/claude-usage-observer.d.ts +58 -0
  5. package/dist/activities/agent-turn/code-search.d.ts +60 -0
  6. package/dist/activities/agent-turn/codex-capacity.d.ts +13 -0
  7. package/dist/activities/agent-turn/codex-plan-entitlement.d.ts +105 -0
  8. package/dist/activities/agent-turn/codex.d.ts +3 -2
  9. package/dist/activities/agent-turn/compaction-prep.d.ts +21 -5
  10. package/dist/activities/agent-turn/credential-leases.d.ts +19 -33
  11. package/dist/activities/agent-turn/credential-restriction.d.ts +3 -0
  12. package/dist/activities/agent-turn/errors.d.ts +82 -11
  13. package/dist/activities/agent-turn/failure-settlement.d.ts +6 -3
  14. package/dist/activities/agent-turn/final-reply.d.ts +18 -0
  15. package/dist/activities/agent-turn/finalization-monitor.d.ts +17 -0
  16. package/dist/activities/agent-turn/finalization.d.ts +4 -2
  17. package/dist/activities/agent-turn/github-repository-bindings.d.ts +2 -0
  18. package/dist/activities/agent-turn/governance-model.d.ts +9 -2
  19. package/dist/activities/agent-turn/history-sink.d.ts +2 -0
  20. package/dist/activities/agent-turn/history.d.ts +2 -0
  21. package/dist/activities/agent-turn/input-wait-reply.d.ts +41 -0
  22. package/dist/activities/agent-turn/media-artifacts.d.ts +5 -3
  23. package/dist/activities/agent-turn/model-call-admission.d.ts +15 -0
  24. package/dist/activities/agent-turn/model-usage.d.ts +6 -0
  25. package/dist/activities/agent-turn/model-wire-dispatch.d.ts +15 -0
  26. package/dist/activities/agent-turn/optional-repositories.d.ts +59 -0
  27. package/dist/activities/agent-turn/provider-dispatch-barrier.d.ts +12 -1
  28. package/dist/activities/agent-turn/quiescence.d.ts +7 -7
  29. package/dist/activities/agent-turn/recovery-warning.d.ts +9 -0
  30. package/dist/activities/agent-turn/refresh-credentials.d.ts +6 -0
  31. package/dist/activities/agent-turn/run-credentials.d.ts +8 -3
  32. package/dist/activities/agent-turn/sandbox-establish.d.ts +2 -1
  33. package/dist/activities/agent-turn/sandbox-provision.d.ts +3 -1
  34. package/dist/activities/agent-turn/sandbox-route.d.ts +3 -20
  35. package/dist/activities/agent-turn/sandbox-runtime.d.ts +2 -2
  36. package/dist/activities/agent-turn/session-title.d.ts +34 -2
  37. package/dist/activities/agent-turn/skill-checkout.d.ts +25 -6
  38. package/dist/activities/agent-turn/skill-read.d.ts +70 -2
  39. package/dist/activities/agent-turn/skill-remove.d.ts +14 -0
  40. package/dist/activities/agent-turn/skill-search.d.ts +3 -1
  41. package/dist/activities/agent-turn/skill-tools.d.ts +15 -2
  42. package/dist/activities/agent-turn/skill-transfer.d.ts +18 -6
  43. package/dist/activities/agent-turn/stream-attempt.d.ts +7 -3
  44. package/dist/activities/agent-turn/subscription-lease.d.ts +38 -0
  45. package/dist/activities/agent-turn/tool-environment.d.ts +56 -6
  46. package/dist/activities/agent-turn/tool-policy.d.ts +43 -0
  47. package/dist/activities/agent-turn/turn-context.d.ts +29 -0
  48. package/dist/activities/agent-turn/turn-sandbox-access.d.ts +3 -0
  49. package/dist/activities/agent-turn/xai-capacity.d.ts +2 -1
  50. package/dist/activities/automations.d.ts +3 -1
  51. package/dist/activities/browser-deadline-checkpoint.d.ts +29 -0
  52. package/dist/activities/codemode-dispatcher.d.ts +9 -2
  53. package/dist/activities/codex-capacity.d.ts +18 -2
  54. package/dist/activities/codex-rotation.d.ts +7 -1
  55. package/dist/activities/context-compaction.d.ts +16 -2
  56. package/dist/activities/gmail-files.d.ts +32 -0
  57. package/dist/activities/goals.d.ts +8 -0
  58. package/dist/activities/knowledge-indexing.d.ts +19 -0
  59. package/dist/activities/mcp-account-routes.d.ts +3 -0
  60. package/dist/activities/mcp-credentials.d.ts +12 -13
  61. package/dist/activities/mcp-operation-authority.d.ts +0 -5
  62. package/dist/activities/model-call-fact-reconciler.d.ts +34 -0
  63. package/dist/activities/open-suffix-resume.d.ts +13 -0
  64. package/dist/activities/parent-wake.d.ts +6 -12
  65. package/dist/activities/retained-screenshots.d.ts +7 -2
  66. package/dist/activities/rig-verification.d.ts +2 -3
  67. package/dist/activities/run-credential-renewal.d.ts +1 -0
  68. package/dist/activities/run-credentials.d.ts +15 -3
  69. package/dist/activities/sandbox-images.d.ts +1 -1
  70. package/dist/activities/sandbox-lease.d.ts +47 -9
  71. package/dist/activities/scheduled-tasks.d.ts +4 -35
  72. package/dist/activities/session-state.d.ts +70 -3
  73. package/dist/activities/types.d.ts +55 -6
  74. package/dist/activities/workspace-capture.d.ts +2 -0
  75. package/dist/activities/workspace-credential-provider.d.ts +46 -0
  76. package/dist/{activities-control-HMFGSKC5.js → activities-control-BNPTRTOE.js} +1896 -418
  77. package/dist/activities-control-BNPTRTOE.js.map +1 -0
  78. package/dist/activities-control.d.ts +182 -4
  79. package/dist/{activities-turn-AP67JADS.js → activities-turn-5LGZOSVU.js} +4476 -1327
  80. package/dist/activities-turn-5LGZOSVU.js.map +1 -0
  81. package/dist/activities.d.ts +182 -4
  82. package/dist/artifact-materializer-entry.js +5 -2
  83. package/dist/artifact-materializer-entry.js.map +1 -1
  84. package/dist/artifact-outbox-entry.js +5 -2
  85. package/dist/artifact-outbox-entry.js.map +1 -1
  86. package/dist/browser-deadline-checkpoint-contract.d.ts +2 -0
  87. package/dist/{chunk-A4XQWVZK.js → chunk-3ZTRWDMN.js} +307 -4
  88. package/dist/chunk-3ZTRWDMN.js.map +1 -0
  89. package/dist/{chunk-RAMNYSAW.js → chunk-4ER3YXOT.js} +22 -4
  90. package/dist/chunk-4ER3YXOT.js.map +1 -0
  91. package/dist/{chunk-CYITU5UH.js → chunk-LJX7Z2KP.js} +1445 -343
  92. package/dist/chunk-LJX7Z2KP.js.map +1 -0
  93. package/dist/editable-artifact-materializer-service.d.ts +2 -2
  94. package/dist/editable-artifact-outbox-service.d.ts +2 -2
  95. package/dist/host-export-pump.d.ts +3 -1
  96. package/dist/host-export.d.ts +1 -1
  97. package/dist/host-export.js +1 -1
  98. package/dist/http.d.ts +1 -1
  99. package/dist/index.d.ts +95 -3
  100. package/dist/index.js +137 -43
  101. package/dist/index.js.map +1 -1
  102. package/dist/observability-metrics.d.ts +118 -8
  103. package/dist/retained-process-diagnostics.d.ts +4 -0
  104. package/dist/retained-process-retry.d.ts +7 -0
  105. package/dist/sandbox-resume.d.ts +55 -13
  106. package/dist/sandbox-routing.d.ts +5 -3
  107. package/dist/sandbox-snapshot-diagnostics.d.ts +20 -0
  108. package/dist/session-event-fanout.d.ts +6 -0
  109. package/dist/warm-capture-holder.d.ts +3 -0
  110. package/dist/worker-service-lifecycle.d.ts +12 -0
  111. package/dist/workflow-bundle.js +273 -41
  112. package/dist/workflows/activities.d.ts +1 -1
  113. package/dist/workflows/browser-deadline-checkpoint.d.ts +9 -0
  114. package/dist/workflows/scheduled-tasks.d.ts +4 -0
  115. package/dist/workflows/session.d.ts +36 -0
  116. package/dist/workflows.d.ts +1 -0
  117. package/package.json +21 -19
  118. package/src/activities/agent-run-admission.ts +17 -1
  119. package/src/activities/agent-turn/admission.ts +66 -3
  120. package/src/activities/agent-turn/agent-build.ts +84 -10
  121. package/src/activities/agent-turn/claim.ts +186 -43
  122. package/src/activities/agent-turn/claude-usage-observer.ts +221 -0
  123. package/src/activities/agent-turn/code-search.ts +275 -0
  124. package/src/activities/agent-turn/codex-capacity.ts +172 -8
  125. package/src/activities/agent-turn/codex-plan-entitlement.ts +254 -0
  126. package/src/activities/agent-turn/codex.ts +13 -5
  127. package/src/activities/agent-turn/compaction-prep.ts +170 -102
  128. package/src/activities/agent-turn/credential-leases.ts +122 -216
  129. package/src/activities/agent-turn/credential-restriction.ts +14 -0
  130. package/src/activities/agent-turn/errors.ts +647 -48
  131. package/src/activities/agent-turn/failure-settlement.ts +682 -130
  132. package/src/activities/agent-turn/final-reply.ts +46 -0
  133. package/src/activities/agent-turn/finalization-monitor.ts +120 -0
  134. package/src/activities/agent-turn/finalization.ts +146 -43
  135. package/src/activities/agent-turn/github-repository-bindings.ts +3 -1
  136. package/src/activities/agent-turn/governance-model.ts +69 -28
  137. package/src/activities/agent-turn/history-sink.ts +16 -2
  138. package/src/activities/agent-turn/history.ts +38 -11
  139. package/src/activities/agent-turn/input-wait-reply.ts +103 -0
  140. package/src/activities/agent-turn/knowledge-source-tools.ts +2 -0
  141. package/src/activities/agent-turn/media-artifacts.ts +2 -1
  142. package/src/activities/agent-turn/model-call-admission.ts +94 -0
  143. package/src/activities/agent-turn/model-usage.ts +64 -3
  144. package/src/activities/agent-turn/model-wire-dispatch.ts +27 -0
  145. package/src/activities/agent-turn/optional-repositories.ts +224 -0
  146. package/src/activities/agent-turn/provider-dispatch-barrier.ts +22 -0
  147. package/src/activities/agent-turn/quiescence.ts +10 -7
  148. package/src/activities/agent-turn/recovery-warning.ts +16 -0
  149. package/src/activities/agent-turn/refresh-credentials.ts +44 -0
  150. package/src/activities/agent-turn/run-credentials.ts +116 -55
  151. package/src/activities/agent-turn/run.ts +320 -93
  152. package/src/activities/agent-turn/sandbox-establish.ts +84 -8
  153. package/src/activities/agent-turn/sandbox-provision.ts +3 -1
  154. package/src/activities/agent-turn/sandbox-route.ts +4 -21
  155. package/src/activities/agent-turn/sandbox-runtime.ts +343 -18
  156. package/src/activities/agent-turn/session-title.ts +81 -5
  157. package/src/activities/agent-turn/skill-checkout.ts +111 -24
  158. package/src/activities/agent-turn/skill-install.ts +1 -1
  159. package/src/activities/agent-turn/skill-read.ts +374 -28
  160. package/src/activities/agent-turn/skill-remove.ts +46 -0
  161. package/src/activities/agent-turn/skill-save.ts +1 -1
  162. package/src/activities/agent-turn/skill-search.ts +10 -1
  163. package/src/activities/agent-turn/skill-selection.ts +4 -0
  164. package/src/activities/agent-turn/skill-tools.ts +112 -18
  165. package/src/activities/agent-turn/skill-transfer.ts +68 -23
  166. package/src/activities/agent-turn/stream-attempt.ts +313 -77
  167. package/src/activities/agent-turn/subscription-lease.ts +115 -0
  168. package/src/activities/agent-turn/tool-environment.ts +316 -167
  169. package/src/activities/agent-turn/tool-policy.ts +80 -1
  170. package/src/activities/agent-turn/turn-context.ts +35 -0
  171. package/src/activities/agent-turn/turn-sandbox-access.ts +7 -1
  172. package/src/activities/agent-turn/xai-capacity.ts +94 -51
  173. package/src/activities/automations.ts +76 -4
  174. package/src/activities/browser-deadline-checkpoint.ts +279 -0
  175. package/src/activities/capabilities.ts +108 -11
  176. package/src/activities/codemode-dispatcher.ts +36 -8
  177. package/src/activities/codex-capacity.ts +60 -25
  178. package/src/activities/codex-rotation.ts +39 -17
  179. package/src/activities/context-compaction.ts +75 -18
  180. package/src/activities/gmail-files.ts +88 -0
  181. package/src/activities/goals.ts +116 -121
  182. package/src/activities/google-drive-publication.ts +1 -3
  183. package/src/activities/image-generation-operation.ts +1 -1
  184. package/src/activities/knowledge-indexing.ts +269 -15
  185. package/src/activities/knowledge-source-sync.ts +10 -0
  186. package/src/activities/mcp-account-routes.ts +17 -0
  187. package/src/activities/mcp-credentials.ts +83 -194
  188. package/src/activities/mcp-operation-authority.ts +16 -41
  189. package/src/activities/model-call-fact-reconciler.ts +112 -0
  190. package/src/activities/open-suffix-resume.ts +15 -2
  191. package/src/activities/parent-wake.ts +46 -21
  192. package/src/activities/retained-screenshots.ts +82 -11
  193. package/src/activities/rig-verification.ts +38 -37
  194. package/src/activities/run-credential-renewal.ts +13 -1
  195. package/src/activities/run-credentials.ts +59 -17
  196. package/src/activities/run-input.ts +25 -16
  197. package/src/activities/sandbox-images.ts +0 -1
  198. package/src/activities/sandbox-lease.ts +798 -82
  199. package/src/activities/scheduled-tasks.ts +550 -178
  200. package/src/activities/session-state.ts +245 -6
  201. package/src/activities/site-auth-maintenance.ts +3 -0
  202. package/src/activities/types.ts +72 -5
  203. package/src/activities/workflow-wake.ts +2 -17
  204. package/src/activities/workspace-capture.ts +13 -2
  205. package/src/activities/workspace-credential-provider.ts +283 -0
  206. package/src/activities-control.ts +4 -0
  207. package/src/activities-turn.ts +5 -0
  208. package/src/activities.ts +13 -0
  209. package/src/activity-services.ts +16 -4
  210. package/src/browser-deadline-checkpoint-contract.ts +5 -0
  211. package/src/editable-artifact-hint-broker.ts +3 -0
  212. package/src/editable-artifact-materializer-service.ts +7 -3
  213. package/src/editable-artifact-outbox-service.ts +4 -4
  214. package/src/github-rest-mcp.ts +1 -2
  215. package/src/host-export-pump.ts +26 -4
  216. package/src/host-export.ts +3 -0
  217. package/src/http.ts +4 -2
  218. package/src/index.ts +99 -37
  219. package/src/observability-metrics.ts +510 -5
  220. package/src/personal-github-git-credentials.ts +2 -1
  221. package/src/pr-review-credentials.ts +1 -3
  222. package/src/retained-process-diagnostics.ts +50 -0
  223. package/src/retained-process-retry.ts +36 -0
  224. package/src/sandbox-resume.ts +388 -101
  225. package/src/sandbox-routing.ts +150 -25
  226. package/src/sandbox-snapshot-diagnostics.ts +112 -0
  227. package/src/session-event-fanout.ts +23 -0
  228. package/src/warm-capture-holder.ts +15 -0
  229. package/src/worker-service-lifecycle.ts +53 -0
  230. package/src/workflows/activities.ts +16 -1
  231. package/src/workflows/browser-deadline-checkpoint.ts +50 -0
  232. package/src/workflows/file-upload-reaper.ts +2 -0
  233. package/src/workflows/scheduled-tasks.ts +26 -13
  234. package/src/workflows/session.ts +242 -22
  235. package/src/workflows.ts +4 -0
  236. package/dist/activities/agent-turn/knowledge-sources.d.ts +0 -20
  237. package/dist/activities/packs.d.ts +0 -55
  238. package/dist/activities-control-HMFGSKC5.js.map +0 -1
  239. package/dist/activities-turn-AP67JADS.js.map +0 -1
  240. package/dist/chunk-A4XQWVZK.js.map +0 -1
  241. package/dist/chunk-CYITU5UH.js.map +0 -1
  242. package/dist/chunk-RAMNYSAW.js.map +0 -1
  243. package/src/activities/agent-turn/knowledge-sources.ts +0 -86
  244. package/src/activities/packs.ts +0 -166
@@ -3,22 +3,30 @@ import {
3
3
  applySessionTurnSettlement,
4
4
  enqueueSessionWorkflowWake,
5
5
  failSessionWorkBeforeAttemptClaim,
6
+ blockSessionWorkBeforeAttemptClaim,
6
7
  requestSessionTurnRecovery,
7
8
  recoverSessionDispatch,
9
+ reconcileSettledSessionAttempt,
8
10
  reconcileSessionAttemptQuiescence,
11
+ reconcileCompletedSandboxSetup,
9
12
  peekSessionWork as peekSessionWorkDb,
10
13
  settleSessionInputWait as settleSessionInputWaitDb,
11
14
  countQueuedTurns,
12
15
  getSessionAttemptActivityRef,
13
16
  getSessionEvent,
14
17
  getSessionTurnForAttempt,
18
+ getWorkspace,
15
19
  expireSessionInteractionIntervention as expireSessionInteractionInterventionDb,
20
+ expireScheduledRunHumanWait as expireScheduledRunHumanWaitDb,
16
21
  expireSessionHumanInputRequest,
17
22
  markSessionAttemptQuiesced,
18
23
  requireSession,
19
24
  settleSessionIdleWithParentOutbox,
25
+ SANDBOX_SETUP_RECOVERY_LIMIT,
20
26
  } from "@opengeni/db";
21
27
  import { publishDurableSessionEvents } from "@opengeni/events";
28
+ import { CancelledFailure } from "@temporalio/activity";
29
+ import { currentActivityContext } from "./streaming";
22
30
  import { deliverFailedChildTurnToParent, notifyParentOfChildIdle } from "./parent-wake";
23
31
  import { recordTurnsQueuedGauge, recordWorkerDeathRecoveryMetrics } from "../observability-metrics";
24
32
  import {
@@ -30,6 +38,8 @@ import type {
30
38
  ExpireSessionHumanInputInput,
31
39
  ExpireSessionHumanInputResult,
32
40
  ExpireSessionInteractionInterventionInput,
41
+ ExpireScheduledRunHumanWaitInput,
42
+ ExpireScheduledRunHumanWaitResult,
33
43
  ExpireSessionInteractionInterventionResult,
34
44
  PeekSessionWorkInput,
35
45
  FailSessionAttemptInput,
@@ -39,6 +49,8 @@ import type {
39
49
  PersistSessionAttemptQuiescenceInput,
40
50
  ReconcileSessionAttemptQuiescenceInput,
41
51
  ReconcileSessionAttemptQuiescenceResult,
52
+ ReconcileSettledSessionAttemptInput,
53
+ ReconcileSettledSessionAttemptResult,
42
54
  RecoverDispatchInput,
43
55
  RecoverDispatchResult,
44
56
  RecoverEscapedMcpTimeoutInput,
@@ -52,17 +64,22 @@ export type SessionStateActivityOverrides = Partial<{
52
64
  applySessionTurnSettlement: typeof applySessionTurnSettlement;
53
65
  enqueueSessionWorkflowWake: typeof enqueueSessionWorkflowWake;
54
66
  failSessionWorkBeforeAttemptClaim: typeof failSessionWorkBeforeAttemptClaim;
67
+ blockSessionWorkBeforeAttemptClaim: typeof blockSessionWorkBeforeAttemptClaim;
55
68
  requestSessionTurnRecovery: typeof requestSessionTurnRecovery;
56
69
  recoverSessionDispatch: typeof recoverSessionDispatch;
70
+ reconcileSettledSessionAttempt: typeof reconcileSettledSessionAttempt;
57
71
  reconcileSessionAttemptQuiescence: typeof reconcileSessionAttemptQuiescence;
72
+ reconcileCompletedSandboxSetup: typeof reconcileCompletedSandboxSetup;
58
73
  peekSessionWork: typeof peekSessionWorkDb;
59
74
  settleSessionInputWait: typeof settleSessionInputWaitDb;
60
75
  countQueuedTurns: typeof countQueuedTurns;
61
76
  getSessionAttemptActivityRef: typeof getSessionAttemptActivityRef;
62
77
  getSessionEvent: typeof getSessionEvent;
63
78
  getSessionTurnForAttempt: typeof getSessionTurnForAttempt;
79
+ getWorkspace: typeof getWorkspace;
64
80
  expireSessionHumanInputRequest: typeof expireSessionHumanInputRequest;
65
81
  expireSessionInteractionIntervention: typeof expireSessionInteractionInterventionDb;
82
+ expireScheduledRunHumanWait: typeof expireScheduledRunHumanWaitDb;
66
83
  requireSession: typeof requireSession;
67
84
  settleSessionIdleWithParentOutbox: typeof settleSessionIdleWithParentOutbox;
68
85
  markSessionAttemptQuiesced: typeof markSessionAttemptQuiesced;
@@ -91,22 +108,31 @@ export function createSessionStateActivities(
91
108
  overrides.enqueueSessionWorkflowWake ?? enqueueSessionWorkflowWake;
92
109
  const failSessionWorkBeforeAttemptClaimFn =
93
110
  overrides.failSessionWorkBeforeAttemptClaim ?? failSessionWorkBeforeAttemptClaim;
111
+ const blockSessionWorkBeforeAttemptClaimFn =
112
+ overrides.blockSessionWorkBeforeAttemptClaim ?? blockSessionWorkBeforeAttemptClaim;
94
113
  const requestSessionTurnRecoveryFn =
95
114
  overrides.requestSessionTurnRecovery ?? requestSessionTurnRecovery;
96
115
  const recoverSessionDispatchFn = overrides.recoverSessionDispatch ?? recoverSessionDispatch;
116
+ const reconcileSettledSessionAttemptFn =
117
+ overrides.reconcileSettledSessionAttempt ?? reconcileSettledSessionAttempt;
97
118
  const reconcileSessionAttemptQuiescenceFn =
98
119
  overrides.reconcileSessionAttemptQuiescence ?? reconcileSessionAttemptQuiescence;
99
120
  const peekSessionWorkFn = overrides.peekSessionWork ?? peekSessionWorkDb;
121
+ const reconcileCompletedSandboxSetupFn =
122
+ overrides.reconcileCompletedSandboxSetup ?? reconcileCompletedSandboxSetup;
100
123
  const settleSessionInputWaitFn = overrides.settleSessionInputWait ?? settleSessionInputWaitDb;
101
124
  const countQueuedTurnsFn = overrides.countQueuedTurns ?? countQueuedTurns;
102
125
  const getSessionAttemptActivityRefFn =
103
126
  overrides.getSessionAttemptActivityRef ?? getSessionAttemptActivityRef;
104
127
  const getSessionEventFn = overrides.getSessionEvent ?? getSessionEvent;
105
128
  const getSessionTurnForAttemptFn = overrides.getSessionTurnForAttempt ?? getSessionTurnForAttempt;
129
+ const getWorkspaceFn = overrides.getWorkspace ?? getWorkspace;
106
130
  const expireSessionHumanInputRequestFn =
107
131
  overrides.expireSessionHumanInputRequest ?? expireSessionHumanInputRequest;
108
132
  const expireSessionInteractionInterventionFn =
109
133
  overrides.expireSessionInteractionIntervention ?? expireSessionInteractionInterventionDb;
134
+ const expireScheduledRunHumanWaitFn =
135
+ overrides.expireScheduledRunHumanWait ?? expireScheduledRunHumanWaitDb;
110
136
  const requireSessionFn = overrides.requireSession ?? requireSession;
111
137
  const settleSessionIdleWithParentOutboxFn =
112
138
  overrides.settleSessionIdleWithParentOutbox ?? settleSessionIdleWithParentOutbox;
@@ -153,6 +179,28 @@ export function createSessionStateActivities(
153
179
 
154
180
  const preClaimFailureDisposition =
155
181
  input.preClaimFailure?.disposition ?? input.preClaimFailureDisposition;
182
+ if (
183
+ preClaimFailureDisposition === "blocked" &&
184
+ input.admissionFence &&
185
+ input.preClaimFailure?.reason
186
+ ) {
187
+ const blocked = await blockSessionWorkBeforeAttemptClaimFn(db, input.workspaceId, {
188
+ accountId: input.accountId,
189
+ sessionId: input.sessionId,
190
+ workflowId,
191
+ attemptId: input.attemptId,
192
+ fence: input.admissionFence,
193
+ reason: input.preClaimFailure.reason,
194
+ sqlState: input.preClaimFailure.sqlState ?? null,
195
+ });
196
+ await publishDurableSessionEventsFn(
197
+ bus,
198
+ input.workspaceId,
199
+ input.sessionId,
200
+ blocked.events,
201
+ );
202
+ return { action: blocked.action };
203
+ }
156
204
  if (preClaimFailureDisposition === "permanent" && input.trigger) {
157
205
  const failed = await failSessionWorkBeforeAttemptClaimFn(db, input.workspaceId, {
158
206
  accountId: input.accountId,
@@ -160,7 +208,14 @@ export function createSessionStateActivities(
160
208
  workflowId,
161
209
  trigger: input.trigger,
162
210
  error: input.error ?? "Agent turn admission failed before attempt claim.",
163
- ...(input.preClaimFailure ? { admissionFailure: input.preClaimFailure } : {}),
211
+ ...(input.preClaimFailure?.disposition === "permanent"
212
+ ? {
213
+ admissionFailure: {
214
+ disposition: "permanent" as const,
215
+ code: input.preClaimFailure.code,
216
+ },
217
+ }
218
+ : {}),
164
219
  });
165
220
  if (failed.action === "terminal") return { action: "terminal" };
166
221
  if (failed.action === "stale") return { action: "stale" };
@@ -198,6 +253,9 @@ export function createSessionStateActivities(
198
253
  turn.triggerEventId === postClaimRecovery.triggerEventId &&
199
254
  turn.executionGeneration === postClaimRecovery.executionGeneration,
200
255
  );
256
+ if (postClaimRecovery?.sandboxSetupRecoveryExhausted && !postClaimIdentityMatches) {
257
+ return { action: "stale" };
258
+ }
201
259
  const providerRecoveryCount = postClaimIdentityMatches
202
260
  ? postClaimRecovery?.providerRecoveryCount
203
261
  : undefined;
@@ -206,6 +264,19 @@ export function createSessionStateActivities(
206
264
  : undefined;
207
265
  const hasProviderRecoveryCount = providerRecoveryCount !== undefined;
208
266
  const hasProviderFailureCode = providerFailureCode !== undefined;
267
+ const setupOutcomeUnknown =
268
+ postClaimIdentityMatches && postClaimRecovery?.sandboxSetupOutcomeUnknown === true;
269
+ const setupRecoveryExhausted =
270
+ postClaimIdentityMatches && postClaimRecovery?.sandboxSetupRecoveryExhausted === true;
271
+ if (
272
+ (setupOutcomeUnknown && setupRecoveryExhausted) ||
273
+ ((setupOutcomeUnknown || setupRecoveryExhausted) &&
274
+ (hasProviderRecoveryCount || hasProviderFailureCode)) ||
275
+ (setupRecoveryExhausted &&
276
+ turn.metadata?.providerRecoveryCount !== SANDBOX_SETUP_RECOVERY_LIMIT)
277
+ ) {
278
+ return { action: "stale" };
279
+ }
209
280
  if (hasProviderRecoveryCount !== hasProviderFailureCode) {
210
281
  return { action: "stale" };
211
282
  }
@@ -234,11 +305,30 @@ export function createSessionStateActivities(
234
305
  turnId: turn.id,
235
306
  triggerEventId: turn.triggerEventId,
236
307
  attemptId: input.attemptId,
237
- reason: providerFailureCode ?? "claimed_attempt_database_failure",
308
+ reason: setupOutcomeUnknown
309
+ ? "sandbox_command_start_outcome_unknown"
310
+ : setupRecoveryExhausted
311
+ ? "sandbox_command_start_recovery_exhausted"
312
+ : (providerFailureCode ?? "claimed_attempt_database_failure"),
313
+ ...(setupOutcomeUnknown ? { sandboxSetupOutcomeUnknown: true } : {}),
314
+ ...(setupRecoveryExhausted ? { sandboxSetupRecoveryExhausted: true } : {}),
238
315
  ...(providerRecoveryCount !== undefined ? { providerRecoveryCount } : {}),
239
316
  detail: {
240
- code: providerFailureCode ?? recoveredClaimCode,
241
- retryable: true,
317
+ code: setupOutcomeUnknown
318
+ ? "sandbox_command_start_outcome_unknown"
319
+ : setupRecoveryExhausted
320
+ ? "sandbox_command_start_recovery_exhausted"
321
+ : (providerFailureCode ?? recoveredClaimCode),
322
+ retryable: !setupOutcomeUnknown && !setupRecoveryExhausted,
323
+ ...(setupOutcomeUnknown ? { setupOutcome: "unknown", replay: "blocked" } : {}),
324
+ ...(setupRecoveryExhausted
325
+ ? {
326
+ setupOutcome: "not_started",
327
+ replay: "blocked",
328
+ recoveryExhausted: true,
329
+ providerRecoveryCount: SANDBOX_SETUP_RECOVERY_LIMIT,
330
+ }
331
+ : {}),
242
332
  ...(providerRecoveryCount !== undefined
243
333
  ? {
244
334
  databaseFailureCode: recoveredClaimCode,
@@ -390,6 +480,63 @@ export function createSessionStateActivities(
390
480
  return { action: result.action };
391
481
  }
392
482
 
483
+ /** A new authenticated inspection, never trust the earlier observer hint.
484
+ * The DB seam independently revalidates the entire stored/current identity,
485
+ * control and both writer predicates under canonical locks before closing. */
486
+ async function reconcileSettledSessionAttemptActivity(
487
+ input: ReconcileSettledSessionAttemptInput,
488
+ ): Promise<ReconcileSettledSessionAttemptResult> {
489
+ const { db, bus, inspectSessionAttemptActivity, settings, observability, wakeSessionWorkflow } =
490
+ await services();
491
+ const ref = await getSessionAttemptActivityRefFn(db, {
492
+ ...input,
493
+ temporalWorkflowId: input.workflowId,
494
+ });
495
+ if (!ref || ref.workflowRunId !== input.workflowRunId || ref.activityId !== input.activityId)
496
+ return { action: "stale" };
497
+ if (!inspectSessionAttemptActivity) return { action: "pending" };
498
+ try {
499
+ if ((await inspectSessionAttemptActivity(ref)) !== "settled") return { action: "pending" };
500
+ } catch (error) {
501
+ if (error instanceof CancelledFailure) throw error;
502
+ if (currentActivityContext()?.cancellationSignal.aborted)
503
+ throw new CancelledFailure("Settled-owner reconciliation cancelled");
504
+ return { action: "pending" };
505
+ }
506
+ if (currentActivityContext()?.cancellationSignal.aborted)
507
+ throw new CancelledFailure("Settled-owner reconciliation cancelled");
508
+ const result = await reconcileSettledSessionAttemptFn(db, {
509
+ accountId: input.accountId,
510
+ workspaceId: input.workspaceId,
511
+ sessionId: input.sessionId,
512
+ turnId: input.turnId,
513
+ attemptId: input.attemptId,
514
+ executionGeneration: input.executionGeneration,
515
+ temporalWorkflowId: ref.workflowId,
516
+ temporalWorkflowRunId: ref.workflowRunId,
517
+ temporalActivityId: ref.activityId,
518
+ activitySettled: true,
519
+ maxRedispatches: WORKER_DEATH_MAX_REDISPATCHES,
520
+ });
521
+ // Atomic Postgres recovery/quiescence/wake truth is already sufficient if
522
+ // live fanout fails. It must not be replaced by an observer-only wake.
523
+ if (result.events.length > 0)
524
+ await publishDurableSessionEventsFn(
525
+ bus,
526
+ input.workspaceId,
527
+ input.sessionId,
528
+ result.events,
529
+ ).catch(() => undefined);
530
+ if (result.action === "exceeded")
531
+ await deliverFailedChildTurnToParentFn(
532
+ { db, bus, settings, observability, wakeSessionWorkflow },
533
+ input.workspaceId,
534
+ input.sessionId,
535
+ result.turnId,
536
+ );
537
+ return { action: result.action };
538
+ }
539
+
393
540
  /**
394
541
  * Recover the same current inference when its worker dies without completing
395
542
  * a graceful checkpoint (heartbeat timeout, SIGKILL, OOM, or node loss).
@@ -488,8 +635,86 @@ export function createSessionStateActivities(
488
635
  }
489
636
 
490
637
  async function peekSessionWork(input: PeekSessionWorkInput) {
491
- const { db, observability } = await services();
492
- const peek = await peekSessionWorkFn(db, input.workspaceId, input.sessionId);
638
+ const { db, bus, observability, inspectSessionAttemptActivity } = await services();
639
+ // Already scheduled activities retain their old input across workflow upgrades.
640
+ // Resolve its workspace scope exactly as the legacy DB path did, then use the
641
+ // observer path so absent rows and a still-owned attempt are observations.
642
+ const observerAccountId =
643
+ input.observerAccountId ?? (await getWorkspaceFn(db, input.workspaceId))?.accountId;
644
+ if (!observerAccountId) return { kind: "unavailable" as const };
645
+ let peek = await peekSessionWorkFn(
646
+ db,
647
+ input.workspaceId,
648
+ input.sessionId,
649
+ input.includeAdmissionFence,
650
+ observerAccountId,
651
+ );
652
+ if (peek.kind === "unavailable") return peek;
653
+ if (peek.kind === "admission-blocked" && peek.reason === "sandbox_setup_outcome_unknown") {
654
+ const ref = peek.ref;
655
+ if (ref && "turnId" in ref && "attemptId" in ref) {
656
+ const settled = await reconcileCompletedSandboxSetupFn(db, {
657
+ accountId: observerAccountId,
658
+ workspaceId: input.workspaceId,
659
+ sessionId: input.sessionId,
660
+ turnId: ref.turnId,
661
+ attemptId: ref.attemptId,
662
+ });
663
+ if (settled.events.length > 0)
664
+ await publishDurableSessionEventsFn(
665
+ bus,
666
+ input.workspaceId,
667
+ input.sessionId,
668
+ settled.events,
669
+ );
670
+ if (settled.reconciled)
671
+ peek = await peekSessionWorkFn(
672
+ db,
673
+ input.workspaceId,
674
+ input.sessionId,
675
+ input.includeAdmissionFence,
676
+ observerAccountId,
677
+ );
678
+ }
679
+ }
680
+ if (peek.kind === "attempt-owned") {
681
+ // Observation never revokes a writer or recovers a live owner. In
682
+ // particular, a settled Temporal activity is not physical-writer proof.
683
+ let ownerActivityState: "pending" | "settled" | "unknown" = "unknown";
684
+ if (inspectSessionAttemptActivity) {
685
+ try {
686
+ ownerActivityState = await inspectSessionAttemptActivity(peek.activityRef);
687
+ } catch (error) {
688
+ if (error instanceof CancelledFailure) throw error;
689
+ if (currentActivityContext()?.cancellationSignal.aborted)
690
+ throw new CancelledFailure("Control observation cancelled");
691
+ // This optional metadata observation grants no recovery authority.
692
+ // An unavailable inspector must not pin the control activity in
693
+ // retries and prevent a fresh Pause/owner/visibility observation.
694
+ // Database reads below remain outside this catch and retry normally.
695
+ }
696
+ }
697
+ if (currentActivityContext()?.cancellationSignal.aborted)
698
+ throw new CancelledFailure("Control observation cancelled");
699
+ const current = await peekSessionWorkFn(
700
+ db,
701
+ input.workspaceId,
702
+ input.sessionId,
703
+ input.includeAdmissionFence,
704
+ observerAccountId,
705
+ );
706
+ if (
707
+ current.kind !== "attempt-owned" ||
708
+ current.turnId !== peek.turnId ||
709
+ current.attemptId !== peek.attemptId ||
710
+ current.executionGeneration !== peek.executionGeneration ||
711
+ current.activityRef.workflowId !== peek.activityRef.workflowId ||
712
+ current.activityRef.workflowRunId !== peek.activityRef.workflowRunId ||
713
+ current.activityRef.activityId !== peek.activityRef.activityId
714
+ )
715
+ return current;
716
+ return { ...current, ownerActivityState };
717
+ }
493
718
  await refreshQueuedTurnsGauge(db, observability, countQueuedTurnsFn, recordTurnsQueuedGaugeFn);
494
719
  return peek;
495
720
  }
@@ -530,6 +755,18 @@ export function createSessionStateActivities(
530
755
  return { action: result.action };
531
756
  }
532
757
 
758
+ /** A scheduled run's approval timeout answers for its unanswered human wait. */
759
+ async function expireScheduledRunHumanWait(
760
+ input: ExpireScheduledRunHumanWaitInput,
761
+ ): Promise<ExpireScheduledRunHumanWaitResult> {
762
+ const { db, bus } = await services();
763
+ const result = await expireScheduledRunHumanWaitFn(db, input);
764
+ if (result.events.length > 0) {
765
+ await publishDurableSessionEventsFn(bus, input.workspaceId, input.sessionId, result.events);
766
+ }
767
+ return { action: result.action };
768
+ }
769
+
533
770
  async function markSessionIdle(input: MarkSessionIdleInput): Promise<void> {
534
771
  const { db, bus, settings, observability, wakeSessionWorkflow } = await services();
535
772
  const settled = await settleSessionIdleWithParentOutboxFn(
@@ -560,12 +797,14 @@ export function createSessionStateActivities(
560
797
  settleSessionInterruptions,
561
798
  persistSessionAttemptQuiescence,
562
799
  reconcileSessionAttemptQuiescence: reconcileSessionAttemptQuiescenceActivity,
800
+ reconcileSettledSessionAttempt: reconcileSettledSessionAttemptActivity,
563
801
  recoverDispatch,
564
802
  recoverEscapedMcpTimeout,
565
803
  peekSessionWork,
566
804
  settleSessionInputWait,
567
805
  expireSessionHumanInput,
568
806
  expireSessionInteractionIntervention,
807
+ expireScheduledRunHumanWait,
569
808
  markSessionIdle,
570
809
  };
571
810
  }
@@ -174,6 +174,9 @@ async function dispatchMaintenanceSession(
174
174
  accountId: maintenance.accountId,
175
175
  workspaceId: maintenance.workspaceId,
176
176
  initialMessage: maintenancePrompt(maintenance),
177
+ // OpenGeni's own periodic check: no human or product surface entered it.
178
+ surface: "system",
179
+ metrics: service.observability,
177
180
  resources: [],
178
181
  tools: [{ kind: "mcp", id: "opengeni" }],
179
182
  toolPolicy: { mode: "explicit", inheritedFromSessionId: null },
@@ -7,7 +7,11 @@ import type {
7
7
  ScheduledTaskTriggerType,
8
8
  TurnInitiator,
9
9
  } from "@opengeni/contracts";
10
- import type { Database, SessionWorkflowWakeDeliveryResult } from "@opengeni/db";
10
+ import type {
11
+ Database,
12
+ SessionWorkflowWakeDeliveryResult,
13
+ SessionAdmissionFence,
14
+ } from "@opengeni/db";
11
15
  import type { DocumentServices } from "@opengeni/documents";
12
16
  import type { EventBus } from "@opengeni/events";
13
17
  import type { Observability } from "@opengeni/observability";
@@ -140,6 +144,11 @@ export type ControlActivityServices = SharedActivityServices;
140
144
 
141
145
  /** Turn workers own the model loop and never construct document parsers. */
142
146
  export type TurnActivityServices = SharedActivityServices & {
147
+ /** Host-owned containment: stop polling and checkpoint peer turns before exit.
148
+ * Bare activity embedders must provide their own worker lifecycle edge. */
149
+ requestWorkerDrain: () => void;
150
+ /** Deterministic test clock for the cleanup-only monitor. */
151
+ turnFinalizationTimeoutMs?: number | undefined;
143
152
  runtime: OpenGeniRuntime;
144
153
  /** Provider-free test/profiling seam; production injects the real runtime summarizer. */
145
154
  summarizeContextForCompaction: typeof import("@opengeni/runtime").summarizeForCompaction;
@@ -153,7 +162,7 @@ export type ActivityServices = ControlActivityServices &
153
162
 
154
163
  export type CodexCapacityWaitRef = {
155
164
  /** Absent only for Temporal histories written before provider-tagged waits. */
156
- provider?: "codex" | "xai";
165
+ provider?: "codex" | "xai" | "claude";
157
166
  waiterId: string;
158
167
  generation: number;
159
168
  nextCheckAt: string;
@@ -175,7 +184,7 @@ export type ReconcileCodexCapacityWaitInput = {
175
184
  generation: number;
176
185
  cause: "timer" | "signal" | "queue" | "recovery";
177
186
  /** Absent only for Codex waits and pre-provider-tagged workflow histories. */
178
- provider?: "codex" | "xai";
187
+ provider?: "codex" | "xai" | "claude";
179
188
  };
180
189
 
181
190
  export type ReconcileCodexCapacityWaitResult =
@@ -235,6 +244,22 @@ export type ReconcileSessionAttemptQuiescenceResult = {
235
244
  action: "quiesced" | "pending" | "stale";
236
245
  };
237
246
 
247
+ export type ReconcileSettledSessionAttemptInput = {
248
+ accountId: string;
249
+ workspaceId: string;
250
+ sessionId: string;
251
+ turnId: string;
252
+ attemptId: string;
253
+ executionGeneration: number;
254
+ workflowId: string;
255
+ workflowRunId: string;
256
+ activityId: string;
257
+ };
258
+
259
+ export type ReconcileSettledSessionAttemptResult = {
260
+ action: "recovering" | "exceeded" | "pending" | "stale";
261
+ };
262
+
238
263
  export type FailSessionAttemptInput = {
239
264
  accountId: string;
240
265
  workspaceId: string;
@@ -252,6 +277,7 @@ export type FailSessionAttemptInput = {
252
277
  * committed claim discovered by the control lane can recover the exact
253
278
  * attempt instead of terminally failing it. */
254
279
  preClaimFailure?: PreClaimFailureDetail;
280
+ admissionFence?: SessionAdmissionFence;
255
281
  /** Added in v4. A claimed attempt that lost operational database access
256
282
  * before turn-start completion carries its exact immutable turn identity so
257
283
  * the DB-only control lane can recover it instead of terminally failing it. */
@@ -263,17 +289,24 @@ export type FailSessionAttemptInput = {
263
289
  };
264
290
 
265
291
  export type FailSessionAttemptResult =
292
+ | { action: "blocked" }
266
293
  | { action: "failed" }
267
294
  | { action: "recovering" }
268
295
  | { action: "unclaimed" }
269
296
  | { action: "terminal" }
270
297
  | { action: "stale" };
271
298
 
272
- export type PreClaimFailureDisposition = "retryable" | "permanent";
299
+ export type PreClaimFailureDisposition = "retryable" | "permanent" | "blocked";
273
300
 
274
301
  export type PreClaimFailureDetail = {
275
302
  disposition: PreClaimFailureDisposition;
276
303
  code: "db_deadlock" | "db_serialization_failure" | "db_failure" | "claim_invariant";
304
+ sqlState?: string | null;
305
+ reason?:
306
+ | "database_claim_rejected"
307
+ | "initiator_membership_required"
308
+ | "personal_resource_grant_required";
309
+ retryPolicy?: "explicit_recheck";
277
310
  };
278
311
 
279
312
  export const PRE_CLAIM_FAILURE_TYPE = "OpenGeniPreClaimFailure";
@@ -290,6 +323,10 @@ export type PostClaimDatabaseRecoveryDetail = {
290
323
  providerRecoveryCount?: number;
291
324
  /** Safe classified provider cause paired with providerRecoveryCount. */
292
325
  providerFailureCode?: string;
326
+ /** Persist the no-replay setup marker, not a new provider/setup attempt. */
327
+ sandboxSetupOutcomeUnknown?: true;
328
+ /** Preserve the exhausted budget for a command proven not dispatched. */
329
+ sandboxSetupRecoveryExhausted?: true;
293
330
  };
294
331
 
295
332
  export const POST_CLAIM_DATABASE_RECOVERY_FAILURE_TYPE = "OpenGeniPostClaimDatabaseRecovery";
@@ -344,6 +381,9 @@ export type RecoverEscapedMcpTimeoutResult = {
344
381
  export type PeekSessionWorkInput = {
345
382
  workspaceId: string;
346
383
  sessionId: string;
384
+ includeAdmissionFence?: boolean;
385
+ /** Versioned workflow observer opt-in, never a caller authorization grant. */
386
+ observerAccountId?: string;
347
387
  };
348
388
 
349
389
  export type SettleSessionInputWaitInput = {
@@ -380,6 +420,18 @@ export type ExpireSessionInteractionInterventionResult = {
380
420
  action: "expired" | "stale" | "not_found";
381
421
  };
382
422
 
423
+ export type ExpireScheduledRunHumanWaitInput = {
424
+ accountId: string;
425
+ workspaceId: string;
426
+ sessionId: string;
427
+ turnId: string;
428
+ runId: string;
429
+ };
430
+
431
+ export type ExpireScheduledRunHumanWaitResult = {
432
+ action: "expired" | "stale" | "not_found";
433
+ };
434
+
383
435
  export type MarkSessionIdleInput = {
384
436
  workspaceId: string;
385
437
  sessionId: string;
@@ -409,6 +461,7 @@ export type DispatchScheduledTaskRunInput = {
409
461
  triggerType: Extract<ScheduledTaskTriggerType, "scheduled">;
410
462
  agentRunUsageIdempotencyKey?: never;
411
463
  initiator?: never;
464
+ credentialRestriction?: never;
412
465
  }
413
466
  | {
414
467
  triggerType: Extract<
@@ -418,6 +471,8 @@ export type DispatchScheduledTaskRunInput = {
418
471
  agentRunUsageIdempotencyKey: string;
419
472
  /** Exact identity used by the API-side charge for this same trigger. */
420
473
  initiator: TurnInitiator;
474
+ /** Trusted API-side caller ceiling for this occurrence, not the schedule. */
475
+ credentialRestriction?: "developer_setup";
421
476
  }
422
477
  );
423
478
 
@@ -425,8 +480,13 @@ export type DispatchScheduledTaskRunResult =
425
480
  | { action: "deleted" }
426
481
  | {
427
482
  action: "blocked";
483
+ runId?: string;
484
+ diagnostic?: import("@opengeni/contracts").ConnectionAccountSelectionDiagnostic;
485
+ /** Present when the occurrence was refused as a visible run receipt. */
486
+ refusal?: import("@opengeni/contracts").ScheduledTaskAdmissionRefusal;
428
487
  reason:
429
488
  | "insufficient_credits"
489
+ | "allowance_exhausted"
430
490
  | "monthly_model_cost_limit"
431
491
  | "monthly_agent_run_limit"
432
492
  | "malformed_manual_trigger"
@@ -434,8 +494,15 @@ export type DispatchScheduledTaskRunResult =
434
494
  | "scheduled_authority_exhausted"
435
495
  | "scheduled_run_terminal"
436
496
  | "scheduled_execution_unrepresentable"
497
+ | "connection_account_unavailable"
498
+ | "scheduled_authority_unavailable"
499
+ | "machine_target_unavailable"
500
+ | "machine_enrollment_inactive"
501
+ | "variable_set_unavailable"
502
+ | "rig_version_unavailable"
437
503
  | "knowledge_source_paused"
438
504
  | "legacy_source_schedule_requires_migration"
505
+ | "atlassian_native_retired"
439
506
  | "incident_preflight_metadata_missing"
440
507
  | "incident_responder_under_capable"
441
508
  | "incident_data_source_unsuitable";
@@ -552,5 +619,5 @@ export type RunAgentTurnResult =
552
619
  | ClaimedRunAgentTurnResult
553
620
  | {
554
621
  status: "unclaimed";
555
- reason: "gate-closed" | "no-work" | "stale-approval" | "control-pending";
622
+ reason: "gate-closed" | "no-work" | "stale-approval" | "control-pending" | "dispatch-expired";
556
623
  };
@@ -6,6 +6,7 @@ import {
6
6
  type Database,
7
7
  } from "@opengeni/db";
8
8
  import { publishDurableWorkspaceControlEvent } from "@opengeni/events";
9
+ import { recordWorkflowWakeReconciliation } from "@opengeni/observability";
9
10
  import type { ControlActivityServices } from "./types";
10
11
  import {
11
12
  reconcileAutomaticSessionTitleFanout,
@@ -115,23 +116,7 @@ export function createWorkflowWakeActivities(services: () => Promise<ControlActi
115
116
  pendingAdmissionBlockers,
116
117
  exhaustedBatchLimit,
117
118
  };
118
- if (claimed > 0) {
119
- service.observability.info("session workflow wake delivery reconciled", {
120
- claimed,
121
- signaled,
122
- delivered,
123
- pendingAdmission,
124
- unconfirmed,
125
- failed,
126
- exhaustedBatchLimit,
127
- ...Object.fromEntries(
128
- Object.entries(pendingAdmissionBlockers).map(([blocker, count]) => [
129
- `pendingAdmissionBlockers.${blocker}`,
130
- count,
131
- ]),
132
- ),
133
- });
134
- }
119
+ recordWorkflowWakeReconciliation(service.observability, result);
135
120
  return result;
136
121
  },
137
122
  };
@@ -947,13 +947,24 @@ async function runCapture(
947
947
  }
948
948
 
949
949
  // ── 10. observe completion ────────────────────────────────────────────────
950
- const durationMs = Date.now() - startedAt;
950
+ recordWorkspaceCaptureCompleted(observability, Date.now() - startedAt);
951
+ }
952
+
953
+ /** Count one committed logical capture and observe its end-to-end duration. */
954
+ export function recordWorkspaceCaptureCompleted(
955
+ observability: Pick<Observability, "incrementCounter" | "observeHistogram">,
956
+ durationMs: number,
957
+ ): void {
951
958
  observability.incrementCounter({
952
959
  name: "opengeni_workspace_capture_total",
953
960
  labels: { result: "ok" },
954
961
  });
962
+ // Distinct from the physical `opengeni_workspace_capture_duration_seconds`
963
+ // {backend,outcome} histogram the runtime hook records in this same
964
+ // registry: one name cannot carry two label sets.
955
965
  observability.observeHistogram({
956
- name: "opengeni_workspace_capture_duration_seconds",
966
+ name: "opengeni_workspace_capture_revision_duration_seconds",
967
+ help: "Turn-end logical workspace revision capture duration for committed revisions.",
957
968
  value: durationMs / 1000,
958
969
  });
959
970
  }