owlrunkit 0.18.4 → 0.19.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 (50) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +109 -4
  3. package/docs/architecture/OWLCODA_RUNKIT_0190_CONSOLIDATED_DAILY_USE_PRODUCT_DECISION_20260812.md +100 -0
  4. package/docs/architecture/OWLCODA_RUNKIT_0191_PROFILE_RECONCILE_PATCH_PRODUCT_DECISION_20260813.md +30 -0
  5. package/docs/architecture/OWLCODA_RUN_KIT_CONTRACT_V0_2.md +57 -0
  6. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +28 -4
  7. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  8. package/integrations/codex/skills/owlcoda-runkit/references/contract-v0.2.md +57 -0
  9. package/package.json +1 -1
  10. package/packages/attest/README.md +9 -5
  11. package/packages/attest/consumer-surface-v2.json +263 -0
  12. package/packages/attest/distribution-manifest-v1.json +14 -1
  13. package/packages/attest/schemas/quick-verification-receipt-v3.schema.json +244 -0
  14. package/packages/attest/schemas/workspace-snapshot-v2.schema.json +114 -0
  15. package/packages/attest/src/dependency-environment.mjs +128 -0
  16. package/packages/attest/src/index.mjs +1 -0
  17. package/packages/attest/src/quick-receipt-contract.mjs +202 -9
  18. package/packages/attest/src/quick.mjs +45 -4
  19. package/packages/attest/src/workspace-snapshot.mjs +133 -6
  20. package/registry-release-policy-v1.json +5 -5
  21. package/sbom.spdx.json +5 -5
  22. package/scripts/runkit-contract/core-contract.mjs +21 -1
  23. package/scripts/runkit-contract/efficiency-metrics.mjs +559 -0
  24. package/scripts/runkit-contract/evidence-store.mjs +130 -0
  25. package/scripts/runkit-contract/onboarding-bootstrap.mjs +685 -0
  26. package/scripts/runkit-contract/onboarding-doctor.mjs +2 -1
  27. package/scripts/runkit-contract/outcome-presentation.mjs +171 -0
  28. package/scripts/runkit-contract/profile-onboarding.mjs +74 -35
  29. package/scripts/runkit-contract/project-cli-resolver.mjs +26 -5
  30. package/scripts/runkit-contract/quick-evidence-reuse.mjs +590 -0
  31. package/scripts/runkit-contract/quick-isolation.mjs +314 -0
  32. package/scripts/runkit-contract/quick-metrics.mjs +51 -3
  33. package/scripts/runkit-contract/quick-receipt.mjs +31 -1
  34. package/scripts/runkit-contract/quick-verify.mjs +216 -25
  35. package/scripts/runkit-contract/quick-workspace-snapshot.mjs +1 -0
  36. package/scripts/runkit-contract/runkit-bootstrap.mjs +1 -0
  37. package/scripts/runkit-contract/runkit-cli.mjs +330 -18
  38. package/scripts/runkit-contract/runtime-transition.mjs +478 -0
  39. package/scripts/runkit-contract/schemas/efficiency-event-v1.schema.json +56 -0
  40. package/scripts/runkit-contract/schemas/efficiency-metrics-v1.schema.json +220 -0
  41. package/scripts/runkit-contract/schemas/external-runtime-report-v1.schema.json +125 -0
  42. package/scripts/runkit-contract/schemas/onboarding-bootstrap-plan-v1.schema.json +168 -0
  43. package/scripts/runkit-contract/schemas/onboarding-bootstrap-receipt-v1.schema.json +130 -0
  44. package/scripts/runkit-contract/schemas/outcome-summary-v1.schema.json +83 -0
  45. package/scripts/runkit-contract/schemas/quick-evidence-reuse-plan-v1.schema.json +59 -0
  46. package/scripts/runkit-contract/schemas/quick-evidence-reuse-receipt-v1.schema.json +79 -0
  47. package/scripts/runkit-contract/schemas/runtime-transition-receipt-v1.schema.json +185 -0
  48. package/scripts/runkit-contract/schemas/team-project-event-v4.schema.json +142 -0
  49. package/scripts/runkit-contract/team-project.mjs +704 -16
  50. package/scripts/runkit-contract/verification-envelope.mjs +15 -18
