intentdna 1.9.0 → 1.9.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 (130) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +227 -87
  4. package/dist/cli/commands/run-lifecycle.d.ts +61 -11
  5. package/dist/cli/commands/run-lifecycle.js +184 -50
  6. package/dist/cli/commands/run-observer.d.ts +15 -0
  7. package/dist/cli/commands/run-observer.js +210 -0
  8. package/dist/cli/commands/run.d.ts +16 -20
  9. package/dist/cli/commands/run.js +461 -659
  10. package/dist/cli/commands/sync.js +16 -12
  11. package/dist/cli/index.js +14 -5
  12. package/dist/compiler/compile.d.ts +1 -0
  13. package/dist/compiler/compile.js +1 -1
  14. package/dist/compiler/controller.d.ts +16 -0
  15. package/dist/compiler/controller.js +693 -0
  16. package/dist/compiler/input-resolver.d.ts +2 -0
  17. package/dist/compiler/input-resolver.js +22 -6
  18. package/dist/hooks/cli.d.ts +45 -0
  19. package/dist/hooks/cli.js +263 -31
  20. package/dist/hooks/host-event.d.ts +57 -0
  21. package/dist/hooks/host-event.js +187 -0
  22. package/dist/hooks/index.d.ts +1 -0
  23. package/dist/hooks/index.js +1 -0
  24. package/dist/hooks/protocol.d.ts +7 -0
  25. package/dist/hooks/schema.d.ts +1 -0
  26. package/dist/hooks/schema.js +89 -1
  27. package/dist/hooks/state.d.ts +23 -1
  28. package/dist/hooks/state.js +9 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +1 -0
  31. package/dist/mcp/index.js +2 -0
  32. package/dist/mcp/tools-run.d.ts +4 -0
  33. package/dist/mcp/tools-run.js +419 -0
  34. package/dist/mcp/tools-state.d.ts +1 -1
  35. package/dist/mcp/tools-state.js +13 -241
  36. package/dist/runtime/artifact-store.d.ts +146 -0
  37. package/dist/runtime/artifact-store.js +1436 -0
  38. package/dist/runtime/canonical-attempt-outcome.d.ts +12 -0
  39. package/dist/runtime/canonical-attempt-outcome.js +195 -0
  40. package/dist/runtime/canonical-json.d.ts +10 -0
  41. package/dist/runtime/canonical-json.js +105 -0
  42. package/dist/runtime/canonical-run-application.d.ts +93 -0
  43. package/dist/runtime/canonical-run-application.js +229 -0
  44. package/dist/runtime/canonical-run-service.d.ts +454 -0
  45. package/dist/runtime/canonical-run-service.js +4760 -0
  46. package/dist/runtime/canonical-runtime-composition.d.ts +22 -0
  47. package/dist/runtime/canonical-runtime-composition.js +34 -0
  48. package/dist/runtime/canonical-runtime-projection.d.ts +3 -0
  49. package/dist/runtime/canonical-runtime-projection.js +4 -0
  50. package/dist/runtime/canonical-target-compiler.d.ts +46 -0
  51. package/dist/runtime/canonical-target-compiler.js +514 -0
  52. package/dist/runtime/claude-agent-identity.d.ts +2 -0
  53. package/dist/runtime/claude-agent-identity.js +21 -0
  54. package/dist/runtime/executable-run-plan.d.ts +328 -0
  55. package/dist/runtime/executable-run-plan.js +1485 -0
  56. package/dist/runtime/execution-authority.d.ts +83 -0
  57. package/dist/runtime/execution-authority.js +98 -0
  58. package/dist/runtime/handoff-resolver.js +4 -1
  59. package/dist/runtime/harness-pull-adapter.d.ts +146 -0
  60. package/dist/runtime/harness-pull-adapter.js +315 -0
  61. package/dist/runtime/index.d.ts +39 -14
  62. package/dist/runtime/index.js +29 -7
  63. package/dist/runtime/local-execution-authority.d.ts +194 -0
  64. package/dist/runtime/local-execution-authority.js +2877 -0
  65. package/dist/runtime/local-execution-reconciliation.d.ts +20 -0
  66. package/dist/runtime/local-execution-reconciliation.js +107 -0
  67. package/dist/runtime/local-execution-supervisor-script.d.ts +7 -0
  68. package/dist/runtime/local-execution-supervisor-script.js +793 -0
  69. package/dist/runtime/local-provider-sandbox.d.ts +42 -0
  70. package/dist/runtime/local-provider-sandbox.js +154 -0
  71. package/dist/runtime/local-verifier-execution.d.ts +24 -0
  72. package/dist/runtime/local-verifier-execution.js +290 -0
  73. package/dist/runtime/local-windows-execution-supervisor-script.d.ts +6 -0
  74. package/dist/runtime/local-windows-execution-supervisor-script.js +771 -0
  75. package/dist/runtime/plan-store.d.ts +30 -0
  76. package/dist/runtime/plan-store.js +231 -0
  77. package/dist/runtime/process-tree.d.ts +9 -0
  78. package/dist/runtime/process-tree.js +97 -24
  79. package/dist/runtime/push-driver.d.ts +184 -0
  80. package/dist/runtime/push-driver.js +1002 -0
  81. package/dist/runtime/result-store.d.ts +34 -3
  82. package/dist/runtime/result-store.js +1073 -2
  83. package/dist/runtime/run-binding.d.ts +68 -0
  84. package/dist/runtime/run-binding.js +278 -0
  85. package/dist/runtime/run-contracts.d.ts +575 -0
  86. package/dist/runtime/run-contracts.js +58 -7
  87. package/dist/runtime/run-controller.d.ts +1 -6
  88. package/dist/runtime/run-controller.js +0 -41
  89. package/dist/runtime/run-store.d.ts +85 -7
  90. package/dist/runtime/run-store.js +2528 -186
  91. package/dist/runtime/skill-adapter.d.ts +18 -7
  92. package/dist/runtime/skill-adapter.js +100 -742
  93. package/dist/runtime/structured-output-validator.d.ts +44 -0
  94. package/dist/runtime/structured-output-validator.js +171 -0
  95. package/dist/runtime/verifier-command-binding.d.ts +22 -0
  96. package/dist/runtime/verifier-command-binding.js +162 -0
  97. package/dist/runtime/verifier.d.ts +46 -6
  98. package/dist/runtime/verifier.js +355 -53
  99. package/dist/runtime/windows-job-keeper.d.ts +47 -0
  100. package/dist/runtime/windows-job-keeper.js +231 -0
  101. package/dist/runtime/worker-executor.d.ts +17 -1
  102. package/dist/runtime/worker-executor.js +26 -5
  103. package/dist/runtime/workflow-plan-adapter.d.ts +19 -0
  104. package/dist/runtime/workflow-plan-adapter.js +502 -6
  105. package/dist/runtime/workflow-runtime-manifest.d.ts +1 -0
  106. package/dist/runtime/workflow-runtime-manifest.js +5 -0
  107. package/dist/runtime/workspace-isolation.d.ts +29 -2
  108. package/dist/runtime/workspace-isolation.js +488 -11
  109. package/dist/runtime/workspace-observation.d.ts +44 -0
  110. package/dist/runtime/workspace-observation.js +216 -0
  111. package/dist/schema/controller-registry.d.ts +0 -7
  112. package/dist/schema/controller-registry.js +0 -8
  113. package/dist/schema/types.d.ts +84 -10
  114. package/dist/schema/types.js +2 -0
  115. package/dist/schema/validate.js +151 -1
  116. package/dist/schema/validators/controllers.d.ts +1 -1
  117. package/dist/schema/validators/controllers.js +126 -41
  118. package/dist/schema/workflow-authoring-contract.js +2 -0
  119. package/dist/schema/yaml-parser.js +1 -1
  120. package/dist/templates/flutter-rewrite-new.dna.yaml +1 -0
  121. package/dist/templates/flutter-rewrite.dna.yaml +87 -60
  122. package/dist/templates/safe-refactoring.dna.yaml +1 -0
  123. package/native/windows-job-keeper/README.md +80 -0
  124. package/native/windows-job-keeper/bin/aarch64/intentdna-windows-job-keeper.exe +0 -0
  125. package/native/windows-job-keeper/bin/x86_64/intentdna-windows-job-keeper.exe +0 -0
  126. package/native/windows-job-keeper/keeper.c +979 -0
  127. package/native/windows-job-keeper/manifest.json +33 -0
  128. package/package.json +5 -1
  129. package/scripts/build-windows-job-keeper.mjs +172 -0
  130. package/scripts/verify-windows-job-keeper.mjs +184 -0
