@martinloop/mcp 0.7.1 → 0.8.1

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 (77) hide show
  1. package/dist/package-version.d.ts +1 -1
  2. package/dist/package-version.js +1 -1
  3. package/dist/vendor/adapters/claude-cli.d.ts +16 -1
  4. package/dist/vendor/adapters/claude-cli.js +286 -71
  5. package/dist/vendor/adapters/cli-bridge.d.ts +12 -3
  6. package/dist/vendor/adapters/cli-bridge.js +129 -149
  7. package/dist/vendor/adapters/codex-capabilities.d.ts +4 -1
  8. package/dist/vendor/adapters/codex-capabilities.js +36 -4
  9. package/dist/vendor/adapters/codex-cli.d.ts +10 -3
  10. package/dist/vendor/adapters/codex-cli.js +21 -24
  11. package/dist/vendor/adapters/codex-host.js +150 -132
  12. package/dist/vendor/adapters/index.d.ts +3 -2
  13. package/dist/vendor/adapters/index.js +3 -2
  14. package/dist/vendor/adapters/openai-compatible.js +88 -6
  15. package/dist/vendor/adapters/process-supervisor.d.ts +60 -0
  16. package/dist/vendor/adapters/process-supervisor.js +541 -0
  17. package/dist/vendor/adapters/verifier-only.d.ts +10 -1
  18. package/dist/vendor/adapters/verifier-only.js +43 -1
  19. package/dist/vendor/contracts/external-outcome.d.ts +102 -0
  20. package/dist/vendor/contracts/external-outcome.js +226 -0
  21. package/dist/vendor/contracts/index.d.ts +12 -1
  22. package/dist/vendor/contracts/index.js +2 -0
  23. package/dist/vendor/contracts/swarm-hosted.d.ts +204 -0
  24. package/dist/vendor/contracts/swarm-hosted.js +629 -0
  25. package/dist/vendor/contracts/swarm.d.ts +449 -0
  26. package/dist/vendor/contracts/swarm.js +550 -0
  27. package/dist/vendor/core/external-outcome.d.ts +34 -0
  28. package/dist/vendor/core/external-outcome.js +515 -0
  29. package/dist/vendor/core/grounding.js +1 -1
  30. package/dist/vendor/core/index.d.ts +52 -1
  31. package/dist/vendor/core/index.js +55 -3
  32. package/dist/vendor/core/leash.d.ts +1 -0
  33. package/dist/vendor/core/leash.js +13 -0
  34. package/dist/vendor/core/persistence/integrity.d.ts +4 -0
  35. package/dist/vendor/core/persistence/integrity.js +19 -6
  36. package/dist/vendor/core/persistence/swarm-integrity.d.ts +63 -0
  37. package/dist/vendor/core/persistence/swarm-integrity.js +309 -0
  38. package/dist/vendor/core/policy.d.ts +3 -0
  39. package/dist/vendor/core/policy.js +13 -0
  40. package/dist/vendor/core/swarm/candidates.d.ts +78 -0
  41. package/dist/vendor/core/swarm/candidates.js +810 -0
  42. package/dist/vendor/core/swarm/evidence-projection.d.ts +87 -0
  43. package/dist/vendor/core/swarm/evidence-projection.js +128 -0
  44. package/dist/vendor/core/swarm/evidence.d.ts +40 -0
  45. package/dist/vendor/core/swarm/evidence.js +575 -0
  46. package/dist/vendor/core/swarm/hosted-export.d.ts +48 -0
  47. package/dist/vendor/core/swarm/hosted-export.js +362 -0
  48. package/dist/vendor/core/swarm/hosted-projection.d.ts +5 -0
  49. package/dist/vendor/core/swarm/hosted-projection.js +258 -0
  50. package/dist/vendor/core/swarm/index.d.ts +110 -0
  51. package/dist/vendor/core/swarm/index.js +1060 -0
  52. package/dist/vendor/core/swarm/integration.d.ts +76 -0
  53. package/dist/vendor/core/swarm/integration.js +615 -0
  54. package/dist/vendor/core/swarm/lifecycle.d.ts +72 -0
  55. package/dist/vendor/core/swarm/lifecycle.js +252 -0
  56. package/dist/vendor/core/swarm/live-runtime.d.ts +78 -0
  57. package/dist/vendor/core/swarm/live-runtime.js +1482 -0
  58. package/dist/vendor/core/swarm/live-store.d.ts +99 -0
  59. package/dist/vendor/core/swarm/live-store.js +860 -0
  60. package/dist/vendor/core/swarm/operational-reader.d.ts +17 -0
  61. package/dist/vendor/core/swarm/operational-reader.js +96 -0
  62. package/dist/vendor/core/swarm/operations.d.ts +29 -0
  63. package/dist/vendor/core/swarm/operations.js +128 -0
  64. package/dist/vendor/core/swarm/parent-receipt.d.ts +13 -0
  65. package/dist/vendor/core/swarm/parent-receipt.js +489 -0
  66. package/dist/vendor/core/swarm/receipt-projection.d.ts +26 -0
  67. package/dist/vendor/core/swarm/receipt-projection.js +120 -0
  68. package/dist/vendor/core/swarm/scheduler.d.ts +92 -0
  69. package/dist/vendor/core/swarm/scheduler.js +555 -0
  70. package/dist/vendor/core/swarm/verification.d.ts +70 -0
  71. package/dist/vendor/core/swarm/verification.js +295 -0
  72. package/dist/vendor/core/swarm/workspaces.d.ts +77 -0
  73. package/dist/vendor/core/swarm/workspaces.js +488 -0
  74. package/dist/vendor/core/verified-handoff.d.ts +4 -0
  75. package/dist/vendor/core/verified-handoff.js +4 -0
  76. package/package.json +1 -1
  77. package/server.json +2 -2
