@fitlab-ai/agent-infra 0.9.5 → 0.9.7

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 (172) hide show
  1. package/dist/bin/internal-cli.js +8 -3
  2. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +171 -20
  3. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +162 -0
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +244 -0
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +14 -2
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +370 -0
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +68 -8
  8. package/dist/lib/agent-clients/adapters/codex.js +1 -1
  9. package/dist/lib/defaults.json +10 -2
  10. package/dist/lib/git/workflow.js +30 -4
  11. package/dist/lib/internal/codex-lifecycle.js +169 -3
  12. package/dist/lib/internal/codex-sandbox-controller.js +106 -0
  13. package/dist/lib/internal/release-workflow.js +108 -11
  14. package/dist/lib/internal/sandbox-control.js +43 -6
  15. package/dist/lib/internal/task-create.js +12 -4
  16. package/dist/lib/internal/task-orchestration.js +40 -7
  17. package/dist/lib/platform/context.js +6 -4
  18. package/dist/lib/platform/github-client.js +55 -2
  19. package/dist/lib/platform/issue-comments.js +2 -1
  20. package/dist/lib/process-data/checkpoint.js +319 -0
  21. package/dist/lib/process-data/index.js +128 -60
  22. package/dist/lib/process-data/materialize.js +84 -0
  23. package/dist/lib/process-data/normalize.js +34 -1
  24. package/dist/lib/process-data/reconcile.js +55 -1
  25. package/dist/lib/process-data/sources.js +422 -1
  26. package/dist/lib/process-data/store.js +341 -11
  27. package/dist/lib/release/workflow.js +29 -21
  28. package/dist/lib/sandbox/commands/create.js +111 -60
  29. package/dist/lib/sandbox/commands/prune.js +40 -16
  30. package/dist/lib/sandbox/commands/rm.js +372 -94
  31. package/dist/lib/sandbox/commands/start.js +4 -3
  32. package/dist/lib/sandbox/control/client.js +138 -22
  33. package/dist/lib/sandbox/control/container-identity.js +64 -0
  34. package/dist/lib/sandbox/control/executor.js +142 -0
  35. package/dist/lib/sandbox/control/lifecycle.js +557 -0
  36. package/dist/lib/sandbox/control/protocol.js +69 -26
  37. package/dist/lib/sandbox/control/server.js +395 -99
  38. package/dist/lib/sandbox/control/state.js +191 -0
  39. package/dist/lib/sandbox/control/timing.js +8 -0
  40. package/dist/lib/sandbox/index.js +2 -2
  41. package/dist/lib/sandbox/managed-fs.js +14 -2
  42. package/dist/lib/sandbox/mounts.js +22 -19
  43. package/dist/lib/sandbox/recovery.js +284 -50
  44. package/dist/lib/sandbox/workspace-view.js +90 -10
  45. package/dist/lib/sandbox/worktree-safety.js +196 -0
  46. package/dist/lib/server/daemon.js +1 -1
  47. package/dist/lib/server/process-control.js +17 -1
  48. package/dist/lib/server/process-state.js +57 -20
  49. package/dist/lib/task/artifact-lifecycle.js +87 -15
  50. package/dist/lib/task/artifact-receipts.js +128 -0
  51. package/dist/lib/task/codex-orchestration.js +236 -0
  52. package/dist/lib/task/commands/status.js +3 -0
  53. package/dist/lib/task/commands/validate.js +289 -0
  54. package/dist/lib/task/commit-finalization.js +36 -9
  55. package/dist/lib/task/create.js +10 -2
  56. package/dist/lib/task/delegation-receipts.js +109 -2
  57. package/dist/lib/task/events.js +149 -6
  58. package/dist/lib/task/finalization-artifacts.js +2 -1
  59. package/dist/lib/task/implementation-inputs.js +1 -7
  60. package/dist/lib/task/index.js +9 -0
  61. package/dist/lib/task/ledger.js +13 -1
  62. package/dist/lib/task/orchestration.js +365 -15
  63. package/dist/lib/task/sections.js +5 -1
  64. package/dist/lib/task/task-execution-lock.js +5 -4
  65. package/dist/lib/task/verification-engine.js +78 -14
  66. package/dist/lib/task/verification.js +1 -0
  67. package/dist/lifecycle-build-manifest.json +6 -0
  68. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +202 -18
  69. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +227 -0
  70. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +321 -0
  71. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +19 -3
  72. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +26 -0
  73. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +453 -0
  74. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +83 -6
  75. package/lib/agent-clients/adapters/codex.ts +1 -1
  76. package/lib/defaults.json +10 -2
  77. package/lib/git/workflow.ts +25 -3
  78. package/lib/internal/codex-lifecycle.ts +175 -4
  79. package/lib/internal/codex-sandbox-controller.ts +109 -0
  80. package/lib/internal/release-workflow.ts +107 -11
  81. package/lib/internal/sandbox-control.ts +38 -6
  82. package/lib/internal/task-create.ts +16 -4
  83. package/lib/internal/task-orchestration.ts +34 -7
  84. package/lib/platform/context.ts +8 -5
  85. package/lib/platform/github-client.ts +61 -3
  86. package/lib/platform/issue-comments.ts +2 -1
  87. package/lib/process-data/checkpoint.ts +335 -0
  88. package/lib/process-data/index.ts +112 -60
  89. package/lib/process-data/materialize.ts +83 -0
  90. package/lib/process-data/normalize.ts +29 -1
  91. package/lib/process-data/reconcile.ts +64 -2
  92. package/lib/process-data/sources.ts +449 -2
  93. package/lib/process-data/store.ts +304 -11
  94. package/lib/process-data/types.ts +124 -2
  95. package/lib/release/workflow.ts +69 -20
  96. package/lib/sandbox/commands/create.ts +70 -25
  97. package/lib/sandbox/commands/prune.ts +53 -15
  98. package/lib/sandbox/commands/rm.ts +423 -108
  99. package/lib/sandbox/commands/start.ts +4 -3
  100. package/lib/sandbox/control/client.ts +152 -28
  101. package/lib/sandbox/control/container-identity.ts +93 -0
  102. package/lib/sandbox/control/executor.ts +167 -0
  103. package/lib/sandbox/control/lifecycle.ts +573 -0
  104. package/lib/sandbox/control/protocol.ts +121 -68
  105. package/lib/sandbox/control/server.ts +398 -109
  106. package/lib/sandbox/control/state.ts +213 -0
  107. package/lib/sandbox/control/timing.ts +12 -0
  108. package/lib/sandbox/index.ts +2 -2
  109. package/lib/sandbox/managed-fs.ts +17 -2
  110. package/lib/sandbox/mounts.ts +16 -8
  111. package/lib/sandbox/recovery.ts +335 -65
  112. package/lib/sandbox/workspace-view.ts +102 -11
  113. package/lib/sandbox/worktree-safety.ts +234 -0
  114. package/lib/server/daemon.ts +1 -1
  115. package/lib/server/process-control.ts +24 -3
  116. package/lib/server/process-state.ts +82 -27
  117. package/lib/task/artifact-lifecycle.ts +78 -14
  118. package/lib/task/artifact-receipts.ts +161 -0
  119. package/lib/task/codex-orchestration.ts +319 -0
  120. package/lib/task/commands/status.ts +2 -0
  121. package/lib/task/commands/validate.ts +282 -0
  122. package/lib/task/commit-finalization.ts +52 -9
  123. package/lib/task/create.ts +11 -2
  124. package/lib/task/delegation-receipts.ts +208 -7
  125. package/lib/task/events.ts +131 -5
  126. package/lib/task/finalization-artifacts.ts +2 -1
  127. package/lib/task/implementation-inputs.ts +1 -5
  128. package/lib/task/index.ts +8 -0
  129. package/lib/task/ledger.ts +16 -1
  130. package/lib/task/orchestration.ts +552 -18
  131. package/lib/task/sections.ts +6 -2
  132. package/lib/task/task-execution-lock.ts +11 -9
  133. package/lib/task/verification-engine.ts +93 -24
  134. package/lib/task/verification.ts +2 -1
  135. package/package.json +1 -1
  136. package/templates/.agents/README.en.md +7 -0
  137. package/templates/.agents/README.zh-CN.md +5 -0
  138. package/templates/.agents/hooks/lifecycle-delegation.js +72 -12
  139. package/templates/.agents/rules/lifecycle-orchestration.en.md +8 -2
  140. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +8 -2
  141. package/templates/.agents/rules/no-mid-flow-questions.en.md +1 -0
  142. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +1 -0
  143. package/templates/.agents/rules/pr-checks-commands.github.en.md +1 -1
  144. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +1 -1
  145. package/templates/.agents/rules/review-handshake.en.md +3 -1
  146. package/templates/.agents/rules/review-handshake.zh-CN.md +3 -1
  147. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +3 -1
  148. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +3 -1
  149. package/templates/.agents/skills/complete-task/SKILL.en.md +4 -0
  150. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +4 -0
  151. package/templates/.agents/skills/post-release/SKILL.en.md +32 -6
  152. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +32 -6
  153. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +42 -0
  154. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +42 -0
  155. package/templates/.agents/skills/run-manual-validation/config/verify.en.json +25 -0
  156. package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +25 -0
  157. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +67 -0
  158. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +67 -0
  159. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +69 -0
  160. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +69 -0
  161. package/templates/.agents/skills/run-task/SKILL.en.md +9 -7
  162. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +9 -7
  163. package/templates/.agents/skills/run-task/reference/host-validation.en.md +5 -3
  164. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +5 -3
  165. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +75 -3
  166. package/templates/.claude/commands/run-manual-validation.en.md +9 -0
  167. package/templates/.claude/commands/run-manual-validation.zh-CN.md +9 -0
  168. package/templates/.codex/hooks.json +8 -8
  169. package/templates/.opencode/commands/run-manual-validation.en.md +11 -0
  170. package/templates/.opencode/commands/run-manual-validation.zh-CN.md +11 -0
  171. package/templates/.agents/workspace/README.en.md +0 -26
  172. package/templates/.agents/workspace/README.zh-CN.md +0 -26