@@ -0,0 +1,2877 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { chmodSync, closeSync, constants as fsConstants, existsSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readdirSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync, } from "node:fs";
4
+ import { connect } from "node:net";
5
+ import { basename, dirname, join, relative, resolve, win32 as win32Path } from "node:path";
6
+ import { canonicalizeJson } from "./canonical-json.js";
7
+ import { validateCanonicalAttemptOutcome } from "./canonical-attempt-outcome.js";
8
+ import { createWorkerAlreadyStoppedEvidence, createWorkerStopReceipt, workerAlreadyStoppedEvidenceDigest, workerAlreadyStoppedEvidenceMatchesStop, workerNonlaunchAttestationDigest, workerStopReceiptDigest, } from "./execution-authority.js";
9
+ import { LOCAL_EXECUTION_SUPERVISOR_DIGEST, LOCAL_EXECUTION_SUPERVISOR_SOURCE, } from "./local-execution-supervisor-script.js";
10
+ import { LOCAL_WINDOWS_EXECUTION_SUPERVISOR_DIGEST, LOCAL_WINDOWS_EXECUTION_SUPERVISOR_SOURCE, } from "./local-windows-execution-supervisor-script.js";
11
+ import { resolveProcessCommand, } from "./process-tree.js";
12
+ import { resolveWindowsJobKeeperArtifact, WindowsJobKeeperArtifactError, } from "./windows-job-keeper.js";
13
+ const RECORD_SCHEMA_VERSION = "intentdna.local_execution_record.v1";
14
+ const CONTROL_SCHEMA_VERSION = "intentdna.local_execution_control.v1";
15
+ const AUTHORITY_SCHEMA_VERSION = "intentdna.local_execution_authority.v1";
16
+ const PREPARATION_SCHEMA_VERSION = "intentdna.local_execution_preparation.v1";
17
+ const PREPARATION_HANDLE_SCHEMA_VERSION = "intentdna.local_execution_preparation_handle.v1";
18
+ const NONLAUNCH_EVIDENCE_SCHEMA_VERSION = "intentdna.local_nonlaunch_evidence.v1";
19
+ const DIRECTORY_MODE = 0o700;
20
+ const PRIVATE_FILE_MODE = 0o600;
21
+ const SCRIPT_FILE_MODE = 0o500;
22
+ const DEFAULT_CONTROL_TIMEOUT_MS = 10_000;
23
+ const DEFAULT_POLL_INTERVAL_MS = 10;
24
+ const DEFAULT_MAX_OUTPUT_BYTES = 16 * 1024 * 1024;
25
+ const MAX_CONTROL_RESPONSE_BYTES = 1024 * 1024;
26
+ export class LocalExecutionAuthorityError extends Error {
27
+ code;
28
+ constructor(code, message, options) {
29
+ super(message, options);
30
+ this.name = "LocalExecutionAuthorityError";
31
+ this.code = code;
32
+ }
33
+ }
34
+ function durableLockOwnersEqual(left, right) {
35
+ return left !== null && canonicalizeJson(left) === canonicalizeJson(right);
36
+ }
37
+ function durableLockOwnerDigest(owner) {
38
+ return createHash("sha256").update(canonicalizeJson(owner), "utf8").digest("hex");
39
+ }
40
+ function recoveryIdentity(request) {
41
+ return {
42
+ run_id: request.run_id,
43
+ step_id: request.step_id,
44
+ activation_id: request.activation_id,
45
+ attempt_id: request.attempt_id,
46
+ claim_epoch: request.execution_claim_epoch,
47
+ worker_session_id: request.executor.worker_session_id,
48
+ started_at: request.started_at,
49
+ };
50
+ }
51
+ function requirePreparationRequest(request) {
52
+ for (const [name, value] of Object.entries({
53
+ run_id: request.run_id,
54
+ step_id: request.step_id,
55
+ activation_id: request.activation_id,
56
+ attempt_id: request.attempt_id,
57
+ worker_session_id: request.worker_session_id,
58
+ })) {
59
+ if (typeof value !== "string" || value.length === 0 || value.includes("\0")) {
60
+ throw new TypeError(`${name} must be a non-empty string without NUL bytes`);
61
+ }
62
+ }
63
+ if (!Number.isSafeInteger(request.execution_claim_epoch) || request.execution_claim_epoch <= 0) {
64
+ throw new TypeError("execution_claim_epoch must be a positive safe integer");
65
+ }
66
+ if (request.execution_instance_id !== undefined
67
+ && (request.execution_instance_id.length === 0 || request.execution_instance_id.includes("\0"))) {
68
+ throw new TypeError("execution_instance_id must be a non-empty string without NUL bytes");
69
+ }
70
+ }
71
+ function preparationCoreIdentity(value) {
72
+ return {
73
+ run_id: value.run_id,
74
+ step_id: value.step_id,
75
+ activation_id: value.activation_id,
76
+ attempt_id: value.attempt_id,
77
+ execution_claim_epoch: value.execution_claim_epoch,
78
+ worker_session_id: value.worker_session_id,
79
+ };
80
+ }
81
+ function preparationDigest(value) {
82
+ return digest({
83
+ schema_version: PREPARATION_SCHEMA_VERSION,
84
+ identity: preparationCoreIdentity(value),
85
+ execution_instance_id: value.execution_instance_id,
86
+ });
87
+ }
88
+ function preparedHandle(preparation) {
89
+ return {
90
+ schema_version: PREPARATION_HANDLE_SCHEMA_VERSION,
91
+ ...preparationCoreIdentity(preparation.identity),
92
+ execution_instance_id: preparation.execution_instance_id,
93
+ preparation_digest: preparation.preparation_digest,
94
+ };
95
+ }
96
+ function digest(value) {
97
+ return `sha256:${createHash("sha256").update(canonicalizeJson(value), "utf8").digest("hex")}`;
98
+ }
99
+ function textDigest(value) {
100
+ return `sha256:${createHash("sha256").update(value, "utf8").digest("hex")}`;
101
+ }
102
+ function digestBytes(value) {
103
+ return `sha256:${createHash("sha256").update(value).digest("hex")}`;
104
+ }
105
+ function isErrno(error, code) {
106
+ return error instanceof Error
107
+ && "code" in error
108
+ && error.code === code;
109
+ }
110
+ function requirePositiveInteger(value, label) {
111
+ if (!Number.isSafeInteger(value) || value <= 0) {
112
+ throw new LocalExecutionAuthorityError("invalid_configuration", `${label} must be a positive safe integer`);
113
+ }
114
+ return value;
115
+ }
116
+ function isCanonicalTimestamp(value) {
117
+ return typeof value === "string"
118
+ && Number.isFinite(Date.parse(value))
119
+ && new Date(Date.parse(value)).toISOString() === value;
120
+ }
121
+ function isCanonicalDigest(value) {
122
+ return typeof value === "string" && /^sha256:[0-9a-f]{64}$/.test(value);
123
+ }
124
+ function isPositiveSafeInteger(value) {
125
+ return Number.isSafeInteger(value) && value > 0;
126
+ }
127
+ function isCanonicalWorkerOutcome(value, workerSessionId) {
128
+ try {
129
+ validateCanonicalAttemptOutcome({ kind: "worker", worker_session_id: workerSessionId }, value);
130
+ return true;
131
+ }
132
+ catch {
133
+ return false;
134
+ }
135
+ }
136
+ function requireIdentity(identity) {
137
+ for (const [name, value] of Object.entries({
138
+ run_id: identity.run_id,
139
+ step_id: identity.step_id,
140
+ activation_id: identity.activation_id,
141
+ attempt_id: identity.attempt_id,
142
+ worker_session_id: identity.worker_session_id,
143
+ started_at: identity.started_at,
144
+ })) {
145
+ if (typeof value !== "string" || value.length === 0 || value.includes("\0")) {
146
+ throw new TypeError(`${name} must be a non-empty string without NUL bytes`);
147
+ }
148
+ }
149
+ if (!Number.isSafeInteger(identity.claim_epoch) || identity.claim_epoch <= 0) {
150
+ throw new TypeError("claim_epoch must be a positive safe integer");
151
+ }
152
+ if (!isCanonicalTimestamp(identity.started_at)) {
153
+ throw new TypeError("started_at must be a canonical RFC 3339 timestamp");
154
+ }
155
+ }
156
+ function coreIdentity(value) {
157
+ return {
158
+ run_id: value.run_id,
159
+ step_id: value.step_id,
160
+ activation_id: value.activation_id,
161
+ attempt_id: value.attempt_id,
162
+ claim_epoch: value.claim_epoch,
163
+ worker_session_id: value.worker_session_id,
164
+ started_at: value.started_at,
165
+ };
166
+ }
167
+ function identityDigest(value) {
168
+ return digest(coreIdentity(value));
169
+ }
170
+ function attemptDigest(value) {
171
+ return digest({
172
+ schema_version: "intentdna.local_execution_attempt_key.v1",
173
+ run_id: value.run_id,
174
+ step_id: value.step_id,
175
+ attempt_id: value.attempt_id,
176
+ });
177
+ }
178
+ function executionRecordDigest(value) {
179
+ return digest({
180
+ schema_version: "intentdna.local_execution_record_key.v2",
181
+ run_id: value.run_id,
182
+ step_id: value.step_id,
183
+ attempt_id: value.attempt_id,
184
+ claim_epoch: value.claim_epoch,
185
+ });
186
+ }
187
+ function requestIdentity(value) {
188
+ return {
189
+ run_id: value.run_id,
190
+ step_id: value.step_id,
191
+ activation_id: value.activation_id,
192
+ attempt_id: value.attempt_id,
193
+ claim_epoch: value.claim_epoch,
194
+ worker_session_id: value.executor.worker_session_id,
195
+ started_at: "started_at" in value ? value.started_at : value.reported_execution.started_at,
196
+ };
197
+ }
198
+ function processMatchesCanonical(actual, canonical) {
199
+ return canonical.kind === "worker_process"
200
+ && canonicalizeJson(actual) === canonicalizeJson(canonical.process);
201
+ }
202
+ function terminalOutcomeToCanonical(process) {
203
+ if (process.kind === "success") {
204
+ return {
205
+ kind: "worker_process",
206
+ status: "succeeded",
207
+ reason_code: null,
208
+ message: null,
209
+ process,
210
+ };
211
+ }
212
+ if (process.kind === "cancelled") {
213
+ return {
214
+ kind: "worker_process",
215
+ status: "cancelled",
216
+ reason_code: "cancelled",
217
+ message: process.reason,
218
+ process,
219
+ };
220
+ }
221
+ return {
222
+ kind: "worker_process",
223
+ status: "failed",
224
+ reason_code: process.kind,
225
+ message: process.kind === "malformed_result" || process.kind === "launch_error"
226
+ ? process.error
227
+ : null,
228
+ process,
229
+ };
230
+ }
231
+ function ensureRealPrivateDirectory(path) {
232
+ mkdirSync(path, { recursive: true, mode: DIRECTORY_MODE });
233
+ const metadata = lstatSync(path);
234
+ if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
235
+ throw new LocalExecutionAuthorityError("corrupt_state", `authority path is not a real directory: ${path}`);
236
+ }
237
+ chmodSync(path, DIRECTORY_MODE);
238
+ }
239
+ function syncDirectory(path) {
240
+ let descriptor = null;
241
+ try {
242
+ descriptor = openSync(path, "r");
243
+ fsyncSync(descriptor);
244
+ }
245
+ catch (error) {
246
+ if (!isErrno(error, "EINVAL")
247
+ && !isErrno(error, "ENOTSUP")
248
+ && !isErrno(error, "EPERM")
249
+ && !isErrno(error, "EACCES")
250
+ && !isErrno(error, "EISDIR"))
251
+ throw error;
252
+ }
253
+ finally {
254
+ if (descriptor !== null)
255
+ closeSync(descriptor);
256
+ }
257
+ }
258
+ function atomicWriteJson(path, value) {
259
+ const directory = dirname(path);
260
+ const temporary = join(directory, `.${basename(path)}.tmp.${process.pid}.${randomUUID()}`);
261
+ const descriptor = openSync(temporary, "wx", PRIVATE_FILE_MODE);
262
+ try {
263
+ writeFileSync(descriptor, `${canonicalizeJson(value)}\n`, "utf8");
264
+ fsyncSync(descriptor);
265
+ }
266
+ finally {
267
+ closeSync(descriptor);
268
+ }
269
+ renameSync(temporary, path);
270
+ syncDirectory(directory);
271
+ }
272
+ function readJson(path) {
273
+ try {
274
+ const metadata = lstatSync(path);
275
+ if (!metadata.isFile()
276
+ || metadata.isSymbolicLink()
277
+ || (process.platform !== "win32" && (metadata.mode & 0o077) !== 0)) {
278
+ throw new LocalExecutionAuthorityError("corrupt_state", `authority file is not private: ${path}`);
279
+ }
280
+ return JSON.parse(readFileSync(path, "utf8"));
281
+ }
282
+ catch (error) {
283
+ if (error instanceof LocalExecutionAuthorityError)
284
+ throw error;
285
+ throw new LocalExecutionAuthorityError("corrupt_state", `cannot read authority file ${path}`, { cause: error });
286
+ }
287
+ }
288
+ function isRecord(value) {
289
+ return typeof value === "object" && value !== null && !Array.isArray(value);
290
+ }
291
+ function hasExactKeys(value, keys) {
292
+ const actual = Object.keys(value).sort();
293
+ const expected = [...keys].sort();
294
+ return actual.length === expected.length
295
+ && actual.every((key, index) => key === expected[index]);
296
+ }
297
+ function isDurablePosixProvider(value) {
298
+ return isRecord(value)
299
+ && hasExactKeys(value, ["pid", "process_group_id", "child_pid", "launched_at"])
300
+ && Number.isSafeInteger(value.pid)
301
+ && value.pid > 0
302
+ && value.process_group_id === value.pid
303
+ && Number.isSafeInteger(value.child_pid)
304
+ && value.child_pid > 0
305
+ && isCanonicalTimestamp(value.launched_at);
306
+ }
307
+ function isPositiveFiletime(value) {
308
+ return typeof value === "string" && /^[1-9][0-9]*$/.test(value);
309
+ }
310
+ function isDurableWindowsProvider(value) {
311
+ return isRecord(value)
312
+ && hasExactKeys(value, [
313
+ "pid",
314
+ "keeper_pid",
315
+ "keeper_creation_filetime",
316
+ "root_pid",
317
+ "root_creation_filetime",
318
+ "job_identifier",
319
+ "containment_nonce",
320
+ "contained_at",
321
+ "released_at",
322
+ ])
323
+ && Number.isSafeInteger(value.pid)
324
+ && value.pid > 0
325
+ && value.pid === value.root_pid
326
+ && Number.isSafeInteger(value.keeper_pid)
327
+ && value.keeper_pid > 0
328
+ && isPositiveFiletime(value.keeper_creation_filetime)
329
+ && Number.isSafeInteger(value.root_pid)
330
+ && value.root_pid > 0
331
+ && isPositiveFiletime(value.root_creation_filetime)
332
+ && isCanonicalDigest(value.job_identifier)
333
+ && typeof value.containment_nonce === "string"
334
+ && /^[0-9a-f]{64}$/.test(value.containment_nonce)
335
+ && isCanonicalTimestamp(value.contained_at)
336
+ && (value.released_at === null || isCanonicalTimestamp(value.released_at));
337
+ }
338
+ function isDurableWindowsJobCompletion(value) {
339
+ return isRecord(value)
340
+ && hasExactKeys(value, [
341
+ "schema_version",
342
+ "kind",
343
+ "reason",
344
+ "root_exit_observed",
345
+ "root_exit_code",
346
+ "windows_signal",
347
+ "active_processes",
348
+ "process_tree_drained",
349
+ ])
350
+ && value.schema_version === "intentdna.windows_job_keeper_fact.v1"
351
+ && value.kind === "completed"
352
+ && ["root_exit", "terminate", "parent_eof", "protocol_error", "drain_timeout", "output_limit"].includes(String(value.reason))
353
+ && typeof value.root_exit_observed === "boolean"
354
+ && Number.isSafeInteger(value.root_exit_code)
355
+ && value.root_exit_code >= 0
356
+ && value.root_exit_code <= 0xffff_ffff
357
+ && value.windows_signal === null
358
+ && value.active_processes === 0
359
+ && value.process_tree_drained === true;
360
+ }
361
+ function isDurableRawCompletion(value) {
362
+ return isRecord(value)
363
+ && hasExactKeys(value, [
364
+ "stdout",
365
+ "stderr",
366
+ "max_output_bytes",
367
+ "timeout_ms",
368
+ "status",
369
+ "signal",
370
+ "timed_out",
371
+ "cancelled",
372
+ "cancellation_reason",
373
+ "process_limit_exceeded",
374
+ "output_limit_exceeded",
375
+ "termination_reason",
376
+ "process_id",
377
+ "process_tree_drained",
378
+ "completed_at",
379
+ "error",
380
+ ...(value.windows_job_completion === undefined ? [] : ["windows_job_completion"]),
381
+ ])
382
+ && isDurableStreamEvidence(value.stdout)
383
+ && isDurableStreamEvidence(value.stderr)
384
+ && Number.isSafeInteger(value.max_output_bytes)
385
+ && value.max_output_bytes > 0
386
+ && (value.timeout_ms === null
387
+ || (Number.isSafeInteger(value.timeout_ms) && value.timeout_ms > 0))
388
+ && (value.status === null || Number.isSafeInteger(value.status))
389
+ && (value.signal === null || typeof value.signal === "string")
390
+ && typeof value.timed_out === "boolean"
391
+ && typeof value.cancelled === "boolean"
392
+ && (value.cancellation_reason === null || typeof value.cancellation_reason === "string")
393
+ && typeof value.process_limit_exceeded === "boolean"
394
+ && typeof value.output_limit_exceeded === "boolean"
395
+ && (value.termination_reason === null
396
+ || ["timeout", "cancellation", "process_limit", "output_limit"].includes(String(value.termination_reason)))
397
+ && (value.process_id === null || (Number.isSafeInteger(value.process_id) && value.process_id > 0))
398
+ && value.process_tree_drained === true
399
+ && isCanonicalTimestamp(value.completed_at)
400
+ && (value.error === null || (isRecord(value.error)
401
+ && hasExactKeys(value.error, ["code", "message"])
402
+ && typeof value.error.code === "string"
403
+ && value.error.code.length > 0
404
+ && typeof value.error.message === "string"
405
+ && value.error.message.length > 0))
406
+ && rawCompletionFlagsAreConsistent(value);
407
+ }
408
+ function isDurableStreamEvidence(value) {
409
+ return isRecord(value)
410
+ && hasExactKeys(value, ["path", "byte_count", "sha256", "device", "inode", "birthtime_ns"])
411
+ && typeof value.path === "string"
412
+ && value.path.length > 0
413
+ && Number.isSafeInteger(value.byte_count)
414
+ && value.byte_count >= 0
415
+ && isCanonicalDigest(value.sha256)
416
+ && typeof value.device === "string"
417
+ && /^(0|[1-9][0-9]*)$/.test(value.device)
418
+ && typeof value.inode === "string"
419
+ && /^(0|[1-9][0-9]*)$/.test(value.inode)
420
+ && typeof value.birthtime_ns === "string"
421
+ && /^(0|[1-9][0-9]*)$/.test(value.birthtime_ns);
422
+ }
423
+ function rawCompletionFlagsAreConsistent(raw) {
424
+ if (raw.stdout.byte_count > raw.max_output_bytes || raw.stderr.byte_count > raw.max_output_bytes) {
425
+ return false;
426
+ }
427
+ if ((raw.status !== null && raw.signal !== null) || (raw.error !== null && raw.termination_reason !== null)) {
428
+ return false;
429
+ }
430
+ if (raw.cancelled !== (raw.termination_reason === "cancellation")
431
+ || raw.timed_out !== (raw.termination_reason === "timeout")
432
+ || raw.process_limit_exceeded !== (raw.termination_reason === "process_limit")
433
+ || raw.output_limit_exceeded !== (raw.termination_reason === "output_limit")) {
434
+ return false;
435
+ }
436
+ if ((raw.cancelled ? true : raw.cancellation_reason === null) === false)
437
+ return false;
438
+ if (raw.timed_out && raw.timeout_ms === null)
439
+ return false;
440
+ if (raw.output_limit_exceeded
441
+ && raw.stdout.byte_count < raw.max_output_bytes
442
+ && raw.stderr.byte_count < raw.max_output_bytes)
443
+ return false;
444
+ if (raw.termination_reason === null && raw.error === null) {
445
+ if (raw.signal !== null)
446
+ return raw.status === null;
447
+ return raw.status !== null;
448
+ }
449
+ return true;
450
+ }
451
+ function windowsCanonicalStopMode(value) {
452
+ if (!isRecord(value)
453
+ || value.kind !== "worker_process"
454
+ || !isRecord(value.process))
455
+ return null;
456
+ if (value.status === "failed"
457
+ && value.process.kind === "timeout"
458
+ && hasExactKeys(value.process, ["kind", "exit_code", "signal", "timeout_ms"])
459
+ && value.process.exit_code === null
460
+ && value.process.signal === null
461
+ && Number.isSafeInteger(value.process.timeout_ms)
462
+ && value.process.timeout_ms > 0)
463
+ return { kind: "timeout", reason: null };
464
+ if (value.status === "cancelled"
465
+ && value.process.kind === "cancelled"
466
+ && hasExactKeys(value.process, ["kind", "exit_code", "signal", "reason"])
467
+ && value.process.exit_code === null
468
+ && value.process.signal === null
469
+ && (value.process.reason === null || typeof value.process.reason === "string"))
470
+ return { kind: "cancellation", reason: value.process.reason };
471
+ return null;
472
+ }
473
+ function windowsStopExpectation(value) {
474
+ if (value === null) {
475
+ return {
476
+ timedOut: false,
477
+ cancelled: false,
478
+ outputLimited: false,
479
+ cancellationReason: null,
480
+ terminationReason: null,
481
+ };
482
+ }
483
+ if (value.kind === "timeout") {
484
+ if (!hasExactKeys(value, ["kind", "reason"])
485
+ || value.reason !== "timeout")
486
+ return null;
487
+ return {
488
+ timedOut: true,
489
+ cancelled: false,
490
+ outputLimited: false,
491
+ cancellationReason: null,
492
+ terminationReason: "timeout",
493
+ };
494
+ }
495
+ if (value.kind === "local_cancel") {
496
+ if (!hasExactKeys(value, ["kind", "reason"])
497
+ || (value.reason !== null && typeof value.reason !== "string"))
498
+ return null;
499
+ return {
500
+ timedOut: false,
501
+ cancelled: true,
502
+ outputLimited: false,
503
+ cancellationReason: value.reason ?? null,
504
+ terminationReason: "cancellation",
505
+ };
506
+ }
507
+ if (value.kind === "output_limit") {
508
+ if (!hasExactKeys(value, ["kind", "reason"])
509
+ || value.reason !== "output_limit")
510
+ return null;
511
+ return {
512
+ timedOut: false,
513
+ cancelled: false,
514
+ outputLimited: true,
515
+ cancellationReason: null,
516
+ terminationReason: "output_limit",
517
+ };
518
+ }
519
+ if (value.kind !== "canonical_stop"
520
+ || !hasExactKeys(value, [
521
+ "kind",
522
+ "stop_idempotency_key",
523
+ "requested_at",
524
+ "requested_outcome",
525
+ ])
526
+ || !isCanonicalDigest(value.stop_idempotency_key)
527
+ || !isCanonicalTimestamp(value.requested_at))
528
+ return null;
529
+ const mode = windowsCanonicalStopMode(value.requested_outcome);
530
+ return mode === null ? null : {
531
+ timedOut: mode.kind === "timeout",
532
+ cancelled: mode.kind === "cancellation",
533
+ outputLimited: false,
534
+ cancellationReason: mode.reason,
535
+ terminationReason: mode.kind,
536
+ };
537
+ }
538
+ function windowsCompletionMatchesRecord(record) {
539
+ if (record.backend.kind !== "windows_job" || record.raw_completion === null)
540
+ return true;
541
+ const raw = record.raw_completion;
542
+ const provider = record.provider;
543
+ const fact = raw.windows_job_completion;
544
+ const expected = windowsStopExpectation(record.stop_fact);
545
+ if (!isDurableWindowsProvider(provider)
546
+ || provider.released_at === null
547
+ || !isDurableWindowsJobCompletion(fact)
548
+ || expected === null
549
+ || raw.process_id !== provider.root_pid
550
+ || raw.signal !== null
551
+ || raw.error !== null
552
+ || raw.completed_at < provider.released_at
553
+ || fact.reason === "parent_eof"
554
+ || fact.reason === "protocol_error")
555
+ return false;
556
+ const stopped = expected.timedOut || expected.cancelled || expected.outputLimited;
557
+ return raw.timed_out === expected.timedOut
558
+ && raw.cancelled === expected.cancelled
559
+ && raw.cancellation_reason === expected.cancellationReason
560
+ && raw.process_limit_exceeded === false
561
+ && raw.output_limit_exceeded === expected.outputLimited
562
+ && (stopped
563
+ ? fact.reason === (expected.outputLimited ? "output_limit" : "terminate")
564
+ && raw.status === null
565
+ && raw.termination_reason === expected.terminationReason
566
+ : (fact.reason === "root_exit" || fact.reason === "drain_timeout")
567
+ && fact.root_exit_observed
568
+ && raw.status === fact.root_exit_code
569
+ && raw.termination_reason === null);
570
+ }
571
+ function windowsPhaseMatchesRecord(record) {
572
+ if (record.backend.kind !== "windows_job")
573
+ return true;
574
+ const supervisorReady = record.supervisor.pid !== null && record.supervisor.ready_at !== null;
575
+ if (record.phase === "never_launched" || record.phase === "prepared" || record.phase === "launching") {
576
+ return !supervisorReady
577
+ && record.provider === null
578
+ && record.raw_completion === null
579
+ && record.stop_fact === null;
580
+ }
581
+ if (record.phase === "running") {
582
+ return supervisorReady && record.raw_completion === null;
583
+ }
584
+ if (["raw_completed", "normalized_completed", "receipted"].includes(record.phase)) {
585
+ return supervisorReady
586
+ && isDurableWindowsProvider(record.provider)
587
+ && record.provider.released_at !== null
588
+ && record.raw_completion !== null;
589
+ }
590
+ return record.phase === "unsupported";
591
+ }
592
+ function isDurableBackend(value) {
593
+ if (!isRecord(value) || typeof value.kind !== "string")
594
+ return false;
595
+ if (value.kind === "posix_process_group") {
596
+ return hasExactKeys(value, ["kind"]);
597
+ }
598
+ return value.kind === "windows_job"
599
+ && hasExactKeys(value, [
600
+ "kind",
601
+ "architecture",
602
+ "helper_path",
603
+ "helper_digest",
604
+ "helper_source_digest",
605
+ "helper_protocol_version",
606
+ "containment_nonce",
607
+ ])
608
+ && ["x86_64", "aarch64"].includes(String(value.architecture))
609
+ && typeof value.helper_path === "string"
610
+ && value.helper_path.length > 0
611
+ && isCanonicalDigest(value.helper_digest)
612
+ && isCanonicalDigest(value.helper_source_digest)
613
+ && value.helper_protocol_version === "IDNA_WINDOWS_JOB_KEEPER_V1"
614
+ && typeof value.containment_nonce === "string"
615
+ && /^[0-9a-f]{64}$/.test(value.containment_nonce);
616
+ }
617
+ function isDurableSupervisor(value, backend) {
618
+ if (!isRecord(value) || !hasExactKeys(value, [
619
+ "kind",
620
+ "socket_path",
621
+ "script_digest",
622
+ "pid",
623
+ "ready_at",
624
+ ]))
625
+ return false;
626
+ const expectedKind = backend.kind === "windows_job" ? "windows" : "posix";
627
+ const expectedDigest = backend.kind === "windows_job"
628
+ ? LOCAL_WINDOWS_EXECUTION_SUPERVISOR_DIGEST
629
+ : LOCAL_EXECUTION_SUPERVISOR_DIGEST;
630
+ return value.kind === expectedKind
631
+ && typeof value.socket_path === "string"
632
+ && value.socket_path.length > 0
633
+ && value.script_digest === expectedDigest
634
+ && (value.pid === null || (Number.isSafeInteger(value.pid) && value.pid > 0))
635
+ && (value.ready_at === null || isCanonicalTimestamp(value.ready_at));
636
+ }
637
+ function nonlaunchSourceEvidenceDigest(record) {
638
+ const { nonlaunch_attestation: _attestation, ...durableEvidence } = record;
639
+ return digest({
640
+ schema_version: NONLAUNCH_EVIDENCE_SCHEMA_VERSION,
641
+ durable_record: durableEvidence,
642
+ });
643
+ }
644
+ function alreadyStoppedSourceEvidenceDigest(record) {
645
+ return digest({
646
+ schema_version: "intentdna.local_already_stopped_source_evidence.v1",
647
+ identity_digest: record.identity_digest,
648
+ execution_instance_id: record.execution_instance_id,
649
+ authority_instance_id: record.authority_instance_id,
650
+ backend: record.backend,
651
+ supervisor: record.supervisor,
652
+ provider: record.provider,
653
+ raw_completion: record.raw_completion,
654
+ normalized_process_outcome: record.normalized_process_outcome,
655
+ });
656
+ }
657
+ function stopReceiptSourceEvidenceDigest(record) {
658
+ return digest({
659
+ identity_digest: record.identity_digest,
660
+ supervisor: record.supervisor,
661
+ provider: record.provider,
662
+ raw_completion: record.raw_completion,
663
+ normalized_process_outcome: record.normalized_process_outcome,
664
+ stop_fact: record.stop_fact,
665
+ });
666
+ }
667
+ function isDurableStopFact(value, workerSessionId) {
668
+ if (!isRecord(value) || typeof value.kind !== "string")
669
+ return false;
670
+ if (value.kind === "canonical_stop") {
671
+ return hasExactKeys(value, [
672
+ "kind",
673
+ "stop_idempotency_key",
674
+ "requested_at",
675
+ "requested_outcome",
676
+ ])
677
+ && isCanonicalDigest(value.stop_idempotency_key)
678
+ && isCanonicalTimestamp(value.requested_at)
679
+ && isCanonicalWorkerOutcome(value.requested_outcome, workerSessionId);
680
+ }
681
+ if (!hasExactKeys(value, ["kind", "reason"]))
682
+ return false;
683
+ if (value.kind === "local_cancel") {
684
+ return value.reason === null || typeof value.reason === "string";
685
+ }
686
+ return (value.kind === "timeout" && value.reason === "timeout")
687
+ || (value.kind === "process_limit" && value.reason === "process_limit")
688
+ || (value.kind === "output_limit" && value.reason === "output_limit");
689
+ }
690
+ function isDurableStopReceipt(value, record) {
691
+ if (!isRecord(value)
692
+ || !hasExactKeys(value, ["receipt_digest", "payload"])
693
+ || !isCanonicalDigest(value.receipt_digest)
694
+ || !isRecord(value.payload)
695
+ || !hasExactKeys(value.payload, [
696
+ "schema_version",
697
+ "run_id",
698
+ "step_id",
699
+ "activation_id",
700
+ "attempt_id",
701
+ "claim_epoch",
702
+ "worker_session_id",
703
+ "execution_instance_id",
704
+ "authority_kind",
705
+ "authority_instance_id",
706
+ "fencing_epoch",
707
+ "started_at",
708
+ "stopped_at",
709
+ "terminal_outcome",
710
+ "process_tree_drained",
711
+ "source_evidence_digest",
712
+ ]))
713
+ return false;
714
+ const receipt = value;
715
+ const payload = receipt.payload;
716
+ if (payload.schema_version !== "intentdna.worker_stop_receipt.v1"
717
+ || payload.run_id !== record.identity.run_id
718
+ || payload.step_id !== record.identity.step_id
719
+ || payload.activation_id !== record.identity.activation_id
720
+ || payload.attempt_id !== record.identity.attempt_id
721
+ || payload.claim_epoch !== record.identity.claim_epoch
722
+ || payload.worker_session_id !== record.identity.worker_session_id
723
+ || payload.execution_instance_id !== record.execution_instance_id
724
+ || payload.authority_kind !== "local_process"
725
+ || payload.authority_instance_id !== record.authority_instance_id
726
+ || !isPositiveSafeInteger(payload.fencing_epoch)
727
+ || payload.fencing_epoch !== record.fencing_epoch
728
+ || payload.started_at !== record.identity.started_at
729
+ || !isCanonicalTimestamp(payload.stopped_at)
730
+ || payload.stopped_at < payload.started_at
731
+ || record.raw_completion === null
732
+ || payload.stopped_at < record.raw_completion.completed_at
733
+ || !isCanonicalWorkerOutcome(payload.terminal_outcome, record.identity.worker_session_id)
734
+ || payload.process_tree_drained !== true
735
+ || !isCanonicalDigest(payload.source_evidence_digest)
736
+ || payload.source_evidence_digest !== stopReceiptSourceEvidenceDigest(record)
737
+ || receipt.receipt_digest !== workerStopReceiptDigest(payload))
738
+ return false;
739
+ if (record.stop_fact?.kind === "canonical_stop") {
740
+ return payload.stopped_at >= record.stop_fact.requested_at
741
+ && canonicalizeJson(payload.terminal_outcome)
742
+ === canonicalizeJson(record.stop_fact.requested_outcome);
743
+ }
744
+ return record.normalized_process_outcome !== null
745
+ && processMatchesCanonical(record.normalized_process_outcome, payload.terminal_outcome);
746
+ }
747
+ function parseRecord(value) {
748
+ if (!isRecord(value)
749
+ || !hasExactKeys(value, [
750
+ "schema_version",
751
+ "revision",
752
+ "phase",
753
+ "identity",
754
+ "identity_digest",
755
+ "execution_instance_id",
756
+ "challenge",
757
+ "authority_instance_id",
758
+ "backend",
759
+ "supervisor",
760
+ "provider",
761
+ "raw_completion",
762
+ "normalized_process_outcome",
763
+ "stop_fact",
764
+ "stop_receipt",
765
+ "already_stopped_evidence",
766
+ "nonlaunch_attestation",
767
+ "fencing_epoch",
768
+ "supervisor_error",
769
+ "created_at",
770
+ "updated_at",
771
+ ])
772
+ || value.schema_version !== RECORD_SCHEMA_VERSION) {
773
+ throw new LocalExecutionAuthorityError("corrupt_state", "execution authority record has an invalid schema");
774
+ }
775
+ const record = value;
776
+ const nonlaunchAttestation = record.nonlaunch_attestation;
777
+ requireIdentity(record.identity);
778
+ const hasFencedEvidence = record.stop_receipt !== null
779
+ || record.already_stopped_evidence !== null
780
+ || record.nonlaunch_attestation !== null;
781
+ if (record.identity_digest !== identityDigest(record.identity)
782
+ || record.execution_instance_id !== record.identity.execution_instance_id
783
+ || !Number.isSafeInteger(record.revision)
784
+ || record.revision <= 0
785
+ || !["never_launched", "prepared", "launching", "running", "raw_completed", "normalized_completed", "receipted", "unsupported"].includes(record.phase)
786
+ || typeof record.challenge !== "string"
787
+ || record.challenge.length < 32
788
+ || typeof record.authority_instance_id !== "string"
789
+ || record.authority_instance_id.length === 0
790
+ || !isDurableBackend(record.backend)
791
+ || !isDurableSupervisor(record.supervisor, record.backend)
792
+ || ((record.supervisor.pid === null) !== (record.supervisor.ready_at === null))
793
+ || (record.raw_completion !== null && !isDurableRawCompletion(record.raw_completion))
794
+ || (record.stop_fact !== null
795
+ && !isDurableStopFact(record.stop_fact, record.identity.worker_session_id))
796
+ || (hasFencedEvidence
797
+ ? !isPositiveSafeInteger(record.fencing_epoch)
798
+ : record.fencing_epoch !== null)
799
+ || !isCanonicalTimestamp(record.created_at)
800
+ || !isCanonicalTimestamp(record.updated_at)
801
+ || record.updated_at < record.created_at) {
802
+ throw new LocalExecutionAuthorityError("corrupt_state", "execution authority record failed identity validation");
803
+ }
804
+ if ((record.phase === "never_launched" && (nonlaunchAttestation === null
805
+ || record.provider !== null
806
+ || record.raw_completion !== null
807
+ || record.supervisor.pid !== null
808
+ || nonlaunchAttestation.attestation_digest
809
+ !== workerNonlaunchAttestationDigest(nonlaunchAttestation.payload)
810
+ || nonlaunchAttestation.payload.execution_instance_id !== record.execution_instance_id
811
+ || nonlaunchAttestation.payload.authority_instance_id !== record.authority_instance_id
812
+ || nonlaunchAttestation.payload.run_id !== record.identity.run_id
813
+ || nonlaunchAttestation.payload.step_id !== record.identity.step_id
814
+ || nonlaunchAttestation.payload.activation_id !== record.identity.activation_id
815
+ || nonlaunchAttestation.payload.attempt_id !== record.identity.attempt_id
816
+ || nonlaunchAttestation.payload.claim_epoch !== record.identity.claim_epoch
817
+ || nonlaunchAttestation.payload.worker_session_id !== record.identity.worker_session_id
818
+ || nonlaunchAttestation.payload.started_at !== record.identity.started_at
819
+ || nonlaunchAttestation.payload.launch_state !== "never_launched"
820
+ || nonlaunchAttestation.payload.authority_kind !== "local_process"
821
+ || nonlaunchAttestation.payload.schema_version !== "intentdna.worker_nonlaunch_attestation.v1"
822
+ || !Number.isSafeInteger(nonlaunchAttestation.payload.fencing_epoch)
823
+ || nonlaunchAttestation.payload.fencing_epoch <= 0
824
+ || nonlaunchAttestation.payload.fencing_epoch !== record.fencing_epoch
825
+ || !isCanonicalTimestamp(nonlaunchAttestation.payload.attested_at)
826
+ || !isCanonicalDigest(nonlaunchAttestation.payload.failure_idempotency_key)
827
+ || !isCanonicalDigest(nonlaunchAttestation.payload.source_evidence_digest)
828
+ || nonlaunchAttestation.payload.source_evidence_digest
829
+ !== nonlaunchSourceEvidenceDigest(record)))
830
+ || (record.phase !== "never_launched" && nonlaunchAttestation !== null)
831
+ || (record.already_stopped_evidence !== null && (record.raw_completion === null
832
+ || record.stop_receipt !== null
833
+ || record.fencing_epoch === null
834
+ || record.already_stopped_evidence.evidence_digest
835
+ !== workerAlreadyStoppedEvidenceDigest(record.already_stopped_evidence.payload)
836
+ || record.already_stopped_evidence.payload.schema_version
837
+ !== "intentdna.worker_already_stopped_evidence.v1"
838
+ || record.already_stopped_evidence.payload.run_id !== record.identity.run_id
839
+ || record.already_stopped_evidence.payload.step_id !== record.identity.step_id
840
+ || record.already_stopped_evidence.payload.activation_id !== record.identity.activation_id
841
+ || record.already_stopped_evidence.payload.attempt_id !== record.identity.attempt_id
842
+ || record.already_stopped_evidence.payload.claim_epoch !== record.identity.claim_epoch
843
+ || record.already_stopped_evidence.payload.worker_session_id !== record.identity.worker_session_id
844
+ || record.already_stopped_evidence.payload.execution_instance_id !== record.execution_instance_id
845
+ || record.already_stopped_evidence.payload.authority_instance_id !== record.authority_instance_id
846
+ || record.already_stopped_evidence.payload.authority_kind !== "local_process"
847
+ || record.already_stopped_evidence.payload.fencing_epoch !== record.fencing_epoch
848
+ || record.already_stopped_evidence.payload.started_at !== record.identity.started_at
849
+ || record.already_stopped_evidence.payload.completed_at !== record.raw_completion.completed_at
850
+ || canonicalizeJson(record.already_stopped_evidence.payload.observed_outcome)
851
+ !== canonicalizeJson(terminalOutcomeToCanonical(rawCompletionToOutcome(record.raw_completion)))
852
+ || record.already_stopped_evidence.payload.process_tree_drained !== true
853
+ || !isCanonicalDigest(record.already_stopped_evidence.payload.stop_idempotency_key)
854
+ || !isCanonicalTimestamp(record.already_stopped_evidence.payload.stop_requested_at)
855
+ || !["cancel", "execution_deadline", "peer_terminal"].includes(record.already_stopped_evidence.payload.stop_purpose)
856
+ || record.already_stopped_evidence.payload.source_evidence_digest
857
+ !== alreadyStoppedSourceEvidenceDigest(record)))
858
+ || (record.stop_receipt !== null && record.already_stopped_evidence !== null)
859
+ || (record.stop_receipt !== null && !isDurableStopReceipt(record.stop_receipt, record))
860
+ || (record.provider !== null && (record.backend.kind === "windows_job"
861
+ ? !isDurableWindowsProvider(record.provider)
862
+ : !isDurablePosixProvider(record.provider)))
863
+ || (record.backend.kind === "windows_job" && record.provider !== null
864
+ && (!isDurableWindowsProvider(record.provider)
865
+ || record.provider.containment_nonce !== record.backend.containment_nonce))
866
+ || (record.phase === "prepared" && record.provider !== null)
867
+ || (record.phase === "raw_completed" && record.raw_completion === null)
868
+ || (record.raw_completion !== null && record.raw_completion.process_tree_drained !== true)
869
+ || !windowsPhaseMatchesRecord(record)
870
+ || !windowsCompletionMatchesRecord(record)
871
+ || (record.phase === "normalized_completed" && (record.raw_completion === null || record.normalized_process_outcome === null))
872
+ || (record.phase === "receipted" && (record.raw_completion === null
873
+ || (record.stop_receipt === null && record.already_stopped_evidence === null)
874
+ || record.fencing_epoch === null))) {
875
+ throw new LocalExecutionAuthorityError("corrupt_state", "execution authority phase lacks required evidence");
876
+ }
877
+ return record;
878
+ }
879
+ function processIsAlive(pid) {
880
+ try {
881
+ process.kill(pid, 0);
882
+ return true;
883
+ }
884
+ catch (error) {
885
+ return isErrno(error, "EPERM");
886
+ }
887
+ }
888
+ function processBirthIdentity(pid, platform) {
889
+ if (!Number.isSafeInteger(pid) || pid <= 0)
890
+ return null;
891
+ if (platform === "linux") {
892
+ try {
893
+ const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
894
+ const fields = stat.slice(stat.lastIndexOf(")") + 2).trim().split(/\s+/);
895
+ const startTicks = fields[19];
896
+ return startTicks !== undefined && /^[0-9]+$/.test(startTicks)
897
+ ? `linux-start-ticks:${startTicks}`
898
+ : null;
899
+ }
900
+ catch {
901
+ return null;
902
+ }
903
+ }
904
+ if (platform !== "win32") {
905
+ const result = spawnSync("ps", ["-p", String(pid), "-o", "lstart="], {
906
+ encoding: "utf8",
907
+ timeout: 1_000,
908
+ windowsHide: true,
909
+ });
910
+ const started = result.status === 0 ? result.stdout.trim().replace(/\s+/g, " ") : "";
911
+ return started === "" ? null : `${platform}-lstart:${started}`;
912
+ }
913
+ return pid === process.pid ? `node-time-origin-ms:${Math.floor(performance.timeOrigin)}` : null;
914
+ }
915
+ function durableLockOwner(platform) {
916
+ const processBirthId = processBirthIdentity(process.pid, platform);
917
+ if (processBirthId === null) {
918
+ throw new LocalExecutionAuthorityError("unsupported", "cannot establish execution lock owner identity");
919
+ }
920
+ return {
921
+ schema_version: "intentdna.execution_lock_owner.v1",
922
+ pid: process.pid,
923
+ process_birth_id: processBirthId,
924
+ generation: randomUUID(),
925
+ acquired_at: Date.now(),
926
+ };
927
+ }
928
+ function readDurableLockOwner(path) {
929
+ try {
930
+ const value = JSON.parse(readFileSync(path, "utf8"));
931
+ if (!isRecord(value)
932
+ || !hasExactKeys(value, ["schema_version", "pid", "process_birth_id", "generation", "acquired_at"])
933
+ || value.schema_version !== "intentdna.execution_lock_owner.v1"
934
+ || !Number.isSafeInteger(value.pid)
935
+ || value.pid <= 0
936
+ || typeof value.process_birth_id !== "string"
937
+ || value.process_birth_id.length === 0
938
+ || typeof value.generation !== "string"
939
+ || value.generation.length === 0
940
+ || !Number.isSafeInteger(value.acquired_at)
941
+ || value.acquired_at < 0)
942
+ return null;
943
+ return value;
944
+ }
945
+ catch {
946
+ return null;
947
+ }
948
+ }
949
+ function publishDurableLock(lockPath, owner) {
950
+ const candidatePath = `${lockPath}.candidate.${process.pid}.${randomUUID()}`;
951
+ mkdirSync(candidatePath, { mode: DIRECTORY_MODE });
952
+ try {
953
+ const descriptor = openSync(join(candidatePath, "owner.json"), "wx", PRIVATE_FILE_MODE);
954
+ try {
955
+ writeFileSync(descriptor, `${canonicalizeJson(owner)}\n`, "utf8");
956
+ fsyncSync(descriptor);
957
+ }
958
+ finally {
959
+ closeSync(descriptor);
960
+ }
961
+ syncDirectory(candidatePath);
962
+ try {
963
+ renameSync(candidatePath, lockPath);
964
+ }
965
+ catch (error) {
966
+ if (isErrno(error, "EEXIST") || isErrno(error, "ENOTEMPTY")
967
+ || (isErrno(error, "EPERM") && existsSync(lockPath)))
968
+ return false;
969
+ throw error;
970
+ }
971
+ syncDirectory(dirname(lockPath));
972
+ return true;
973
+ }
974
+ finally {
975
+ rmSync(candidatePath, { recursive: true, force: true });
976
+ }
977
+ }
978
+ function releaseDurableLock(lockPath, owner) {
979
+ const ownerPath = join(lockPath, "owner.json");
980
+ if (!existsSync(ownerPath))
981
+ return;
982
+ const current = readDurableLockOwner(ownerPath);
983
+ if (current === null) {
984
+ throw new LocalExecutionAuthorityError("corrupt_state", "execution authority lock owner is invalid during release");
985
+ }
986
+ if (!durableLockOwnersEqual(current, owner))
987
+ return;
988
+ const releasedPath = `${lockPath}.released.${durableLockOwnerDigest(owner)}.${randomUUID()}`;
989
+ try {
990
+ renameSync(lockPath, releasedPath);
991
+ }
992
+ catch (error) {
993
+ if (isErrno(error, "ENOENT"))
994
+ return;
995
+ throw error;
996
+ }
997
+ syncDirectory(dirname(lockPath));
998
+ const releasedOwner = readDurableLockOwner(join(releasedPath, "owner.json"));
999
+ if (!durableLockOwnersEqual(releasedOwner, owner)) {
1000
+ throw new LocalExecutionAuthorityError("corrupt_state", "execution authority lock ownership changed during release");
1001
+ }
1002
+ rmSync(releasedPath, { recursive: true, force: true });
1003
+ syncDirectory(dirname(lockPath));
1004
+ }
1005
+ /**
1006
+ * Retires one observed stale generation without exposing a later generation to
1007
+ * delayed contenders. The non-empty, generation-specific tombstone is retained
1008
+ * so a contender that observed the same owner can never rename a successor over it.
1009
+ * This is exported only for lock-protocol regression tests, not from the runtime barrel.
1010
+ */
1011
+ export function retireObservedStaleDurableLock(lockPath, observed) {
1012
+ const quarantine = `${lockPath}.stale.${durableLockOwnerDigest(observed)}`;
1013
+ try {
1014
+ renameSync(lockPath, quarantine);
1015
+ }
1016
+ catch (error) {
1017
+ if (isErrno(error, "ENOENT")
1018
+ || isErrno(error, "EEXIST")
1019
+ || isErrno(error, "ENOTEMPTY")
1020
+ || ((isErrno(error, "EPERM") || isErrno(error, "EACCES")) && existsSync(quarantine)))
1021
+ return false;
1022
+ throw error;
1023
+ }
1024
+ syncDirectory(dirname(lockPath));
1025
+ const retiredOwner = readDurableLockOwner(join(quarantine, "owner.json"));
1026
+ if (!durableLockOwnersEqual(retiredOwner, observed)) {
1027
+ throw new LocalExecutionAuthorityError("corrupt_state", "execution authority lock ownership changed during stale takeover");
1028
+ }
1029
+ return true;
1030
+ }
1031
+ function staleDurableLock(owner, platform) {
1032
+ if (platform === "win32" || owner === null)
1033
+ return false;
1034
+ if (!processIsAlive(owner.pid))
1035
+ return true;
1036
+ const actualBirthId = processBirthIdentity(owner.pid, platform);
1037
+ return actualBirthId !== null && actualBirthId !== owner.process_birth_id;
1038
+ }
1039
+ function providerProcessId(record) {
1040
+ if (record.provider === null)
1041
+ return null;
1042
+ return record.backend.kind === "windows_job"
1043
+ ? isDurableWindowsProvider(record.provider) ? record.provider.root_pid : null
1044
+ : isDurablePosixProvider(record.provider) ? record.provider.process_group_id : null;
1045
+ }
1046
+ function providerMatchesProcessId(record, processId) {
1047
+ return providerProcessId(record) === processId;
1048
+ }
1049
+ function windowsVerbatimCommandLine(executable, args) {
1050
+ if (executable.includes("\0") || executable.includes('"')) {
1051
+ throw new LocalExecutionAuthorityError("unsupported", "Windows executable path cannot be represented verbatim");
1052
+ }
1053
+ const executableToken = /\s/.test(executable) ? `"${executable}"` : executable;
1054
+ const value = [executableToken, ...args].join(" ");
1055
+ if (value.length === 0 || value.length > 32_766 || value.includes("\0")) {
1056
+ throw new LocalExecutionAuthorityError("unsupported", "Windows verbatim command line exceeds the platform limit");
1057
+ }
1058
+ return value;
1059
+ }
1060
+ function sleep(milliseconds) {
1061
+ return new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds));
1062
+ }
1063
+ function rawCompletionToOutcome(raw) {
1064
+ if (raw.cancelled) {
1065
+ return {
1066
+ kind: "cancelled",
1067
+ exit_code: raw.status,
1068
+ signal: raw.signal,
1069
+ reason: raw.cancellation_reason,
1070
+ };
1071
+ }
1072
+ if (raw.timed_out) {
1073
+ return {
1074
+ kind: "timeout",
1075
+ exit_code: raw.status,
1076
+ signal: raw.signal,
1077
+ timeout_ms: raw.timeout_ms,
1078
+ };
1079
+ }
1080
+ if (raw.error !== null) {
1081
+ return {
1082
+ kind: "launch_error",
1083
+ exit_code: null,
1084
+ signal: null,
1085
+ error: raw.error.message,
1086
+ };
1087
+ }
1088
+ if (raw.output_limit_exceeded || raw.process_limit_exceeded) {
1089
+ return {
1090
+ kind: "malformed_result",
1091
+ exit_code: raw.status,
1092
+ signal: null,
1093
+ error: raw.output_limit_exceeded
1094
+ ? "provider output limit exceeded"
1095
+ : "provider process limit exceeded",
1096
+ };
1097
+ }
1098
+ if (raw.signal !== null) {
1099
+ return { kind: "signal", exit_code: null, signal: raw.signal };
1100
+ }
1101
+ if (raw.status === 0)
1102
+ return { kind: "success", exit_code: 0, signal: null };
1103
+ return { kind: "non_zero_exit", exit_code: raw.status ?? -1, signal: null };
1104
+ }
1105
+ function rawCompletionToResult(raw, stdout, stderr) {
1106
+ return {
1107
+ stdout,
1108
+ stderr,
1109
+ status: raw.status,
1110
+ signal: raw.signal,
1111
+ timedOut: raw.timed_out,
1112
+ cancelled: raw.cancelled,
1113
+ cancellationReason: raw.cancellation_reason,
1114
+ processLimitExceeded: raw.process_limit_exceeded,
1115
+ outputLimitExceeded: raw.output_limit_exceeded,
1116
+ terminationReason: raw.termination_reason,
1117
+ processId: raw.process_id,
1118
+ processTreeDrained: raw.process_tree_drained,
1119
+ ...(raw.error === null
1120
+ ? {}
1121
+ : {
1122
+ error: Object.assign(new Error(raw.error.message), { code: raw.error.code }),
1123
+ }),
1124
+ };
1125
+ }
1126
+ export class LocalAttemptExecutionAuthority {
1127
+ rootDirectory;
1128
+ preparationsDirectory;
1129
+ transitionsDirectory;
1130
+ recordsDirectory;
1131
+ socketsDirectory;
1132
+ streamsDirectory;
1133
+ controlNamespace;
1134
+ authorityInstanceId;
1135
+ controlTimeoutMs;
1136
+ pollIntervalMs;
1137
+ platform;
1138
+ architecture;
1139
+ windowsResolverOptions;
1140
+ registrations = new Map();
1141
+ constructor(options = {}) {
1142
+ this.platform = options.platform ?? process.platform;
1143
+ this.architecture = options.architecture ?? process.arch;
1144
+ this.windowsResolverOptions = {
1145
+ platform: this.platform,
1146
+ architecture: this.architecture,
1147
+ ...(options.helper_path === undefined ? {} : { helper_path: options.helper_path }),
1148
+ ...(options.expected_digest === undefined ? {} : { expected_digest: options.expected_digest }),
1149
+ };
1150
+ this.controlTimeoutMs = requirePositiveInteger(options.control_timeout_ms ?? DEFAULT_CONTROL_TIMEOUT_MS, "control_timeout_ms");
1151
+ this.pollIntervalMs = requirePositiveInteger(options.poll_interval_ms ?? DEFAULT_POLL_INTERVAL_MS, "poll_interval_ms");
1152
+ if (options.root_directory === undefined || options.root_directory.length === 0) {
1153
+ throw new LocalExecutionAuthorityError("invalid_configuration", "root_directory is required for durable local execution authority");
1154
+ }
1155
+ this.rootDirectory = resolve(options.root_directory);
1156
+ this.preparationsDirectory = join(this.rootDirectory, "preparations");
1157
+ this.transitionsDirectory = join(this.rootDirectory, "attempt-transitions");
1158
+ this.recordsDirectory = join(this.rootDirectory, "records");
1159
+ this.controlNamespace = createHash("sha256")
1160
+ .update(this.rootDirectory, "utf8")
1161
+ .digest("hex")
1162
+ .slice(0, 24);
1163
+ this.socketsDirectory = this.platform === "win32"
1164
+ ? ""
1165
+ : join("/tmp", `intentdna-exec-${process.getuid?.() ?? "user"}-${this.controlNamespace}`);
1166
+ this.streamsDirectory = join(this.rootDirectory, "streams");
1167
+ for (const directory of [
1168
+ this.rootDirectory,
1169
+ this.preparationsDirectory,
1170
+ this.transitionsDirectory,
1171
+ this.recordsDirectory,
1172
+ this.streamsDirectory,
1173
+ ...(this.platform === "win32" ? [] : [this.socketsDirectory]),
1174
+ ])
1175
+ ensureRealPrivateDirectory(directory);
1176
+ this.ensureSupervisorScript();
1177
+ this.authorityInstanceId = this.loadOrCreateMetadata(options.authority_instance_id).authority_instance_id;
1178
+ }
1179
+ get authority_instance_id() {
1180
+ return this.authorityInstanceId;
1181
+ }
1182
+ resolveWindowsArtifact() {
1183
+ let artifact;
1184
+ try {
1185
+ artifact = resolveWindowsJobKeeperArtifact(this.windowsResolverOptions);
1186
+ }
1187
+ catch (error) {
1188
+ if (error instanceof WindowsJobKeeperArtifactError) {
1189
+ throw new LocalExecutionAuthorityError("unsupported", error.message, { cause: error });
1190
+ }
1191
+ throw error;
1192
+ }
1193
+ if (artifact === null) {
1194
+ throw new LocalExecutionAuthorityError("unsupported", "Windows Job keeper is unavailable");
1195
+ }
1196
+ return artifact;
1197
+ }
1198
+ ensureSupported() {
1199
+ if (this.platform === "win32")
1200
+ this.resolveWindowsArtifact();
1201
+ }
1202
+ assertExecutionSupported() {
1203
+ this.ensureSupported();
1204
+ }
1205
+ supervisorScriptPath() {
1206
+ const digestValue = this.platform === "win32"
1207
+ ? LOCAL_WINDOWS_EXECUTION_SUPERVISOR_DIGEST
1208
+ : LOCAL_EXECUTION_SUPERVISOR_DIGEST;
1209
+ const version = digestValue.slice("sha256:".length);
1210
+ return join(this.rootDirectory, `supervisor.${this.platform === "win32" ? "windows." : ""}${version}.cjs`);
1211
+ }
1212
+ ensureSupervisorScript() {
1213
+ const path = this.supervisorScriptPath();
1214
+ const expectedSource = this.platform === "win32"
1215
+ ? LOCAL_WINDOWS_EXECUTION_SUPERVISOR_SOURCE
1216
+ : LOCAL_EXECUTION_SUPERVISOR_SOURCE;
1217
+ const expectedDigest = this.platform === "win32"
1218
+ ? LOCAL_WINDOWS_EXECUTION_SUPERVISOR_DIGEST
1219
+ : LOCAL_EXECUTION_SUPERVISOR_DIGEST;
1220
+ const validateExisting = () => {
1221
+ const metadata = lstatSync(path);
1222
+ if (!metadata.isFile() || metadata.isSymbolicLink()) {
1223
+ throw new LocalExecutionAuthorityError("corrupt_state", "execution supervisor is not a regular file");
1224
+ }
1225
+ const source = readFileSync(path, "utf8");
1226
+ if (textDigest(source) !== expectedDigest) {
1227
+ throw new LocalExecutionAuthorityError("corrupt_state", "execution supervisor digest changed");
1228
+ }
1229
+ chmodSync(path, SCRIPT_FILE_MODE);
1230
+ };
1231
+ if (existsSync(path)) {
1232
+ validateExisting();
1233
+ return;
1234
+ }
1235
+ let descriptor;
1236
+ try {
1237
+ descriptor = openSync(path, "wx", PRIVATE_FILE_MODE);
1238
+ }
1239
+ catch (error) {
1240
+ if (!isErrno(error, "EEXIST"))
1241
+ throw error;
1242
+ validateExisting();
1243
+ return;
1244
+ }
1245
+ try {
1246
+ writeFileSync(descriptor, expectedSource, "utf8");
1247
+ fsyncSync(descriptor);
1248
+ }
1249
+ finally {
1250
+ closeSync(descriptor);
1251
+ }
1252
+ chmodSync(path, SCRIPT_FILE_MODE);
1253
+ syncDirectory(this.rootDirectory);
1254
+ }
1255
+ loadOrCreateMetadata(requested) {
1256
+ const path = join(this.rootDirectory, "authority.json");
1257
+ const load = () => {
1258
+ const value = readJson(path);
1259
+ if (!isRecord(value)
1260
+ || value.schema_version !== AUTHORITY_SCHEMA_VERSION
1261
+ || typeof value.authority_instance_id !== "string"
1262
+ || value.authority_instance_id.length === 0) {
1263
+ throw new LocalExecutionAuthorityError("corrupt_state", "local authority metadata is invalid");
1264
+ }
1265
+ const metadata = value;
1266
+ if (requested !== undefined && requested !== metadata.authority_instance_id) {
1267
+ throw new LocalExecutionAuthorityError("identity_conflict", "configured authority_instance_id conflicts with the durable authority root");
1268
+ }
1269
+ return metadata;
1270
+ };
1271
+ if (existsSync(path)) {
1272
+ return load();
1273
+ }
1274
+ const metadata = {
1275
+ schema_version: AUTHORITY_SCHEMA_VERSION,
1276
+ authority_instance_id: requested ?? `local-execution-authority:${randomUUID()}`,
1277
+ created_at: new Date().toISOString(),
1278
+ };
1279
+ try {
1280
+ const descriptor = openSync(path, "wx", PRIVATE_FILE_MODE);
1281
+ try {
1282
+ writeFileSync(descriptor, `${canonicalizeJson(metadata)}\n`, "utf8");
1283
+ fsyncSync(descriptor);
1284
+ }
1285
+ finally {
1286
+ closeSync(descriptor);
1287
+ }
1288
+ syncDirectory(this.rootDirectory);
1289
+ return metadata;
1290
+ }
1291
+ catch (error) {
1292
+ if (!isErrno(error, "EEXIST"))
1293
+ throw error;
1294
+ return load();
1295
+ }
1296
+ }
1297
+ recordPath(identity) {
1298
+ return join(this.recordsDirectory, `${executionRecordDigest(identity).slice("sha256:".length)}.json`);
1299
+ }
1300
+ hasOtherAttemptRecord(identity) {
1301
+ const expectedPath = this.recordPath(identity);
1302
+ return readdirSync(this.recordsDirectory, { withFileTypes: true }).some((entry) => {
1303
+ if (!entry.isFile() || entry.isSymbolicLink() || !entry.name.endsWith(".json"))
1304
+ return false;
1305
+ const path = join(this.recordsDirectory, entry.name);
1306
+ if (path === expectedPath)
1307
+ return false;
1308
+ const record = this.readRecord(path);
1309
+ return record.identity.run_id === identity.run_id
1310
+ && record.identity.step_id === identity.step_id
1311
+ && record.identity.attempt_id === identity.attempt_id;
1312
+ });
1313
+ }
1314
+ preparationPath(identity) {
1315
+ return join(this.preparationsDirectory, `${attemptDigest(identity).slice("sha256:".length)}.json`);
1316
+ }
1317
+ transitionPath(identity) {
1318
+ return join(this.transitionsDirectory, attemptDigest(identity).slice("sha256:".length));
1319
+ }
1320
+ controlEndpoint(identity) {
1321
+ const token = attemptDigest(identity).slice("sha256:".length, "sha256:".length + 24);
1322
+ if (this.platform === "win32") {
1323
+ return `\\\\.\\pipe\\intentdna-exec-${this.controlNamespace}-${token}`;
1324
+ }
1325
+ const socketPath = join(this.socketsDirectory, `${token}.sock`);
1326
+ if (Buffer.byteLength(socketPath, "utf8") > 100) {
1327
+ throw new LocalExecutionAuthorityError("unsupported", "execution control socket path is too long");
1328
+ }
1329
+ return socketPath;
1330
+ }
1331
+ backend() {
1332
+ if (this.platform !== "win32")
1333
+ return { kind: "posix_process_group" };
1334
+ const artifact = this.resolveWindowsArtifact();
1335
+ return {
1336
+ kind: "windows_job",
1337
+ architecture: artifact.architecture,
1338
+ helper_path: artifact.path,
1339
+ helper_digest: artifact.digest,
1340
+ helper_source_digest: artifact.source_digest,
1341
+ helper_protocol_version: artifact.protocol_version,
1342
+ containment_nonce: randomUUID().replaceAll("-", "") + randomUUID().replaceAll("-", ""),
1343
+ };
1344
+ }
1345
+ supervisor(endpoint) {
1346
+ return {
1347
+ kind: this.platform === "win32" ? "windows" : "posix",
1348
+ socket_path: endpoint,
1349
+ script_digest: this.platform === "win32"
1350
+ ? LOCAL_WINDOWS_EXECUTION_SUPERVISOR_DIGEST
1351
+ : LOCAL_EXECUTION_SUPERVISOR_DIGEST,
1352
+ pid: null,
1353
+ ready_at: null,
1354
+ };
1355
+ }
1356
+ resolveAbsoluteWindowsExecutable(command, environment, cwd) {
1357
+ const direct = win32Path.isAbsolute(command)
1358
+ ? command
1359
+ : (command.includes("\\") || command.includes("/"))
1360
+ ? win32Path.resolve(cwd, command)
1361
+ : null;
1362
+ if (direct !== null && existsSync(direct))
1363
+ return resolve(direct);
1364
+ const resolved = resolveProcessCommand(command, [], "win32", environment, cwd).command;
1365
+ if (win32Path.isAbsolute(resolved) && existsSync(resolved))
1366
+ return resolve(resolved);
1367
+ throw new LocalExecutionAuthorityError("unsupported", `Windows provider executable could not be resolved to an absolute path: ${command}`);
1368
+ }
1369
+ readRecord(path) {
1370
+ return parseRecord(readJson(path));
1371
+ }
1372
+ readPreparation(path) {
1373
+ const value = readJson(path);
1374
+ if (!isRecord(value) || !hasExactKeys(value, [
1375
+ "schema_version",
1376
+ "identity",
1377
+ "preparation_digest",
1378
+ "execution_instance_id",
1379
+ "challenge",
1380
+ "authority_instance_id",
1381
+ "backend",
1382
+ "supervisor",
1383
+ "created_at",
1384
+ ]) || value.schema_version !== PREPARATION_SCHEMA_VERSION || !isRecord(value.identity)) {
1385
+ throw new LocalExecutionAuthorityError("corrupt_state", "local execution preparation has an invalid schema");
1386
+ }
1387
+ const preparation = value;
1388
+ requirePreparationRequest(preparation.identity);
1389
+ if (preparation.identity.execution_instance_id !== preparation.execution_instance_id
1390
+ || preparation.preparation_digest !== preparationDigest(preparation.identity)
1391
+ || typeof preparation.challenge !== "string"
1392
+ || preparation.challenge.length < 32
1393
+ || typeof preparation.authority_instance_id !== "string"
1394
+ || preparation.authority_instance_id.length === 0
1395
+ || !isDurableBackend(preparation.backend)
1396
+ || !isDurableSupervisor(preparation.supervisor, preparation.backend)
1397
+ || preparation.supervisor.pid !== null
1398
+ || preparation.supervisor.ready_at !== null
1399
+ || !isCanonicalTimestamp(preparation.created_at)) {
1400
+ throw new LocalExecutionAuthorityError("corrupt_state", "local execution preparation failed validation");
1401
+ }
1402
+ return preparation;
1403
+ }
1404
+ readVerifiedStream(evidence, expectedPath, maxOutputBytes) {
1405
+ const expected = resolve(expectedPath);
1406
+ const actual = resolve(evidence.path);
1407
+ const relativePath = relative(this.streamsDirectory, actual);
1408
+ if (actual !== expected
1409
+ || relativePath === ""
1410
+ || relativePath === ".."
1411
+ || relativePath.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`)) {
1412
+ throw new LocalExecutionAuthorityError("corrupt_state", "durable stream path escapes its execution identity");
1413
+ }
1414
+ const pathMetadata = lstatSync(actual, { bigint: true });
1415
+ if (!pathMetadata.isFile() || pathMetadata.isSymbolicLink()) {
1416
+ throw new LocalExecutionAuthorityError("corrupt_state", "durable stream is not a regular file");
1417
+ }
1418
+ const descriptor = openSync(actual, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
1419
+ try {
1420
+ const before = fstatSync(descriptor, { bigint: true });
1421
+ if (!before.isFile()
1422
+ || before.dev.toString() !== evidence.device
1423
+ || before.ino.toString() !== evidence.inode
1424
+ || before.birthtimeNs.toString() !== evidence.birthtime_ns
1425
+ || before.size !== BigInt(evidence.byte_count)
1426
+ || before.size > BigInt(maxOutputBytes)) {
1427
+ throw new LocalExecutionAuthorityError("corrupt_state", "durable stream identity does not match its evidence");
1428
+ }
1429
+ const bytes = readFileSync(descriptor);
1430
+ const after = fstatSync(descriptor, { bigint: true });
1431
+ const currentPath = lstatSync(actual, { bigint: true });
1432
+ if (bytes.byteLength !== evidence.byte_count
1433
+ || after.dev !== before.dev
1434
+ || after.ino !== before.ino
1435
+ || after.birthtimeNs !== before.birthtimeNs
1436
+ || after.size !== before.size
1437
+ || currentPath.dev !== before.dev
1438
+ || currentPath.ino !== before.ino
1439
+ || currentPath.birthtimeNs !== before.birthtimeNs
1440
+ || digestBytes(bytes) !== evidence.sha256) {
1441
+ throw new LocalExecutionAuthorityError("corrupt_state", "durable stream changed after completion");
1442
+ }
1443
+ return bytes.toString("utf8");
1444
+ }
1445
+ finally {
1446
+ closeSync(descriptor);
1447
+ }
1448
+ }
1449
+ rawCompletionResult(record) {
1450
+ const raw = record.raw_completion;
1451
+ if (raw === null) {
1452
+ throw new LocalExecutionAuthorityError("corrupt_state", "durable raw completion is missing");
1453
+ }
1454
+ const streamToken = record.identity_digest.slice("sha256:".length, "sha256:".length + 24);
1455
+ const stdout = this.readVerifiedStream(raw.stdout, join(this.streamsDirectory, `${streamToken}.stdout`), raw.max_output_bytes);
1456
+ const stderr = this.readVerifiedStream(raw.stderr, join(this.streamsDirectory, `${streamToken}.stderr`), raw.max_output_bytes);
1457
+ return {
1458
+ ...rawCompletionToResult(raw, stdout, stderr),
1459
+ startedAt: record.identity.started_at,
1460
+ completedAt: raw.completed_at,
1461
+ stdoutDigest: raw.stdout.sha256,
1462
+ stdoutBytes: raw.stdout.byte_count,
1463
+ stderrDigest: raw.stderr.sha256,
1464
+ stderrBytes: raw.stderr.byte_count,
1465
+ };
1466
+ }
1467
+ windowsArtifactMatchesBackend(artifact, backend) {
1468
+ return artifact.architecture === backend.architecture
1469
+ && artifact.path === backend.helper_path
1470
+ && artifact.digest === backend.helper_digest
1471
+ && artifact.source_digest === backend.helper_source_digest
1472
+ && artifact.protocol_version === backend.helper_protocol_version;
1473
+ }
1474
+ async markUnsupported(path, message) {
1475
+ return this.updateRecord(path, (current) => {
1476
+ if (current.phase === "unsupported"
1477
+ || current.phase === "never_launched"
1478
+ || current.raw_completion !== null)
1479
+ return current;
1480
+ return {
1481
+ ...current,
1482
+ phase: "unsupported",
1483
+ supervisor_error: message,
1484
+ revision: current.revision + 1,
1485
+ updated_at: new Date().toISOString(),
1486
+ };
1487
+ });
1488
+ }
1489
+ async failWindowsAuthentication(path, message, cause) {
1490
+ const updated = await this.markUnsupported(path, message);
1491
+ if (updated.raw_completion !== null) {
1492
+ throw new LocalExecutionAuthorityError("identity_conflict", "Windows execution identity changed while completion was committed", { cause });
1493
+ }
1494
+ throw new LocalExecutionAuthorityError("identity_conflict", message, { cause });
1495
+ }
1496
+ async ensureWindowsBackendTrusted(record, path) {
1497
+ if (record.backend.kind !== "windows_job")
1498
+ return;
1499
+ try {
1500
+ const artifact = this.resolveWindowsArtifact();
1501
+ if (!this.windowsArtifactMatchesBackend(artifact, record.backend)) {
1502
+ throw new LocalExecutionAuthorityError("unsupported", "Windows Job keeper trust identity does not match the durable execution record");
1503
+ }
1504
+ }
1505
+ catch (error) {
1506
+ const message = error instanceof Error ? error.message : String(error);
1507
+ const updated = await this.markUnsupported(path, message);
1508
+ if (updated.raw_completion !== null)
1509
+ return;
1510
+ throw error instanceof LocalExecutionAuthorityError
1511
+ ? error
1512
+ : new LocalExecutionAuthorityError("unsupported", message, { cause: error });
1513
+ }
1514
+ }
1515
+ async authenticateWindowsSupervisor(initial, path) {
1516
+ if (initial.backend.kind !== "windows_job" || initial.raw_completion !== null)
1517
+ return initial;
1518
+ await this.ensureWindowsBackendTrusted(initial, path);
1519
+ let lastError = null;
1520
+ for (let attempt = 0; attempt < 3; attempt += 1) {
1521
+ const before = this.readRecord(path);
1522
+ if (before.raw_completion !== null || before.phase === "unsupported")
1523
+ return before;
1524
+ if (before.phase !== "running" || before.supervisor.pid === null || before.supervisor.ready_at === null) {
1525
+ lastError = new Error("Windows execution supervisor is not durably ready");
1526
+ break;
1527
+ }
1528
+ try {
1529
+ const response = await this.sendControl(before, { action: "probe" });
1530
+ const after = this.readRecord(path);
1531
+ if (after.raw_completion !== null || after.phase === "unsupported")
1532
+ return after;
1533
+ if (after.revision !== before.revision)
1534
+ continue;
1535
+ const identity = response.identity;
1536
+ const expected = {
1537
+ record_revision: after.revision,
1538
+ execution_instance_id: after.execution_instance_id,
1539
+ supervisor_pid: after.supervisor.pid,
1540
+ supervisor_ready_at: after.supervisor.ready_at,
1541
+ containment_nonce: after.backend.kind === "windows_job"
1542
+ ? after.backend.containment_nonce
1543
+ : "",
1544
+ backend: after.backend,
1545
+ provider: after.provider,
1546
+ };
1547
+ if (!isRecord(identity)
1548
+ || !hasExactKeys(identity, Object.keys(expected))
1549
+ || canonicalizeJson(identity) !== canonicalizeJson(expected)) {
1550
+ throw new Error("Windows execution supervisor identity does not match durable containment evidence");
1551
+ }
1552
+ return after;
1553
+ }
1554
+ catch (error) {
1555
+ lastError = error;
1556
+ break;
1557
+ }
1558
+ }
1559
+ const message = lastError instanceof Error
1560
+ ? lastError.message
1561
+ : "Windows execution supervisor identity could not be authenticated";
1562
+ return this.failWindowsAuthentication(path, message, lastError);
1563
+ }
1564
+ readRecoveryRecord(request) {
1565
+ const identity = recoveryIdentity(request);
1566
+ const path = this.recordPath(identity);
1567
+ if (!existsSync(path)) {
1568
+ if (this.hasOtherAttemptRecord(identity)) {
1569
+ throw new LocalExecutionAuthorityError("identity_conflict", "recovery identity does not match the original execution authority claim");
1570
+ }
1571
+ return null;
1572
+ }
1573
+ const record = this.readRecord(path);
1574
+ if (canonicalizeJson(coreIdentity(record.identity)) !== canonicalizeJson(coreIdentity(identity))) {
1575
+ throw new LocalExecutionAuthorityError("identity_conflict", "recovery identity does not match the original execution authority");
1576
+ }
1577
+ return record;
1578
+ }
1579
+ requireRequestRecord(request) {
1580
+ const identity = requestIdentity(request);
1581
+ const record = this.readRecord(this.recordPath(identity));
1582
+ if (canonicalizeJson(coreIdentity(record.identity)) !== canonicalizeJson(coreIdentity(identity))) {
1583
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution authority identity does not match");
1584
+ }
1585
+ const requestedExecutionInstance = request.execution_instance_id;
1586
+ if (requestedExecutionInstance !== undefined
1587
+ && requestedExecutionInstance !== record.execution_instance_id) {
1588
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution instance identity does not match");
1589
+ }
1590
+ return record;
1591
+ }
1592
+ async withLock(targetPath, operation) {
1593
+ const lockPath = `${targetPath}.lock`;
1594
+ const ownerPath = join(lockPath, "owner.json");
1595
+ const owner = durableLockOwner(this.platform);
1596
+ const deadline = Date.now() + this.controlTimeoutMs;
1597
+ for (;;) {
1598
+ if (publishDurableLock(lockPath, owner))
1599
+ break;
1600
+ const observed = readDurableLockOwner(ownerPath);
1601
+ if (staleDurableLock(observed, this.platform)
1602
+ && observed !== null
1603
+ && retireObservedStaleDurableLock(lockPath, observed)) {
1604
+ continue;
1605
+ }
1606
+ if (Date.now() >= deadline) {
1607
+ throw new LocalExecutionAuthorityError("unsupported", `execution authority lock is unavailable for ${targetPath}`);
1608
+ }
1609
+ await sleep(this.pollIntervalMs);
1610
+ }
1611
+ try {
1612
+ return await operation();
1613
+ }
1614
+ finally {
1615
+ releaseDurableLock(lockPath, owner);
1616
+ }
1617
+ }
1618
+ withLockSync(targetPath, operation) {
1619
+ const lockPath = `${targetPath}.lock`;
1620
+ const ownerPath = join(lockPath, "owner.json");
1621
+ const owner = durableLockOwner(this.platform);
1622
+ const deadline = Date.now() + this.controlTimeoutMs;
1623
+ for (;;) {
1624
+ if (publishDurableLock(lockPath, owner))
1625
+ break;
1626
+ const observed = readDurableLockOwner(ownerPath);
1627
+ if (staleDurableLock(observed, this.platform)
1628
+ && observed !== null
1629
+ && retireObservedStaleDurableLock(lockPath, observed)) {
1630
+ continue;
1631
+ }
1632
+ if (Date.now() >= deadline) {
1633
+ throw new LocalExecutionAuthorityError("unsupported", `execution authority lock is unavailable for ${targetPath}`);
1634
+ }
1635
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, this.pollIntervalMs);
1636
+ }
1637
+ try {
1638
+ return operation();
1639
+ }
1640
+ finally {
1641
+ releaseDurableLock(lockPath, owner);
1642
+ }
1643
+ }
1644
+ async updateRecord(path, operation) {
1645
+ return this.withLock(path, () => {
1646
+ const current = this.readRecord(path);
1647
+ const next = operation(current);
1648
+ if (next === current)
1649
+ return current;
1650
+ if (next.execution_instance_id !== current.execution_instance_id
1651
+ || next.challenge !== current.challenge
1652
+ || next.revision !== current.revision + 1) {
1653
+ throw new LocalExecutionAuthorityError("identity_conflict", "invalid execution record transition");
1654
+ }
1655
+ atomicWriteJson(path, next);
1656
+ return next;
1657
+ });
1658
+ }
1659
+ nextFencingEpoch() {
1660
+ const path = join(this.rootDirectory, "fencing.epoch");
1661
+ return this.withLock(path, () => {
1662
+ let current = 0;
1663
+ if (existsSync(path)) {
1664
+ const metadata = lstatSync(path);
1665
+ if (!metadata.isFile() || metadata.isSymbolicLink()) {
1666
+ throw new LocalExecutionAuthorityError("corrupt_state", "fencing epoch is not a regular file");
1667
+ }
1668
+ current = Number(readFileSync(path, "utf8"));
1669
+ if (!Number.isSafeInteger(current) || current < 0) {
1670
+ throw new LocalExecutionAuthorityError("corrupt_state", "fencing epoch is invalid");
1671
+ }
1672
+ }
1673
+ const next = current + 1;
1674
+ if (!Number.isSafeInteger(next)) {
1675
+ throw new LocalExecutionAuthorityError("unsupported", "fencing epoch is exhausted");
1676
+ }
1677
+ const temporary = `${path}.tmp.${process.pid}.${randomUUID()}`;
1678
+ const descriptor = openSync(temporary, "wx", PRIVATE_FILE_MODE);
1679
+ try {
1680
+ writeFileSync(descriptor, String(next), "utf8");
1681
+ fsyncSync(descriptor);
1682
+ }
1683
+ finally {
1684
+ closeSync(descriptor);
1685
+ }
1686
+ renameSync(temporary, path);
1687
+ syncDirectory(this.rootDirectory);
1688
+ return next;
1689
+ });
1690
+ }
1691
+ nextFencingEpochSync() {
1692
+ const path = join(this.rootDirectory, "fencing.epoch");
1693
+ return this.withLockSync(path, () => {
1694
+ let current = 0;
1695
+ if (existsSync(path)) {
1696
+ const metadata = lstatSync(path);
1697
+ if (!metadata.isFile() || metadata.isSymbolicLink()) {
1698
+ throw new LocalExecutionAuthorityError("corrupt_state", "fencing epoch is not a regular file");
1699
+ }
1700
+ current = Number(readFileSync(path, "utf8"));
1701
+ if (!Number.isSafeInteger(current) || current < 0) {
1702
+ throw new LocalExecutionAuthorityError("corrupt_state", "fencing epoch is invalid");
1703
+ }
1704
+ }
1705
+ const next = current + 1;
1706
+ if (!Number.isSafeInteger(next)) {
1707
+ throw new LocalExecutionAuthorityError("unsupported", "fencing epoch is exhausted");
1708
+ }
1709
+ atomicWriteJson(path, next);
1710
+ return next;
1711
+ });
1712
+ }
1713
+ createLaunchBinding(record) {
1714
+ if (record.phase !== "prepared") {
1715
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution is no longer prepared for launch");
1716
+ }
1717
+ const recordPath = this.recordPath(record.identity);
1718
+ const existing = this.registrations.get(record.identity_digest);
1719
+ if (existing !== undefined) {
1720
+ return this.bindingForRegistration(existing);
1721
+ }
1722
+ let resolveProcessStarted;
1723
+ let rejectProcessStarted;
1724
+ const processStarted = new Promise((resolvePromise, rejectPromise) => {
1725
+ resolveProcessStarted = resolvePromise;
1726
+ rejectProcessStarted = rejectPromise;
1727
+ });
1728
+ const registration = {
1729
+ identity: record.identity,
1730
+ recordPath,
1731
+ abortController: new AbortController(),
1732
+ processStarted,
1733
+ resolveProcessStarted,
1734
+ rejectProcessStarted,
1735
+ };
1736
+ this.registrations.set(record.identity_digest, registration);
1737
+ return this.bindingForRegistration(registration);
1738
+ }
1739
+ bindingForRegistration(registration) {
1740
+ return {
1741
+ cancellation_signal: registration.abortController.signal,
1742
+ process_started: registration.processStarted,
1743
+ processStarted: (processId) => {
1744
+ if (!Number.isSafeInteger(processId) || processId <= 0) {
1745
+ const error = new LocalExecutionAuthorityError("corrupt_state", "execution process id is invalid");
1746
+ registration.rejectProcessStarted(error);
1747
+ throw error;
1748
+ }
1749
+ const current = this.readRecord(registration.recordPath);
1750
+ if (!providerMatchesProcessId(current, processId)) {
1751
+ const error = new LocalExecutionAuthorityError("identity_conflict", "execution process does not match the durable supervisor record");
1752
+ registration.rejectProcessStarted(error);
1753
+ throw error;
1754
+ }
1755
+ registration.resolveProcessStarted(processId);
1756
+ },
1757
+ processTreeCompleted: (observation) => this.recordNormalizedCompletion(registration.recordPath, observation),
1758
+ executeProcessTree: (command, args, processOptions) => this.executeSupervised(registration, command, args, processOptions),
1759
+ };
1760
+ }
1761
+ prepareExecution(request) {
1762
+ requirePreparationRequest(request);
1763
+ this.ensureSupported();
1764
+ const path = this.preparationPath(request);
1765
+ return this.withLockSync(this.transitionPath(request), () => {
1766
+ const recordPath = this.recordPath({
1767
+ ...request,
1768
+ claim_epoch: request.execution_claim_epoch,
1769
+ started_at: "1970-01-01T00:00:00.000Z",
1770
+ });
1771
+ const boundRecord = existsSync(recordPath) ? this.readRecord(recordPath) : null;
1772
+ if (existsSync(path)) {
1773
+ const current = this.readPreparation(path);
1774
+ const sameAttempt = current.identity.run_id === request.run_id
1775
+ && current.identity.step_id === request.step_id
1776
+ && current.identity.activation_id === request.activation_id
1777
+ && current.identity.attempt_id === request.attempt_id;
1778
+ if (!sameAttempt || request.execution_claim_epoch < current.identity.execution_claim_epoch) {
1779
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution attempt already has a different durable preparation");
1780
+ }
1781
+ if (request.execution_claim_epoch > current.identity.execution_claim_epoch) {
1782
+ if (boundRecord !== null) {
1783
+ throw new LocalExecutionAuthorityError("identity_conflict", "a bound execution preparation cannot be superseded");
1784
+ }
1785
+ unlinkSync(path);
1786
+ }
1787
+ else if (canonicalizeJson(preparationCoreIdentity(current.identity))
1788
+ !== canonicalizeJson(preparationCoreIdentity(request))) {
1789
+ throw new LocalExecutionAuthorityError("identity_conflict", "same-epoch preparation has a different worker identity");
1790
+ }
1791
+ else {
1792
+ if (request.execution_instance_id !== undefined
1793
+ && request.execution_instance_id !== current.execution_instance_id) {
1794
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution instance conflicts with the durable preparation");
1795
+ }
1796
+ return preparedHandle(current);
1797
+ }
1798
+ }
1799
+ if (boundRecord !== null) {
1800
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution attempt is already bound and cannot be prepared again");
1801
+ }
1802
+ const executionInstanceId = request.execution_instance_id ?? `local-process:${randomUUID()}`;
1803
+ const fullIdentity = {
1804
+ ...request,
1805
+ execution_instance_id: executionInstanceId,
1806
+ };
1807
+ const preparation = {
1808
+ schema_version: PREPARATION_SCHEMA_VERSION,
1809
+ identity: fullIdentity,
1810
+ preparation_digest: preparationDigest(fullIdentity),
1811
+ execution_instance_id: executionInstanceId,
1812
+ challenge: randomUUID().replaceAll("-", "") + randomUUID().replaceAll("-", ""),
1813
+ authority_instance_id: this.authorityInstanceId,
1814
+ backend: this.backend(),
1815
+ supervisor: this.supervisor(this.controlEndpoint({
1816
+ ...request,
1817
+ claim_epoch: request.execution_claim_epoch,
1818
+ started_at: "1970-01-01T00:00:00.000Z",
1819
+ })),
1820
+ created_at: new Date().toISOString(),
1821
+ };
1822
+ atomicWriteJson(path, preparation);
1823
+ return preparedHandle(preparation);
1824
+ });
1825
+ }
1826
+ recoverPreparedExecution(request) {
1827
+ requirePreparationRequest(request);
1828
+ this.ensureSupported();
1829
+ const path = this.preparationPath(request);
1830
+ if (!existsSync(path))
1831
+ return null;
1832
+ const preparation = this.readPreparation(path);
1833
+ if (canonicalizeJson(preparationCoreIdentity(preparation.identity))
1834
+ !== canonicalizeJson(preparationCoreIdentity(request))) {
1835
+ throw new LocalExecutionAuthorityError("identity_conflict", "prepared execution recovery identity does not match");
1836
+ }
1837
+ return preparedHandle(preparation);
1838
+ }
1839
+ recoverExecutionForPreparation(request) {
1840
+ requirePreparationRequest(request);
1841
+ this.ensureSupported();
1842
+ const recordPath = this.recordPath({
1843
+ ...request,
1844
+ claim_epoch: request.execution_claim_epoch,
1845
+ started_at: "1970-01-01T00:00:00.000Z",
1846
+ });
1847
+ if (!existsSync(recordPath))
1848
+ return null;
1849
+ const record = this.readRecord(recordPath);
1850
+ const recordedPreparationIdentity = {
1851
+ run_id: record.identity.run_id,
1852
+ step_id: record.identity.step_id,
1853
+ activation_id: record.identity.activation_id,
1854
+ attempt_id: record.identity.attempt_id,
1855
+ execution_claim_epoch: record.identity.claim_epoch,
1856
+ worker_session_id: record.identity.worker_session_id,
1857
+ execution_instance_id: record.identity.execution_instance_id,
1858
+ };
1859
+ if (canonicalizeJson(preparationCoreIdentity(recordedPreparationIdentity))
1860
+ !== canonicalizeJson(preparationCoreIdentity(request))) {
1861
+ throw new LocalExecutionAuthorityError("identity_conflict", "durable execution identity does not match the verifier preparation");
1862
+ }
1863
+ return this.recoverExecution({
1864
+ run_id: record.identity.run_id,
1865
+ step_id: record.identity.step_id,
1866
+ activation_id: record.identity.activation_id,
1867
+ attempt_id: record.identity.attempt_id,
1868
+ execution_claim_epoch: record.identity.claim_epoch,
1869
+ executor: { kind: "worker", worker_session_id: record.identity.worker_session_id },
1870
+ started_at: record.identity.started_at,
1871
+ });
1872
+ }
1873
+ listPreparedExecutions() {
1874
+ const entries = readdirSync(this.preparationsDirectory, { withFileTypes: true })
1875
+ .filter((entry) => !/^\..+\.json\.tmp\.\d+\.[0-9a-f-]+$/u.test(entry.name))
1876
+ .sort((left, right) => left.name.localeCompare(right.name));
1877
+ return entries.map((entry) => {
1878
+ if (!entry.isFile() || entry.isSymbolicLink() || !entry.name.endsWith(".json")) {
1879
+ throw new LocalExecutionAuthorityError("corrupt_state", "local execution preparations directory contains an unexpected entry");
1880
+ }
1881
+ const preparation = this.readPreparation(join(this.preparationsDirectory, entry.name));
1882
+ return {
1883
+ handle: preparedHandle(preparation),
1884
+ created_at: preparation.created_at,
1885
+ };
1886
+ });
1887
+ }
1888
+ abandonPreparedExecution(handle) {
1889
+ requirePreparationRequest(handle);
1890
+ if (handle.schema_version !== PREPARATION_HANDLE_SCHEMA_VERSION
1891
+ || handle.preparation_digest !== preparationDigest(handle)) {
1892
+ throw new TypeError("local execution preparation handle is invalid");
1893
+ }
1894
+ const path = this.preparationPath(handle);
1895
+ this.withLockSync(this.transitionPath(handle), () => {
1896
+ const recordPath = this.recordPath({
1897
+ ...handle,
1898
+ claim_epoch: handle.execution_claim_epoch,
1899
+ started_at: "1970-01-01T00:00:00.000Z",
1900
+ });
1901
+ if (!existsSync(path)) {
1902
+ if (existsSync(recordPath)) {
1903
+ throw new LocalExecutionAuthorityError("identity_conflict", "bound execution preparation cannot be abandoned");
1904
+ }
1905
+ return;
1906
+ }
1907
+ const preparation = this.readPreparation(path);
1908
+ if (canonicalizeJson(preparedHandle(preparation)) !== canonicalizeJson(handle)) {
1909
+ throw new LocalExecutionAuthorityError("identity_conflict", "prepared execution handle does not match durable authority state");
1910
+ }
1911
+ if (existsSync(recordPath)) {
1912
+ throw new LocalExecutionAuthorityError("identity_conflict", "bound execution preparation cannot be abandoned");
1913
+ }
1914
+ unlinkSync(path);
1915
+ syncDirectory(this.preparationsDirectory);
1916
+ });
1917
+ }
1918
+ bindExecution(handle, request) {
1919
+ if (handle.schema_version !== PREPARATION_HANDLE_SCHEMA_VERSION
1920
+ || !isCanonicalTimestamp(request.started_at)) {
1921
+ throw new TypeError("local execution bind request is invalid");
1922
+ }
1923
+ const path = this.preparationPath(handle);
1924
+ return this.withLockSync(this.transitionPath(handle), () => {
1925
+ const identity = {
1926
+ run_id: handle.run_id,
1927
+ step_id: handle.step_id,
1928
+ activation_id: handle.activation_id,
1929
+ attempt_id: handle.attempt_id,
1930
+ claim_epoch: handle.execution_claim_epoch,
1931
+ worker_session_id: handle.worker_session_id,
1932
+ started_at: request.started_at,
1933
+ execution_instance_id: handle.execution_instance_id,
1934
+ };
1935
+ const recordPath = this.recordPath(identity);
1936
+ if (existsSync(recordPath)) {
1937
+ const current = this.readRecord(recordPath);
1938
+ if (canonicalizeJson(coreIdentity(current.identity)) !== canonicalizeJson(coreIdentity(identity))
1939
+ || current.execution_instance_id !== handle.execution_instance_id) {
1940
+ throw new LocalExecutionAuthorityError("identity_conflict", "bound execution record conflicts with the prepared handle");
1941
+ }
1942
+ if (existsSync(path)) {
1943
+ const lingering = this.readPreparation(path);
1944
+ if (canonicalizeJson(preparedHandle(lingering)) !== canonicalizeJson(handle)) {
1945
+ throw new LocalExecutionAuthorityError("identity_conflict", "lingering preparation conflicts with the bound execution record");
1946
+ }
1947
+ unlinkSync(path);
1948
+ syncDirectory(this.preparationsDirectory);
1949
+ }
1950
+ return this.createLaunchBinding(current);
1951
+ }
1952
+ const preparation = this.readPreparation(path);
1953
+ if (canonicalizeJson(preparedHandle(preparation)) !== canonicalizeJson(handle)) {
1954
+ throw new LocalExecutionAuthorityError("identity_conflict", "prepared execution handle does not match durable authority state");
1955
+ }
1956
+ const binding = this.registerExecution(identity, preparation);
1957
+ unlinkSync(path);
1958
+ syncDirectory(this.preparationsDirectory);
1959
+ return binding;
1960
+ });
1961
+ }
1962
+ registerExecution(identity, prepared) {
1963
+ requireIdentity(identity);
1964
+ this.ensureSupported();
1965
+ if (prepared === undefined && this.hasOtherAttemptRecord(identity)) {
1966
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution attempt already has durable authority under a different claim");
1967
+ }
1968
+ if (prepared === undefined) {
1969
+ const replay = () => {
1970
+ const recordPath = this.recordPath(identity);
1971
+ if (!existsSync(recordPath))
1972
+ return null;
1973
+ const current = this.readRecord(recordPath);
1974
+ if (canonicalizeJson(coreIdentity(current.identity)) !== canonicalizeJson(coreIdentity(identity))
1975
+ || (identity.execution_instance_id !== undefined
1976
+ && current.execution_instance_id !== identity.execution_instance_id)) {
1977
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution attempt already has a different durable identity");
1978
+ }
1979
+ if (current.phase === "prepared")
1980
+ return this.createLaunchBinding(current);
1981
+ if (current.phase === "never_launched") {
1982
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution was durably attested as never launched");
1983
+ }
1984
+ if (current.phase === "unsupported") {
1985
+ throw new LocalExecutionAuthorityError("unsupported", current.supervisor_error ?? "execution supervisor evidence is unavailable");
1986
+ }
1987
+ return this.recoverExecution({
1988
+ run_id: identity.run_id,
1989
+ step_id: identity.step_id,
1990
+ activation_id: identity.activation_id,
1991
+ attempt_id: identity.attempt_id,
1992
+ execution_claim_epoch: identity.claim_epoch,
1993
+ executor: { kind: "worker", worker_session_id: identity.worker_session_id },
1994
+ started_at: identity.started_at,
1995
+ }).binding;
1996
+ };
1997
+ const existing = replay();
1998
+ if (existing !== null)
1999
+ return existing;
2000
+ try {
2001
+ const handle = this.prepareExecution({
2002
+ run_id: identity.run_id,
2003
+ step_id: identity.step_id,
2004
+ activation_id: identity.activation_id,
2005
+ attempt_id: identity.attempt_id,
2006
+ execution_claim_epoch: identity.claim_epoch,
2007
+ worker_session_id: identity.worker_session_id,
2008
+ ...(identity.execution_instance_id === undefined
2009
+ ? {}
2010
+ : { execution_instance_id: identity.execution_instance_id }),
2011
+ });
2012
+ return this.bindExecution(handle, { started_at: identity.started_at });
2013
+ }
2014
+ catch (error) {
2015
+ if (error instanceof LocalExecutionAuthorityError && error.code === "identity_conflict") {
2016
+ const raced = replay();
2017
+ if (raced !== null)
2018
+ return raced;
2019
+ }
2020
+ throw error;
2021
+ }
2022
+ }
2023
+ const backend = prepared?.backend ?? this.backend();
2024
+ const executionInstanceId = identity.execution_instance_id ?? `local-process:${randomUUID()}`;
2025
+ const requiredIdentity = {
2026
+ ...identity,
2027
+ execution_instance_id: executionInstanceId,
2028
+ };
2029
+ const recordPath = this.recordPath(identity);
2030
+ const controlEndpoint = this.controlEndpoint(identity);
2031
+ const now = new Date().toISOString();
2032
+ const record = {
2033
+ schema_version: RECORD_SCHEMA_VERSION,
2034
+ revision: 1,
2035
+ phase: "prepared",
2036
+ identity: requiredIdentity,
2037
+ identity_digest: identityDigest(identity),
2038
+ execution_instance_id: executionInstanceId,
2039
+ challenge: prepared?.challenge
2040
+ ?? randomUUID().replaceAll("-", "") + randomUUID().replaceAll("-", ""),
2041
+ authority_instance_id: prepared?.authority_instance_id ?? this.authorityInstanceId,
2042
+ backend,
2043
+ supervisor: prepared?.supervisor ?? this.supervisor(controlEndpoint),
2044
+ provider: null,
2045
+ raw_completion: null,
2046
+ normalized_process_outcome: null,
2047
+ stop_fact: null,
2048
+ stop_receipt: null,
2049
+ already_stopped_evidence: null,
2050
+ nonlaunch_attestation: null,
2051
+ fencing_epoch: null,
2052
+ supervisor_error: null,
2053
+ created_at: now,
2054
+ updated_at: now,
2055
+ };
2056
+ this.withLockSync(recordPath, () => {
2057
+ if (existsSync(recordPath)) {
2058
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution identity is already registered");
2059
+ }
2060
+ const descriptor = openSync(recordPath, "wx", PRIVATE_FILE_MODE);
2061
+ try {
2062
+ writeFileSync(descriptor, `${canonicalizeJson(record)}\n`, "utf8");
2063
+ fsyncSync(descriptor);
2064
+ }
2065
+ finally {
2066
+ closeSync(descriptor);
2067
+ }
2068
+ syncDirectory(this.recordsDirectory);
2069
+ });
2070
+ return this.createLaunchBinding(record);
2071
+ }
2072
+ async probeRecovery(request) {
2073
+ requireIdentity(recoveryIdentity(request));
2074
+ let record = this.readRecoveryRecord(request);
2075
+ if (record !== null
2076
+ && record.backend.kind === "windows_job"
2077
+ && record.raw_completion === null
2078
+ && record.phase !== "never_launched"
2079
+ && record.phase !== "unsupported") {
2080
+ record = await this.authenticateWindowsSupervisor(record, this.recordPath(record.identity));
2081
+ }
2082
+ return { raw_completion_durable: record?.raw_completion !== null && record?.raw_completion !== undefined };
2083
+ }
2084
+ async attestNeverLaunched(request) {
2085
+ const identity = recoveryIdentity(request);
2086
+ requireIdentity(identity);
2087
+ if (!isCanonicalDigest(request.failure_idempotency_key)) {
2088
+ throw new TypeError("failure_idempotency_key must be a canonical SHA-256 digest");
2089
+ }
2090
+ if (!isCanonicalTimestamp(request.requested_at)) {
2091
+ throw new TypeError("requested_at must be a canonical RFC 3339 timestamp");
2092
+ }
2093
+ const path = this.recordPath(identity);
2094
+ const preparationPath = this.preparationPath(identity);
2095
+ return this.withLockSync(this.transitionPath(identity), () => {
2096
+ let current = null;
2097
+ let preparation = null;
2098
+ if (existsSync(preparationPath)) {
2099
+ preparation = this.readPreparation(preparationPath);
2100
+ if (canonicalizeJson(preparationCoreIdentity(preparation.identity))
2101
+ !== canonicalizeJson({
2102
+ run_id: identity.run_id,
2103
+ step_id: identity.step_id,
2104
+ activation_id: identity.activation_id,
2105
+ attempt_id: identity.attempt_id,
2106
+ execution_claim_epoch: identity.claim_epoch,
2107
+ worker_session_id: identity.worker_session_id,
2108
+ })) {
2109
+ throw new LocalExecutionAuthorityError("identity_conflict", "nonlaunch identity does not match the durable preparation");
2110
+ }
2111
+ }
2112
+ if (existsSync(path)) {
2113
+ current = this.readRecord(path);
2114
+ if (canonicalizeJson(coreIdentity(current.identity)) !== canonicalizeJson(coreIdentity(identity))) {
2115
+ throw new LocalExecutionAuthorityError("identity_conflict", "nonlaunch identity does not match durable authority state");
2116
+ }
2117
+ if (current.phase === "never_launched") {
2118
+ const attestation = current.nonlaunch_attestation;
2119
+ if (attestation.payload.failure_idempotency_key !== request.failure_idempotency_key) {
2120
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution already has a different nonlaunch failure");
2121
+ }
2122
+ if (preparation !== null) {
2123
+ if (preparation.execution_instance_id !== current.execution_instance_id) {
2124
+ throw new LocalExecutionAuthorityError("corrupt_state", "never-launched record conflicts with its lingering preparation");
2125
+ }
2126
+ unlinkSync(preparationPath);
2127
+ syncDirectory(this.preparationsDirectory);
2128
+ }
2129
+ return attestation;
2130
+ }
2131
+ if (current.phase !== "prepared" || current.supervisor.pid !== null || current.provider !== null) {
2132
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution launch ownership has already begun");
2133
+ }
2134
+ }
2135
+ if (current === null && preparation === null) {
2136
+ if (this.hasOtherAttemptRecord(identity)) {
2137
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution attempt already has durable authority under a different claim");
2138
+ }
2139
+ throw new LocalExecutionAuthorityError("unsupported", "never-launched state cannot be attested without durable preparation evidence");
2140
+ }
2141
+ const fencingEpoch = this.nextFencingEpochSync();
2142
+ const now = new Date().toISOString();
2143
+ const executionInstanceId = current?.execution_instance_id
2144
+ ?? preparation?.execution_instance_id
2145
+ ?? `local-process:${randomUUID()}`;
2146
+ const authorityInstanceId = current?.authority_instance_id
2147
+ ?? preparation?.authority_instance_id
2148
+ ?? this.authorityInstanceId;
2149
+ const requiredIdentity = {
2150
+ ...identity,
2151
+ execution_instance_id: executionInstanceId,
2152
+ };
2153
+ const backend = current?.backend ?? preparation?.backend ?? this.backend();
2154
+ const controlEndpoint = this.controlEndpoint(identity);
2155
+ const tombstone = current === null ? {
2156
+ schema_version: RECORD_SCHEMA_VERSION,
2157
+ revision: 1,
2158
+ phase: "never_launched",
2159
+ identity: requiredIdentity,
2160
+ identity_digest: identityDigest(identity),
2161
+ execution_instance_id: executionInstanceId,
2162
+ challenge: preparation?.challenge
2163
+ ?? randomUUID().replaceAll("-", "") + randomUUID().replaceAll("-", ""),
2164
+ authority_instance_id: authorityInstanceId,
2165
+ backend,
2166
+ supervisor: preparation?.supervisor ?? this.supervisor(controlEndpoint),
2167
+ provider: null,
2168
+ raw_completion: null,
2169
+ normalized_process_outcome: null,
2170
+ stop_fact: null,
2171
+ stop_receipt: null,
2172
+ already_stopped_evidence: null,
2173
+ nonlaunch_attestation: null,
2174
+ fencing_epoch: fencingEpoch,
2175
+ supervisor_error: null,
2176
+ created_at: now,
2177
+ updated_at: now,
2178
+ } : {
2179
+ ...current,
2180
+ phase: "never_launched",
2181
+ nonlaunch_attestation: null,
2182
+ fencing_epoch: fencingEpoch,
2183
+ revision: current.revision + 1,
2184
+ updated_at: now,
2185
+ };
2186
+ const payload = {
2187
+ schema_version: "intentdna.worker_nonlaunch_attestation.v1",
2188
+ run_id: identity.run_id,
2189
+ step_id: identity.step_id,
2190
+ activation_id: identity.activation_id,
2191
+ attempt_id: identity.attempt_id,
2192
+ claim_epoch: identity.claim_epoch,
2193
+ worker_session_id: identity.worker_session_id,
2194
+ execution_instance_id: executionInstanceId,
2195
+ authority_kind: "local_process",
2196
+ authority_instance_id: authorityInstanceId,
2197
+ fencing_epoch: fencingEpoch,
2198
+ started_at: identity.started_at,
2199
+ attested_at: now,
2200
+ failure_idempotency_key: request.failure_idempotency_key,
2201
+ launch_state: "never_launched",
2202
+ source_evidence_digest: nonlaunchSourceEvidenceDigest(tombstone),
2203
+ };
2204
+ const attestation = JSON.parse(canonicalizeJson({
2205
+ attestation_digest: workerNonlaunchAttestationDigest(payload),
2206
+ payload,
2207
+ }));
2208
+ const next = { ...tombstone, nonlaunch_attestation: attestation };
2209
+ atomicWriteJson(path, next);
2210
+ if (preparation !== null) {
2211
+ unlinkSync(preparationPath);
2212
+ syncDirectory(this.preparationsDirectory);
2213
+ }
2214
+ return attestation;
2215
+ });
2216
+ }
2217
+ recoverExecution(request) {
2218
+ const identity = recoveryIdentity(request);
2219
+ requireIdentity(identity);
2220
+ this.ensureSupported();
2221
+ const record = this.readRecoveryRecord(request);
2222
+ if (record === null) {
2223
+ throw new LocalExecutionAuthorityError("unsupported", "durable execution authority record is unavailable");
2224
+ }
2225
+ if (record.phase === "prepared") {
2226
+ return { kind: "launch", binding: this.createLaunchBinding(record) };
2227
+ }
2228
+ if (record.phase === "never_launched") {
2229
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution was durably attested as never launched");
2230
+ }
2231
+ if (record.phase === "unsupported") {
2232
+ throw new LocalExecutionAuthorityError("unsupported", record.supervisor_error ?? "execution supervisor evidence is unavailable");
2233
+ }
2234
+ const recordPath = this.recordPath(identity);
2235
+ const authentication = record.backend.kind === "windows_job" && record.raw_completion === null
2236
+ ? this.authenticateWindowsSupervisor(record, recordPath)
2237
+ : Promise.resolve(record);
2238
+ const processStarted = (async () => {
2239
+ await authentication;
2240
+ for (;;) {
2241
+ const current = this.readRecord(recordPath);
2242
+ if (current.provider?.pid !== null && current.provider !== null)
2243
+ return current.provider.pid;
2244
+ if (current.raw_completion !== null) {
2245
+ if (current.raw_completion.process_id !== null)
2246
+ return current.raw_completion.process_id;
2247
+ throw new LocalExecutionAuthorityError("unsupported", "durable execution completed without a provider identity");
2248
+ }
2249
+ if (current.phase === "unsupported") {
2250
+ throw new LocalExecutionAuthorityError("unsupported", current.supervisor_error ?? "execution supervisor evidence is unavailable");
2251
+ }
2252
+ await sleep(this.pollIntervalMs);
2253
+ }
2254
+ })();
2255
+ const registration = {
2256
+ identity: record.identity,
2257
+ recordPath,
2258
+ abortController: new AbortController(),
2259
+ processStarted,
2260
+ resolveProcessStarted: () => undefined,
2261
+ rejectProcessStarted: () => undefined,
2262
+ };
2263
+ registration.processStarted.catch(() => undefined);
2264
+ return { kind: "observe", binding: {
2265
+ cancellation_signal: registration.abortController.signal,
2266
+ process_started: registration.processStarted,
2267
+ processStarted: (processId) => {
2268
+ const current = this.readRecord(registration.recordPath);
2269
+ if (!providerMatchesProcessId(current, processId)) {
2270
+ throw new LocalExecutionAuthorityError("identity_conflict", "recovered execution process does not match durable guardian identity");
2271
+ }
2272
+ },
2273
+ processTreeCompleted: (observation) => this.recordNormalizedCompletion(registration.recordPath, observation),
2274
+ executeProcessTree: (_command, _args, options) => this.observeRecoveredExecution(registration, options),
2275
+ } };
2276
+ }
2277
+ async executeSupervised(registration, command, args, options) {
2278
+ if (options.spawnImpl !== undefined || options.platform !== undefined) {
2279
+ throw new LocalExecutionAuthorityError("unsupported", "custom process launch adapters are unsupported");
2280
+ }
2281
+ if (options.maxProcessCount !== undefined) {
2282
+ throw new LocalExecutionAuthorityError("unsupported", "durable supervisor process limits are not implemented");
2283
+ }
2284
+ if (options.killSignal === "SIGKILL" || options.killSignal === "SIGSTOP") {
2285
+ throw new LocalExecutionAuthorityError("unsupported", `durable supervisor cannot preserve guardian identity with ${options.killSignal}`);
2286
+ }
2287
+ const record = await this.withLock(this.transitionPath(registration.identity), () => this.updateRecord(registration.recordPath, (current) => {
2288
+ if (current.phase !== "prepared") {
2289
+ throw new LocalExecutionAuthorityError("identity_conflict", "another execution binding already owns provider launch");
2290
+ }
2291
+ return {
2292
+ ...current,
2293
+ phase: "launching",
2294
+ revision: current.revision + 1,
2295
+ updated_at: new Date().toISOString(),
2296
+ };
2297
+ }));
2298
+ const streamToken = record.identity_digest.slice("sha256:".length, "sha256:".length + 24);
2299
+ const stdoutPath = join(this.streamsDirectory, `${streamToken}.stdout`);
2300
+ const stderrPath = join(this.streamsDirectory, `${streamToken}.stderr`);
2301
+ const gatePath = join(this.streamsDirectory, `${streamToken}.gate`);
2302
+ const stdinPath = join(this.streamsDirectory, `${streamToken}.stdin`);
2303
+ for (const path of [stdoutPath, stderrPath, gatePath, stdinPath]) {
2304
+ try {
2305
+ unlinkSync(path);
2306
+ }
2307
+ catch (error) {
2308
+ if (!isErrno(error, "ENOENT"))
2309
+ throw error;
2310
+ }
2311
+ }
2312
+ const environment = Object.fromEntries(Object.entries(options.env ?? process.env)
2313
+ .filter((entry) => entry[1] !== undefined));
2314
+ const cwd = resolve(options.cwd ?? process.cwd());
2315
+ const timeoutMs = options.timeoutMs !== undefined
2316
+ && Number.isFinite(options.timeoutMs)
2317
+ && options.timeoutMs > 0
2318
+ ? Math.floor(options.timeoutMs)
2319
+ : null;
2320
+ const maxOutputBytes = options.maxOutputBytes === undefined
2321
+ ? DEFAULT_MAX_OUTPUT_BYTES
2322
+ : requirePositiveInteger(Math.floor(options.maxOutputBytes), "maxOutputBytes");
2323
+ const naturalDrainGraceMs = options.sigkillGraceMs !== undefined
2324
+ && Number.isFinite(options.sigkillGraceMs)
2325
+ && options.sigkillGraceMs >= 0
2326
+ ? Math.floor(options.sigkillGraceMs)
2327
+ : 1_000;
2328
+ const forcedDrainGraceMs = options.cancellationGraceMs !== undefined
2329
+ && Number.isFinite(options.cancellationGraceMs)
2330
+ && options.cancellationGraceMs >= 0
2331
+ ? Math.floor(options.cancellationGraceMs)
2332
+ : 1_000;
2333
+ let configuration;
2334
+ if (record.backend.kind === "windows_job") {
2335
+ const spec = resolveProcessCommand(command, args, "win32", environment, cwd);
2336
+ const executable = this.resolveAbsoluteWindowsExecutable(spec.command, environment, cwd);
2337
+ configuration = {
2338
+ execution_instance_id: record.execution_instance_id,
2339
+ challenge: record.challenge,
2340
+ containment_nonce: record.backend.containment_nonce,
2341
+ control_endpoint: record.supervisor.socket_path,
2342
+ helper_path: record.backend.helper_path,
2343
+ helper_digest: record.backend.helper_digest,
2344
+ executable,
2345
+ args: [...spec.args],
2346
+ command_line: spec.windowsVerbatimArguments
2347
+ ? windowsVerbatimCommandLine(executable, spec.args)
2348
+ : null,
2349
+ cwd,
2350
+ env: environment,
2351
+ stdin_path: options.stdin === undefined ? null : stdinPath,
2352
+ stdin: options.stdin ?? "",
2353
+ stdout_path: stdoutPath,
2354
+ stderr_path: stderrPath,
2355
+ max_output_bytes: maxOutputBytes,
2356
+ timeout_ms: timeoutMs,
2357
+ natural_drain_grace_ms: naturalDrainGraceMs,
2358
+ forced_drain_grace_ms: forcedDrainGraceMs,
2359
+ };
2360
+ }
2361
+ else {
2362
+ configuration = {
2363
+ execution_instance_id: record.execution_instance_id,
2364
+ challenge: record.challenge,
2365
+ socket_path: record.supervisor.socket_path,
2366
+ stdout_path: stdoutPath,
2367
+ stderr_path: stderrPath,
2368
+ max_output_bytes: maxOutputBytes,
2369
+ gate_path: gatePath,
2370
+ command,
2371
+ args: [...args],
2372
+ cwd,
2373
+ env: environment,
2374
+ stdin: options.stdin ?? null,
2375
+ timeout_ms: timeoutMs,
2376
+ kill_signal: options.killSignal ?? "SIGTERM",
2377
+ cancellation_grace_ms: options.cancellationGraceMs ?? 1_000,
2378
+ timeout_grace_ms: options.sigkillGraceMs ?? 1_000,
2379
+ windows_verbatim_arguments: false,
2380
+ auto_release_gate: true,
2381
+ };
2382
+ }
2383
+ const child = spawn(process.execPath, [this.supervisorScriptPath(), registration.recordPath], {
2384
+ detached: true,
2385
+ stdio: ["pipe", "ignore", "ignore"],
2386
+ windowsHide: true,
2387
+ });
2388
+ child.unref();
2389
+ child.stdin?.end(JSON.stringify(configuration));
2390
+ let supervisorExit = null;
2391
+ child.once("exit", (status, signal) => { supervisorExit = { status, signal }; });
2392
+ let processObserved = false;
2393
+ let cancellationSent = false;
2394
+ const cancellationSignal = options.cancellationSignal;
2395
+ const cancel = async () => {
2396
+ if (cancellationSent)
2397
+ return;
2398
+ let current = this.readRecord(registration.recordPath);
2399
+ if (current.raw_completion !== null)
2400
+ return;
2401
+ if (current.supervisor.ready_at === null)
2402
+ return;
2403
+ if (current.backend.kind === "windows_job") {
2404
+ current = await this.authenticateWindowsSupervisor(current, registration.recordPath);
2405
+ if (current.raw_completion !== null)
2406
+ return;
2407
+ }
2408
+ await this.sendControl(current, {
2409
+ action: "stop",
2410
+ reason: typeof cancellationSignal?.reason === "string"
2411
+ ? cancellationSignal.reason
2412
+ : options.cancellationReason ?? null,
2413
+ });
2414
+ cancellationSent = true;
2415
+ };
2416
+ const onAbort = () => { void cancel().catch(() => undefined); };
2417
+ cancellationSignal?.addEventListener("abort", onAbort, { once: true });
2418
+ if (cancellationSignal?.aborted)
2419
+ onAbort();
2420
+ try {
2421
+ const deadline = timeoutMs === null
2422
+ ? Number.POSITIVE_INFINITY
2423
+ : Date.now()
2424
+ + Math.max(this.controlTimeoutMs, timeoutMs)
2425
+ + Math.max(forcedDrainGraceMs, naturalDrainGraceMs)
2426
+ + 5_000;
2427
+ for (;;) {
2428
+ const current = this.readRecord(registration.recordPath);
2429
+ if (cancellationSignal?.aborted && !cancellationSent && current.supervisor.ready_at !== null) {
2430
+ await cancel();
2431
+ continue;
2432
+ }
2433
+ if (!processObserved && current.provider?.pid !== null && current.provider?.pid !== undefined) {
2434
+ processObserved = true;
2435
+ options.onProcessStart?.(current.provider.pid);
2436
+ }
2437
+ if (current.phase === "unsupported") {
2438
+ throw new LocalExecutionAuthorityError("unsupported", current.supervisor_error ?? "execution supervisor failed without trusted evidence");
2439
+ }
2440
+ if (["raw_completed", "normalized_completed", "receipted"].includes(current.phase)) {
2441
+ if (current.raw_completion === null) {
2442
+ throw new LocalExecutionAuthorityError("corrupt_state", "supervisor completed without raw evidence");
2443
+ }
2444
+ const result = this.rawCompletionResult(current);
2445
+ if (result.stdout !== "")
2446
+ options.onStdout?.(result.stdout);
2447
+ if (result.stderr !== "")
2448
+ options.onStderr?.(result.stderr);
2449
+ if (result.terminationReason !== null)
2450
+ options.onTerminationRequested?.(result.terminationReason);
2451
+ return result;
2452
+ }
2453
+ const supervisorPid = current.supervisor.pid ?? child.pid ?? null;
2454
+ if (record.backend.kind === "windows_job" && supervisorExit !== null) {
2455
+ const detail = supervisorExit;
2456
+ const message = `Windows execution supervisor exited before trusted completion (status ${String(detail.status)}, signal ${String(detail.signal)})`;
2457
+ await this.markUnsupported(registration.recordPath, message);
2458
+ throw new LocalExecutionAuthorityError("unsupported", message);
2459
+ }
2460
+ if (record.backend.kind !== "windows_job" && supervisorPid !== null && !processIsAlive(supervisorPid)) {
2461
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor exited before publishing trusted completion evidence");
2462
+ }
2463
+ if (Date.now() >= deadline) {
2464
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor did not publish completion before the authority deadline");
2465
+ }
2466
+ await sleep(this.pollIntervalMs);
2467
+ }
2468
+ }
2469
+ finally {
2470
+ cancellationSignal?.removeEventListener("abort", onAbort);
2471
+ }
2472
+ }
2473
+ async observeRecoveredExecution(registration, options) {
2474
+ const initial = this.readRecord(registration.recordPath);
2475
+ if (initial.backend.kind === "windows_job" && initial.raw_completion === null) {
2476
+ await this.authenticateWindowsSupervisor(initial, registration.recordPath);
2477
+ }
2478
+ let cancellationSent = false;
2479
+ const cancel = async () => {
2480
+ if (cancellationSent)
2481
+ return;
2482
+ const current = this.readRecord(registration.recordPath);
2483
+ if (current.raw_completion !== null)
2484
+ return;
2485
+ const authenticated = current.backend.kind === "windows_job"
2486
+ ? await this.authenticateWindowsSupervisor(current, registration.recordPath)
2487
+ : current;
2488
+ if (authenticated.raw_completion !== null)
2489
+ return;
2490
+ await this.sendControl(authenticated, {
2491
+ action: "stop",
2492
+ reason: typeof options.cancellationSignal?.reason === "string"
2493
+ ? options.cancellationSignal.reason
2494
+ : options.cancellationReason ?? null,
2495
+ });
2496
+ cancellationSent = true;
2497
+ };
2498
+ const onAbort = () => { void cancel().catch(() => undefined); };
2499
+ options.cancellationSignal?.addEventListener("abort", onAbort, { once: true });
2500
+ if (options.cancellationSignal?.aborted)
2501
+ onAbort();
2502
+ let processObserved = false;
2503
+ let nextWindowsProbeAt = 0;
2504
+ try {
2505
+ for (;;) {
2506
+ const current = this.readRecord(registration.recordPath);
2507
+ if (current.phase === "unsupported") {
2508
+ throw new LocalExecutionAuthorityError("unsupported", current.supervisor_error ?? "recovered execution supervisor failed");
2509
+ }
2510
+ if (current.raw_completion !== null) {
2511
+ const result = this.rawCompletionResult(current);
2512
+ if (result.stdout !== "")
2513
+ options.onStdout?.(result.stdout);
2514
+ if (result.stderr !== "")
2515
+ options.onStderr?.(result.stderr);
2516
+ if (result.terminationReason !== null)
2517
+ options.onTerminationRequested?.(result.terminationReason);
2518
+ return result;
2519
+ }
2520
+ if (!processObserved && current.provider?.pid !== null && current.provider !== null) {
2521
+ processObserved = true;
2522
+ options.onProcessStart?.(current.provider.pid);
2523
+ }
2524
+ if (current.backend.kind === "windows_job" && Date.now() >= nextWindowsProbeAt) {
2525
+ await this.authenticateWindowsSupervisor(current, registration.recordPath);
2526
+ nextWindowsProbeAt = Date.now() + 250;
2527
+ }
2528
+ if (current.backend.kind !== "windows_job"
2529
+ && (current.supervisor.pid === null || !processIsAlive(current.supervisor.pid))) {
2530
+ throw new LocalExecutionAuthorityError("unsupported", "recovered execution supervisor exited without durable completion");
2531
+ }
2532
+ await sleep(this.pollIntervalMs);
2533
+ }
2534
+ }
2535
+ finally {
2536
+ options.cancellationSignal?.removeEventListener("abort", onAbort);
2537
+ }
2538
+ }
2539
+ async recordNormalizedCompletion(path, observation) {
2540
+ await this.updateRecord(path, (current) => {
2541
+ const matchesDurableEvidence = current.raw_completion !== null
2542
+ && observation.process_tree_drained
2543
+ && current.raw_completion.process_tree_drained
2544
+ && observation.started_at === current.identity.started_at
2545
+ && observation.completed_at >= current.raw_completion.completed_at
2546
+ && observation.process_id === current.raw_completion.process_id;
2547
+ if (current.phase === "receipted") {
2548
+ if (!matchesDurableEvidence
2549
+ || (current.normalized_process_outcome !== null
2550
+ && canonicalizeJson(current.normalized_process_outcome) !== canonicalizeJson(observation.outcome))) {
2551
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution completion conflicts with the durable receipt");
2552
+ }
2553
+ return current;
2554
+ }
2555
+ if (current.phase === "normalized_completed" && current.normalized_process_outcome !== null) {
2556
+ if (!matchesDurableEvidence
2557
+ || canonicalizeJson(current.normalized_process_outcome) !== canonicalizeJson(observation.outcome)) {
2558
+ throw new LocalExecutionAuthorityError("identity_conflict", "execution completion was already normalized differently");
2559
+ }
2560
+ return current;
2561
+ }
2562
+ if (current.phase !== "raw_completed" || current.raw_completion === null) {
2563
+ throw new LocalExecutionAuthorityError("unsupported", "raw supervisor completion is unavailable");
2564
+ }
2565
+ if (!matchesDurableEvidence) {
2566
+ throw new LocalExecutionAuthorityError("identity_conflict", "normalized completion does not match durable supervisor evidence");
2567
+ }
2568
+ return {
2569
+ ...current,
2570
+ phase: "normalized_completed",
2571
+ normalized_process_outcome: observation.outcome,
2572
+ revision: current.revision + 1,
2573
+ updated_at: new Date().toISOString(),
2574
+ };
2575
+ });
2576
+ }
2577
+ sendControl(record, request) {
2578
+ const socketPath = record.supervisor.socket_path;
2579
+ if (record.backend.kind !== "windows_job") {
2580
+ let metadata;
2581
+ try {
2582
+ metadata = lstatSync(socketPath);
2583
+ }
2584
+ catch (error) {
2585
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor control socket is unavailable", { cause: error });
2586
+ }
2587
+ if (!metadata.isSocket() || metadata.isSymbolicLink() || (metadata.mode & 0o077) !== 0) {
2588
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor control socket is not trusted");
2589
+ }
2590
+ }
2591
+ return new Promise((resolvePromise, rejectPromise) => {
2592
+ const socket = connect(socketPath);
2593
+ const framedControl = record.backend.kind === "windows_job";
2594
+ let response = "";
2595
+ const timer = setTimeout(() => {
2596
+ socket.destroy();
2597
+ rejectPromise(new LocalExecutionAuthorityError("unsupported", "execution supervisor control timed out"));
2598
+ }, this.controlTimeoutMs);
2599
+ timer.unref?.();
2600
+ const fail = (error) => {
2601
+ clearTimeout(timer);
2602
+ rejectPromise(new LocalExecutionAuthorityError("unsupported", "execution supervisor control failed", { cause: error }));
2603
+ };
2604
+ socket.once("error", fail);
2605
+ socket.setEncoding("utf8");
2606
+ socket.on("data", (chunk) => {
2607
+ response += chunk;
2608
+ if (Buffer.byteLength(response, "utf8") > MAX_CONTROL_RESPONSE_BYTES) {
2609
+ socket.destroy(new Error("execution control response too large"));
2610
+ }
2611
+ });
2612
+ socket.once("end", () => {
2613
+ clearTimeout(timer);
2614
+ try {
2615
+ if (response.trim().length === 0) {
2616
+ try {
2617
+ const durable = this.readRecord(this.recordPath(record.identity));
2618
+ const matchesStop = durable.raw_completion !== null
2619
+ && (request.stop_idempotency_key === undefined
2620
+ || (durable.stop_fact?.kind === "canonical_stop"
2621
+ && durable.stop_fact.stop_idempotency_key === request.stop_idempotency_key
2622
+ && canonicalizeJson(durable.stop_fact.requested_outcome)
2623
+ === canonicalizeJson(request.requested_outcome)));
2624
+ if (matchesStop) {
2625
+ resolvePromise({ ok: true, raw_completion: durable.raw_completion });
2626
+ return;
2627
+ }
2628
+ }
2629
+ catch {
2630
+ // The control response remains authoritative unless durable completion proves the stop.
2631
+ }
2632
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor control response was empty");
2633
+ }
2634
+ let responseText = response;
2635
+ if (framedControl) {
2636
+ const newline = response.indexOf("\n");
2637
+ if (newline < 0 || response.slice(newline + 1).length !== 0) {
2638
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor control response was incomplete or invalid");
2639
+ }
2640
+ responseText = response.slice(0, newline);
2641
+ }
2642
+ let value;
2643
+ try {
2644
+ value = JSON.parse(responseText);
2645
+ }
2646
+ catch (error) {
2647
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor control response was incomplete or invalid", { cause: error });
2648
+ }
2649
+ if (value === null || typeof value !== "object" || typeof value.ok !== "boolean") {
2650
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor control response was incomplete or invalid");
2651
+ }
2652
+ if (!value.ok) {
2653
+ throw new LocalExecutionAuthorityError("identity_conflict", value.error ?? "execution supervisor rejected the control request");
2654
+ }
2655
+ resolvePromise(value);
2656
+ }
2657
+ catch (error) {
2658
+ rejectPromise(error);
2659
+ }
2660
+ });
2661
+ socket.once("connect", () => {
2662
+ const payload = JSON.stringify({
2663
+ schema_version: CONTROL_SCHEMA_VERSION,
2664
+ execution_instance_id: record.execution_instance_id,
2665
+ challenge: record.challenge,
2666
+ ...(record.backend.kind === "windows_job"
2667
+ ? { containment_nonce: record.backend.containment_nonce }
2668
+ : {}),
2669
+ ...request,
2670
+ });
2671
+ if (framedControl)
2672
+ socket.write(`${payload}\n`);
2673
+ else
2674
+ socket.end(payload);
2675
+ });
2676
+ });
2677
+ }
2678
+ async issueReceipt(path, requestedOutcome, stoppedAt, expectedReceipt) {
2679
+ return this.withLock(path, async () => {
2680
+ const current = this.readRecord(path);
2681
+ if (current.stop_receipt !== null) {
2682
+ if (canonicalizeJson(current.stop_receipt.payload.terminal_outcome) !== canonicalizeJson(requestedOutcome)
2683
+ || current.stop_receipt.payload.stopped_at !== stoppedAt
2684
+ || (expectedReceipt !== null && canonicalizeJson(current.stop_receipt) !== canonicalizeJson(expectedReceipt))) {
2685
+ throw new LocalExecutionAuthorityError("identity_conflict", "durable stop receipt conflicts with the request");
2686
+ }
2687
+ return {
2688
+ stop_receipt: current.stop_receipt,
2689
+ authority_instance_id: current.authority_instance_id,
2690
+ fencing_epoch: current.fencing_epoch,
2691
+ };
2692
+ }
2693
+ if (current.raw_completion === null) {
2694
+ throw new LocalExecutionAuthorityError("unsupported", "trusted process completion evidence is unavailable");
2695
+ }
2696
+ if (current.raw_completion.process_tree_drained !== true) {
2697
+ throw new LocalExecutionAuthorityError("corrupt_state", "trusted process-tree drain evidence is unavailable");
2698
+ }
2699
+ const fencingEpoch = await this.nextFencingEpoch();
2700
+ const receipt = createWorkerStopReceipt({
2701
+ schema_version: "intentdna.worker_stop_receipt.v1",
2702
+ run_id: current.identity.run_id,
2703
+ step_id: current.identity.step_id,
2704
+ activation_id: current.identity.activation_id,
2705
+ attempt_id: current.identity.attempt_id,
2706
+ claim_epoch: current.identity.claim_epoch,
2707
+ worker_session_id: current.identity.worker_session_id,
2708
+ execution_instance_id: current.execution_instance_id,
2709
+ authority_kind: "local_process",
2710
+ authority_instance_id: current.authority_instance_id,
2711
+ fencing_epoch: fencingEpoch,
2712
+ started_at: current.identity.started_at,
2713
+ stopped_at: stoppedAt,
2714
+ terminal_outcome: requestedOutcome,
2715
+ process_tree_drained: true,
2716
+ source_evidence_digest: stopReceiptSourceEvidenceDigest(current),
2717
+ });
2718
+ if (expectedReceipt !== null && canonicalizeJson(receipt) !== canonicalizeJson(expectedReceipt)) {
2719
+ throw new LocalExecutionAuthorityError("identity_conflict", "expected stop receipt does not match durable evidence");
2720
+ }
2721
+ const updated = {
2722
+ ...current,
2723
+ phase: "receipted",
2724
+ stop_receipt: receipt,
2725
+ fencing_epoch: fencingEpoch,
2726
+ revision: current.revision + 1,
2727
+ updated_at: new Date().toISOString(),
2728
+ };
2729
+ atomicWriteJson(path, updated);
2730
+ return {
2731
+ stop_receipt: receipt,
2732
+ authority_instance_id: updated.authority_instance_id,
2733
+ fencing_epoch: fencingEpoch,
2734
+ };
2735
+ });
2736
+ }
2737
+ async issueAlreadyStoppedEvidence(path, request) {
2738
+ return this.withLock(path, async () => {
2739
+ const current = this.readRecord(path);
2740
+ if (current.already_stopped_evidence !== null) {
2741
+ if (!workerAlreadyStoppedEvidenceMatchesStop(current.already_stopped_evidence, request)) {
2742
+ throw new LocalExecutionAuthorityError("identity_conflict", "durable already-stopped evidence conflicts with the request");
2743
+ }
2744
+ return current.already_stopped_evidence;
2745
+ }
2746
+ if (request.expected_receipt !== null) {
2747
+ throw new LocalExecutionAuthorityError("identity_conflict", "expected stop receipt cannot match a naturally completed execution");
2748
+ }
2749
+ if (current.stop_receipt !== null || current.stop_fact?.kind === "canonical_stop") {
2750
+ throw new LocalExecutionAuthorityError("identity_conflict", "canonical stop already owns the durable terminal transition");
2751
+ }
2752
+ if (current.raw_completion === null) {
2753
+ throw new LocalExecutionAuthorityError("unsupported", "trusted natural completion evidence is unavailable");
2754
+ }
2755
+ const fencingEpoch = await this.nextFencingEpoch();
2756
+ const evidence = createWorkerAlreadyStoppedEvidence({
2757
+ schema_version: "intentdna.worker_already_stopped_evidence.v1",
2758
+ run_id: current.identity.run_id,
2759
+ step_id: current.identity.step_id,
2760
+ activation_id: current.identity.activation_id,
2761
+ attempt_id: current.identity.attempt_id,
2762
+ claim_epoch: current.identity.claim_epoch,
2763
+ worker_session_id: current.identity.worker_session_id,
2764
+ execution_instance_id: current.execution_instance_id,
2765
+ authority_kind: "local_process",
2766
+ authority_instance_id: current.authority_instance_id,
2767
+ fencing_epoch: fencingEpoch,
2768
+ started_at: current.identity.started_at,
2769
+ completed_at: current.raw_completion.completed_at,
2770
+ observed_outcome: terminalOutcomeToCanonical(rawCompletionToOutcome(current.raw_completion)),
2771
+ process_tree_drained: true,
2772
+ stop_idempotency_key: request.stop_idempotency_key,
2773
+ stop_requested_at: request.requested_at,
2774
+ stop_purpose: request.purpose,
2775
+ stop_requested_outcome: request.requested_outcome,
2776
+ source_evidence_digest: alreadyStoppedSourceEvidenceDigest(current),
2777
+ });
2778
+ const updated = {
2779
+ ...current,
2780
+ phase: "receipted",
2781
+ already_stopped_evidence: evidence,
2782
+ fencing_epoch: fencingEpoch,
2783
+ revision: current.revision + 1,
2784
+ updated_at: new Date().toISOString(),
2785
+ };
2786
+ atomicWriteJson(path, updated);
2787
+ return evidence;
2788
+ });
2789
+ }
2790
+ async withStoppedExecution(request, operation) {
2791
+ const record = this.requireRequestRecord(request);
2792
+ if (record.phase === "unsupported" || record.raw_completion === null) {
2793
+ throw new LocalExecutionAuthorityError("unsupported", "trusted execution completion is unavailable");
2794
+ }
2795
+ if (record.normalized_process_outcome === null
2796
+ || !processMatchesCanonical(record.normalized_process_outcome, request.reported_execution.outcome)
2797
+ || request.reported_execution.started_at !== record.identity.started_at
2798
+ || request.reported_execution.completed_at < record.raw_completion.completed_at) {
2799
+ throw new LocalExecutionAuthorityError("identity_conflict", "reported execution does not match durable evidence");
2800
+ }
2801
+ const authority = await this.issueReceipt(this.recordPath(requestIdentity(request)), request.reported_execution.outcome, request.reported_execution.completed_at, request.expected_receipt);
2802
+ return operation(authority);
2803
+ }
2804
+ async requestStop(request) {
2805
+ const identity = requestIdentity(request);
2806
+ const path = this.recordPath(identity);
2807
+ const nonlaunchRequest = {
2808
+ run_id: request.run_id,
2809
+ step_id: request.step_id,
2810
+ activation_id: request.activation_id,
2811
+ attempt_id: request.attempt_id,
2812
+ execution_claim_epoch: request.claim_epoch,
2813
+ executor: request.executor,
2814
+ started_at: request.started_at,
2815
+ failure_idempotency_key: request.stop_idempotency_key,
2816
+ requested_at: request.requested_at,
2817
+ };
2818
+ if (!existsSync(path)) {
2819
+ return {
2820
+ kind: "never_launched",
2821
+ nonlaunch_attestation: await this.attestNeverLaunched(nonlaunchRequest),
2822
+ };
2823
+ }
2824
+ let record = this.requireRequestRecord(request);
2825
+ if (record.phase === "never_launched" || (record.phase === "prepared"
2826
+ && record.supervisor.pid === null
2827
+ && record.provider === null
2828
+ && record.raw_completion === null)) {
2829
+ if (request.expected_receipt !== null) {
2830
+ throw new LocalExecutionAuthorityError("identity_conflict", "expected stop receipt cannot match a never-launched execution");
2831
+ }
2832
+ return {
2833
+ kind: "never_launched",
2834
+ nonlaunch_attestation: await this.attestNeverLaunched(nonlaunchRequest),
2835
+ };
2836
+ }
2837
+ if (record.already_stopped_evidence !== null) {
2838
+ const evidence = await this.issueAlreadyStoppedEvidence(path, request);
2839
+ return { kind: "already_stopped", drain_evidence: evidence };
2840
+ }
2841
+ if (record.stop_receipt !== null) {
2842
+ const authority = await this.issueReceipt(path, request.requested_outcome, record.stop_receipt.payload.stopped_at, request.expected_receipt);
2843
+ return { kind: "stopped_by_request", authority };
2844
+ }
2845
+ if (record.phase === "unsupported") {
2846
+ throw new LocalExecutionAuthorityError("unsupported", "execution supervisor evidence is unavailable");
2847
+ }
2848
+ if (record.raw_completion !== null && record.stop_fact?.kind !== "canonical_stop") {
2849
+ const evidence = await this.issueAlreadyStoppedEvidence(path, request);
2850
+ return { kind: "already_stopped", drain_evidence: evidence };
2851
+ }
2852
+ if (record.raw_completion === null) {
2853
+ if (record.backend.kind === "windows_job") {
2854
+ record = await this.authenticateWindowsSupervisor(record, path);
2855
+ }
2856
+ }
2857
+ if (record.raw_completion === null) {
2858
+ await this.sendControl(record, {
2859
+ action: "stop",
2860
+ stop_idempotency_key: request.stop_idempotency_key,
2861
+ requested_at: request.requested_at,
2862
+ requested_outcome: request.requested_outcome,
2863
+ });
2864
+ record = this.readRecord(path);
2865
+ }
2866
+ if (record.raw_completion === null
2867
+ || record.stop_fact?.kind !== "canonical_stop"
2868
+ || record.stop_fact.stop_idempotency_key !== request.stop_idempotency_key
2869
+ || canonicalizeJson(record.stop_fact.requested_outcome) !== canonicalizeJson(request.requested_outcome)) {
2870
+ throw new LocalExecutionAuthorityError("unsupported", "canonical stop evidence was not durably published");
2871
+ }
2872
+ const authority = await this.issueReceipt(path, request.requested_outcome, record.raw_completion.completed_at < request.requested_at
2873
+ ? request.requested_at
2874
+ : record.raw_completion.completed_at, request.expected_receipt);
2875
+ return { kind: "stopped_by_request", authority };
2876
+ }
2877
+ }