@@ -0,0 +1,1482 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstat, mkdir, open, readFile, realpath } from "node:fs/promises";
3
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { createSwarmRunRecord, validateSwarmLivePlan } from "../../contracts/index.js";
5
+ import { runMartin } from "../index.js";
6
+ import { redactSecretsFromText } from "../leash.js";
7
+ import { createFileRunStore, runDir, verifyReceiptIntegrityFromFiles } from "../persistence/index.js";
8
+ import { authenticateSwarmReceiptSealCommit, resolveSwarmReceiptIntegrityPath, verifySwarmReceiptIntegrityFromFiles, writeSwarmReceiptIntegrityMaterial, } from "../persistence/swarm-integrity.js";
9
+ export { readSwarmReceiptProjection, verifySwarmReceiptProjection, } from "./receipt-projection.js";
10
+ import { readAndSealSwarmEvidence } from "./evidence.js";
11
+ import { buildParentSwarmReceipt } from "./parent-receipt.js";
12
+ import { captureAndAdmitSwarmCandidate, inventorySwarmCandidatePaths } from "./candidates.js";
13
+ import { runParentSwarmPipeline } from "./index.js";
14
+ import { createSwarmLiveStore } from "./live-store.js";
15
+ import { createSwarmBudgetLedger, extendSwarmBudgetLease, releaseSwarmBudgetLease, reserveSwarmBudgetLease, selectNextSwarmBatch, settleSwarmBudgetLease } from "./scheduler.js";
16
+ import { assertSwarmPathIdentifier, createSwarmWorkspaceManager } from "./workspaces.js";
17
+ const authoritativeVerifiedResults = new WeakSet();
18
+ /** Checks in-process Core authority; structurally forged CLI/test objects cannot pass. */
19
+ export function isAuthoritativeLiveSwarmVerified(result) {
20
+ if (!authoritativeVerifiedResults.has(result))
21
+ return false;
22
+ const verifiedEvents = result.record.events.filter((event) => event.type === "SWARM_VERIFIED");
23
+ return result.outcome.state === "verified"
24
+ && result.parent?.outcome.state === "verified"
25
+ && result.parent.disposition === "ready"
26
+ && result.parent.blockingInvariants.length === 0
27
+ && verifiedEvents.length === 1
28
+ && verifiedEvents[0]?.swarmId === result.record.swarmId
29
+ && verifiedEvents[0]?.parentPolicyVersion === result.record.parentContract.policyVersion;
30
+ }
31
+ const productionDependencies = {
32
+ captureCandidate: captureAndAdmitSwarmCandidate,
33
+ inventoryCandidatePaths: inventorySwarmCandidatePaths,
34
+ parentPipeline: runParentSwarmPipeline
35
+ };
36
+ /** Public high-level live entrypoint. Raw lifecycle and finalization authority stay internal. */
37
+ export function runLiveSwarm(input) {
38
+ return runLiveSwarmWithDependencies(input, productionDependencies);
39
+ }
40
+ /**
41
+ * Production composition boundary for CLI/operator callers. It accepts only
42
+ * validated operator paths plus narrow child/verifier executors. Raw store,
43
+ * worktree, evidence, lifecycle, and parent-finalization authority remain
44
+ * inside Core and are never exported from the package root.
45
+ */
46
+ export async function runProductionLiveSwarm(input) {
47
+ const validation = validateSwarmLivePlan(input.plan);
48
+ if (!validation.ok)
49
+ throw codedRuntimeError("INVALID_LIVE_PLAN", "Core rejected the live swarm plan.");
50
+ assertSwarmPathIdentifier(input.plan.swarmId, "swarm ID");
51
+ const paths = await resolveProductionRuntimePaths(input);
52
+ const storeRoot = paths.storeRoot;
53
+ const liveStore = await createSwarmLiveStore({ rootDir: storeRoot, plan: input.plan });
54
+ const workspaceManager = await createSwarmWorkspaceManager({
55
+ canonicalRoot: resolve(input.canonicalRoot),
56
+ ownedRoot: paths.ownedRoot,
57
+ swarmId: input.plan.swarmId,
58
+ ...(input.workspaceIsolationMode ? { isolationMode: input.workspaceIsolationMode } : {}),
59
+ });
60
+ if (workspaceManager.baselineCommit.toLowerCase() !== input.plan.baselineCommit.toLowerCase()) {
61
+ throw codedRuntimeError("LIVE_PLAN_BASELINE_MISMATCH", "Live swarm plan baseline no longer matches the canonical repository.");
62
+ }
63
+ await liveStore.claimStart();
64
+ const claimedSnapshot = await liveStore.readSnapshot();
65
+ if (claimedSnapshot.eventCount > 0) {
66
+ throw codedRuntimeError("LIVE_SWARM_ALREADY_STARTED", "This live swarm contains pre-claim execution state; replay remains blocked before spend.");
67
+ }
68
+ const evidenceStore = new FileSwarmLiveRuntimeEvidenceStore(paths.evidenceRoot);
69
+ return runLiveSwarmWithDependencies({
70
+ plan: input.plan,
71
+ liveStore,
72
+ workspaceManager,
73
+ evidenceStore,
74
+ adapterFactory: input.adapterFactory,
75
+ verifierExecutor: input.verifierExecutor,
76
+ runsRoot: paths.runsRoot,
77
+ ...(input.signal ? { signal: input.signal } : {}),
78
+ }, {
79
+ ...productionDependencies,
80
+ sealTerminal: async (result) => {
81
+ try {
82
+ await sealProductionSwarmTerminal(paths, input.plan, result);
83
+ }
84
+ catch (error) {
85
+ await persistSwarmSealFailure(paths.evidenceRoot, input.plan, "terminal_evidence_sealing_failed");
86
+ throw error;
87
+ }
88
+ }
89
+ });
90
+ }
91
+ async function resolveProductionRuntimePaths(input) {
92
+ const runsRoot = await realpath(resolve(input.runsRoot));
93
+ const requestedStoreRoot = resolve(input.storeRoot);
94
+ const canonicalRequestedStoreRoot = await resolveForContainment(requestedStoreRoot);
95
+ assertContainedOrSame(runsRoot, canonicalRequestedStoreRoot, "Live swarm store root escaped the caller runs root.");
96
+ await mkdir(requestedStoreRoot, { recursive: true });
97
+ const storeRoot = await realpath(requestedStoreRoot);
98
+ assertContainedOrSame(runsRoot, storeRoot, "Live swarm store root escaped the real caller runs root.");
99
+ const swarmsRoot = await resolveOrCreateStrictlyContained(storeRoot, join(storeRoot, "_swarms"));
100
+ const swarmRoot = await resolveOrCreateStrictlyContained(swarmsRoot, join(swarmsRoot, input.plan.swarmId));
101
+ const expectedRequestedOwnedRoot = join(requestedStoreRoot, "_swarms", input.plan.swarmId, "worktrees");
102
+ const expectedOwnedRoot = join(swarmRoot, "worktrees");
103
+ if (resolve(input.ownedRoot) !== resolve(expectedRequestedOwnedRoot)) {
104
+ throw codedRuntimeError("LIVE_SWARM_PATH_ESCAPE", "Live swarm worktree root must use the governed run layout.");
105
+ }
106
+ const ownedRoot = await resolveOrCreateStrictlyContained(swarmRoot, expectedOwnedRoot);
107
+ const evidenceRoot = await resolveOrCreateStrictlyContained(swarmRoot, join(swarmRoot, "evidence"));
108
+ return { runsRoot, storeRoot, ownedRoot, evidenceRoot };
109
+ }
110
+ async function sealProductionSwarmTerminal(paths, plan, result) {
111
+ const sealed = await readAndSealSwarmEvidence({ rootDir: paths.runsRoot, swarmId: plan.swarmId });
112
+ const receipt = buildParentSwarmReceipt(sealed);
113
+ if (receipt.parentOutcome.state !== result.outcome.state || receipt.planHash !== plan.planHash) {
114
+ throw codedRuntimeError("SWARM_SEAL_OUTCOME_MISMATCH", "Sealed evidence disagrees with the terminal runtime outcome.");
115
+ }
116
+ const receiptPath = join(paths.evidenceRoot, "parent-receipt.json");
117
+ const receiptBytes = `${JSON.stringify(receipt, null, 2)}\n`;
118
+ await writeExclusiveIdempotent(receiptPath, receiptBytes);
119
+ const integrity = await writeSwarmReceiptIntegrityMaterial({
120
+ runsRoot: paths.runsRoot,
121
+ swarmId: plan.swarmId,
122
+ signedAt: sealed.index.sealedAt
123
+ });
124
+ if (!integrity) {
125
+ throw codedRuntimeError("SWARM_SEAL_KEY_UNAVAILABLE", "Swarm receipt integrity key material was unavailable.");
126
+ }
127
+ const verified = await verifySwarmReceiptIntegrityFromFiles({ runsRoot: paths.runsRoot, swarmId: plan.swarmId });
128
+ if (verified.state !== "verified") {
129
+ throw codedRuntimeError("SWARM_SEAL_INTEGRITY_FAILED", "Swarm receipt integrity verification failed before commit.");
130
+ }
131
+ const integrityPath = resolveSwarmReceiptIntegrityPath(paths.runsRoot, plan.swarmId);
132
+ const integrityBytes = await readFile(integrityPath, "utf8");
133
+ const sealBase = {
134
+ schemaVersion: "martin.swarm-receipt-seal.v1",
135
+ swarmId: plan.swarmId,
136
+ planHash: plan.planHash,
137
+ receiptSha256: sha256Text(receiptBytes),
138
+ evidenceIndexSha256: sha256Text(await readFile(sealed.indexPath, "utf8")),
139
+ integrityMaterialSha256: sha256Text(integrityBytes),
140
+ committedAt: sealed.index.sealedAt
141
+ };
142
+ const seal = {
143
+ ...sealBase,
144
+ commitHmacSha256: await authenticateSwarmReceiptSealCommit({
145
+ runsRoot: paths.runsRoot,
146
+ swarmId: plan.swarmId,
147
+ commit: sealBase
148
+ })
149
+ };
150
+ await writeExclusiveIdempotent(join(paths.evidenceRoot, "swarm-receipt-seal.json"), `${JSON.stringify(seal, null, 2)}\n`);
151
+ }
152
+ async function persistSwarmSealFailure(evidenceRoot, plan, reason) {
153
+ await writeExclusiveIdempotent(join(evidenceRoot, "swarm-receipt-seal-status.json"), `${JSON.stringify({
154
+ schemaVersion: "martin.swarm-receipt-seal-status.v1",
155
+ swarmId: plan.swarmId,
156
+ planHash: plan.planHash,
157
+ state: "needs_review",
158
+ reason
159
+ }, null, 2)}\n`);
160
+ }
161
+ function sha256Text(value) {
162
+ return createHash("sha256").update(value).digest("hex");
163
+ }
164
+ async function resolveOrCreateStrictlyContained(parent, requested) {
165
+ assertStrictlyContained(parent, requested, "Live swarm runtime path escaped its governed ancestor.");
166
+ let resolved;
167
+ try {
168
+ resolved = await realpath(requested);
169
+ }
170
+ catch (error) {
171
+ if (!isNodeError(error, "ENOENT"))
172
+ throw error;
173
+ await mkdir(requested, { recursive: true });
174
+ resolved = await realpath(requested);
175
+ }
176
+ assertStrictlyContained(parent, resolved, "Live swarm runtime realpath escaped its governed ancestor.");
177
+ return resolved;
178
+ }
179
+ async function resolveForContainment(requested) {
180
+ let cursor = resolve(requested);
181
+ const suffix = [];
182
+ while (true) {
183
+ try {
184
+ const canonical = await realpath(cursor);
185
+ return resolve(canonical, ...suffix);
186
+ }
187
+ catch (error) {
188
+ if (!isNodeError(error, "ENOENT"))
189
+ throw error;
190
+ const parent = dirname(cursor);
191
+ if (parent === cursor)
192
+ throw error;
193
+ suffix.unshift(basename(cursor));
194
+ cursor = parent;
195
+ }
196
+ }
197
+ }
198
+ function assertContainedOrSame(parent, candidate, message) {
199
+ const relation = relative(parent, candidate);
200
+ if (relation === "")
201
+ return;
202
+ assertStrictlyContained(parent, candidate, message);
203
+ }
204
+ function assertStrictlyContained(parent, candidate, message) {
205
+ const relation = relative(parent, candidate);
206
+ if (!relation || relation === ".." || relation.startsWith(`..${sep}`) || isAbsolute(relation)) {
207
+ throw codedRuntimeError("LIVE_SWARM_PATH_ESCAPE", message);
208
+ }
209
+ }
210
+ function isNodeError(error, code) {
211
+ return error instanceof Error && "code" in error && error.code === code;
212
+ }
213
+ function codedRuntimeError(code, message) {
214
+ return Object.assign(new Error(message), { code });
215
+ }
216
+ /** Internal test seam; intentionally not re-exported from the Core package root. */
217
+ export async function runLiveSwarmWithDependencies(input, dependencies) {
218
+ assertRuntimeInput(input);
219
+ const now = input.now ?? (() => new Date().toISOString());
220
+ const nowMs = input.nowMs ?? (() => Date.now());
221
+ const parentDeadlineMs = nowMs() + input.plan.parentContract.maxWallClockMs;
222
+ const createId = input.createId ?? ((prefix) => `${prefix}-${Math.random().toString(36).slice(2, 10)}`);
223
+ const parentController = new AbortController();
224
+ const cancellationMonitorController = new AbortController();
225
+ let schedulingOpen = true;
226
+ const parentDeadlineTimer = setTimeout(() => {
227
+ schedulingOpen = false;
228
+ if (!parentController.signal.aborted) {
229
+ parentController.abort(new Error("Parent swarm wall-clock deadline reached."));
230
+ }
231
+ }, Math.min(input.plan.parentContract.maxWallClockMs, 2_147_483_647));
232
+ parentDeadlineTimer.unref();
233
+ const abortParent = () => {
234
+ schedulingOpen = false;
235
+ if (!parentController.signal.aborted)
236
+ parentController.abort(input.signal?.reason);
237
+ };
238
+ if (input.signal?.aborted)
239
+ abortParent();
240
+ else {
241
+ input.signal?.addEventListener("abort", abortParent, { once: true });
242
+ if (input.signal?.aborted)
243
+ abortParent();
244
+ }
245
+ const observeDurableCancellation = async () => {
246
+ const snapshot = await input.liveStore.readSnapshot();
247
+ if (!snapshot.cancellation)
248
+ return false;
249
+ schedulingOpen = false;
250
+ if (!parentController.signal.aborted) {
251
+ parentController.abort(new Error(`Durable swarm cancellation requested: ${snapshot.cancellation.reason}`));
252
+ }
253
+ return true;
254
+ };
255
+ let cancellationMonitorFailure;
256
+ const cancellationMonitor = (async () => {
257
+ let revision = (await input.liveStore.readSnapshot()).revision;
258
+ if (await observeDurableCancellation())
259
+ return;
260
+ while (!cancellationMonitorController.signal.aborted && !parentController.signal.aborted) {
261
+ const snapshot = await input.liveStore.waitForRevision(revision, cancellationMonitorController.signal);
262
+ revision = snapshot.revision;
263
+ if (snapshot.cancellation) {
264
+ schedulingOpen = false;
265
+ if (!parentController.signal.aborted) {
266
+ parentController.abort(new Error(`Durable swarm cancellation requested: ${snapshot.cancellation.reason}`));
267
+ }
268
+ return;
269
+ }
270
+ }
271
+ })().catch((error) => {
272
+ if (cancellationMonitorController.signal.aborted)
273
+ return;
274
+ cancellationMonitorFailure = error;
275
+ schedulingOpen = false;
276
+ if (!parentController.signal.aborted)
277
+ parentController.abort(error);
278
+ });
279
+ let record = createSwarmRunRecord({
280
+ swarmId: input.plan.swarmId,
281
+ workspaceId: input.plan.workspaceId,
282
+ projectId: input.plan.projectId,
283
+ parentContract: input.plan.parentContract,
284
+ tasks: input.plan.tasks.map((task) => ({ ...task, status: "queued" })),
285
+ agents: input.plan.agents.map((agent) => ({ ...agent, status: "queued", childRunId: undefined })),
286
+ budgetLedger: createSwarmBudgetLedger({
287
+ capUsd: input.plan.parentContract.budget.maxUsd,
288
+ ...(input.plan.parentContract.budget.maxTokens === undefined
289
+ ? {}
290
+ : { capTokens: input.plan.parentContract.budget.maxTokens })
291
+ }),
292
+ createdAt: now(),
293
+ updatedAt: now()
294
+ }, { now: now() });
295
+ const runStore = createFileRunStore({ runsRoot: input.runsRoot });
296
+ const active = new Map();
297
+ const candidateIds = [];
298
+ const reassignmentCounts = new Map();
299
+ const preboundAttemptIds = new Map();
300
+ const observedUsageByLease = new Map();
301
+ try {
302
+ await appendEvent({
303
+ idempotencyKey: `${input.plan.planHash}:created`,
304
+ type: "SWARM_CREATED",
305
+ timestamp: now(),
306
+ payload: { engine: input.plan.engine.engine, model: input.plan.engine.model }
307
+ });
308
+ while (true) {
309
+ await observeDurableCancellation();
310
+ if (nowMs() >= parentDeadlineMs && !parentController.signal.aborted) {
311
+ parentController.abort(new Error("Parent swarm wall-clock deadline reached."));
312
+ }
313
+ if (parentController.signal.aborted) {
314
+ record = await cancelActiveChildren("cancelled");
315
+ if (cancellationMonitorFailure !== undefined) {
316
+ record = withTerminal(record, "needs_review", safeError(cancellationMonitorFailure), now());
317
+ }
318
+ const needsReview = record.outcome.state === "needs_review";
319
+ const terminalReason = needsReview ? record.outcome.reason : "parent_cancelled";
320
+ await appendEvent({
321
+ idempotencyKey: `${input.plan.planHash}:${needsReview ? "needs-review" : "stopped"}:cancelled`,
322
+ type: needsReview ? "SWARM_NEEDS_REVIEW" : "SWARM_STOPPED",
323
+ timestamp: now(),
324
+ payload: { reason: terminalReason }
325
+ });
326
+ return finalizeTerminalResult(needsReview
327
+ ? { record, outcome: record.outcome, candidateIds: Object.freeze([...candidateIds]) }
328
+ : terminalResult(record, candidateIds, "stopped", "Parent cancelled the live swarm."));
329
+ }
330
+ if (schedulingOpen) {
331
+ const batch = selectNextSwarmBatch({
332
+ swarmId: record.swarmId,
333
+ tasks: record.tasks,
334
+ maxConcurrency: record.parentContract.maxConcurrency,
335
+ parentContract: record.parentContract
336
+ });
337
+ if (!batch.ok) {
338
+ schedulingOpen = false;
339
+ record = withTerminal(record, "needs_review", batch.errors.map((error) => error.code).join(","), now());
340
+ }
341
+ else {
342
+ for (const task of batch.tasks) {
343
+ await observeDurableCancellation();
344
+ if (!schedulingOpen || parentController.signal.aborted)
345
+ break;
346
+ const launched = await launchTask(task);
347
+ if (!launched) {
348
+ schedulingOpen = false;
349
+ break;
350
+ }
351
+ }
352
+ }
353
+ }
354
+ if (parentController.signal.aborted)
355
+ continue;
356
+ if (active.size === 0) {
357
+ const incompleteRequired = record.tasks.filter((task) => task.required && task.status !== "accepted");
358
+ if (incompleteRequired.length > 0) {
359
+ if (record.outcome.state === "running") {
360
+ record = withTerminal(record, "needs_review", "Required tasks could not reach accepted state.", now());
361
+ }
362
+ return finalizeTerminalResult({ record, outcome: record.outcome, candidateIds: Object.freeze([...candidateIds]) });
363
+ }
364
+ break;
365
+ }
366
+ const completed = await Promise.race([...active.values()].map((attempt) => attempt.completion));
367
+ const terminal = await settleAttemptOnce(completed, parentController.signal.aborted);
368
+ if (terminal)
369
+ schedulingOpen = false;
370
+ }
371
+ if (parentController.signal.aborted || record.outcome.state !== "running") {
372
+ return finalizeTerminalResult({ record, outcome: record.outcome, candidateIds: Object.freeze([...candidateIds]) });
373
+ }
374
+ const parent = await dependencies.parentPipeline({
375
+ record,
376
+ candidateIds,
377
+ workspaceManager: input.workspaceManager,
378
+ evidenceStore: input.evidenceStore,
379
+ integrationWorkspaceId: createId("integration-workspace"),
380
+ verifierWorkspaceId: createId("verifier-workspace"),
381
+ verifierExecutor: input.verifierExecutor,
382
+ signal: parentController.signal,
383
+ now,
384
+ createId
385
+ });
386
+ const verifiedEvents = parent.record.events.filter((event) => (event.type === "SWARM_VERIFIED"
387
+ && event.swarmId === record.swarmId
388
+ && event.parentPolicyVersion === record.parentContract.policyVersion));
389
+ if (parent.outcome.state === "verified"
390
+ && (parent.disposition !== "ready"
391
+ || parent.blockingInvariants.length !== 0
392
+ || verifiedEvents.length !== 1)) {
393
+ const rejected = withTerminal(parent.record, "needs_review", "Parent result lacked one exact SWARM_VERIFIED authority event.", now());
394
+ await appendEvent({
395
+ idempotencyKey: `${input.plan.planHash}:needs-review:parent-verified-event`,
396
+ type: "SWARM_NEEDS_REVIEW",
397
+ timestamp: now(),
398
+ payload: { reason: rejected.outcome.reason }
399
+ });
400
+ return finalizeTerminalResult({ record: rejected, outcome: rejected.outcome, candidateIds: Object.freeze([...candidateIds]), parent });
401
+ }
402
+ try {
403
+ const snapshot = await input.liveStore.readSnapshot();
404
+ await input.liveStore.persistParentOutcome(parent, { expectedRevision: snapshot.revision });
405
+ }
406
+ catch {
407
+ const rejected = withTerminal(parent.record, "needs_review", "Parent pipeline outcome lacked operational-store authority or could not be persisted.", now());
408
+ await appendEvent({
409
+ idempotencyKey: `${input.plan.planHash}:needs-review:parent-outcome-authority`,
410
+ type: "SWARM_NEEDS_REVIEW",
411
+ timestamp: now(),
412
+ payload: { reason: rejected.outcome.reason }
413
+ });
414
+ return finalizeTerminalResult({ record: rejected, outcome: rejected.outcome, candidateIds: Object.freeze([...candidateIds]), parent });
415
+ }
416
+ const result = {
417
+ record: parent.record,
418
+ outcome: parent.outcome,
419
+ candidateIds: Object.freeze([...candidateIds]),
420
+ parent
421
+ };
422
+ return finalizeTerminalResult(result);
423
+ }
424
+ finally {
425
+ schedulingOpen = false;
426
+ clearTimeout(parentDeadlineTimer);
427
+ input.signal?.removeEventListener("abort", abortParent);
428
+ cancellationMonitorController.abort("runtime closed");
429
+ await cancellationMonitor;
430
+ }
431
+ async function launchTask(task) {
432
+ if (await observeDurableCancellation())
433
+ return false;
434
+ const agent = record.agents.find((candidate) => candidate.agentId === task.assignedAgentId);
435
+ if (!agent) {
436
+ record = withTerminal(record, "needs_review", `Task ${task.taskId} has no assigned agent.`, now());
437
+ return false;
438
+ }
439
+ const leaseId = createId("lease");
440
+ const attemptId = preboundAttemptIds.get(task.taskId) ?? createId("attempt");
441
+ preboundAttemptIds.delete(task.taskId);
442
+ const reservationBudget = {
443
+ ...agent.contract.budget,
444
+ maxIterations: Math.min(agent.contract.budget.maxIterations, input.plan.childMaxIterations)
445
+ };
446
+ const budget = {
447
+ ...reservationBudget,
448
+ maxUsd: agent.contract.hardMaxUsd ?? input.plan.parentContract.budget.maxUsd,
449
+ softLimitUsd: agent.contract.hardMaxUsd ?? input.plan.parentContract.budget.maxUsd,
450
+ ...(agent.contract.hardMaxTokens !== undefined
451
+ ? { maxTokens: agent.contract.hardMaxTokens }
452
+ : input.plan.parentContract.budget.maxTokens !== undefined
453
+ ? { maxTokens: input.plan.parentContract.budget.maxTokens }
454
+ : {})
455
+ };
456
+ const reservation = reserveSwarmBudgetLease(record.budgetLedger, {
457
+ leaseId,
458
+ agentId: agent.agentId,
459
+ taskId: task.taskId,
460
+ reservedUsd: reservationBudget.maxUsd,
461
+ reservedTokens: reservationBudget.maxTokens ?? 0
462
+ });
463
+ if (!reservation.ok) {
464
+ await appendBlockedAction({
465
+ taskId: task.taskId,
466
+ agentId: agent.agentId,
467
+ attemptId,
468
+ action: "budget_reservation",
469
+ reason: reservation.errors.map((error) => error.code).join(",")
470
+ });
471
+ record = withTerminal(record, "stopped", reservation.errors.map((error) => error.code).join(","), now());
472
+ return false;
473
+ }
474
+ record = { ...record, budgetLedger: reservation.ledger, updatedAt: now() };
475
+ const childRunId = createId("child-run");
476
+ const workspaceId = createId("child-workspace");
477
+ const proposalId = createId("proposal");
478
+ const candidateId = task.mutationMode === "write" ? createId("candidate") : undefined;
479
+ let workspace;
480
+ try {
481
+ workspace = await input.workspaceManager.createWorkspace({
482
+ kind: "child",
483
+ workspaceId,
484
+ childRunId,
485
+ agentId: agent.agentId,
486
+ taskIds: [task.taskId]
487
+ });
488
+ }
489
+ catch (error) {
490
+ const released = releaseSwarmBudgetLease(record.budgetLedger, leaseId);
491
+ if (released.ok)
492
+ record = { ...record, budgetLedger: released.ledger };
493
+ const lease = record.budgetLedger.leases.find((candidate) => candidate.leaseId === leaseId);
494
+ await appendBlockedAction({
495
+ taskId: task.taskId,
496
+ agentId: agent.agentId,
497
+ childRunId,
498
+ attemptId,
499
+ action: "workspace_creation",
500
+ reason: safeError(error),
501
+ details: {
502
+ leaseId,
503
+ leaseState: lease?.status,
504
+ reservedUsd: lease?.reservedUsd,
505
+ reservedTokens: lease?.reservedTokens,
506
+ actualUsd: 0,
507
+ actualTokens: 0
508
+ }
509
+ });
510
+ record = withTerminal(record, "needs_review", safeError(error), now());
511
+ return false;
512
+ }
513
+ let adapter;
514
+ try {
515
+ if (await observeDurableCancellation()) {
516
+ await cancelPreparedLaunch({ task, agent, childRunId, leaseId, workspace, attemptId });
517
+ return false;
518
+ }
519
+ const factoryResult = input.adapterFactory({
520
+ engine: input.plan.engine,
521
+ task,
522
+ agent,
523
+ childRunId,
524
+ workspace,
525
+ budget
526
+ });
527
+ adapter = isAdapterHandle(factoryResult) ? factoryResult.adapter : factoryResult;
528
+ if (adapter.metadata.providerId !== input.plan.engine.engine) {
529
+ throw new Error("LIVE_ENGINE_PROVIDER_MISMATCH: every child must use the parent-selected provider.");
530
+ }
531
+ if (adapter.metadata.model !== input.plan.engine.model) {
532
+ throw new Error("LIVE_ENGINE_MODEL_MISMATCH: every child must use the parent-selected model.");
533
+ }
534
+ }
535
+ catch (error) {
536
+ await failPreparedLaunch({ task, agent, childRunId, leaseId, workspace, attemptId }, error);
537
+ return false;
538
+ }
539
+ const controller = new AbortController();
540
+ const relayAbort = () => controller.abort(parentController.signal.reason);
541
+ if (parentController.signal.aborted)
542
+ relayAbort();
543
+ else {
544
+ parentController.signal.addEventListener("abort", relayAbort, { once: true });
545
+ if (parentController.signal.aborted)
546
+ relayAbort();
547
+ }
548
+ record = updateTaskAndAgent(record, task.taskId, agent.agentId, childRunId, "running", "running", now());
549
+ try {
550
+ await appendEvent({
551
+ idempotencyKey: `${childRunId}:started`,
552
+ type: "CHILD_STARTED",
553
+ timestamp: now(),
554
+ taskId: task.taskId,
555
+ agentId: agent.agentId,
556
+ childRunId,
557
+ payload: {
558
+ attemptId,
559
+ engine: input.plan.engine.engine,
560
+ model: input.plan.engine.model,
561
+ workspaceId,
562
+ leaseId,
563
+ reservedUsd: record.budgetLedger.leases.find((lease) => lease.leaseId === leaseId)?.reservedUsd,
564
+ reservedTokens: record.budgetLedger.leases.find((lease) => lease.leaseId === leaseId)?.reservedTokens,
565
+ maxIterations: budget.maxIterations
566
+ }
567
+ });
568
+ }
569
+ catch (error) {
570
+ parentController.signal.removeEventListener("abort", relayAbort);
571
+ await failPreparedLaunch({ task, agent, childRunId, leaseId, workspace, attemptId }, error);
572
+ return false;
573
+ }
574
+ const effectiveWallClockMs = Math.max(1, Math.min(agent.contract.maxWallClockMs, parentDeadlineMs - nowMs()));
575
+ const childDeadlineTimer = setTimeout(() => {
576
+ if (!controller.signal.aborted) {
577
+ controller.abort(new Error("Child swarm wall-clock deadline reached."));
578
+ }
579
+ }, Math.min(effectiveWallClockMs, 2_147_483_647));
580
+ childDeadlineTimer.unref();
581
+ const observedUsageGovernor = (observation) => {
582
+ const currentLease = record.budgetLedger.leases.find((lease) => lease.leaseId === leaseId);
583
+ const prior = observedUsageByLease.get(leaseId) ?? { usd: 0, tokens: 0 };
584
+ const grantedUsd = currentLease?.reservedUsd ?? 0;
585
+ const grantedTokens = currentLease?.reservedTokens ?? 0;
586
+ if (record.outcome.state !== "running" || currentLease?.status !== "reserved") {
587
+ return { action: "terminate", grantedUsd, grantedTokens, reason: "parent_terminal" };
588
+ }
589
+ if (!Number.isFinite(observation.cumulativeUsd)
590
+ || observation.cumulativeUsd < prior.usd
591
+ || !Number.isInteger(observation.cumulativeTokens)
592
+ || observation.cumulativeTokens < prior.tokens) {
593
+ return { action: "terminate", grantedUsd, grantedTokens, reason: "non_monotonic_usage_observation" };
594
+ }
595
+ if ((agent.contract.hardMaxUsd !== undefined && observation.cumulativeUsd > agent.contract.hardMaxUsd)
596
+ || (agent.contract.hardMaxTokens !== undefined && observation.cumulativeTokens > agent.contract.hardMaxTokens)) {
597
+ return { action: "terminate", grantedUsd, grantedTokens, reason: "child_hard_cap_exceeded" };
598
+ }
599
+ const protectedUsage = Object.fromEntries(observedUsageByLease);
600
+ protectedUsage[leaseId] = { usd: observation.cumulativeUsd, tokens: observation.cumulativeTokens };
601
+ const extended = extendSwarmBudgetLease(record.budgetLedger, {
602
+ leaseId,
603
+ requiredUsd: observation.cumulativeUsd,
604
+ requiredTokens: observation.cumulativeTokens,
605
+ protectedUsage
606
+ });
607
+ if (!extended.ok) {
608
+ return {
609
+ action: "terminate",
610
+ grantedUsd,
611
+ grantedTokens,
612
+ reason: extended.errors.map((error) => error.code).join(",")
613
+ };
614
+ }
615
+ observedUsageByLease.set(leaseId, {
616
+ usd: observation.cumulativeUsd,
617
+ tokens: observation.cumulativeTokens
618
+ });
619
+ record = { ...record, budgetLedger: extended.ledger, updatedAt: now() };
620
+ return {
621
+ action: "continue",
622
+ grantedUsd: extended.lease.reservedUsd,
623
+ grantedTokens: extended.lease.reservedTokens
624
+ };
625
+ };
626
+ const runPromise = runMartin({
627
+ workspaceId,
628
+ projectId: input.plan.projectId,
629
+ task: {
630
+ title: task.title,
631
+ objective: task.objective,
632
+ verificationPlan: agent.contract.permissions.commands,
633
+ repoRoot: workspace.path,
634
+ // Scope controls what the child may inspect; mutationMode controls
635
+ // whether any of that scope may be changed. Keeping those concerns
636
+ // separate lets CLI and remote/model adapters share one Swarm contract.
637
+ allowedPaths: agent.contract.scope.allowedPaths,
638
+ deniedPaths: agent.contract.scope.deniedPaths,
639
+ allowedNetworkDomains: agent.contract.permissions.networkDomains,
640
+ approvalPolicy: agent.contract.approvalPolicy,
641
+ providerExecutionTimeoutMs: effectiveWallClockMs,
642
+ mutationMode: task.mutationMode === "write" ? "edit" : "read_only"
643
+ },
644
+ budget,
645
+ adapter,
646
+ store: runStore,
647
+ receiptScope: {
648
+ repoRoot: workspace.path,
649
+ workingDirectory: workspace.path,
650
+ runsRoot: input.runsRoot,
651
+ swarmChild: {
652
+ parentSwarmId: record.swarmId,
653
+ agentId: agent.agentId,
654
+ attemptId,
655
+ taskIds: [task.taskId]
656
+ }
657
+ },
658
+ metadata: {
659
+ "swarm.parentId": record.swarmId,
660
+ "swarm.agentId": agent.agentId,
661
+ "swarm.taskIds": JSON.stringify([task.taskId]),
662
+ "swarm.attemptId": attemptId,
663
+ "swarm.proposalId": proposalId,
664
+ "swarm.baselineCommit": input.plan.baselineCommit,
665
+ "swarm.engine": input.plan.engine.engine,
666
+ "swarm.model": input.plan.engine.model
667
+ },
668
+ verificationExecutionOwner: "host_only",
669
+ observedUsageGovernor,
670
+ signal: controller.signal,
671
+ now,
672
+ idFactory: childIdFactory(childRunId, createId)
673
+ });
674
+ const activeAttempt = {};
675
+ Object.assign(activeAttempt, {
676
+ task,
677
+ agent,
678
+ childRunId,
679
+ leaseId,
680
+ workspace,
681
+ controller,
682
+ attemptId,
683
+ proposalId,
684
+ ...(candidateId ? { candidateId } : {}),
685
+ completion: runPromise.then((result) => ({ active: activeAttempt, result }), (error) => ({ active: activeAttempt, error })).finally(() => {
686
+ clearTimeout(childDeadlineTimer);
687
+ parentController.signal.removeEventListener("abort", relayAbort);
688
+ })
689
+ });
690
+ active.set(childRunId, activeAttempt);
691
+ return true;
692
+ }
693
+ async function failPreparedLaunch(attempt, error) {
694
+ const released = releaseSwarmBudgetLease(record.budgetLedger, attempt.leaseId);
695
+ if (released.ok)
696
+ record = { ...record, budgetLedger: released.ledger, updatedAt: now() };
697
+ const closurePersisted = await persistProcessClosure(attempt);
698
+ const cleanup = closurePersisted
699
+ ? await cleanupWorkspace(attempt.workspace, true)
700
+ : await preserveWorkspaceForMissingEvidence(attempt.workspace);
701
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "needs_review", "needs_review", now());
702
+ const reason = !closurePersisted
703
+ ? "process_closure_evidence_not_persisted"
704
+ : cleanup.state === "completed" ? safeError(error) : "cleanup_pending";
705
+ await appendBlockedAction({
706
+ taskId: attempt.task.taskId,
707
+ agentId: attempt.agent.agentId,
708
+ childRunId: attempt.childRunId,
709
+ attemptId: attempt.attemptId,
710
+ action: "child_launch",
711
+ reason
712
+ });
713
+ record = withTerminal(record, "needs_review", safeError(error), now());
714
+ await appendEvent(childTerminalEvent(attempt, "CHILD_NEEDS_REVIEW", reason, now(), "environment_mismatch", budgetEventDetails(attempt))).catch(() => undefined);
715
+ }
716
+ async function cancelPreparedLaunch(attempt) {
717
+ const released = releaseSwarmBudgetLease(record.budgetLedger, attempt.leaseId);
718
+ if (released.ok)
719
+ record = { ...record, budgetLedger: released.ledger, updatedAt: now() };
720
+ const closurePersisted = await persistProcessClosure(attempt);
721
+ const cleanup = closurePersisted
722
+ ? await cleanupWorkspace(attempt.workspace, true)
723
+ : await preserveWorkspaceForMissingEvidence(attempt.workspace);
724
+ const clean = closurePersisted && cleanup.state === "completed";
725
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, clean ? "stopped" : "needs_review", clean ? "stopped" : "needs_review", now());
726
+ if (!clean)
727
+ record = withTerminal(record, "needs_review", "cleanup_pending", now());
728
+ await appendEvent(childTerminalEvent(attempt, clean ? "CHILD_STOPPED" : "CHILD_NEEDS_REVIEW", clean ? "parent_cancelled" : "cleanup_pending", now(), undefined, budgetEventDetails(attempt)));
729
+ }
730
+ function settleAttemptOnce(completed, cancellationRequested) {
731
+ const attempt = completed.active;
732
+ if (!attempt.settlement) {
733
+ attempt.settlement = settleAttempt(completed, cancellationRequested).finally(() => {
734
+ active.delete(attempt.childRunId);
735
+ });
736
+ }
737
+ return attempt.settlement;
738
+ }
739
+ async function settleAttempt(completed, cancellationRequested = false) {
740
+ const { active: attempt } = completed;
741
+ const closurePersisted = await persistProcessClosure(attempt);
742
+ if (completed.error || !completed.result) {
743
+ const released = releaseSwarmBudgetLease(record.budgetLedger, attempt.leaseId);
744
+ if (released.ok)
745
+ record = { ...record, budgetLedger: released.ledger };
746
+ const cleanup = closurePersisted
747
+ ? await cleanupWorkspace(attempt.workspace, true)
748
+ : await preserveWorkspaceForMissingEvidence(attempt.workspace);
749
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "needs_review", "needs_review", now());
750
+ await appendEvent(childTerminalEvent(attempt, "CHILD_NEEDS_REVIEW", !closurePersisted
751
+ ? "process_closure_evidence_not_persisted"
752
+ : cleanup.state === "completed" ? "child_crash" : "cleanup_pending", now(), "environment_mismatch", budgetEventDetails(attempt)));
753
+ record = withTerminal(record, "needs_review", completed.error ? safeError(completed.error) : "Child execution returned no result.", now());
754
+ return true;
755
+ }
756
+ const actualUsd = completed.result.loop.cost.actualUsd;
757
+ const actualTokens = completed.result.loop.cost.tokensIn + completed.result.loop.cost.tokensOut;
758
+ const childPassed = completed.result.loop.status === "completed"
759
+ && completed.result.decision.lifecycleState === "completed";
760
+ const withinExplicitChildCap = ((attempt.agent.contract.hardMaxUsd === undefined || actualUsd <= attempt.agent.contract.hardMaxUsd)
761
+ && (attempt.agent.contract.hardMaxTokens === undefined || actualTokens <= attempt.agent.contract.hardMaxTokens));
762
+ if (withinExplicitChildCap) {
763
+ const protectedUsage = Object.fromEntries(observedUsageByLease);
764
+ const priorObserved = observedUsageByLease.get(attempt.leaseId) ?? { usd: 0, tokens: 0 };
765
+ const finalObserved = {
766
+ usd: Math.max(priorObserved.usd, actualUsd),
767
+ tokens: Math.max(priorObserved.tokens, actualTokens)
768
+ };
769
+ protectedUsage[attempt.leaseId] = finalObserved;
770
+ const reconciled = extendSwarmBudgetLease(record.budgetLedger, {
771
+ leaseId: attempt.leaseId,
772
+ requiredUsd: finalObserved.usd,
773
+ requiredTokens: finalObserved.tokens,
774
+ protectedUsage
775
+ });
776
+ if (reconciled.ok) {
777
+ record = { ...record, budgetLedger: reconciled.ledger, updatedAt: now() };
778
+ }
779
+ }
780
+ const settlement = settleSwarmBudgetLease(record.budgetLedger, {
781
+ leaseId: attempt.leaseId,
782
+ actualUsd,
783
+ actualTokens,
784
+ provenance: completed.result.loop.cost.provenance
785
+ });
786
+ observedUsageByLease.delete(attempt.leaseId);
787
+ if (!settlement.ok) {
788
+ const leaseOverspent = settlement.errors.some((error) => error.code === "LEASE_OVERSPEND");
789
+ if (leaseOverspent) {
790
+ record = { ...record, budgetLedger: settlement.ledger, updatedAt: now() };
791
+ }
792
+ else {
793
+ const released = releaseSwarmBudgetLease(record.budgetLedger, attempt.leaseId);
794
+ if (released.ok)
795
+ record = { ...record, budgetLedger: released.ledger, updatedAt: now() };
796
+ }
797
+ if (!closurePersisted) {
798
+ await terminalizeMissingClosureEvidence(attempt, { actualUsd, actualTokens });
799
+ return true;
800
+ }
801
+ const cleanup = await cleanupWorkspace(attempt.workspace, true);
802
+ if (leaseOverspent && cleanup.state === "completed") {
803
+ await persistCompletion(attempt, completed.result, "overspent", cleanup);
804
+ }
805
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "stopped", "stopped", now());
806
+ const originalFailureReason = completed.result.decision.reason;
807
+ const originalFailureClass = childFailureClass(completed.result);
808
+ // A completed child with no structural/provider failure that exits only
809
+ // because accounting crossed its limit is a budget-primary failure.
810
+ // Concrete provider/safety classes remain primary and are preserved.
811
+ const budgetIsPrimary = childPassed
812
+ || originalFailureClass === undefined
813
+ || originalFailureClass === "budget_pressure";
814
+ await appendEvent(childTerminalEvent(attempt, "CHILD_STOPPED", cleanup.state === "completed"
815
+ ? (!budgetIsPrimary ? "child_terminal_failure" : leaseOverspent ? "lease_overage" : "budget_settlement_failed")
816
+ : "cleanup_pending", now(), budgetIsPrimary ? "budget_pressure" : originalFailureClass, {
817
+ actualUsd,
818
+ actualTokens,
819
+ reservedUsd: record.budgetLedger.leases.find((lease) => lease.leaseId === attempt.leaseId)?.reservedUsd,
820
+ reservedTokens: record.budgetLedger.leases.find((lease) => lease.leaseId === attempt.leaseId)?.reservedTokens,
821
+ leaseState: record.budgetLedger.leases.find((lease) => lease.leaseId === attempt.leaseId)?.status,
822
+ budgetStatus: leaseOverspent ? "exceeded" : "settlement_failed",
823
+ settlementStatus: "failed",
824
+ ...(!budgetIsPrimary ? { originalFailureReason } : {})
825
+ }));
826
+ record = withTerminal(record, "stopped", !budgetIsPrimary
827
+ ? originalFailureReason
828
+ : leaseOverspent
829
+ ? "Child actual usage exceeded its reserved lease."
830
+ : "Child budget settlement failed.", now());
831
+ return true;
832
+ }
833
+ record = { ...record, budgetLedger: settlement.ledger, updatedAt: now() };
834
+ if (!closurePersisted) {
835
+ await terminalizeMissingClosureEvidence(attempt, { actualUsd, actualTokens });
836
+ return true;
837
+ }
838
+ if (record.outcome.state !== "running" || !schedulingOpen) {
839
+ const cleanup = await cleanupWorkspace(attempt.workspace, true);
840
+ if (cleanup.state === "completed") {
841
+ await persistCompletion(attempt, completed.result, "settled", cleanup);
842
+ }
843
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "stopped", "stopped", now());
844
+ await appendEvent(childTerminalEvent(attempt, "CHILD_STOPPED", cleanup.state === "completed" ? "parent_terminal_not_admitted" : "cleanup_pending", now(), childFailureClass(completed.result), budgetEventDetails(attempt, actualUsd, actualTokens)));
845
+ return true;
846
+ }
847
+ if (cancellationRequested || parentController.signal.aborted) {
848
+ const cleanup = await cleanupWorkspace(attempt.workspace, true);
849
+ if (cleanup.state === "completed") {
850
+ await persistCompletion(attempt, completed.result, "settled", cleanup);
851
+ }
852
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "stopped", "stopped", now());
853
+ await appendEvent(childTerminalEvent(attempt, "CHILD_STOPPED", cleanup.state === "completed" ? "parent_cancelled" : "cleanup_pending", now(), childFailureClass(completed.result), budgetEventDetails(attempt, actualUsd, actualTokens)));
854
+ return true;
855
+ }
856
+ if (!childPassed) {
857
+ const cleanup = await cleanupWorkspace(attempt.workspace, true);
858
+ if (cleanup.state === "completed") {
859
+ await persistCompletion(attempt, completed.result, "settled", cleanup);
860
+ }
861
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "stopped", "stopped", now());
862
+ await appendEvent(childTerminalEvent(attempt, "CHILD_STOPPED", "child_terminal_failure", now(), childFailureClass(completed.result), budgetEventDetails(attempt, actualUsd, actualTokens)));
863
+ if (cleanup.state !== "completed")
864
+ return true;
865
+ return await reassignTask(attempt.task.taskId, attempt.agent.agentId, attempt.attemptId, "child_terminal_failure");
866
+ }
867
+ const integrity = await verifyChildReceipt(attempt);
868
+ if (integrity.state !== "verified") {
869
+ const cleanup = await cleanupWorkspace(attempt.workspace, true);
870
+ if (cleanup.state === "completed") {
871
+ await persistCompletion(attempt, completed.result, "settled", cleanup, integrity);
872
+ }
873
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "needs_review", "needs_review", now());
874
+ await appendEvent(childTerminalEvent(attempt, "CHILD_NEEDS_REVIEW", cleanup.state === "completed" ? "receipt_not_verified" : "cleanup_pending", now(), undefined, budgetEventDetails(attempt, actualUsd, actualTokens)));
875
+ return true;
876
+ }
877
+ let candidateId;
878
+ if (attempt.task.mutationMode === "write") {
879
+ candidateId = attempt.candidateId;
880
+ if (!candidateId)
881
+ throw new Error("LIVE_CANDIDATE_ID_MISSING");
882
+ const paths = runPaths(input.runsRoot, attempt.childRunId);
883
+ let declaredPaths;
884
+ try {
885
+ declaredPaths = await dependencies.inventoryCandidatePaths(attempt.workspace.path);
886
+ }
887
+ catch (error) {
888
+ const cleanup = await cleanupWorkspace(attempt.workspace, true);
889
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "needs_review", "needs_review", now());
890
+ await appendEvent(childTerminalEvent(attempt, "CHILD_NEEDS_REVIEW", cleanup.state === "completed" ? "git_inventory_failed" : "cleanup_pending", now(), undefined, { ...budgetEventDetails(attempt, actualUsd, actualTokens), diagnostic: safeError(error) }));
891
+ return true;
892
+ }
893
+ const admission = await dependencies.captureCandidate({
894
+ swarmRecord: record,
895
+ canonicalRoot: input.workspaceManager.canonicalRoot,
896
+ swarmId: record.swarmId,
897
+ candidateId,
898
+ admissionId: createId("admission"),
899
+ attemptId: attempt.attemptId,
900
+ proposalId: attempt.proposalId,
901
+ childRunId: attempt.childRunId,
902
+ agentId: attempt.agent.agentId,
903
+ taskIds: [attempt.task.taskId],
904
+ expectedBaselineCommit: input.plan.baselineCommit,
905
+ workspace: attempt.workspace,
906
+ childState: "verified",
907
+ declaredPaths,
908
+ childAllowedPaths: attempt.agent.contract.scope.allowedPaths,
909
+ inheritedDeniedPaths: [...new Set([
910
+ ...record.parentContract.scope.deniedPaths,
911
+ ...attempt.agent.contract.scope.deniedPaths
912
+ ])],
913
+ taskWriteScope: attempt.task.writeScope,
914
+ runsRoot: input.runsRoot,
915
+ loopRecordPath: paths.loopRecord,
916
+ ledgerPath: paths.ledger,
917
+ artifactWriter: input.evidenceStore,
918
+ now
919
+ });
920
+ if (admission.admission.state !== "admitted" || !admission.cleanupAuthorized) {
921
+ const cleanup = admission.cleanupAuthorized
922
+ ? await cleanupWorkspace(attempt.workspace, true)
923
+ : undefined;
924
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "needs_review", "needs_review", now());
925
+ await appendBlockedAction({
926
+ taskId: attempt.task.taskId,
927
+ agentId: attempt.agent.agentId,
928
+ childRunId: attempt.childRunId,
929
+ attemptId: attempt.attemptId,
930
+ action: "candidate_admission",
931
+ reason: admission.admission.reasonCode
932
+ });
933
+ await appendEvent(childTerminalEvent(attempt, "CHILD_NEEDS_REVIEW", cleanup && cleanup.state !== "completed" ? "cleanup_pending" : admission.admission.reasonCode, now(), undefined, budgetEventDetails(attempt, actualUsd, actualTokens)));
934
+ return true;
935
+ }
936
+ candidateIds.push(candidateId);
937
+ }
938
+ const cleanup = await cleanupWorkspace(attempt.workspace, true, candidateId !== undefined);
939
+ if (cleanup.state !== "completed") {
940
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "needs_review", "needs_review", now());
941
+ await appendEvent(childTerminalEvent(attempt, "CHILD_NEEDS_REVIEW", "cleanup_pending", now(), undefined, budgetEventDetails(attempt, actualUsd, actualTokens)));
942
+ return true;
943
+ }
944
+ await persistCompletion(attempt, completed.result, "settled", cleanup, integrity);
945
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "accepted", "verified", now());
946
+ await appendEvent({
947
+ idempotencyKey: `${attempt.childRunId}:verified`,
948
+ type: "CHILD_VERIFIED",
949
+ timestamp: now(),
950
+ taskId: attempt.task.taskId,
951
+ agentId: attempt.agent.agentId,
952
+ childRunId: attempt.childRunId,
953
+ payload: {
954
+ processCloseState: "closed",
955
+ ...budgetEventDetails(attempt, actualUsd, actualTokens),
956
+ cleanupState: cleanup.state,
957
+ ...(candidateId ? { candidateId } : {})
958
+ }
959
+ });
960
+ return false;
961
+ }
962
+ async function cleanupWorkspace(workspace, evidencePersisted, force = false) {
963
+ let cleanup;
964
+ try {
965
+ cleanup = await input.workspaceManager.removeWorkspace(workspace, {
966
+ evidencePersisted,
967
+ processTreeClosed: true,
968
+ ...(force ? { force: true } : {})
969
+ });
970
+ }
971
+ catch (error) {
972
+ cleanup = {
973
+ schemaVersion: "martin.swarm.v1",
974
+ cleanupId: createId("cleanup-pending"),
975
+ swarmId: record.swarmId,
976
+ workspaceId: workspace.record.workspaceId,
977
+ workspaceKind: workspace.record.kind,
978
+ evidencePersisted,
979
+ processCloseState: "closed",
980
+ removalState: "failed",
981
+ state: "cleanup_pending",
982
+ attemptedAt: now(),
983
+ errorCode: safeErrorCode(error)
984
+ };
985
+ }
986
+ try {
987
+ await input.evidenceStore.persistCleanupEvidence(cleanup);
988
+ return cleanup;
989
+ }
990
+ catch {
991
+ return {
992
+ ...cleanup,
993
+ evidencePersisted: false,
994
+ removalState: "failed",
995
+ state: "cleanup_pending",
996
+ completedAt: undefined,
997
+ errorCode: "CLEANUP_EVIDENCE_NOT_PERSISTED"
998
+ };
999
+ }
1000
+ }
1001
+ async function persistProcessClosure(attempt) {
1002
+ const closure = {
1003
+ swarmId: record.swarmId,
1004
+ workspaceId: attempt.workspace.record.workspaceId,
1005
+ childRunId: attempt.childRunId,
1006
+ agentId: attempt.agent.agentId,
1007
+ state: "closed",
1008
+ completedAt: now()
1009
+ };
1010
+ try {
1011
+ await input.evidenceStore.persistProcessClosure(closure);
1012
+ return true;
1013
+ }
1014
+ catch {
1015
+ return false;
1016
+ }
1017
+ }
1018
+ async function preserveWorkspaceForMissingEvidence(workspace) {
1019
+ const cleanup = {
1020
+ schemaVersion: "martin.swarm.v1",
1021
+ cleanupId: createId("cleanup-pending"),
1022
+ swarmId: record.swarmId,
1023
+ workspaceId: workspace.record.workspaceId,
1024
+ workspaceKind: workspace.record.kind,
1025
+ evidencePersisted: false,
1026
+ processCloseState: "closed",
1027
+ removalState: "failed",
1028
+ state: "cleanup_pending",
1029
+ attemptedAt: now(),
1030
+ errorCode: "PROCESS_CLOSURE_EVIDENCE_NOT_PERSISTED"
1031
+ };
1032
+ try {
1033
+ await input.evidenceStore.persistCleanupEvidence(cleanup);
1034
+ return cleanup;
1035
+ }
1036
+ catch {
1037
+ return {
1038
+ ...cleanup,
1039
+ errorCode: "CLEANUP_EVIDENCE_NOT_PERSISTED"
1040
+ };
1041
+ }
1042
+ }
1043
+ async function terminalizeMissingClosureEvidence(attempt, usage) {
1044
+ await preserveWorkspaceForMissingEvidence(attempt.workspace);
1045
+ record = updateTaskAndAgent(record, attempt.task.taskId, attempt.agent.agentId, attempt.childRunId, "needs_review", "needs_review", now());
1046
+ record = withTerminal(record, "needs_review", "Child process-closure evidence could not be persisted; workspace retained.", now());
1047
+ await appendEvent(childTerminalEvent(attempt, "CHILD_NEEDS_REVIEW", "process_closure_evidence_not_persisted", now(), "environment_mismatch", budgetEventDetails(attempt, usage.actualUsd, usage.actualTokens))).catch(() => undefined);
1048
+ }
1049
+ async function verifyChildReceipt(attempt) {
1050
+ const paths = runPaths(input.runsRoot, attempt.childRunId);
1051
+ return verifyReceiptIntegrityFromFiles({
1052
+ runId: attempt.childRunId,
1053
+ runsRoot: input.runsRoot,
1054
+ loopRecordPath: paths.loopRecord,
1055
+ ledgerPath: paths.ledger
1056
+ });
1057
+ }
1058
+ function budgetEventDetails(attempt, actualUsd = 0, actualTokens = 0) {
1059
+ const lease = record.budgetLedger.leases.find((candidate) => candidate.leaseId === attempt.leaseId);
1060
+ return {
1061
+ leaseId: attempt.leaseId,
1062
+ leaseState: lease?.status,
1063
+ reservedUsd: lease?.reservedUsd,
1064
+ reservedTokens: lease?.reservedTokens,
1065
+ actualUsd,
1066
+ actualTokens
1067
+ };
1068
+ }
1069
+ async function persistCompletion(attempt, result, leaseState, cleanup, preverifiedIntegrity) {
1070
+ const integrity = preverifiedIntegrity ?? await verifyChildReceipt(attempt);
1071
+ const receiptId = `receipt-${attempt.childRunId}`;
1072
+ const receipt = {
1073
+ receiptId,
1074
+ swarmId: record.swarmId,
1075
+ childRunId: attempt.childRunId,
1076
+ agentId: attempt.agent.agentId,
1077
+ attemptId: attempt.attemptId,
1078
+ taskIds: [attempt.task.taskId],
1079
+ integrity,
1080
+ bindingSha256: receiptBindingSha256({
1081
+ receiptId,
1082
+ swarmId: record.swarmId,
1083
+ childRunId: attempt.childRunId,
1084
+ agentId: attempt.agent.agentId,
1085
+ attemptId: attempt.attemptId,
1086
+ taskIds: [attempt.task.taskId],
1087
+ integrity
1088
+ })
1089
+ };
1090
+ await input.evidenceStore.persistChildCompletion({
1091
+ swarmId: record.swarmId,
1092
+ childRunId: attempt.childRunId,
1093
+ agentId: attempt.agent.agentId,
1094
+ attemptId: attempt.attemptId,
1095
+ taskIds: [attempt.task.taskId],
1096
+ workspaceId: attempt.workspace.record.workspaceId,
1097
+ processCloseState: "closed",
1098
+ leaseState,
1099
+ receipt,
1100
+ evidencePersisted: true,
1101
+ workspaceCleanupState: "completed",
1102
+ cleanup
1103
+ });
1104
+ void result;
1105
+ }
1106
+ async function reassignTask(taskId, fromAgentId, fromAttemptId, reason) {
1107
+ const used = reassignmentCounts.get(taskId) ?? 0;
1108
+ if (used >= record.parentContract.recoveryPolicy.maxReassignmentsPerTask) {
1109
+ record = withTerminal(record, "needs_review", `Reassignment cap reached for ${taskId}.`, now());
1110
+ return true;
1111
+ }
1112
+ const alternate = record.agents.find((agent) => (agent.agentId !== fromAgentId
1113
+ && agent.status === "queued"
1114
+ && agent.contract.taskIds.includes(taskId)));
1115
+ if (!alternate) {
1116
+ record = withTerminal(record, "needs_review", `No eligible reassignment agent for ${taskId}.`, now());
1117
+ return true;
1118
+ }
1119
+ const toAttemptId = createId("attempt");
1120
+ preboundAttemptIds.set(taskId, toAttemptId);
1121
+ reassignmentCounts.set(taskId, used + 1);
1122
+ record = {
1123
+ ...record,
1124
+ tasks: record.tasks.map((task) => task.taskId === taskId
1125
+ ? { ...task, assignedAgentId: alternate.agentId, status: "queued" }
1126
+ : task),
1127
+ updatedAt: now()
1128
+ };
1129
+ await appendEvent({
1130
+ idempotencyKey: `${taskId}:reassigned:${used + 1}`,
1131
+ type: "TASK_REASSIGNED",
1132
+ timestamp: now(),
1133
+ taskId,
1134
+ agentId: alternate.agentId,
1135
+ payload: {
1136
+ fromAgentId,
1137
+ toAgentId: alternate.agentId,
1138
+ fromAttemptId,
1139
+ toAttemptId,
1140
+ reason,
1141
+ reassignment: used + 1
1142
+ }
1143
+ });
1144
+ return false;
1145
+ }
1146
+ async function appendBlockedAction(input) {
1147
+ await appendEvent({
1148
+ idempotencyKey: `${input.attemptId}:blocked:${input.action}`,
1149
+ type: "ACTION_BLOCKED",
1150
+ timestamp: now(),
1151
+ taskId: input.taskId,
1152
+ agentId: input.agentId,
1153
+ ...(input.childRunId ? { childRunId: input.childRunId } : {}),
1154
+ payload: {
1155
+ attemptId: input.attemptId,
1156
+ action: input.action,
1157
+ reason: input.reason,
1158
+ ...input.details
1159
+ }
1160
+ });
1161
+ }
1162
+ async function cancelActiveChildren(reason) {
1163
+ if (active.size === 0) {
1164
+ return record.outcome.state === "running" ? withTerminal(record, "stopped", reason, now()) : record;
1165
+ }
1166
+ const attempts = [...active.values()];
1167
+ for (const attempt of attempts) {
1168
+ if (!attempt.controller.signal.aborted)
1169
+ attempt.controller.abort(reason);
1170
+ }
1171
+ const completions = await Promise.all(attempts.map((attempt) => attempt.completion));
1172
+ await Promise.all(completions.map((completion) => settleAttemptOnce(completion, true)));
1173
+ return record.outcome.state === "running" ? withTerminal(record, "stopped", reason, now()) : record;
1174
+ }
1175
+ async function appendEvent(event) {
1176
+ for (let attempt = 0; attempt < 8; attempt += 1) {
1177
+ const snapshot = await input.liveStore.readSnapshot();
1178
+ try {
1179
+ const appended = await input.liveStore.append(event, { expectedRevision: snapshot.revision });
1180
+ const recordEvent = {
1181
+ type: appended.event.type,
1182
+ swarmId: appended.event.swarmId,
1183
+ timestamp: appended.event.timestamp,
1184
+ parentPolicyVersion: appended.event.parentPolicyVersion,
1185
+ ...(appended.event.taskId ? { taskId: appended.event.taskId } : {}),
1186
+ ...(appended.event.agentId ? { agentId: appended.event.agentId } : {}),
1187
+ ...(appended.event.childRunId ? { childRunId: appended.event.childRunId } : {}),
1188
+ ...(appended.event.failureClass ? { failureClass: appended.event.failureClass } : {}),
1189
+ payload: { ...appended.event.payload }
1190
+ };
1191
+ if (!record.events.some((candidate) => sameCanonicalSwarmEvent(candidate, recordEvent))) {
1192
+ record = { ...record, events: [...record.events, recordEvent], updatedAt: recordEvent.timestamp };
1193
+ }
1194
+ return;
1195
+ }
1196
+ catch (error) {
1197
+ if (!isStaleRevision(error) || parentController.signal.aborted)
1198
+ throw error;
1199
+ }
1200
+ }
1201
+ throw new Error("SWARM_LIVE_EVENT_CONTENTION: event revision did not settle.");
1202
+ }
1203
+ async function finalizeTerminalResult(proposed) {
1204
+ let canonical = proposed;
1205
+ let terminalEvents = (await input.liveStore.readEvents()).filter((event) => (event.type === "SWARM_STOPPED" || event.type === "SWARM_NEEDS_REVIEW" || event.type === "SWARM_VERIFIED"));
1206
+ if (terminalEvents.length === 0) {
1207
+ if (canonical.outcome.state === "verified") {
1208
+ const rejected = withTerminal(canonical.record, "needs_review", "Parent verification lacked a durable terminal authority event.", now());
1209
+ canonical = { ...canonical, record: rejected, outcome: rejected.outcome };
1210
+ }
1211
+ else if (canonical.outcome.state === "running") {
1212
+ const rejected = withTerminal(canonical.record, "needs_review", "Terminal outcome was incomplete.", now());
1213
+ canonical = { ...canonical, record: rejected, outcome: rejected.outcome };
1214
+ }
1215
+ const type = canonical.outcome.state === "stopped" ? "SWARM_STOPPED" : "SWARM_NEEDS_REVIEW";
1216
+ await appendEvent({
1217
+ idempotencyKey: `${input.plan.planHash}:terminal:${canonical.outcome.state}`,
1218
+ type,
1219
+ timestamp: now(),
1220
+ payload: { reason: canonical.outcome.reason }
1221
+ });
1222
+ terminalEvents = (await input.liveStore.readEvents()).filter((event) => (event.type === "SWARM_STOPPED" || event.type === "SWARM_NEEDS_REVIEW" || event.type === "SWARM_VERIFIED"));
1223
+ }
1224
+ if (terminalEvents.length !== 1) {
1225
+ const rejected = withTerminal(canonical.record, "needs_review", "Parent terminal event cardinality is invalid.", now());
1226
+ return { ...canonical, record: rejected, outcome: rejected.outcome };
1227
+ }
1228
+ if (!dependencies.sealTerminal) {
1229
+ if (canonical.outcome.state !== "verified")
1230
+ return canonical;
1231
+ const rejected = withTerminal(canonical.record, "needs_review", "terminal_evidence_sealing_required", now());
1232
+ return { ...canonical, record: rejected, outcome: rejected.outcome };
1233
+ }
1234
+ try {
1235
+ await dependencies.sealTerminal(canonical);
1236
+ }
1237
+ catch {
1238
+ // A seal failure must never erase the primary stopped/needs-review
1239
+ // cause. VERIFIED still fails closed because no verified claim is
1240
+ // authoritative without its committed seal.
1241
+ if (canonical.outcome.state !== "verified")
1242
+ return canonical;
1243
+ const rejected = withTerminal(canonical.record, "needs_review", "terminal_evidence_sealing_failed", now());
1244
+ return { ...canonical, record: rejected, outcome: rejected.outcome };
1245
+ }
1246
+ if (canonical.outcome.state === "verified")
1247
+ authoritativeVerifiedResults.add(canonical);
1248
+ return canonical;
1249
+ }
1250
+ }
1251
+ function assertRuntimeInput(input) {
1252
+ const validation = validateSwarmLivePlan(input.plan);
1253
+ if (!validation.ok)
1254
+ throw new Error("INVALID_LIVE_SWARM_PLAN");
1255
+ if (input.liveStore.plan.planHash !== input.plan.planHash)
1256
+ throw new Error("LIVE_PLAN_STORE_MISMATCH");
1257
+ if (input.workspaceManager.baselineCommit !== input.plan.baselineCommit)
1258
+ throw new Error("LIVE_BASELINE_MISMATCH");
1259
+ }
1260
+ class FileSwarmLiveRuntimeEvidenceStore {
1261
+ root;
1262
+ constructor(root) {
1263
+ this.root = root;
1264
+ }
1265
+ async loadProcessClosure(childRunId) {
1266
+ return this.readJson("process-closures", childRunId);
1267
+ }
1268
+ async persistProcessClosure(evidence) {
1269
+ await this.writeJson("process-closures", evidence.childRunId, evidence);
1270
+ }
1271
+ async persistCandidate(artifact) {
1272
+ const path = await this.resolvePath("candidates", artifact.candidate.candidateId);
1273
+ const payload = JSON.stringify({
1274
+ ...artifact,
1275
+ patch: artifact.patch.toString("base64"),
1276
+ manifest: artifact.manifest.toString("base64"),
1277
+ });
1278
+ await writeExclusive(path, payload);
1279
+ }
1280
+ async loadPersistedCandidate(candidateId) {
1281
+ const stored = await this.readJson("candidates", candidateId);
1282
+ if (!stored)
1283
+ return undefined;
1284
+ return {
1285
+ ...stored,
1286
+ patch: Buffer.from(String(stored.patch ?? ""), "base64"),
1287
+ manifest: Buffer.from(String(stored.manifest ?? ""), "base64"),
1288
+ };
1289
+ }
1290
+ async persistDecision(decision) {
1291
+ await this.writeJson("decisions", decision.candidateId, decision);
1292
+ }
1293
+ async loadPersistedAdmission(candidateId) {
1294
+ const integrated = await this.readJson("integration-outcomes", candidateId);
1295
+ if (integrated !== undefined)
1296
+ return integrated.decision;
1297
+ return this.readJson("decisions", candidateId);
1298
+ }
1299
+ async claimCandidateIntegration(input) {
1300
+ const path = await this.resolvePath("integration-claims", `${input.swarmId}:${input.candidateId}`);
1301
+ try {
1302
+ await writeExclusive(path, JSON.stringify(input));
1303
+ return "claimed";
1304
+ }
1305
+ catch (error) {
1306
+ if (error.code === "EEXIST")
1307
+ return "already_claimed";
1308
+ throw error;
1309
+ }
1310
+ }
1311
+ async persistOutcome(bundle) {
1312
+ await this.writeJson("integration-outcomes", bundle.decision.candidateId, bundle);
1313
+ }
1314
+ async persistReconstruction(record) {
1315
+ await this.writeJson("integration-reconstructions", record.reconstructionId, record);
1316
+ }
1317
+ async persistGlobalVerification(evidence) {
1318
+ await this.writeJson("global-verification", evidence.verificationId, evidence);
1319
+ }
1320
+ async persistChildCompletion(evidence) {
1321
+ await this.writeJson("child-completions", evidence.childRunId, evidence);
1322
+ }
1323
+ async loadPersistedChildCompletion(childRunId) {
1324
+ return this.readJson("child-completions", childRunId);
1325
+ }
1326
+ async persistWorkspaceFailureEvidence(evidence) {
1327
+ await this.writeJson("workspace-failures", evidence.failureId, evidence);
1328
+ }
1329
+ async persistCleanupEvidence(cleanup) {
1330
+ await this.writeJson("cleanup", cleanup.cleanupId, cleanup);
1331
+ }
1332
+ async persistTerminalRecord(record) {
1333
+ await this.writeJson("terminal", record.swarmId, record);
1334
+ }
1335
+ async persistBeforeCleanup(evidence) {
1336
+ await this.writeJson("pre-cleanup", evidence.terminal.childRunId, evidence);
1337
+ }
1338
+ async writeJson(directory, id, value) {
1339
+ const path = await this.resolvePath(directory, id);
1340
+ await writeExclusiveIdempotent(path, JSON.stringify(value, null, 2));
1341
+ }
1342
+ async readJson(directory, id) {
1343
+ const path = await this.resolvePath(directory, id);
1344
+ try {
1345
+ return JSON.parse(await readFile(path, "utf8"));
1346
+ }
1347
+ catch (error) {
1348
+ if (error.code === "ENOENT")
1349
+ return undefined;
1350
+ throw error;
1351
+ }
1352
+ }
1353
+ async resolvePath(directory, id) {
1354
+ const targetDirectory = join(this.root, directory);
1355
+ await mkdir(targetDirectory, { recursive: true });
1356
+ return join(targetDirectory, `${createHash("sha256").update(id).digest("hex")}.json`);
1357
+ }
1358
+ }
1359
+ async function writeExclusive(path, contents) {
1360
+ const handle = await open(path, "wx");
1361
+ try {
1362
+ await handle.writeFile(contents, "utf8");
1363
+ }
1364
+ finally {
1365
+ await handle.close();
1366
+ }
1367
+ }
1368
+ async function writeExclusiveIdempotent(path, contents) {
1369
+ const existing = await lstat(path).catch((error) => {
1370
+ if (isNodeError(error, "ENOENT"))
1371
+ return undefined;
1372
+ throw error;
1373
+ });
1374
+ if (existing?.isSymbolicLink() || (existing && !existing.isFile())) {
1375
+ throw codedRuntimeError("SWARM_SEAL_PATH_ALIAS", "Immutable evidence output path is not an exact regular file.");
1376
+ }
1377
+ try {
1378
+ await writeExclusive(path, contents);
1379
+ return;
1380
+ }
1381
+ catch (error) {
1382
+ if (error.code !== "EEXIST")
1383
+ throw error;
1384
+ }
1385
+ if (await readFile(path, "utf8") === contents)
1386
+ return;
1387
+ throw Object.assign(new Error("Evidence identity already contains different immutable bytes."), {
1388
+ code: "SWARM_EVIDENCE_IDENTITY_CONFLICT",
1389
+ });
1390
+ }
1391
+ function updateTaskAndAgent(record, taskId, agentId, childRunId, taskStatus, agentStatus, updatedAt) {
1392
+ return {
1393
+ ...record,
1394
+ tasks: record.tasks.map((task) => task.taskId === taskId ? { ...task, status: taskStatus, assignedAgentId: agentId } : task),
1395
+ agents: record.agents.map((agent) => agent.agentId === agentId ? { ...agent, status: agentStatus, childRunId } : agent),
1396
+ updatedAt
1397
+ };
1398
+ }
1399
+ function childTerminalEvent(attempt, type, reason, timestamp, failureClass, details = {}) {
1400
+ return {
1401
+ idempotencyKey: `${attempt.childRunId}:${type.toLowerCase()}`,
1402
+ type,
1403
+ timestamp,
1404
+ taskId: attempt.task.taskId,
1405
+ agentId: attempt.agent.agentId,
1406
+ childRunId: attempt.childRunId,
1407
+ ...(failureClass ? { failureClass } : {}),
1408
+ payload: { reason, ...(failureClass ? { failureClass } : {}), ...details, attemptId: attempt.attemptId }
1409
+ };
1410
+ }
1411
+ function withTerminal(record, state, reason, updatedAt) {
1412
+ return { ...record, outcome: { state, reason }, updatedAt };
1413
+ }
1414
+ function terminalResult(record, candidateIds, state, reason) {
1415
+ const finalRecord = withTerminal(record, state, reason, record.updatedAt);
1416
+ return { record: finalRecord, outcome: finalRecord.outcome, candidateIds: Object.freeze([...candidateIds]) };
1417
+ }
1418
+ function runPaths(runsRoot, childRunId) {
1419
+ const directory = runDir(runsRoot, childRunId);
1420
+ return { loopRecord: join(directory, "loop-record.json"), ledger: join(directory, "ledger.jsonl") };
1421
+ }
1422
+ function receiptBindingSha256(input) {
1423
+ return createHash("sha256").update(JSON.stringify({
1424
+ receiptId: input.receiptId,
1425
+ swarmId: input.swarmId,
1426
+ childRunId: input.childRunId,
1427
+ agentId: input.agentId,
1428
+ attemptId: input.attemptId,
1429
+ taskIds: [...input.taskIds].sort(),
1430
+ integrity: {
1431
+ state: input.integrity.state,
1432
+ keyId: input.integrity.keyId,
1433
+ loopRecordSha256: input.integrity.loopRecordSha256,
1434
+ ledgerSha256: input.integrity.ledgerSha256,
1435
+ ledgerHeadHash: input.integrity.ledgerHeadHash
1436
+ }
1437
+ }), "utf8").digest("hex");
1438
+ }
1439
+ function childIdFactory(childRunId, createId) {
1440
+ let issuedLoop = false;
1441
+ return (prefix) => {
1442
+ if (prefix === "loop" && !issuedLoop) {
1443
+ issuedLoop = true;
1444
+ return childRunId;
1445
+ }
1446
+ return createId(prefix);
1447
+ };
1448
+ }
1449
+ function isAdapterHandle(value) {
1450
+ return typeof value === "object" && value !== null && "adapter" in value;
1451
+ }
1452
+ function isStaleRevision(error) {
1453
+ return (typeof error === "object" && error !== null && "code" in error && error.code === "STALE_REVISION")
1454
+ || (error instanceof Error && error.message.includes("STALE_REVISION"));
1455
+ }
1456
+ /** Internal production identity seam; intentionally not exported from the Core root. */
1457
+ export function sameCanonicalSwarmEvent(left, right) {
1458
+ const leftFailureClass = left.failureClass;
1459
+ const rightFailureClass = right.failureClass;
1460
+ return left.type === right.type
1461
+ && left.swarmId === right.swarmId
1462
+ && left.parentPolicyVersion === right.parentPolicyVersion
1463
+ && left.taskId === right.taskId
1464
+ && left.agentId === right.agentId
1465
+ && left.childRunId === right.childRunId
1466
+ && left.timestamp === right.timestamp
1467
+ && leftFailureClass === rightFailureClass
1468
+ && JSON.stringify(left.payload) === JSON.stringify(right.payload);
1469
+ }
1470
+ function safeError(error) {
1471
+ return redactSecretsFromText(error instanceof Error ? error.message : String(error));
1472
+ }
1473
+ function safeErrorCode(error) {
1474
+ if (error instanceof Error && "code" in error) {
1475
+ const code = String(error.code ?? "WORKSPACE_CLEANUP_FAILED");
1476
+ return redactSecretsFromText(code).slice(0, 96);
1477
+ }
1478
+ return "WORKSPACE_CLEANUP_FAILED";
1479
+ }
1480
+ function childFailureClass(result) {
1481
+ return result.decision.failureClass ?? result.loop.attempts.at(-1)?.failureClass;
1482
+ }