@@ -7,7 +7,7 @@ import { parseReviewSummary } from './review-artifacts.js';
7
7
  import { inspectArtifactDirectory } from './artifact-lifecycle.js';
8
8
  import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
9
9
  import { resolveTaskRef } from './resolve-ref.js';
10
- import { activateDelegation, completeDelegationStage, consumeDelegation, managedDelegationRole, prepareDelegation, sealDelegation } from './delegation-receipts.js';
10
+ import { activateDelegation, abortPreparedDelegation, completeDelegationStage, consumeDelegation, dispatchDelegation, managedDelegationRole, prepareDelegation, sealDelegation } from './delegation-receipts.js';
11
11
  import { normalizeAgentClients } from '../agent-clients/config.js';
12
12
  import { inspectPlatformPullRequest } from '../platform/pull-requests.js';
13
13
  import { getAgentClientCapability, getAgentClientDelegationEvidence, getAgentClientModelSelection } from '../agent-clients/registry.js';
@@ -15,6 +15,7 @@ import { isAgentClientId } from '../agent-clients/types.js';
15
15
  import { captureRepositorySnapshot, captureWorkspaceSnapshot, diffWorkspaceSnapshots } from './workspace-snapshot.js';
16
16
  import { assertGitRepositoryBinding } from '../git/worktree-identity.js';
17
17
  import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
18
+ import { hasActiveCodexLifecycleEvidence } from '../agent-clients/adapters/codex-lifecycle/store.js';
18
19
  import { CommitIntentError, commitIntentPath, createCommitIntent, digest, readCommitIntent, removeCommitIntent, removeCommitIntentByDigest, serialize, updateCommitIntent } from './commit-intent.js';
19
20
  import { inspectCommitFinalization, planCommitTaskFinalization } from './commit-finalization.js';
20
21
  import { captureTaskWriteMetadata, writeTask } from './write.js';
