owlrunkit 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +274 -66
  3. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +223 -117
  4. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  5. package/integrations/codex/skills/owlcoda-runkit/assets/templates/ready-for-commit-request.json +2 -2
  6. package/package.json +2 -2
  7. package/packages/attest/distribution-manifest-v1.json +10 -0
  8. package/packages/attest/src/quick.mjs +10 -0
  9. package/registry-release-policy-v1.json +8 -2
  10. package/sbom.spdx.json +5 -5
  11. package/scripts/runkit-contract/assurance-router.mjs +119 -0
  12. package/scripts/runkit-contract/core-contract.mjs +250 -115
  13. package/scripts/runkit-contract/core-successor.mjs +2043 -0
  14. package/scripts/runkit-contract/deployment-workflow.mjs +2040 -0
  15. package/scripts/runkit-contract/finalize.mjs +242 -21
  16. package/scripts/runkit-contract/fleet-discovery.mjs +456 -0
  17. package/scripts/runkit-contract/formal-workflow.mjs +850 -0
  18. package/scripts/runkit-contract/human-status.mjs +553 -0
  19. package/scripts/runkit-contract/inspect-presentation.mjs +25 -8
  20. package/scripts/runkit-contract/install-codex-skill.mjs +73 -30
  21. package/scripts/runkit-contract/lease-lifecycle.mjs +8 -2
  22. package/scripts/runkit-contract/lifecycle-orchestration.mjs +135 -12
  23. package/scripts/runkit-contract/onboarding-doctor.mjs +43 -90
  24. package/scripts/runkit-contract/owner-authority-trust.mjs +230 -0
  25. package/scripts/runkit-contract/owner-deployment-decision.mjs +385 -0
  26. package/scripts/runkit-contract/profile-onboarding.mjs +841 -13
  27. package/scripts/runkit-contract/project-cli-resolver.mjs +701 -0
  28. package/scripts/runkit-contract/project-control-parser.mjs +830 -0
  29. package/scripts/runkit-contract/project-control-state.mjs +28 -0
  30. package/scripts/runkit-contract/provenance-common.mjs +19 -2
  31. package/scripts/runkit-contract/ready-for-commit.mjs +330 -18
  32. package/scripts/runkit-contract/remote-deployment.mjs +1596 -0
  33. package/scripts/runkit-contract/remote-process-adapter.mjs +177 -0
  34. package/scripts/runkit-contract/runkit-bootstrap.mjs +131 -0
  35. package/scripts/runkit-contract/runkit-cli.mjs +1097 -21
  36. package/scripts/runkit-contract/schemas/assurance-route-v1.schema.json +26 -0
  37. package/scripts/runkit-contract/schemas/core-successor-batch-receipt-v1.schema.json +126 -0
  38. package/scripts/runkit-contract/schemas/core-successor-plan-v1.schema.json +155 -0
  39. package/scripts/runkit-contract/schemas/core-successor-project-success-receipt-v1.schema.json +72 -0
  40. package/scripts/runkit-contract/schemas/deployment-execute-request-v1.schema.json +63 -0
  41. package/scripts/runkit-contract/schemas/deployment-lineage-v1.schema.json +292 -0
  42. package/scripts/runkit-contract/schemas/deployment-prepare-receipt-v1.schema.json +140 -0
  43. package/scripts/runkit-contract/schemas/fleet-discovery-v1.schema.json +31 -0
  44. package/scripts/runkit-contract/schemas/fleet-manifest-v1.schema.json +20 -0
  45. package/scripts/runkit-contract/schemas/fleet-root-registry-v1.schema.json +34 -0
  46. package/scripts/runkit-contract/schemas/human-status-v1.schema.json +102 -0
  47. package/scripts/runkit-contract/schemas/owner-authority-trust-v1.schema.json +66 -0
  48. package/scripts/runkit-contract/schemas/owner-deployment-authority-v1.schema.json +46 -0
  49. package/scripts/runkit-contract/schemas/owner-deployment-authority-v2.schema.json +94 -0
  50. package/scripts/runkit-contract/schemas/owner-deployment-decision-v1.schema.json +102 -0
  51. package/scripts/runkit-contract/schemas/owner-migration-authority-v1.schema.json +33 -0
  52. package/scripts/runkit-contract/schemas/owner-migration-authority-v2.schema.json +67 -0
  53. package/scripts/runkit-contract/schemas/profile-apply-receipt-v1.schema.json +32 -0
  54. package/scripts/runkit-contract/schemas/profile-detection-v2.schema.json +145 -0
  55. package/scripts/runkit-contract/schemas/ready-for-commit-v2.schema.json +37 -0
  56. package/scripts/runkit-contract/schemas/remote-deployment-manifest-v1.schema.json +379 -0
  57. package/scripts/runkit-contract/schemas/remote-deployment-result-v1.schema.json +153 -0
  58. package/scripts/runkit-contract/schemas/remote-deployment-stage-journal-v1.schema.json +183 -0
  59. package/scripts/runkit-contract/schemas/remote-target-v1.schema.json +32 -0
  60. package/scripts/runkit-contract/schemas/source-candidate-v2.schema.json +152 -0
  61. package/scripts/runkit-contract/schemas/verification-receipt-v2.schema.json +13 -0
  62. package/scripts/runkit-contract/snapshot.mjs +1 -1
  63. package/scripts/runkit-contract/source-candidate.mjs +1382 -0
  64. package/scripts/runkit-contract/ssh-remote-adapter.mjs +1184 -0
  65. package/scripts/runkit-contract/sync-core016-release-identity.mjs +161 -0
  66. package/scripts/runkit-contract/templates/assurance-request.json +13 -0
  67. package/scripts/runkit-contract/templates/core-successor-owner-authority.json +15 -0
  68. package/scripts/runkit-contract/templates/deployment-execute-request.json +39 -0
  69. package/scripts/runkit-contract/templates/deployment-owner-authority.json +23 -0
  70. package/scripts/runkit-contract/templates/deployment-owner-decision.json +26 -0
  71. package/scripts/runkit-contract/templates/fleet-manifest.json +8 -0
  72. package/scripts/runkit-contract/templates/fleet-root-registry.json +8 -0
  73. package/scripts/runkit-contract/templates/owner-authority-trust.json +16 -0
  74. package/scripts/runkit-contract/templates/ready-for-commit-request.json +2 -2
  75. package/scripts/runkit-contract/templates/remote-deployment-manifest.json +108 -0
  76. package/scripts/runkit-contract/verification-receipt-gate.mjs +28 -0