@@ -15,7 +15,19 @@ import {
15
15
  persistQuickInputArtifact,
16
16
  persistQuickReceipt,
17
17
  } from "./quick-receipt.mjs";
18
- import { captureWorkspaceSnapshot } from "./quick-workspace-snapshot.mjs";
18
+ import {
19
+ inspectQuickIsolation,
20
+ prepareQuickIsolation,
21
+ removeQuickIsolation,
22
+ } from "./quick-isolation.mjs";
23
+ import {
24
+ captureWorkspaceSnapshot,
25
+ workspaceSourceStateFingerprint,
26
+ } from "./quick-workspace-snapshot.mjs";
27
+ import {
28
+ captureRuntimeTransition,
29
+ runtimeReportPath,
30
+ } from "./runtime-transition.mjs";
19
31
 
20
32
  function shellQuote(value) {
21
33
  return `'${String(value).replaceAll("'", `'"'"'`)}'`;
@@ -25,7 +37,7 @@ function quickAttestCommand(workspaceRoot, receiptPath) {
25
37
  return `npx --no-install owlrunkit quick-attest --workspace ${shellQuote(workspaceRoot)} --receipt ${shellQuote(receiptPath)}`;
26
38
  }
27
39
 
28
- function runExactCommand({ executable, argv, cwd, stdinPath, stdoutFd, stderrFd }) {
40
+ function runExactCommand({ executable, argv, cwd, stdinPath, stdoutFd, stderrFd, env }) {
29
41
  return new Promise((resolve) => {
30
42
  let settled = false;
31
43
  let stdinFd;
@@ -38,7 +50,7 @@ function runExactCommand({ executable, argv, cwd, stdinPath, stdoutFd, stderrFd
38
50
  cwd,
39
51
  shell: false,
40
52
  stdio: [stdinFd ?? "ignore", stdoutFd, stderrFd],
41
- env: process.env,
53
+ env: env ?? process.env,
42
54
  });
43
55
  } catch (error) {
44
56
  if (stdinFd !== undefined) closeSync(stdinFd);
@@ -69,7 +81,82 @@ function inputArtifactResult(stdinArtifact) {
69
81
  : { inputArtifacts: { stdin: stdinArtifact } };
70
82
  }
71
83
 
72
- export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFile }) {
84
+ function mutationTruth({ workspaceBefore, workspaceAfter, isolationResult, cleanupStatus }) {
85
+ const workspaceSourceChanged = workspaceSourceStateFingerprint(workspaceBefore)
86
+ !== workspaceSourceStateFingerprint(workspaceAfter);
87
+ const boundIgnoredChanged = workspaceBefore.ignoredPathsBound === true
88
+ && workspaceBefore.ignoredPathsFingerprint !== workspaceAfter.ignoredPathsFingerprint;
89
+ const dependencyChanged = isolationResult?.dependencyChanged === true;
90
+ const consumerSourceChanged = (isolationResult?.consumerDelta.sourcePaths.length ?? 0) > 0;
91
+ const cleanupFailed = cleanupStatus === "cleanup_failed";
92
+ const issueCodes = [
93
+ ...(workspaceSourceChanged ? ["source_mutated_during_verification"] : []),
94
+ ...(boundIgnoredChanged ? ["bound_ignored_path_mutated_during_verification"] : []),
95
+ ...(dependencyChanged ? ["dependency_environment_mutated_during_verification"] : []),
96
+ ...(consumerSourceChanged ? ["consumer_source_mutated_during_verification"] : []),
97
+ ...(cleanupFailed ? ["quick_isolation_cleanup_failed"] : []),
98
+ ];
99
+ const decisions = [
100
+ ...(workspaceSourceChanged ? ["invalidated_by_command_source_mutation"] : []),
101
+ ...(boundIgnoredChanged ? ["invalidated_by_bound_ignored_mutation"] : []),
102
+ ...(dependencyChanged ? ["invalidated_by_dependency_environment_mutation"] : []),
103
+ ...(consumerSourceChanged ? ["invalidated_by_consumer_source_mutation"] : []),
104
+ ...(cleanupFailed ? ["invalidated_by_isolation_cleanup_failure"] : []),
105
+ ];
106
+ return {
107
+ mutationDecision: decisions.length === 0
108
+ ? "source_unchanged"
109
+ : decisions.length === 1
110
+ ? decisions[0]
111
+ : "invalidated_by_multiple_mutations",
112
+ issueCodes,
113
+ mutationClasses: {
114
+ workspaceSource: workspaceSourceChanged ? "changed" : "unchanged",
115
+ boundIgnoredPaths: workspaceBefore.ignoredPathsBound !== true
116
+ ? "not_bound"
117
+ : boundIgnoredChanged ? "changed" : "unchanged",
118
+ dependencyEnvironment: isolationResult?.dependencyEnvironmentAfter === null
119
+ || isolationResult?.dependencyEnvironmentAfter === undefined
120
+ ? "not_bound"
121
+ : dependencyChanged ? "changed" : "unchanged",
122
+ consumerSource: isolationResult === null
123
+ ? "not_isolated"
124
+ : consumerSourceChanged ? "changed" : "unchanged",
125
+ consumerIgnoredArtifacts: (isolationResult?.consumerDelta.ignoredPaths.length ?? 0) > 0
126
+ ? "changed_and_discarded"
127
+ : isolationResult === null ? "not_isolated" : "none",
128
+ },
129
+ };
130
+ }
131
+
132
+ function isolationReceipt(isolation, isolationResult, cleanupStatus) {
133
+ if (isolation === null) return null;
134
+ return {
135
+ schemaVersion: isolation.schemaVersion,
136
+ mode: "temporary_consumer",
137
+ consumerRoot: isolation.consumerRoot,
138
+ sourceCopy: {
139
+ fileCount: isolation.sourceCopy.fileCount,
140
+ totalBytes: isolation.sourceCopy.totalBytes,
141
+ fingerprint: isolation.sourceCopy.fingerprint,
142
+ },
143
+ cacheEnvironmentVariables: isolation.environment.environmentVariables,
144
+ dependencyEnvironment: isolation.dependencyEnvironment,
145
+ dependencyEnvironmentAfter: isolationResult.dependencyEnvironmentAfter,
146
+ consumerDelta: isolationResult.consumerDelta,
147
+ cleanupStatus,
148
+ };
149
+ }
150
+
151
+ export async function runQuickVerification({
152
+ workspaceRoot,
153
+ commandArgv,
154
+ stdinFile,
155
+ isolate = false,
156
+ dependencyRoot,
157
+ ignoredPaths = [],
158
+ captureRuntime = false,
159
+ }) {
73
160
  if (!Array.isArray(commandArgv) || commandArgv.length === 0 || !commandArgv.every((value) => typeof value === "string")) {
74
161
  return {
75
162
  status: "quick_verification_input_invalid",
@@ -89,6 +176,22 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
89
176
  authorizationGranted: false,
90
177
  };
91
178
  }
179
+ if (dependencyRoot !== undefined && isolate !== true) {
180
+ return {
181
+ status: "quick_verification_input_invalid",
182
+ exitCode: 3,
183
+ issues: ["--dependency-root requires --isolate."],
184
+ authorizationGranted: false,
185
+ };
186
+ }
187
+ if (!Array.isArray(ignoredPaths) || ignoredPaths.some(value => typeof value !== "string")) {
188
+ return {
189
+ status: "quick_verification_input_invalid",
190
+ exitCode: 3,
191
+ issues: ["--bind-ignored must contain literal workspace-relative paths."],
192
+ authorizationGranted: false,
193
+ };
194
+ }
92
195
 
93
196
  let stdinBytes;
94
197
  if (stdinFile !== undefined) {
@@ -119,8 +222,9 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
119
222
  let store;
120
223
  let stdinArtifact = null;
121
224
  let persistedStdinPath;
225
+ let isolation = null;
122
226
  try {
123
- workspaceBefore = captureWorkspaceSnapshot(root);
227
+ workspaceBefore = captureWorkspaceSnapshot(root, { ignoredPaths });
124
228
  store = createQuickReceiptStore(root);
125
229
  if (stdinBytes !== undefined) {
126
230
  const persistedInput = persistQuickInputArtifact({
@@ -131,7 +235,15 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
131
235
  stdinArtifact = persistedInput.artifact;
132
236
  persistedStdinPath = persistedInput.inputPath;
133
237
  }
238
+ if (isolate === true) {
239
+ isolation = prepareQuickIsolation({ workspaceRoot: root, dependencyRoot });
240
+ const stableSource = captureWorkspaceSnapshot(root, { ignoredPaths });
241
+ if (stableSource.sourceFingerprint !== workspaceBefore.sourceFingerprint) {
242
+ throw new Error("Source workspace changed while the temporary consumer was being prepared.");
243
+ }
244
+ }
134
245
  } catch (error) {
246
+ if (isolation !== null) removeQuickIsolation(isolation);
135
247
  if (store !== undefined) closeQuickOutputFiles(store);
136
248
  return {
137
249
  status: "quick_verification_input_invalid",
@@ -142,22 +254,43 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
142
254
  }
143
255
 
144
256
  const [executable, ...argv] = commandArgv;
257
+ const executionCwd = isolation?.consumerRoot ?? root;
258
+ const expectedRuntimeReportPath = captureRuntime
259
+ ? runtimeReportPath(store.receiptRoot)
260
+ : null;
261
+ const executionEnvironment = isolation === null
262
+ ? { ...process.env }
263
+ : { ...process.env, ...isolation.environment.overrides };
264
+ delete executionEnvironment.OWLRUNKIT_RUNTIME_REPORT;
265
+ if (expectedRuntimeReportPath !== null) {
266
+ executionEnvironment.OWLRUNKIT_RUNTIME_REPORT = expectedRuntimeReportPath;
267
+ }
145
268
  const startedAt = new Date().toISOString();
146
269
  const execution = await runExactCommand({
147
270
  executable,
148
271
  argv,
149
- cwd: root,
272
+ cwd: executionCwd,
150
273
  stdinPath: persistedStdinPath,
151
274
  stdoutFd: store.stdoutFd,
152
275
  stderrFd: store.stderrFd,
276
+ env: executionEnvironment,
153
277
  });
154
278
  closeQuickOutputFiles(store);
155
279
  const finishedAt = new Date().toISOString();
156
280
 
157
281
  let workspaceAfter;
282
+ let isolationResult = null;
283
+ let cleanupStatus = "not_required";
158
284
  try {
159
- workspaceAfter = captureWorkspaceSnapshot(root);
285
+ if (isolation !== null) {
286
+ isolationResult = inspectQuickIsolation(isolation);
287
+ cleanupStatus = removeQuickIsolation(isolation);
288
+ }
289
+ workspaceAfter = captureWorkspaceSnapshot(root, { ignoredPaths });
160
290
  } catch (error) {
291
+ if (isolation !== null && cleanupStatus === "not_required") {
292
+ removeQuickIsolation(isolation);
293
+ }
161
294
  return {
162
295
  status: "quick_verification_source_mutated",
163
296
  exitCode: 2,
@@ -168,16 +301,23 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
168
301
  };
169
302
  }
170
303
 
171
- const sourceMutated = workspaceBefore.sourceFingerprint !== workspaceAfter.sourceFingerprint;
172
- const issueCodes = [];
173
- if (sourceMutated) issueCodes.push("source_mutated_during_verification");
304
+ const mutation = mutationTruth({
305
+ workspaceBefore,
306
+ workspaceAfter,
307
+ isolationResult,
308
+ cleanupStatus,
309
+ });
310
+ const sourceMutated = mutation.mutationDecision !== "source_unchanged";
311
+ const receiptV3 = isolate === true || ignoredPaths.length > 0;
174
312
  let persisted;
175
313
  try {
176
314
  persisted = persistQuickReceipt({
177
315
  workspaceRoot: root,
178
316
  store,
179
317
  receipt: {
180
- schemaVersion: stdinArtifact === null
318
+ schemaVersion: receiptV3
319
+ ? "OwlCodaQuickVerificationReceiptV3"
320
+ : stdinArtifact === null
181
321
  ? "OwlCodaQuickVerificationReceiptV1"
182
322
  : "OwlCodaQuickVerificationReceiptV2",
183
323
  receiptId: store.receiptId,
@@ -192,8 +332,15 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
192
332
  exactCommand: {
193
333
  executable,
194
334
  argv,
195
- cwd: root,
335
+ cwd: executionCwd,
196
336
  },
337
+ ...(receiptV3
338
+ ? {
339
+ sourceWorkspaceRoot: root,
340
+ executionIsolation: isolationReceipt(isolation, isolationResult, cleanupStatus),
341
+ mutationClasses: mutation.mutationClasses,
342
+ }
343
+ : {}),
197
344
  ...(stdinArtifact === null
198
345
  ? {}
199
346
  : { inputArtifacts: { stdin: stdinArtifact } }),
@@ -209,10 +356,8 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
209
356
  signal: execution.signal,
210
357
  },
211
358
  workspaceAfter,
212
- mutationDecision: sourceMutated
213
- ? "invalidated_by_command_source_mutation"
214
- : "source_unchanged",
215
- issueCodes,
359
+ mutationDecision: mutation.mutationDecision,
360
+ issueCodes: mutation.issueCodes,
216
361
  },
217
362
  });
218
363
  } catch (error) {
@@ -223,10 +368,8 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
223
368
  receiptSha256: null,
224
369
  sourceFingerprint: workspaceAfter.sourceFingerprint,
225
370
  commandExitCode: execution.exitCode,
226
- mutationDecision: sourceMutated
227
- ? "invalidated_by_command_source_mutation"
228
- : "source_unchanged",
229
- issueCodes: [...issueCodes, "quick_receipt_store_invalid"],
371
+ mutationDecision: mutation.mutationDecision,
372
+ issueCodes: [...mutation.issueCodes, "quick_receipt_store_invalid"],
230
373
  ...inputArtifactResult(stdinArtifact),
231
374
  issues: [error instanceof Error ? error.message : String(error)],
232
375
  nextAllowedAction: "repair_quick_receipt_store_and_rerun",
@@ -234,7 +377,25 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
234
377
  };
235
378
  }
236
379
 
237
- const { outputSummary } = persisted;
380
+ const { outputSummary, evidenceStorage } = persisted;
381
+ let runtimeTransition = null;
382
+ if (expectedRuntimeReportPath !== null) {
383
+ try {
384
+ runtimeTransition = captureRuntimeTransition({
385
+ workspaceRoot: root,
386
+ quickReceiptPath: persisted.receiptPath,
387
+ runtimeReportPath: expectedRuntimeReportPath,
388
+ });
389
+ } catch (error) {
390
+ runtimeTransition = {
391
+ status: "runtime_transition_invalid",
392
+ receiptPath: null,
393
+ issues: [error instanceof Error ? error.message : String(error)],
394
+ authorizationGranted: false,
395
+ };
396
+ }
397
+ }
398
+ const runtimeFields = runtimeTransition === null ? {} : { runtimeTransition };
238
399
 
239
400
  if (sourceMutated) {
240
401
  const attestCommand = quickAttestCommand(root, persisted.receiptPath);
@@ -245,16 +406,42 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
245
406
  receiptSha256: persisted.receiptSha256,
246
407
  sourceFingerprint: workspaceAfter.sourceFingerprint,
247
408
  commandExitCode: execution.exitCode,
248
- mutationDecision: "invalidated_by_command_source_mutation",
249
- issueCodes,
409
+ mutationDecision: mutation.mutationDecision,
410
+ issueCodes: mutation.issueCodes,
250
411
  ...inputArtifactResult(stdinArtifact),
251
412
  outputSummary,
413
+ evidenceStorage,
414
+ ...runtimeFields,
252
415
  attestCommand,
253
416
  issues: [],
254
417
  nextAllowedAction: "restore_source_or_run_a_new_quick_verification",
255
418
  authorizationGranted: false,
256
419
  };
257
420
  }
421
+ if (runtimeTransition?.status === "runtime_transition_invalid") {
422
+ const attestCommand = quickAttestCommand(root, persisted.receiptPath);
423
+ return {
424
+ status: "quick_verification_runtime_truth_invalid",
425
+ exitCode: 1,
426
+ quickVerificationStatus: execution.launchError || execution.exitCode !== 0
427
+ ? "quick_verification_failed"
428
+ : "quick_verification_passed",
429
+ receiptPath: persisted.receiptPath,
430
+ receiptSha256: persisted.receiptSha256,
431
+ sourceFingerprint: workspaceAfter.sourceFingerprint,
432
+ commandExitCode: execution.exitCode,
433
+ mutationDecision: "source_unchanged",
434
+ issueCodes: mutation.issueCodes,
435
+ ...inputArtifactResult(stdinArtifact),
436
+ outputSummary,
437
+ evidenceStorage,
438
+ runtimeTransition,
439
+ attestCommand,
440
+ issues: runtimeTransition.issues,
441
+ nextAllowedAction: "repair_runtime_report_and_run_a_new_quick_verification",
442
+ authorizationGranted: false,
443
+ };
444
+ }
258
445
  if (execution.launchError || execution.exitCode !== 0) {
259
446
  const attestCommand = quickAttestCommand(root, persisted.receiptPath);
260
447
  return {
@@ -265,9 +452,11 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
265
452
  sourceFingerprint: workspaceAfter.sourceFingerprint,
266
453
  commandExitCode: execution.exitCode,
267
454
  mutationDecision: "source_unchanged",
268
- issueCodes,
455
+ issueCodes: mutation.issueCodes,
269
456
  ...inputArtifactResult(stdinArtifact),
270
457
  outputSummary,
458
+ evidenceStorage,
459
+ ...runtimeFields,
271
460
  attestCommand,
272
461
  issues: execution.launchError ? [execution.launchError] : [],
273
462
  nextAllowedAction: "inspect_output_and_rerun",
@@ -283,9 +472,11 @@ export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFi
283
472
  sourceFingerprint: workspaceAfter.sourceFingerprint,
284
473
  commandExitCode: 0,
285
474
  mutationDecision: "source_unchanged",
286
- issueCodes,
475
+ issueCodes: mutation.issueCodes,
287
476
  ...inputArtifactResult(stdinArtifact),
288
477
  outputSummary,
478
+ evidenceStorage,
479
+ ...runtimeFields,
289
480
  attestCommand,
290
481
  issues: [],
291
482
  nextAllowedAction: attestCommand,
@@ -1,3 +1,4 @@
1
1
  export {
2
2
  captureWorkspaceSnapshot,
3
+ workspaceSourceStateFingerprint,
3
4
  } from "../../packages/attest/src/workspace-snapshot.mjs";
@@ -12,6 +12,7 @@ import { resolveProjectCli } from "./project-cli-resolver.mjs";
12
12
 
13
13
  const CURRENT_PACKAGE_COMMANDS = new Set([
14
14
  "adopt",
15
+ "bootstrap",
15
16
  "core-successor",
16
17
  "fleet",
17
18
  "init",