@@ -33,7 +34,7 @@ function readRun(taskDir) {
33
34
  if (!fs.existsSync(file))
34
35
  return null;
35
36
  const run = JSON.parse(fs.readFileSync(file, 'utf8'));
36
- if (run.schemaVersion !== 2 || !isV2Policy(run.modelPolicy))
37
+ if (![2, 3].includes(run.schemaVersion) || !isV2Policy(run.modelPolicy))
37
38
  return run;
38
39
  return {
39
40
  ...run,
@@ -110,7 +111,7 @@ function commitFinalizationView(inspection) {
110
111
  }
111
112
  function validCommitRun(run, taskId) {
112
113
  return run !== null
113
- && [1, 2].includes(run.schemaVersion)
114
+ && [1, 2, 3].includes(run.schemaVersion)
114
115
  && run.taskId === taskId
115
116
  && ['running', 'paused', 'completed'].includes(run.status)
116
117
  && Array.isArray(run.receipts)
@@ -159,6 +160,36 @@ function resolveProjectPolicy(repoRoot, client) {
159
160
  const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
160
161
  return normalizeAgentClients(raw).state[client].orchestration;
161
162
  }
163
+ function canRecoverCodexUnsupportedPause(run, taskDir) {
164
+ return run.schemaVersion === 2
165
+ && run.status === 'paused'
166
+ && run.pause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED'
167
+ && run.modelPolicySource?.client === 'codex'
168
+ && run.stepCount === 0
169
+ && run.nextStage === null
170
+ && run.baseline === ''
171
+ && run.pendingDelegation === null
172
+ && run.receipts.length === 0
173
+ && run.commitAuthorization?.issuedAt === null
174
+ && run.commitAuthorization?.consumedAt === null
175
+ && run.completionEvidence == null
176
+ && !fs.existsSync(commitIntentPath(taskDir))
177
+ && (run.recoveryHistory ?? []).every((entry) => entry.code === 'MODEL_POLICY_SUPPLEMENTED');
178
+ }
179
+ function canMigrateRecoverableV2Pause(run, taskDir) {
180
+ return run.schemaVersion === 2
181
+ && run.status === 'paused'
182
+ && run.pause?.recoverable === true
183
+ && run.stepCount === 0
184
+ && run.nextStage === null
185
+ && run.baseline === ''
186
+ && run.pendingDelegation === null
187
+ && run.receipts.length === 0
188
+ && run.commitAuthorization?.issuedAt === null
189
+ && run.commitAuthorization?.consumedAt === null
190
+ && run.completionEvidence == null
191
+ && !fs.existsSync(commitIntentPath(taskDir));
192
+ }
162
193
  function beginOrResumeOrchestration(taskRef, options = {}) {
163
194
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
164
195
  if (!resolved.ok)
@@ -174,7 +205,7 @@ function beginOrResumeOrchestration(taskRef, options = {}) {
174
205
  return failed('ORCHESTRATION_STATE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
175
206
  }
176
207
  if (existing) {
177
- if (![1, 2].includes(existing.schemaVersion)
208
+ if (![1, 2, 3].includes(existing.schemaVersion)
178
209
  || !Array.isArray(existing.receipts)
179
210
  || !Object.prototype.hasOwnProperty.call(existing, 'pendingDelegation')) {
180
211
  return failed('ORCHESTRATION_STATE_INVALID', 'orchestration state has an invalid schema', resolved.taskId);
@@ -182,17 +213,20 @@ function beginOrResumeOrchestration(taskRef, options = {}) {
182
213
  if (existing.status === 'completed' && existing.schemaVersion === 1) {
183
214
  return { status: 'completed', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
184
215
  }
185
- if (existing.schemaVersion === 2) {
216
+ if (existing.schemaVersion === 2 || existing.schemaVersion === 3) {
186
217
  const policyError = validateModelPolicy(isV2Policy(existing.modelPolicy) ? existing.modelPolicy : undefined);
187
218
  if (policyError
188
219
  || !existing.modelPolicySource
189
220
  || !isAgentClientId(existing.modelPolicySource.client)
190
221
  || !Array.isArray(existing.recoveryHistory)) {
191
- return failed('ORCHESTRATION_STATE_INVALID', 'schemaVersion 2 orchestration state is incomplete', resolved.taskId);
222
+ return failed('ORCHESTRATION_STATE_INVALID', `schemaVersion ${existing.schemaVersion} orchestration state is incomplete`, resolved.taskId);
192
223
  }
193
224
  if (existing.status === 'completed') {
194
225
  return { status: 'completed', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
195
226
  }
227
+ if (existing.schemaVersion === 2 && existing.status === 'running') {
228
+ return failed('ORCHESTRATION_STATE_INVALID', 'active schemaVersion 2 runs cannot be advanced by lifecycle protocol v3', resolved.taskId);
229
+ }
196
230
  if (existing.modelPolicySource.client !== options.client) {
197
231
  return failed('ORCHESTRATION_CLIENT_MISMATCH', 'provided client does not match the persisted run policy source', resolved.taskId);
198
232
  }
@@ -204,8 +238,77 @@ function beginOrResumeOrchestration(taskRef, options = {}) {
204
238
  return failed('ORCHESTRATION_MODEL_POLICY_MISMATCH', 'provided model policy does not match the persisted run policy', resolved.taskId);
205
239
  }
206
240
  }
241
+ if (existing.status === 'paused' && existing.pause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED') {
242
+ if (!canRecoverCodexUnsupportedPause(existing, resolved.taskDir)) {
243
+ return { status: 'paused', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
244
+ }
245
+ const now = (options.now ?? (() => new Date().toISOString()))();
246
+ const previousPause = existing.pause;
247
+ const recovery = {
248
+ code: 'CLIENT_CAPABILITY_ENABLED',
249
+ recoveredAt: now,
250
+ previousSchemaVersion: 2,
251
+ previousStatus: 'paused',
252
+ previousPause,
253
+ client: 'codex',
254
+ guards: {
255
+ stepCount: 0,
256
+ nextStage: null,
257
+ baselineEmpty: true,
258
+ receiptCount: 0,
259
+ pendingDelegation: false,
260
+ commitAuthorizationUnused: true,
261
+ completionEvidenceAbsent: true,
262
+ commitIntentAbsent: true
263
+ },
264
+ resultingStatus: 'running'
265
+ };
266
+ const resumed = withUpdatedRun(existing, {
267
+ schemaVersion: 3,
268
+ status: 'running',
269
+ pause: null,
270
+ recoveryHistory: Object.freeze([...(existing.recoveryHistory ?? []), recovery])
271
+ }, () => now);
272
+ saveRun(resolved.taskDir, resumed);
273
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
274
+ }
207
275
  if (existing.status === 'paused' && existing.pause?.recoverable && existing.pendingDelegation === null) {
208
- const resumed = withUpdatedRun(existing, { status: 'running', pause: null });
276
+ if (existing.schemaVersion === 2 && !canMigrateRecoverableV2Pause(existing, resolved.taskDir)) {
277
+ const paused = withUpdatedRun(existing, {
278
+ pause: {
279
+ code: 'ORCHESTRATION_SCHEMA_MIGRATION_REQUIRED',
280
+ message: 'schemaVersion 2 recoverable pause contains execution evidence and cannot migrate automatically',
281
+ recoverable: false
282
+ }
283
+ });
284
+ saveRun(resolved.taskDir, paused);
285
+ return { status: 'paused', changed: true, taskId: resolved.taskId, run: paused, next: null, error: null };
286
+ }
287
+ const now = (options.now ?? (() => new Date().toISOString()))();
288
+ const recovery = existing.schemaVersion === 2 ? {
289
+ code: 'SCHEMA_V3_MIGRATED',
290
+ recoveredAt: now,
291
+ previousSchemaVersion: 2,
292
+ previousStatus: 'paused',
293
+ previousPause: existing.pause,
294
+ guards: {
295
+ stepCount: 0,
296
+ nextStage: null,
297
+ baselineEmpty: true,
298
+ receiptCount: 0,
299
+ pendingDelegation: false,
300
+ commitAuthorizationUnused: true,
301
+ completionEvidenceAbsent: true,
302
+ commitIntentAbsent: true
303
+ },
304
+ resultingStatus: 'running'
305
+ } : null;
306
+ const resumed = withUpdatedRun(existing, {
307
+ schemaVersion: 3,
308
+ status: 'running',
309
+ pause: null,
310
+ ...(recovery ? { recoveryHistory: Object.freeze([...(existing.recoveryHistory ?? []), recovery]) } : {})
311
+ }, () => now);
209
312
  saveRun(resolved.taskDir, resumed);
210
313
  return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
211
314
  }
@@ -279,7 +382,7 @@ function beginOrResumeOrchestration(taskRef, options = {}) {
279
382
  };
280
383
  const recovered = Object.freeze({
281
384
  ...existing,
282
- schemaVersion: 2,
385
+ schemaVersion: 3,
283
386
  status: resultingStatus,
284
387
  modelPolicy: policy,
285
388
  modelPolicySource: source,
@@ -311,7 +414,7 @@ function beginOrResumeOrchestration(taskRef, options = {}) {
311
414
  const now = (options.now ?? (() => new Date().toISOString()))();
312
415
  const source = { kind: sourceKind, client: options.client, resolvedAt: now };
313
416
  const run = {
314
- schemaVersion: 2,
417
+ schemaVersion: 3,
315
418
  taskId: resolved.taskId,
316
419
  runId: (options.id ?? randomUUID)(),
317
420
  status: 'running',
@@ -976,6 +1079,9 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
976
1079
  const run = readRun(resolved.taskDir);
977
1080
  if (!run || run.status !== 'running')
978
1081
  return failed('ORCHESTRATION_RUN_NOT_RUNNING', 'a running orchestration is required', resolved.taskId);
1082
+ if (run.schemaVersion !== 3) {
1083
+ return failed('ORCHESTRATION_STATE_INVALID', 'delegation preparation requires orchestration schemaVersion 3', resolved.taskId);
1084
+ }
979
1085
  if (!isV2Policy(run.modelPolicy))
980
1086
  return failed('ORCHESTRATION_MODEL_EVIDENCE_MISSING', 'running orchestration has no persisted model policy', resolved.taskId);
981
1087
  if (run.pendingDelegation)
@@ -996,6 +1102,9 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
996
1102
  if (!validModel(input.requestedReasoningEffort)) {
997
1103
  return failed('ORCHESTRATION_REQUESTED_REASONING_EFFORT_REQUIRED', 'prepare requires the exact requested reasoning effort', resolved.taskId);
998
1104
  }
1105
+ if (input.client === 'codex' && !input.lifecycleProvenance) {
1106
+ return failed('ORCHESTRATION_CODEX_PROVENANCE_REQUIRED', 'Codex prepare requires lifecycle provenance', resolved.taskId);
1107
+ }
999
1108
  const expectedPolicy = run.modelPolicy[next.role];
1000
1109
  if (input.requestedModel !== expectedPolicy.model) {
1001
1110
  return failed('ORCHESTRATION_REQUESTED_MODEL_MISMATCH', `requested model does not match the persisted ${next.role} model`, resolved.taskId);
@@ -1025,8 +1134,9 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
1025
1134
  requestedModel: input.requestedModel,
1026
1135
  requestedReasoningEffort: input.requestedReasoningEffort,
1027
1136
  workspaceSnapshotScope: 'task',
1137
+ lifecycleProvenance: input.lifecycleProvenance ?? null,
1028
1138
  beforeFingerprint
1029
- }, { id: options.id, now: options.now });
1139
+ }, { id: options.id, now: options.now, monotonicNow: options.monotonicNow });
1030
1140
  const updated = withUpdatedRun(run, {
1031
1141
  nextStage: next.stage,
1032
1142
  pendingDelegation: receipt,
@@ -1050,6 +1160,39 @@ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
1050
1160
  throw error;
1051
1161
  }
1052
1162
  }
1163
+ function dispatchOrchestrationDelegationUnlocked(taskRef, options = {}) {
1164
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1165
+ if (!resolved.ok)
1166
+ return failed(resolved.code, resolved.message, resolved.taskId);
1167
+ const run = readRun(resolved.taskDir);
1168
+ if (!run?.pendingDelegation)
1169
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1170
+ if (run.schemaVersion !== 3 || run.status !== 'running') {
1171
+ return failed('ORCHESTRATION_STATE_INVALID', 'spawn dispatch requires a running schemaVersion 3 orchestration', resolved.taskId);
1172
+ }
1173
+ const result = dispatchDelegation(run.pendingDelegation, {
1174
+ now: options.now,
1175
+ monotonicNow: options.monotonicNow
1176
+ });
1177
+ if (!result.ok)
1178
+ return pauseOrchestration(taskRef, result.code, result.message, true, options);
1179
+ const updated = withUpdatedRun(run, { pendingDelegation: result.receipt });
1180
+ saveRun(resolved.taskDir, updated);
1181
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
1182
+ }
1183
+ function dispatchOrchestrationDelegation(taskRef, options = {}) {
1184
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1185
+ if (!resolved.ok)
1186
+ return failed(resolved.code, resolved.message, resolved.taskId);
1187
+ try {
1188
+ return withTaskExecutionLock(resolved.repoRoot, '__repository__', 'task-orchestration.dispatch.repository', () => withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.dispatch.task', () => dispatchOrchestrationDelegationUnlocked(taskRef, options)));
1189
+ }
1190
+ catch (error) {
1191
+ if (error instanceof TaskExecutionLockError)
1192
+ return failed(error.code, error.message, resolved.taskId);
1193
+ throw error;
1194
+ }
1195
+ }
1053
1196
  function matchingDelegations(predicate, options) {
1054
1197
  const repoRoot = options.repoRoot ?? process.cwd();
1055
1198
  const activeRoot = path.join(repoRoot, '.agents', 'workspace', 'active');
@@ -1059,7 +1202,7 @@ function matchingDelegations(predicate, options) {
1059
1202
  .filter((entry) => entry.isDirectory())
1060
1203
  .flatMap((entry) => {
1061
1204
  const run = readRun(path.join(activeRoot, entry.name));
1062
- if (!run?.pendingDelegation)
1205
+ if (run?.schemaVersion !== 3 || run.status !== 'running' || !run.pendingDelegation)
1063
1206
  return [];
1064
1207
  const receipt = run.pendingDelegation;
1065
1208
  return predicate(receipt)
@@ -1075,18 +1218,50 @@ function uniqueMatchingDelegation(client, predicate, options) {
1075
1218
  return failed('ORCHESTRATION_DELEGATION_AMBIGUOUS', 'multiple lifecycle delegations match the native hook event');
1076
1219
  return matches[0];
1077
1220
  }
1221
+ function hasActivatableOrchestrationDelegation(client, childId, options = {}) {
1222
+ return matchingDelegations((receipt) => receipt.client === client && (receipt.status === 'prepared'
1223
+ || (receipt.childId === childId && ['activated', 'stage-completed'].includes(receipt.status))), options).length > 0;
1224
+ }
1225
+ function hasSealableOrchestrationDelegation(client, childId, options = {}) {
1226
+ return matchingDelegations((receipt) => receipt.client === client
1227
+ && receipt.childId === childId
1228
+ && ['stage-completed', 'sealed'].includes(receipt.status), options).length > 0;
1229
+ }
1078
1230
  function activateMatchingOrchestrationDelegation(client, event, options = {}) {
1079
1231
  const role = managedDelegationRole(event.nativeAgent);
1080
1232
  if (!role)
1081
1233
  return failed('DELEGATION_IGNORED', `subagent '${event.nativeAgent}' is not lifecycle-managed`);
1082
1234
  const matched = uniqueMatchingDelegation(client, (receipt) => receipt.status === 'prepared', options);
1083
- if ('status' in matched)
1084
- return matched;
1235
+ if ('status' in matched) {
1236
+ if (matched.error?.code !== 'ORCHESTRATION_DELEGATION_MISSING')
1237
+ return matched;
1238
+ const replay = uniqueMatchingDelegation(client, (receipt) => receipt.childId === event.childId && ['activated', 'stage-completed'].includes(receipt.status), options);
1239
+ if ('status' in replay)
1240
+ return matched;
1241
+ const receipt = replay.run.pendingDelegation;
1242
+ const sameEvidence = receipt.parentId === event.parentId
1243
+ && receipt.spawnMode === event.spawnMode
1244
+ && receipt.actualModel === event.actualModel
1245
+ && receipt.actualReasoningEffort === event.actualReasoningEffort
1246
+ && receipt.modelFallbackReason === (event.modelFallbackReason ?? null)
1247
+ && receipt.reasoningEffortFallbackReason === (event.reasoningEffortFallbackReason ?? null)
1248
+ && receipt.hostEvidence?.hookDefinitionHash === event.hostEvidence?.hookDefinitionHash;
1249
+ if (!sameEvidence) {
1250
+ return pauseOrchestration(replay.taskId, 'DELEGATION_REPLAY_CONFLICT', 'replayed native start evidence conflicts with the active receipt', true, options);
1251
+ }
1252
+ return { status: replay.run.status, changed: false, taskId: replay.taskId, run: replay.run, next: null, error: null };
1253
+ }
1085
1254
  if (matched.run.receipts.some((receipt) => receipt.childId === event.childId)) {
1086
1255
  return pauseOrchestration(matched.taskId, 'DELEGATION_IDENTITY_REUSED', 'native child identity was already used by this run', true, options);
1087
1256
  }
1088
1257
  return activateOrchestrationDelegation(matched.taskId, event, options);
1089
1258
  }
1259
+ function pauseMatchingOrchestrationDelegation(client, code, message, options = {}) {
1260
+ const matched = uniqueMatchingDelegation(client, () => true, options);
1261
+ if ('status' in matched)
1262
+ return matched;
1263
+ return pauseOrchestration(matched.taskId, code, message, true, options);
1264
+ }
1090
1265
  function sealMatchingOrchestrationDelegation(client, event, options = {}) {
1091
1266
  const role = managedDelegationRole(event.nativeAgent);
1092
1267
  if (!role)
@@ -1119,6 +1294,63 @@ function sealMatchingOrchestrationDelegation(client, event, options = {}) {
1119
1294
  return pauseOrchestration(matched.taskId, 'ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), true, options);
1120
1295
  }
1121
1296
  }
1297
+ function sealMatchingOrchestrationDelegationWithHostEvidence(client, event, consumeEvidence, options = {}) {
1298
+ const role = managedDelegationRole(event.nativeAgent);
1299
+ if (!role)
1300
+ return failed('DELEGATION_IGNORED', `subagent '${event.nativeAgent}' is not lifecycle-managed`);
1301
+ const matched = uniqueMatchingDelegation(client, (receipt) => ((receipt.status === 'stage-completed' || receipt.status === 'sealed')
1302
+ && receipt.childId === event.childId), options);
1303
+ if ('status' in matched)
1304
+ return matched;
1305
+ const receipt = matched.run.pendingDelegation;
1306
+ if (receipt.status === 'sealed') {
1307
+ return reconcileMatchingOrchestrationDelegation(client, event.childId, options);
1308
+ }
1309
+ if (receipt.role !== role) {
1310
+ return pauseOrchestration(matched.taskId, 'DELEGATION_ROLE_MISMATCH', `managed role ${role} does not match ${receipt.role}`, true, options);
1311
+ }
1312
+ const repoRoot = options.repoRoot ?? process.cwd();
1313
+ try {
1314
+ const gitRoot = gitRootFor(repoRoot, options);
1315
+ const snapshotTaskId = receipt.workspaceSnapshotScope === 'task' ? receipt.taskId : null;
1316
+ const afterFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)({
1317
+ gitRoot,
1318
+ stateRoot: repoRoot,
1319
+ taskId: snapshotTaskId
1320
+ });
1321
+ const changedPaths = (options.diffWorkspace ?? diffWorkspaceSnapshots)(gitRoot, receipt.beforeFingerprint, afterFingerprint);
1322
+ const baseEvent = { childId: event.childId, exitCode: 0, afterFingerprint, changedPaths };
1323
+ const validated = sealDelegation(receipt, baseEvent, { now: options.now, requireHostEvidence: false });
1324
+ if (!validated.ok) {
1325
+ return pauseOrchestration(matched.taskId, validated.code, validated.message, true, options);
1326
+ }
1327
+ const hostEvidence = consumeEvidence(receipt);
1328
+ const sealed = sealDelegation(receipt, { ...baseEvent, hostEvidence }, { now: options.now });
1329
+ if (!sealed.ok)
1330
+ return pauseOrchestration(matched.taskId, sealed.code, sealed.message, true, options);
1331
+ const resolved = resolveTaskRef(matched.taskId, { repoRoot });
1332
+ if (!resolved.ok)
1333
+ return failed(resolved.code, resolved.message, resolved.taskId);
1334
+ const updated = withUpdatedRun(matched.run, { pendingDelegation: sealed.receipt }, options.now);
1335
+ saveRun(resolved.taskDir, updated);
1336
+ return { status: 'running', changed: true, taskId: matched.taskId, run: updated, next: null, error: null };
1337
+ }
1338
+ catch (error) {
1339
+ return pauseOrchestration(matched.taskId, 'ORCHESTRATION_CODEX_EVIDENCE_FAILED', error instanceof Error ? error.message : String(error), true, options);
1340
+ }
1341
+ }
1342
+ function reconcileMatchingOrchestrationDelegation(client, childId, options = {}) {
1343
+ const matched = uniqueMatchingDelegation(client, (receipt) => receipt.childId === childId, options);
1344
+ if ('status' in matched)
1345
+ return matched;
1346
+ const receipt = matched.run.pendingDelegation;
1347
+ if (receipt.status !== 'sealed'
1348
+ || receipt.hostEvidence?.consumer !== receipt.id
1349
+ || receipt.hostEvidence.consumedAt === null) {
1350
+ return pauseOrchestration(matched.taskId, 'ORCHESTRATION_CODEX_RECONCILIATION_FAILED', 'Codex native spawn did not produce one sealed receipt with consumed host evidence', true, options);
1351
+ }
1352
+ return { status: matched.run.status, changed: false, taskId: matched.taskId, run: matched.run, next: null, error: null };
1353
+ }
1122
1354
  function activateOrchestrationDelegation(taskRef, event, options = {}) {
1123
1355
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1124
1356
  if (!resolved.ok)
@@ -1126,7 +1358,15 @@ function activateOrchestrationDelegation(taskRef, event, options = {}) {
1126
1358
  const run = readRun(resolved.taskDir);
1127
1359
  if (!run?.pendingDelegation)
1128
1360
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1129
- const result = activateDelegation(run.pendingDelegation, event, { now: options.now });
1361
+ if (run.schemaVersion !== 3)
1362
+ return failed('ORCHESTRATION_STATE_INVALID', 'active delegation requires schemaVersion 3', resolved.taskId);
1363
+ if (run.status !== 'running') {
1364
+ return { status: run.status, changed: false, taskId: resolved.taskId, run, next: null, error: null };
1365
+ }
1366
+ const result = activateDelegation(run.pendingDelegation, event, {
1367
+ now: options.now,
1368
+ monotonicNow: options.monotonicNow
1369
+ });
1130
1370
  if (!result.ok) {
1131
1371
  if (result.code === 'DELEGATION_IGNORED')
1132
1372
  return { status: run.status, changed: false, taskId: resolved.taskId, run, next: null, error: null };
@@ -1136,6 +1376,108 @@ function activateOrchestrationDelegation(taskRef, event, options = {}) {
1136
1376
  saveRun(resolved.taskDir, updated);
1137
1377
  return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
1138
1378
  }
1379
+ async function awaitOrchestrationDelegationActivation(taskRef, event, options = {}) {
1380
+ const sleep = options.sleep
1381
+ ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
1382
+ while (true) {
1383
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1384
+ if (!resolved.ok)
1385
+ return failed(resolved.code, resolved.message, resolved.taskId);
1386
+ const run = readRun(resolved.taskDir);
1387
+ if (!run?.pendingDelegation) {
1388
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1389
+ }
1390
+ if (run.schemaVersion !== 3) {
1391
+ return failed('ORCHESTRATION_STATE_INVALID', 'activation barrier requires schemaVersion 3', resolved.taskId);
1392
+ }
1393
+ const receipt = run.pendingDelegation;
1394
+ const matches = receipt.stage === event.stage
1395
+ && receipt.round === event.round
1396
+ && receipt.artifact === event.artifact
1397
+ && receipt.role === event.role;
1398
+ if (!matches) {
1399
+ return pauseOrchestration(taskRef, 'ORCHESTRATION_PROVENANCE_MISMATCH', 'activation barrier identity does not match the pending delegation', true, options);
1400
+ }
1401
+ if (receipt.status === 'activated' || receipt.status === 'stage-completed') {
1402
+ return { status: run.status, changed: false, taskId: resolved.taskId, run, next: null, error: null };
1403
+ }
1404
+ if (run.status !== 'running') {
1405
+ return { status: run.status, changed: false, taskId: resolved.taskId, run, next: null, error: null };
1406
+ }
1407
+ if (receipt.status !== 'prepared') {
1408
+ return pauseOrchestration(taskRef, 'ORCHESTRATION_ACTIVATION_STATE_INVALID', `activation barrier found receipt status '${receipt.status}'`, true, options);
1409
+ }
1410
+ if (receipt.activationDeadlineAt == null
1411
+ || !Number.isFinite(Date.parse(receipt.activationDeadlineAt))) {
1412
+ return pauseOrchestration(taskRef, 'ORCHESTRATION_DELEGATION_NOT_DISPATCHED', 'activation barrier was entered before the native spawn dispatch boundary', true, options);
1413
+ }
1414
+ if (Date.parse((options.now ?? (() => new Date().toISOString()))()) >= Date.parse(receipt.activationDeadlineAt)) {
1415
+ return pauseOrchestration(taskRef, 'ORCHESTRATION_ACTIVATION_TIMEOUT', 'fresh child did not receive trusted activation evidence before the deadline', true, options);
1416
+ }
1417
+ await sleep(100);
1418
+ }
1419
+ }
1420
+ function recoverPreparedOrchestrationDelegation(taskRef, options = {}) {
1421
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1422
+ if (!resolved.ok)
1423
+ return failed(resolved.code, resolved.message, resolved.taskId);
1424
+ try {
1425
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.recover-prepared', () => {
1426
+ const run = readRun(resolved.taskDir);
1427
+ const receipt = run?.pendingDelegation;
1428
+ if (!run || !receipt) {
1429
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1430
+ }
1431
+ if (receipt.status !== 'prepared') {
1432
+ return failed('ORCHESTRATION_PREPARED_RECOVERY_UNSAFE', 'only a never-activated prepared receipt can recover', resolved.taskId);
1433
+ }
1434
+ const wallNow = Date.parse((options.now ?? (() => new Date().toISOString()))());
1435
+ if (receipt.activationDeadlineAt != null
1436
+ && Number.isFinite(Date.parse(receipt.activationDeadlineAt))
1437
+ && wallNow <= Date.parse(receipt.activationDeadlineAt)) {
1438
+ return failed('ORCHESTRATION_PREPARED_RECOVERY_EARLY', 'prepared receipt activation deadline has not elapsed', resolved.taskId);
1439
+ }
1440
+ const activeLifecycleEvidence = options.hasActiveLifecycleEvidence?.(receipt)
1441
+ ?? (receipt.client === 'codex'
1442
+ && receipt.lifecycleProvenance
1443
+ && hasActiveCodexLifecycleEvidence(path.join(resolved.repoRoot, '.agents', 'workspace', '.runtime', 'codex-lifecycle'), {
1444
+ nativeAgent: `agent-infra-lifecycle-${receipt.role}`,
1445
+ hookDefinitionHash: receipt.lifecycleProvenance.hookDefinitionHash
1446
+ }));
1447
+ if (activeLifecycleEvidence) {
1448
+ return failed('ORCHESTRATION_PREPARED_RECOVERY_ACTIVE_EVIDENCE', 'active Codex lifecycle evidence blocks prepared receipt recovery', resolved.taskId);
1449
+ }
1450
+ if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
1451
+ return failed('ORCHESTRATION_PREPARED_RECOVERY_UNSAFE', 'active commit intent blocks prepared recovery', resolved.taskId);
1452
+ }
1453
+ const current = (options.captureWorkspace ?? captureWorkspaceSnapshot)({
1454
+ gitRoot: gitRootFor(resolved.repoRoot, options),
1455
+ stateRoot: resolved.repoRoot,
1456
+ taskId: receipt.workspaceSnapshotScope === 'task' ? receipt.taskId : null
1457
+ });
1458
+ if (current !== receipt.beforeFingerprint) {
1459
+ return failed('ORCHESTRATION_PREPARED_RECOVERY_DRIFT', 'workspace changed after delegation preparation', resolved.taskId);
1460
+ }
1461
+ const aborted = abortPreparedDelegation(receipt);
1462
+ if (!aborted.ok)
1463
+ return failed(aborted.code, aborted.message, resolved.taskId);
1464
+ const updated = withUpdatedRun(run, {
1465
+ status: 'running',
1466
+ pause: null,
1467
+ nextStage: null,
1468
+ pendingDelegation: null,
1469
+ receipts: Object.freeze([...run.receipts, aborted.receipt])
1470
+ }, options.now);
1471
+ saveRun(resolved.taskDir, updated);
1472
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
1473
+ });
1474
+ }
1475
+ catch (error) {
1476
+ if (error instanceof TaskExecutionLockError)
1477
+ return failed(error.code, error.message, resolved.taskId);
1478
+ return failed('ORCHESTRATION_PREPARED_RECOVERY_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
1479
+ }
1480
+ }
1139
1481
  function completeOrchestrationStage(taskRef, event, options = {}) {
1140
1482
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1141
1483
  if (!resolved.ok)
@@ -1143,6 +1485,8 @@ function completeOrchestrationStage(taskRef, event, options = {}) {
1143
1485
  const run = readRun(resolved.taskDir);
1144
1486
  if (!run)
1145
1487
  return { status: 'running', changed: false, taskId: resolved.taskId, run: null, next: null, error: null };
1488
+ if (run.schemaVersion !== 3)
1489
+ return failed('ORCHESTRATION_STATE_INVALID', 'stage completion requires schemaVersion 3', resolved.taskId);
1146
1490
  if (!run.pendingDelegation)
1147
1491
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'active run has no pending delegation', resolved.taskId);
1148
1492
  const result = completeDelegationStage(run.pendingDelegation, event);
@@ -1165,6 +1509,8 @@ function inspectOrchestrationStage(taskRef, event, options = {}) {
1165
1509
  }
1166
1510
  if (!run)
1167
1511
  return failed('ORCHESTRATION_RUN_MISSING', 'no orchestration run exists', resolved.taskId);
1512
+ if (run.schemaVersion !== 3)
1513
+ return failed('ORCHESTRATION_STATE_INVALID', 'stage inspection requires schemaVersion 3', resolved.taskId);
1168
1514
  const receipt = run.pendingDelegation;
1169
1515
  if (!receipt
1170
1516
  || receipt.status !== 'activated'
@@ -1209,6 +1555,8 @@ function sealOrchestrationDelegation(taskRef, event, options = {}) {
1209
1555
  const run = readRun(resolved.taskDir);
1210
1556
  if (!run?.pendingDelegation)
1211
1557
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1558
+ if (run.schemaVersion !== 3)
1559
+ return failed('ORCHESTRATION_STATE_INVALID', 'delegation sealing requires schemaVersion 3', resolved.taskId);
1212
1560
  const result = sealDelegation(run.pendingDelegation, event, { now: options.now });
1213
1561
  if (!result.ok)
1214
1562
  return pauseOrchestration(taskRef, result.code, result.message, true, options);
@@ -1223,6 +1571,8 @@ function advanceOrchestration(taskRef, options = {}) {
1223
1571
  const run = readRun(resolved.taskDir);
1224
1572
  if (!run?.pendingDelegation)
1225
1573
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1574
+ if (run.schemaVersion !== 3)
1575
+ return failed('ORCHESTRATION_STATE_INVALID', 'orchestration advance requires schemaVersion 3', resolved.taskId);
1226
1576
  const result = consumeDelegation(run.pendingDelegation, { now: options.now });
1227
1577
  if (!result.ok)
1228
1578
  return pauseOrchestration(taskRef, result.code, result.message, true, options);
@@ -1251,5 +1601,5 @@ function pauseOrchestration(taskRef, code, message, recoverable, options = {}) {
1251
1601
  saveRun(resolved.taskDir, updated);
1252
1602
  return { status: 'paused', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
1253
1603
  }
1254
- export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, abortCommitIntent, beginCommitIntent, beginOrResumeOrchestration, checkpointCommitIntent, commitOrchestrationStageCompletion, completeCommitIntent, completeOrchestrationStage, inspectOrchestrationStage, orchestrationPath, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, recoverCommitIntent, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, startCommitAttempt, statusCommitIntent, statusOrchestration, terminateCommitAttempt };
1604
+ export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, awaitOrchestrationDelegationActivation, advanceOrchestration, abortCommitIntent, beginCommitIntent, beginOrResumeOrchestration, checkpointCommitIntent, commitOrchestrationStageCompletion, completeCommitIntent, completeOrchestrationStage, dispatchOrchestrationDelegation, inspectOrchestrationStage, hasActivatableOrchestrationDelegation, hasSealableOrchestrationDelegation, orchestrationPath, pauseMatchingOrchestrationDelegation, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, reconcileMatchingOrchestrationDelegation, recoverCommitIntent, recoverPreparedOrchestrationDelegation, routeOrchestration, sealMatchingOrchestrationDelegation, sealMatchingOrchestrationDelegationWithHostEvidence, sealOrchestrationDelegation, startCommitAttempt, statusCommitIntent, statusOrchestration, terminateCommitAttempt };
1255
1605
  //# sourceMappingURL=orchestration.js.map
@@ -16,6 +16,10 @@ function parseTable(content, input) {
16
16
  new Set(input.columns).size !== input.columns.length) {
17
17
  throw new DocumentMutationError('MUTATION_INVALID', 'table columns are invalid');
18
18
  }
19
+ const keyColumn = input.keyColumn ?? input.columns[0];
20
+ if (!input.columns.includes(keyColumn)) {
21
+ throw new DocumentMutationError('MUTATION_INVALID', 'table key column is invalid');
22
+ }
19
23
  const sections = matchingSections(content, input.sectionAliases);
20
24
  if (sections.length === 0)
21
25
  return null;
@@ -60,7 +64,7 @@ function parseTable(content, input) {
60
64
  column,
61
65
  decodeCell(parsed.cells[columnIndex]).trim()
62
66
  ]));
63
- const key = values[input.columns[0]];
67
+ const key = values[keyColumn];
64
68
  if (seen.has(key)) {
65
69
  throw new DocumentMutationError('TABLE_DUPLICATE_KEY', `duplicate table key '${key}'`);
66
70
  }
@@ -38,11 +38,12 @@ function parseOwner(raw, key) {
38
38
  try {
39
39
  const value = JSON.parse(raw);
40
40
  if (value !== null
41
- && value.version === 1
41
+ && value.version === 2
42
42
  && Number.isSafeInteger(value.pid)
43
43
  && (value.pid ?? 0) > 0
44
- && typeof value.startTime === 'string'
45
- && value.startTime.length > 0
44
+ && typeof value.startTime === 'number'
45
+ && Number.isSafeInteger(value.startTime)
46
+ && value.startTime >= 0
46
47
  && typeof value.token === 'string'
47
48
  && value.token.length > 0
48
49
  && typeof value.owner === 'string'
@@ -148,7 +149,7 @@ function withTaskExecutionLock(repoRoot, taskId, ownerName, callback, options =
148
149
  throw new TaskExecutionLockError('ORCHESTRATION_LOCK_FAILED', 'current process start time is unavailable', { operation: 'identity', errno: null, key });
149
150
  }
150
151
  const owner = {
151
- version: 1,
152
+ version: 2,
152
153
  pid: process.pid,
153
154
  startTime,
154
155
  token,