@@ -0,0 +1,850 @@
1
+ import {
2
+ existsSync,
3
+ lstatSync,
4
+ readFileSync,
5
+ readdirSync,
6
+ realpathSync,
7
+ } from "node:fs";
8
+ import path from "node:path";
9
+
10
+ import {
11
+ acceptedCloseoutVerificationIssues,
12
+ validateCoreArtifact,
13
+ } from "./core-contract.mjs";
14
+ import { runFinalize } from "./finalize.mjs";
15
+ import { derivedVerificationContext } from "./lifecycle-orchestration.mjs";
16
+ import { withControlTransaction } from "./lease-lifecycle.mjs";
17
+ import {
18
+ loadActiveExecution,
19
+ readJson,
20
+ relativeToWorkspace,
21
+ safeIdentifier,
22
+ safeRelativePath,
23
+ sha256,
24
+ writeJsonExclusiveAtomically,
25
+ } from "./provenance-common.mjs";
26
+ import {
27
+ runSnapshot,
28
+ verifySnapshotEvidence,
29
+ } from "./snapshot.mjs";
30
+ import {
31
+ freezeSourceCandidateWithinControlTransactionV2,
32
+ verifySourceCandidateV2,
33
+ } from "./source-candidate.mjs";
34
+ import { validateReceiptLineage } from "./receipt-lineage.mjs";
35
+ import { verificationContextFingerprint } from "./verification-context.mjs";
36
+
37
+ const FORBIDDEN_EXTERNAL_TOOLS = new Set([
38
+ "curl",
39
+ "ftp",
40
+ "nc",
41
+ "ncat",
42
+ "rsync",
43
+ "scp",
44
+ "sftp",
45
+ "ssh",
46
+ "wget",
47
+ ]);
48
+ const FORBIDDEN_WRAPPERS = new Set([
49
+ "bash",
50
+ "cmd",
51
+ "env",
52
+ "fish",
53
+ "osascript",
54
+ "powershell",
55
+ "pwsh",
56
+ "sh",
57
+ "zsh",
58
+ ]);
59
+ const FORBIDDEN_GIT_ACTIONS = new Set([
60
+ "add",
61
+ "checkout",
62
+ "clean",
63
+ "commit",
64
+ "merge",
65
+ "pull",
66
+ "push",
67
+ "rebase",
68
+ "reset",
69
+ "restore",
70
+ "revert",
71
+ "switch",
72
+ "tag",
73
+ ]);
74
+ const FORBIDDEN_PACKAGE_ACTIONS = new Set([
75
+ "add",
76
+ "deprecate",
77
+ "dist-tag",
78
+ "install",
79
+ "login",
80
+ "logout",
81
+ "owner",
82
+ "publish",
83
+ "remove",
84
+ "uninstall",
85
+ "unpublish",
86
+ "update",
87
+ "version",
88
+ ]);
89
+ const LEGACY_FORBIDDEN_GIT_ACTIONS = new Set(["push", "tag"]);
90
+ const LEGACY_FORBIDDEN_PACKAGE_ACTIONS = new Set(["publish", "unpublish"]);
91
+ const KNOWN_DEPLOYMENT_TOOLS = new Set([
92
+ "firebase",
93
+ "flyctl",
94
+ "netlify",
95
+ "vercel",
96
+ "wrangler",
97
+ ]);
98
+ const PACKAGE_TOOLS = new Set(["bun", "npm", "npx", "pnpm", "yarn"]);
99
+
100
+ function checkRoot(executionRoot) {
101
+ return path.join(executionRoot, "formal-checks");
102
+ }
103
+
104
+ function canonicalJson(value) {
105
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
106
+ if (value && typeof value === "object") {
107
+ return `{${Object.keys(value).sort()
108
+ .map(key => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
109
+ .join(",")}}`;
110
+ }
111
+ const encoded = JSON.stringify(value);
112
+ if (encoded === undefined) {
113
+ throw new Error("Formal artifact is not canonical JSON.");
114
+ }
115
+ return encoded;
116
+ }
117
+
118
+ function readRegularJson(filePath, label) {
119
+ const stat = lstatSync(filePath);
120
+ if (stat.isSymbolicLink() || !stat.isFile()) {
121
+ throw new Error(`${label} must be a regular file.`);
122
+ }
123
+ if (realpathSync(filePath) !== path.resolve(filePath)) {
124
+ throw new Error(`${label} must not traverse a symlink.`);
125
+ }
126
+ return JSON.parse(readFileSync(filePath, "utf8"));
127
+ }
128
+
129
+ function writeOrResumeExactJson(filePath, value, label) {
130
+ if (!existsSync(filePath)) {
131
+ writeJsonExclusiveAtomically(filePath, value);
132
+ return { value, resumed: false };
133
+ }
134
+ const existing = readRegularJson(filePath, label);
135
+ if (canonicalJson(existing) !== canonicalJson(value)) {
136
+ throw new Error(`Existing ${label} differs from the resumed command.`);
137
+ }
138
+ return { value: existing, resumed: true };
139
+ }
140
+
141
+ function withinRoot(root, candidate) {
142
+ const relative = path.relative(root, candidate);
143
+ return relative === ""
144
+ || (!relative.startsWith(`..${path.sep}`)
145
+ && relative !== ".."
146
+ && !path.isAbsolute(relative));
147
+ }
148
+
149
+ function regularExecutable(executable) {
150
+ if (typeof executable !== "string" || !path.isAbsolute(executable)) {
151
+ throw new Error("Formal check executable must be an absolute path.");
152
+ }
153
+ const stat = lstatSync(executable);
154
+ if (stat.isSymbolicLink() || !stat.isFile()) {
155
+ throw new Error("Formal check executable must be a regular file, not a symlink.");
156
+ }
157
+ return realpathSync(executable);
158
+ }
159
+
160
+ function executableName(executable) {
161
+ return path.basename(executable)
162
+ .toLowerCase()
163
+ .replace(/\.(?:cmd|exe)$/u, "");
164
+ }
165
+
166
+ function effectiveTool(executable, argv) {
167
+ const direct = executableName(executable);
168
+ if (
169
+ direct === "node"
170
+ && typeof argv[0] === "string"
171
+ && /^(?:npm-cli|pnpm|yarn)(?:\.[cm]?js)?$/u.test(
172
+ path.basename(argv[0]).toLowerCase(),
173
+ )
174
+ ) {
175
+ const launcher = path.basename(argv[0]).toLowerCase();
176
+ return {
177
+ name: launcher.startsWith("npm")
178
+ ? "npm"
179
+ : launcher.startsWith("pnpm")
180
+ ? "pnpm"
181
+ : "yarn",
182
+ argv: argv.slice(1),
183
+ };
184
+ }
185
+ return { name: direct, argv };
186
+ }
187
+
188
+ function forbiddenFormalCommand(executable, argv) {
189
+ const externalSideEffect = forbiddenLegacyVerificationSideEffect(
190
+ executable,
191
+ argv,
192
+ );
193
+ if (externalSideEffect) return externalSideEffect;
194
+ const tool = effectiveTool(executable, argv);
195
+ if (FORBIDDEN_WRAPPERS.has(tool.name)) return tool.name;
196
+ if (tool.name === "node" && tool.argv.some((argument) =>
197
+ new Set(["-e", "--eval", "-p", "--print"]).has(argument))) {
198
+ return "node-inline-code";
199
+ }
200
+ const action = tool.argv
201
+ .map((argument) => argument.toLowerCase())
202
+ .find((argument) => (
203
+ tool.name === "git"
204
+ ? FORBIDDEN_GIT_ACTIONS.has(argument)
205
+ : FORBIDDEN_PACKAGE_ACTIONS.has(argument)
206
+ ));
207
+ if (tool.name === "git" && action) {
208
+ return `git-${action}`;
209
+ }
210
+ if (
211
+ new Set(["npm", "pnpm", "yarn", "bun"]).has(tool.name)
212
+ && action
213
+ ) {
214
+ return `${tool.name}-${action}`;
215
+ }
216
+ return null;
217
+ }
218
+
219
+ function forbiddenLegacyVerificationSideEffect(executable, argv) {
220
+ const tool = effectiveTool(executable, argv);
221
+ if (FORBIDDEN_EXTERNAL_TOOLS.has(tool.name)) return tool.name;
222
+ const lowered = tool.argv.map((argument) => argument.toLowerCase());
223
+ const gitAction = lowered.find((argument) =>
224
+ LEGACY_FORBIDDEN_GIT_ACTIONS.has(argument));
225
+ if (tool.name === "git" && gitAction) return `git-${gitAction}`;
226
+ const packageAction = lowered.find((argument) =>
227
+ LEGACY_FORBIDDEN_PACKAGE_ACTIONS.has(argument));
228
+ if (PACKAGE_TOOLS.has(tool.name) && packageAction) {
229
+ return `${tool.name}-${packageAction}`;
230
+ }
231
+ const deploymentAction = lowered.find((argument) =>
232
+ argument === "deploy" || argument === "publish");
233
+ if (
234
+ deploymentAction
235
+ && (PACKAGE_TOOLS.has(tool.name) || KNOWN_DEPLOYMENT_TOOLS.has(tool.name))
236
+ ) {
237
+ return `${tool.name}-${deploymentAction}`;
238
+ }
239
+ if (tool.name === "deploy" || tool.name === "publish") return tool.name;
240
+ return null;
241
+ }
242
+
243
+ function safeNodeSyntaxCheck({ workspaceRoot, cwd, executable, argv }) {
244
+ if (
245
+ executable !== realpathSync(process.execPath)
246
+ || argv.length !== 2
247
+ || argv[0] !== "--check"
248
+ ) return false;
249
+ safeRelativePath(argv[1], "Formal Node syntax-check target");
250
+ const cwdRoot = path.resolve(workspaceRoot, cwd);
251
+ const targetPath = path.resolve(cwdRoot, argv[1]);
252
+ if (!withinRoot(workspaceRoot, targetPath)) return false;
253
+ const stat = lstatSync(targetPath);
254
+ return !stat.isSymbolicLink()
255
+ && stat.isFile()
256
+ && realpathSync(targetPath) === targetPath;
257
+ }
258
+
259
+ export function validateFormalVerificationCommandV1({
260
+ workspaceRoot,
261
+ cwd = ".",
262
+ commandArgv,
263
+ }) {
264
+ safeRelativePath(cwd, "Formal check cwd", { allowDot: true });
265
+ if (
266
+ !Array.isArray(commandArgv)
267
+ || commandArgv.length === 0
268
+ || commandArgv.some((argument) => typeof argument !== "string")
269
+ ) {
270
+ throw new Error("Formal check requires one exact command.");
271
+ }
272
+ const root = realpathSync(workspaceRoot);
273
+ const [rawExecutable, ...argv] = commandArgv;
274
+ const executable = regularExecutable(rawExecutable);
275
+ const forbidden = forbiddenFormalCommand(executable, argv);
276
+ if (forbidden) {
277
+ throw new Error(
278
+ `Formal verification-only policy forbids external side-effect command: ${forbidden}.`,
279
+ );
280
+ }
281
+ if (safeNodeSyntaxCheck({
282
+ workspaceRoot: root,
283
+ cwd,
284
+ executable,
285
+ argv,
286
+ })) {
287
+ return {
288
+ schemaVersion: "OwlCodaRunKitFormalVerificationCommandPolicyV1",
289
+ mode: "built_in_safe_verification",
290
+ riskClassification: "built_in_read_only_verification",
291
+ profileCommandIds: [],
292
+ executable,
293
+ argv,
294
+ authorizationGranted: false,
295
+ };
296
+ }
297
+ throw new Error(
298
+ "Formal accepted evidence only admits built-in safe verification; "
299
+ + "profile, package, wrapper, and custom commands lack an enforced "
300
+ + "workspace-write and network sandbox.",
301
+ );
302
+ }
303
+
304
+ export function validateLegacyVerificationSideEffectsV1({ commandArgv }) {
305
+ if (
306
+ !Array.isArray(commandArgv)
307
+ || commandArgv.length === 0
308
+ || commandArgv.some((argument) => typeof argument !== "string")
309
+ ) {
310
+ throw new Error("Legacy verification requires one exact command.");
311
+ }
312
+ const [executable, ...argv] = commandArgv;
313
+ const forbidden = forbiddenLegacyVerificationSideEffect(executable, argv);
314
+ if (forbidden) {
315
+ throw new Error(
316
+ `Legacy verification command forbids external side effect: ${forbidden}.`,
317
+ );
318
+ }
319
+ return {
320
+ schemaVersion: "OwlCodaRunKitLegacyVerificationSideEffectPolicyV1",
321
+ mode: "known_high_risk_side_effect_deny",
322
+ forbidden: false,
323
+ authorizationGranted: false,
324
+ };
325
+ }
326
+
327
+ function readChecks(executionRoot) {
328
+ const root = checkRoot(executionRoot);
329
+ if (!existsSync(root)) return [];
330
+ const stat = lstatSync(root);
331
+ if (stat.isSymbolicLink() || !stat.isDirectory()) {
332
+ throw new Error("Formal checks root must be a regular directory.");
333
+ }
334
+ return readdirSync(root, { withFileTypes: true })
335
+ .filter((entry) => entry.name.endsWith(".json"))
336
+ .sort((left, right) => left.name.localeCompare(right.name))
337
+ .map((entry) => {
338
+ if (entry.isSymbolicLink() || !entry.isFile()) {
339
+ throw new Error(`Formal check must be a regular file: ${entry.name}`);
340
+ }
341
+ const value = readJson(path.join(root, entry.name));
342
+ if (
343
+ value.schemaVersion !== "OwlCodaRunKitFormalCheckV1"
344
+ || !Number.isSafeInteger(value.sequence)
345
+ || value.sequence < 1
346
+ ) {
347
+ throw new Error(`Formal check contract is invalid: ${entry.name}`);
348
+ }
349
+ return value;
350
+ })
351
+ .sort((left, right) => left.sequence - right.sequence);
352
+ }
353
+
354
+ function resumeOrFreezeCandidate({
355
+ workspaceRoot,
356
+ executionRoot,
357
+ runId,
358
+ workItemId,
359
+ checkId,
360
+ }) {
361
+ const candidatePath = path.join(
362
+ executionRoot,
363
+ "source-candidates",
364
+ `${checkId}.json`,
365
+ );
366
+ if (!existsSync(candidatePath)) {
367
+ return {
368
+ candidate: freezeSourceCandidateWithinControlTransactionV2({
369
+ workspaceRoot,
370
+ runId,
371
+ workItemId,
372
+ candidateId: checkId,
373
+ }),
374
+ resumed: false,
375
+ };
376
+ }
377
+ const candidateDocument = readRegularJson(
378
+ candidatePath,
379
+ "Formal source candidate",
380
+ );
381
+ const candidateRelativePath = relativeToWorkspace(
382
+ workspaceRoot,
383
+ candidatePath,
384
+ );
385
+ const gate = verifySourceCandidateV2({
386
+ workspaceRoot,
387
+ candidatePath: candidateRelativePath,
388
+ });
389
+ if (
390
+ gate.status !== "valid"
391
+ || candidateDocument.runId !== runId
392
+ || candidateDocument.candidateId !== checkId
393
+ || candidateDocument.discovery?.fromLease !== workItemId
394
+ ) {
395
+ throw new Error(
396
+ `Existing Formal source candidate differs from the resumed command: ${checkId}`,
397
+ );
398
+ }
399
+ return {
400
+ candidate: {
401
+ status: "source_candidate_frozen",
402
+ exitCode: 0,
403
+ runId,
404
+ candidateId: checkId,
405
+ candidatePath: candidateRelativePath,
406
+ candidateSha256: candidateDocument.candidateSha256,
407
+ sourceFingerprint: candidateDocument.sourceFingerprint.sha256,
408
+ manifestEntryCount: candidateDocument.sourceManifest.entries.length,
409
+ payloadSha256: candidateDocument.payload.sha256,
410
+ ownedPaths: [...candidateDocument.sourceManifest.ownedPaths],
411
+ authorizationGranted: false,
412
+ },
413
+ resumed: true,
414
+ };
415
+ }
416
+
417
+ function resumeSnapshot({
418
+ workspaceRoot,
419
+ executionRoot,
420
+ runId,
421
+ request,
422
+ candidateDocument,
423
+ }) {
424
+ const snapshotPath = path.join(
425
+ executionRoot,
426
+ "snapshots",
427
+ `${request.snapshotId}.json`,
428
+ );
429
+ const evidenceRoot = path.join(executionRoot, "snapshot-evidence");
430
+ const stdoutPath = path.join(evidenceRoot, `${request.snapshotId}.stdout`);
431
+ const stderrPath = path.join(evidenceRoot, `${request.snapshotId}.stderr`);
432
+ if (!existsSync(snapshotPath)) {
433
+ if (existsSync(stdoutPath) || existsSync(stderrPath)) {
434
+ throw new Error(
435
+ "Incomplete Formal snapshot evidence requires a new check id.",
436
+ );
437
+ }
438
+ return {
439
+ snapshot: runSnapshot({ workspaceRoot, runId, request }),
440
+ resumed: false,
441
+ };
442
+ }
443
+ const snapshot = readRegularJson(snapshotPath, "Formal snapshot");
444
+ const expectedFiles = Object.fromEntries(
445
+ candidateDocument.sourceManifest.entries
446
+ .filter(entry => entry.operation !== "deleted")
447
+ .map(entry => [entry.path, entry.sha256])
448
+ .sort(([left], [right]) => left.localeCompare(right)),
449
+ );
450
+ const expectedInputs = Object.entries(expectedFiles)
451
+ .map(([id, hash]) => ({ id, sha256: hash }));
452
+ const evidence = verifySnapshotEvidence({
453
+ workspaceRoot,
454
+ runId,
455
+ snapshot,
456
+ });
457
+ if (
458
+ !evidence.valid
459
+ || snapshot.snapshotId !== request.snapshotId
460
+ || snapshot.targetRoot !== request.targetRoot
461
+ || snapshot.verificationContextFingerprint
462
+ !== verificationContextFingerprint(request.verificationContext)
463
+ || snapshot.repositoryBefore?.head !== candidateDocument.baseline.head
464
+ || snapshot.repositoryAfter?.head !== candidateDocument.baseline.head
465
+ || canonicalJson(snapshot.repositoryBefore?.selectedFiles)
466
+ !== canonicalJson(expectedFiles)
467
+ || canonicalJson(snapshot.repositoryAfter?.selectedFiles)
468
+ !== canonicalJson(expectedFiles)
469
+ || snapshot.command?.evidence?.cwd !== request.cwd
470
+ || canonicalJson(snapshot.command?.evidence?.argv)
471
+ !== canonicalJson([request.executable, ...request.argv])
472
+ || canonicalJson(snapshot.command?.evidence?.materialInputs)
473
+ !== canonicalJson(expectedInputs)
474
+ ) {
475
+ throw new Error(
476
+ `Existing Formal snapshot differs from the resumed command: ${request.snapshotId}`,
477
+ );
478
+ }
479
+ return {
480
+ snapshot: {
481
+ status: snapshot.status,
482
+ exitCode: snapshot.status === "snapshot_passed" ? 0 : 2,
483
+ runId,
484
+ snapshotPath: relativeToWorkspace(workspaceRoot, snapshotPath),
485
+ authorizationGranted: false,
486
+ },
487
+ resumed: true,
488
+ };
489
+ }
490
+
491
+ function recordFormalCheckWithinControlTransaction({
492
+ workspaceRoot,
493
+ runId,
494
+ workItemId,
495
+ checkId,
496
+ cwd = ".",
497
+ commandArgv,
498
+ hooks = {},
499
+ }) {
500
+ safeIdentifier(checkId, "checkId");
501
+ safeRelativePath(cwd, "Formal check cwd", { allowDot: true });
502
+ if (!Array.isArray(commandArgv) || commandArgv.length === 0) {
503
+ throw new Error("Formal check requires one exact command.");
504
+ }
505
+ const root = realpathSync(workspaceRoot);
506
+ const { executionRoot, pinGate } = loadActiveExecution(root, runId);
507
+ if (pinGate.status !== "valid") return { ...pinGate, authorizationGranted: false };
508
+ const verificationCommandPolicy = validateFormalVerificationCommandV1({
509
+ workspaceRoot: root,
510
+ cwd,
511
+ commandArgv,
512
+ });
513
+ const receiptPath = path.join(checkRoot(executionRoot), `${checkId}.json`);
514
+ const candidateResult = resumeOrFreezeCandidate({
515
+ workspaceRoot: root,
516
+ executionRoot,
517
+ runId,
518
+ workItemId,
519
+ checkId,
520
+ });
521
+ const candidate = candidateResult.candidate;
522
+ if (candidate.status !== "source_candidate_frozen") return candidate;
523
+ hooks.afterCandidatePersist?.();
524
+ const candidateDocument = readJson(path.join(root, candidate.candidatePath));
525
+ const context = derivedVerificationContext(root);
526
+ const { executable, argv } = verificationCommandPolicy;
527
+ const request = {
528
+ schemaVersion: "OwlCodaRunKitSnapshotRequestV1",
529
+ snapshotId: `${checkId}-snapshot`,
530
+ mode: "project",
531
+ targetRoot: root,
532
+ cwd,
533
+ executable,
534
+ argv,
535
+ launcherVersion: "owlrunkit-formal-check-v2",
536
+ toolVersions: structuredClone(context.toolchains),
537
+ selectedPaths: candidateDocument.sourceManifest.entries
538
+ .filter((entry) => entry.operation !== "deleted")
539
+ .map((entry) => entry.path)
540
+ .sort(),
541
+ statusMode: "porcelain-v1-z-untracked-all-runkit-excluded",
542
+ verificationContext: context,
543
+ };
544
+ const requestPath = path.join(
545
+ executionRoot,
546
+ "formal-check-requests",
547
+ `${checkId}.json`,
548
+ );
549
+ const requestResult = writeOrResumeExactJson(
550
+ requestPath,
551
+ request,
552
+ "Formal check request",
553
+ );
554
+ hooks.afterRequestPersist?.();
555
+ const snapshotResult = resumeSnapshot({
556
+ workspaceRoot: root,
557
+ executionRoot,
558
+ runId,
559
+ request: requestResult.value,
560
+ candidateDocument,
561
+ });
562
+ const snapshot = snapshotResult.snapshot;
563
+ hooks.afterSnapshotPersist?.();
564
+ const savedSnapshot = readJson(path.join(root, snapshot.snapshotPath));
565
+ const existingReceipt = existsSync(receiptPath)
566
+ ? readRegularJson(receiptPath, "Formal check receipt")
567
+ : null;
568
+ const sequence = existingReceipt?.sequence
569
+ ?? readChecks(executionRoot).length + 1;
570
+ const status = snapshot.status === "snapshot_passed"
571
+ ? "formal_check_passed"
572
+ : "formal_check_failed";
573
+ const receipt = {
574
+ schemaVersion: "OwlCodaRunKitFormalCheckV1",
575
+ runId,
576
+ checkId,
577
+ sequence,
578
+ status,
579
+ candidatePath: candidate.candidatePath,
580
+ candidateSha256: candidate.candidateSha256,
581
+ payloadSha256: candidate.payloadSha256,
582
+ sourceFingerprint: candidate.sourceFingerprint,
583
+ verificationContext: context,
584
+ verificationContextFingerprint: verificationContextFingerprint(context),
585
+ snapshotRequestPath: relativeToWorkspace(root, requestPath),
586
+ snapshotPath: snapshot.snapshotPath,
587
+ commandExitCode: savedSnapshot.command.exitCode,
588
+ verificationCommandPolicy: {
589
+ schemaVersion: verificationCommandPolicy.schemaVersion,
590
+ mode: verificationCommandPolicy.mode,
591
+ riskClassification: verificationCommandPolicy.riskClassification,
592
+ profileCommandIds: verificationCommandPolicy.profileCommandIds,
593
+ authorizationGranted: false,
594
+ },
595
+ finalized: false,
596
+ authorizationGranted: false,
597
+ };
598
+ const receiptResult = writeOrResumeExactJson(
599
+ receiptPath,
600
+ receipt,
601
+ "Formal check receipt",
602
+ );
603
+ hooks.afterReceiptPersist?.();
604
+ return {
605
+ ...receiptResult.value,
606
+ exitCode: status === "formal_check_passed" ? 0 : 2,
607
+ checkReceiptPath: relativeToWorkspace(root, receiptPath),
608
+ resumed: candidateResult.resumed
609
+ || requestResult.resumed
610
+ || snapshotResult.resumed
611
+ || receiptResult.resumed,
612
+ };
613
+ }
614
+
615
+ export function recordFormalCheckV1(options) {
616
+ const workspaceRoot = realpathSync(options.workspaceRoot);
617
+ return withControlTransaction(
618
+ workspaceRoot,
619
+ () => recordFormalCheckWithinControlTransaction({
620
+ ...options,
621
+ workspaceRoot,
622
+ }),
623
+ );
624
+ }
625
+
626
+ function finalizeFormalChecksWithinControlTransaction({
627
+ workspaceRoot,
628
+ runId,
629
+ finalizeId,
630
+ hooks = {},
631
+ }) {
632
+ safeIdentifier(finalizeId, "finalizeId");
633
+ const root = realpathSync(workspaceRoot);
634
+ const { executionRoot, pinGate } = loadActiveExecution(root, runId);
635
+ if (pinGate.status !== "valid") return { ...pinGate, authorizationGranted: false };
636
+ const checks = readChecks(executionRoot);
637
+ if (checks.length === 0) throw new Error("Formal finish requires at least one check.");
638
+ const latest = checks.at(-1);
639
+ const currentCandidate = verifySourceCandidateV2({
640
+ workspaceRoot: root,
641
+ candidatePath: latest.candidatePath,
642
+ });
643
+ if (currentCandidate.status !== "valid") {
644
+ throw new Error("Formal finish requires the latest source candidate to remain current.");
645
+ }
646
+ const selected = checks.filter((check) => (
647
+ check.status === "formal_check_passed"
648
+ && check.sourceFingerprint === latest.sourceFingerprint
649
+ && check.verificationContextFingerprint === latest.verificationContextFingerprint
650
+ ));
651
+ if (latest.status !== "formal_check_passed" || selected.length === 0) {
652
+ throw new Error("Formal finish requires the latest source to have a passed check.");
653
+ }
654
+ const request = {
655
+ schemaVersion: "OwlCodaRunKitFinalizeRequestV1",
656
+ receiptId: `${finalizeId}-receipt`,
657
+ sourceCandidatePath: latest.candidatePath,
658
+ verificationContext: structuredClone(latest.verificationContext),
659
+ snapshotPaths: selected.map((check) => check.snapshotPath),
660
+ };
661
+ const requestPath = path.join(
662
+ executionRoot,
663
+ "formal-finalize-requests",
664
+ `${finalizeId}.json`,
665
+ );
666
+ writeOrResumeExactJson(
667
+ requestPath,
668
+ request,
669
+ "Formal finalize request",
670
+ );
671
+ const finalized = runFinalize({
672
+ workspaceRoot: root,
673
+ runId,
674
+ request,
675
+ hooks,
676
+ });
677
+ return {
678
+ ...finalized,
679
+ finalizeRequestPath: relativeToWorkspace(root, requestPath),
680
+ snapshotCount: selected.length,
681
+ staleCheckCount: checks.length - selected.length,
682
+ sourceFingerprint: latest.sourceFingerprint,
683
+ sourceCandidatePath: latest.candidatePath,
684
+ authorizationGranted: false,
685
+ };
686
+ }
687
+
688
+ export function finalizeFormalChecksV1(options) {
689
+ const workspaceRoot = realpathSync(options.workspaceRoot);
690
+ return withControlTransaction(
691
+ workspaceRoot,
692
+ () => finalizeFormalChecksWithinControlTransaction({
693
+ ...options,
694
+ workspaceRoot,
695
+ }),
696
+ );
697
+ }
698
+
699
+ export function resumeCompletedFormalFinishV1({
700
+ workspaceRoot,
701
+ runId,
702
+ finalizeId,
703
+ decision,
704
+ }) {
705
+ safeIdentifier(finalizeId, "finalizeId");
706
+ const root = realpathSync(workspaceRoot);
707
+ const executionRoot = path.join(
708
+ root,
709
+ ".owlcoda",
710
+ "runkit",
711
+ "executions",
712
+ runId,
713
+ );
714
+ const closeoutPath = path.join(executionRoot, "closeout-receipt.json");
715
+ if (!existsSync(closeoutPath)) return null;
716
+ const closeout = readRegularJson(closeoutPath, "Formal closeout receipt");
717
+ const gate = validateCoreArtifact(closeout.artifact);
718
+ const payload = closeout.artifact?.payload;
719
+ if (
720
+ !gate.valid
721
+ || closeout.acceptanceSha256 !== gate.acceptanceSha256
722
+ || closeout.artifactSha256 !== gate.artifactSha256
723
+ || payload?.runId !== runId
724
+ || payload?.decision !== decision
725
+ || payload?.authorizationGranted !== false
726
+ || (decision === "accepted"
727
+ && acceptedCloseoutVerificationIssues(closeout.artifact).length > 0)
728
+ ) {
729
+ throw new Error(
730
+ "Existing closeout does not match the resumed Formal finish command.",
731
+ );
732
+ }
733
+ if (decision !== "accepted") {
734
+ return {
735
+ status: "formal_finished",
736
+ exitCode: 0,
737
+ runId,
738
+ decision,
739
+ snapshotCount: 0,
740
+ staleCheckCount: 0,
741
+ sourceFingerprint: null,
742
+ activeReceiptSha256: null,
743
+ closeoutArtifactSha256: closeout.artifactSha256,
744
+ releasedLeaseIds: [],
745
+ resumed: true,
746
+ authorizationGranted: false,
747
+ };
748
+ }
749
+ const requestPath = path.join(
750
+ executionRoot,
751
+ "formal-finalize-requests",
752
+ `${finalizeId}.json`,
753
+ );
754
+ const request = readRegularJson(
755
+ requestPath,
756
+ "Formal finalize request",
757
+ );
758
+ if (
759
+ request.schemaVersion !== "OwlCodaRunKitFinalizeRequestV1"
760
+ || request.receiptId !== `${finalizeId}-receipt`
761
+ || typeof request.sourceCandidatePath !== "string"
762
+ || request.deliveryPacketPath !== undefined
763
+ ) {
764
+ throw new Error(
765
+ "Existing closeout does not match the resumed Formal finalize request.",
766
+ );
767
+ }
768
+ const lineagePath = path.join(
769
+ executionRoot,
770
+ "verification-receipts",
771
+ "receipt-lineage.json",
772
+ );
773
+ const lineage = readRegularJson(
774
+ lineagePath,
775
+ "Formal verification receipt lineage",
776
+ );
777
+ const validated = validateReceiptLineage(lineage);
778
+ const active = validated.active;
779
+ if (
780
+ !validated.valid
781
+ || active?.receipt?.status !== "passed"
782
+ || active.receipt.runId !== runId
783
+ || active.receipt.receiptId !== request.receiptId
784
+ || active.receipt.sourceArtifact?.kind !== "source_candidate_v2"
785
+ || active.receipt.sourceArtifact.path !== request.sourceCandidatePath
786
+ || payload.verification.activeReceiptSha256 !== active.receiptSha256
787
+ || canonicalJson(payload.verification.sourceArtifact)
788
+ !== canonicalJson(active.receipt.sourceArtifact)
789
+ ) {
790
+ throw new Error(
791
+ "Existing closeout does not match the resumed Formal verification lineage.",
792
+ );
793
+ }
794
+ const sourceArtifactPath = safeRelativePath(
795
+ active.receipt.sourceArtifact.path,
796
+ "Formal sourceArtifact path",
797
+ );
798
+ const expectedSourceRoot =
799
+ `.owlcoda/runkit/executions/${runId}/source-candidates/`;
800
+ if (!sourceArtifactPath.startsWith(expectedSourceRoot)) {
801
+ throw new Error(
802
+ "Existing closeout Formal sourceArtifact is outside its execution.",
803
+ );
804
+ }
805
+ const sourceArtifactAbsolutePath = path.join(root, sourceArtifactPath);
806
+ readRegularJson(
807
+ sourceArtifactAbsolutePath,
808
+ "Formal sourceArtifact",
809
+ );
810
+ if (
811
+ sha256(readFileSync(sourceArtifactAbsolutePath))
812
+ !== active.receipt.sourceArtifact.sha256
813
+ ) {
814
+ throw new Error(
815
+ "Existing closeout Formal sourceArtifact bytes changed.",
816
+ );
817
+ }
818
+ const checks = readChecks(executionRoot);
819
+ const selected = checks.filter((check) => (
820
+ check.status === "formal_check_passed"
821
+ && check.sourceFingerprint === active.receipt.sourceFingerprint
822
+ && check.verificationContextFingerprint
823
+ === active.receipt.verificationContextFingerprint
824
+ ));
825
+ if (
826
+ selected.length === 0
827
+ || canonicalJson(selected.map(check => check.snapshotPath))
828
+ !== canonicalJson(request.snapshotPaths)
829
+ ) {
830
+ throw new Error(
831
+ "Existing closeout does not match the resumed Formal check set.",
832
+ );
833
+ }
834
+ return {
835
+ status: "formal_finished",
836
+ exitCode: 0,
837
+ runId,
838
+ decision,
839
+ snapshotCount: selected.length,
840
+ staleCheckCount: checks.length - selected.length,
841
+ sourceFingerprint: active.receipt.sourceFingerprint,
842
+ activeReceiptSha256: active.receiptSha256,
843
+ closeoutArtifactSha256: closeout.artifactSha256,
844
+ releasedLeaseIds: [
845
+ ...payload.verification.releasedLeaseIds,
846
+ ],
847
+ resumed: true,
848
+ authorizationGranted: false,
849
+ };
850
+ }