owlrunkit 0.20.0 → 0.21.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 (44) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +63 -10
  3. package/docs/architecture/OWLCODA_RUNKIT_0201_RELEASE_TRUTH_AND_PROFILE_NORMALIZATION_PATCH_DECISION_20260813.md +95 -0
  4. package/docs/architecture/OWLCODA_RUNKIT_021_TEAM_DELIVERY_PHASE2_PRODUCT_DECISION_20260813.md +249 -0
  5. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +92 -12
  6. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  7. package/package.json +1 -1
  8. package/packages/attest/README.md +7 -1
  9. package/packages/attest/consumer-surface-v3.json +275 -0
  10. package/packages/attest/distribution-manifest-v1.json +14 -0
  11. package/packages/attest/schemas/canonical-candidate-identity-v1.schema.json +112 -0
  12. package/packages/attest/schemas/foreign-workspace-filesystem-identity-v1.schema.json +32 -0
  13. package/packages/attest/schemas/quick-verification-receipt-v4.schema.json +226 -0
  14. package/packages/attest/src/candidate-identity.mjs +454 -0
  15. package/packages/attest/src/index.mjs +11 -0
  16. package/packages/attest/src/quick-receipt-contract.mjs +126 -5
  17. package/packages/attest/src/quick.mjs +43 -8
  18. package/{registry-release-policy-v1.json → registry-release-policy-v2.json} +8 -9
  19. package/sbom.spdx.json +4 -4
  20. package/scripts/runkit-contract/core-contract.mjs +14 -1
  21. package/scripts/runkit-contract/fleet-skill-plan.mjs +223 -0
  22. package/scripts/runkit-contract/formal-workflow.mjs +3 -1
  23. package/scripts/runkit-contract/inspect-presentation.mjs +56 -0
  24. package/scripts/runkit-contract/install-codex-skill.mjs +1 -0
  25. package/scripts/runkit-contract/onboarding-bootstrap.mjs +15 -0
  26. package/scripts/runkit-contract/onboarding-doctor.mjs +201 -7
  27. package/scripts/runkit-contract/profile-onboarding.mjs +6 -0
  28. package/scripts/runkit-contract/project-cli-resolver.mjs +9 -1
  29. package/scripts/runkit-contract/quick-metrics.mjs +9 -5
  30. package/scripts/runkit-contract/quick-verify.mjs +108 -24
  31. package/scripts/runkit-contract/registry-adoption-gate.mjs +12 -3
  32. package/scripts/runkit-contract/registry-adoption.mjs +10 -5
  33. package/scripts/runkit-contract/runkit-cli.mjs +289 -19
  34. package/scripts/runkit-contract/schemas/delivery-lifecycle-v1.schema.json +91 -0
  35. package/scripts/runkit-contract/schemas/external-gate-v1.schema.json +68 -0
  36. package/scripts/runkit-contract/schemas/fleet-skill-upgrade-plan-v1.schema.json +140 -0
  37. package/scripts/runkit-contract/schemas/inspect-compact-v1.schema.json +93 -0
  38. package/scripts/runkit-contract/schemas/team-delivery-status-v2.schema.json +219 -0
  39. package/scripts/runkit-contract/schemas/team-project-event-v6.schema.json +82 -0
  40. package/scripts/runkit-contract/schemas/team-project-event-v7.schema.json +80 -0
  41. package/scripts/runkit-contract/schemas/team-project-status-v4.schema.json +208 -0
  42. package/scripts/runkit-contract/sync-release-identity.mjs +87 -0
  43. package/scripts/runkit-contract/team-delivery.mjs +128 -3
  44. package/scripts/runkit-contract/team-project.mjs +970 -9
@@ -29,6 +29,12 @@ import {
29
29
  parseOfflineAttestationBundle,
30
30
  } from "./offline-bundle.mjs";
31
31
  import { captureWorkspaceSnapshot } from "./workspace-snapshot.mjs";
32
+ import {
33
+ captureCanonicalCandidateIdentityV1,
34
+ captureForeignWorkspaceFilesystemIdentityV1,
35
+ validCanonicalCandidateIdentityV1,
36
+ validForeignWorkspaceFilesystemIdentityV1,
37
+ } from "./candidate-identity.mjs";
32
38
 
33
39
  function readSubject(subjectPath) {
34
40
  const { absolutePath, bytes } = readFileBytesBounded(subjectPath);
@@ -45,6 +51,7 @@ export function attestFile({ subjectPath, workspaceRoot }) {
45
51
  "OwlCodaQuickVerificationReceiptV1",
46
52
  "OwlCodaQuickVerificationReceiptV2",
47
53
  "OwlCodaQuickVerificationReceiptV3",
54
+ "OwlCodaQuickVerificationReceiptV4",
48
55
  ]).has(subject.value.schemaVersion)) {
49
56
  const details = attestQuickReceiptDetailsFromBytes({
50
57
  receiptPath: subject.absolutePath,
@@ -99,6 +106,8 @@ export {
99
106
  attestQuickReceipt,
100
107
  attestQuickReceiptDetails,
101
108
  canonicalJson,
109
+ captureCanonicalCandidateIdentityV1,
110
+ captureForeignWorkspaceFilesystemIdentityV1,
102
111
  captureWorkspaceSnapshot,
103
112
  createAttestationRef,
104
113
  createOfflineAttestationBundle,
@@ -113,5 +122,7 @@ export {
113
122
  sha256Bytes,
114
123
  sha256Canonical,
115
124
  validQuickReceiptShape,
125
+ validCanonicalCandidateIdentityV1,
126
+ validForeignWorkspaceFilesystemIdentityV1,
116
127
  verifyBundle,
117
128
  };
@@ -3,6 +3,10 @@ import {
3
3
  isSha256Ref,
4
4
  sha256Canonical,
5
5
  } from "./formal.mjs";
6
+ import {
7
+ validCanonicalCandidateIdentityV1,
8
+ validForeignWorkspaceFilesystemIdentityV1,
9
+ } from "./candidate-identity.mjs";
6
10
 
7
11
  const RECEIPT_REQUIRED_KEYS = [
8
12
  "schemaVersion",
@@ -52,6 +56,10 @@ const V3_RECEIPT_ISSUES = new Set([
52
56
  "consumer_source_mutated_during_verification",
53
57
  "quick_isolation_cleanup_failed",
54
58
  ]);
59
+ const V4_RECEIPT_ISSUES = new Set([
60
+ ...V3_RECEIPT_ISSUES,
61
+ "foreign_workspace_mutated_during_verification",
62
+ ]);
55
63
  const V3_MUTATION_DECISIONS = new Set([
56
64
  "source_unchanged",
57
65
  "invalidated_by_command_source_mutation",
@@ -61,6 +69,10 @@ const V3_MUTATION_DECISIONS = new Set([
61
69
  "invalidated_by_isolation_cleanup_failure",
62
70
  "invalidated_by_multiple_mutations",
63
71
  ]);
72
+ const V4_MUTATION_DECISIONS = new Set([
73
+ ...V3_MUTATION_DECISIONS,
74
+ "invalidated_by_foreign_workspace_mutation",
75
+ ]);
64
76
 
65
77
  function validDateTime(value) {
66
78
  return typeof value === "string"
@@ -237,6 +249,48 @@ function validMutationClasses(value) {
237
249
  && ["not_isolated", "none", "changed_and_discarded"].includes(value.consumerIgnoredArtifacts);
238
250
  }
239
251
 
252
+ function validForeignMutationClasses(value) {
253
+ return hasExactKeys(value, [
254
+ "workspaceSource",
255
+ "boundIgnoredPaths",
256
+ "dependencyEnvironment",
257
+ "consumerSource",
258
+ "consumerIgnoredArtifacts",
259
+ "foreignTarget",
260
+ ])
261
+ && ["unchanged", "changed"].includes(value.workspaceSource)
262
+ && ["not_bound", "unchanged", "changed"].includes(value.boundIgnoredPaths)
263
+ && ["not_bound", "unchanged", "changed"].includes(value.dependencyEnvironment)
264
+ && ["unchanged", "changed"].includes(value.consumerSource)
265
+ && ["none", "changed_and_discarded"].includes(value.consumerIgnoredArtifacts)
266
+ && ["unchanged", "changed"].includes(value.foreignTarget);
267
+ }
268
+
269
+ function validForeignWorkspace(value, sourceWorkspaceRoot) {
270
+ if (!hasExactKeys(value, [
271
+ "candidateBefore",
272
+ "candidateAfter",
273
+ "filesystemBefore",
274
+ "filesystemAfter",
275
+ "zeroWriteObserved",
276
+ ])) return false;
277
+ if (
278
+ !validCanonicalCandidateIdentityV1(value.candidateBefore)
279
+ || !validCanonicalCandidateIdentityV1(value.candidateAfter)
280
+ || !validForeignWorkspaceFilesystemIdentityV1(value.filesystemBefore)
281
+ || !validForeignWorkspaceFilesystemIdentityV1(value.filesystemAfter)
282
+ || value.candidateBefore.workspaceRoot !== sourceWorkspaceRoot
283
+ || value.candidateAfter.workspaceRoot !== sourceWorkspaceRoot
284
+ || value.filesystemBefore.workspaceRoot !== sourceWorkspaceRoot
285
+ || value.filesystemAfter.workspaceRoot !== sourceWorkspaceRoot
286
+ ) return false;
287
+ const unchanged = value.candidateBefore.candidateFingerprint
288
+ === value.candidateAfter.candidateFingerprint
289
+ && value.filesystemBefore.filesystemFingerprint
290
+ === value.filesystemAfter.filesystemFingerprint;
291
+ return value.zeroWriteObserved === unchanged;
292
+ }
293
+
240
294
  function validV3MutationTruth(receipt) {
241
295
  const workspaceSourceChanged = sourceStateFingerprint(receipt.workspaceBefore)
242
296
  !== sourceStateFingerprint(receipt.workspaceAfter);
@@ -283,17 +337,66 @@ function validV3MutationTruth(receipt) {
283
337
  && JSON.stringify([...receipt.issueCodes].sort()) === JSON.stringify(expectedIssues);
284
338
  }
285
339
 
340
+ function validV4MutationTruth(receipt) {
341
+ const workspaceSourceChanged = sourceStateFingerprint(receipt.workspaceBefore)
342
+ !== sourceStateFingerprint(receipt.workspaceAfter);
343
+ const boundIgnored = receipt.workspaceBefore.ignoredPathsBound === true;
344
+ const boundIgnoredChanged = boundIgnored
345
+ && receipt.workspaceBefore.ignoredPathsFingerprint
346
+ !== receipt.workspaceAfter.ignoredPathsFingerprint;
347
+ const isolation = receipt.executionIsolation;
348
+ const consumerSourceChanged = isolation.consumerDelta.sourcePaths.length > 0;
349
+ const consumerIgnoredChanged = isolation.consumerDelta.ignoredPaths.length > 0;
350
+ const dependencyBound = isolation.dependencyEnvironment !== null;
351
+ const dependencyChanged = dependencyBound
352
+ && (isolation.dependencyEnvironmentAfter === null
353
+ || isolation.dependencyEnvironmentAfter.fingerprint
354
+ !== isolation.dependencyEnvironment.fingerprint);
355
+ const cleanupFailed = isolation.cleanupStatus === "cleanup_failed";
356
+ const foreignChanged = receipt.foreignWorkspace.zeroWriteObserved !== true;
357
+ if (receipt.mutationClasses.workspaceSource !== (workspaceSourceChanged ? "changed" : "unchanged")
358
+ || receipt.mutationClasses.boundIgnoredPaths !== (boundIgnored
359
+ ? boundIgnoredChanged ? "changed" : "unchanged"
360
+ : "not_bound")
361
+ || receipt.mutationClasses.dependencyEnvironment !== (dependencyBound
362
+ ? dependencyChanged ? "changed" : "unchanged"
363
+ : "not_bound")
364
+ || receipt.mutationClasses.consumerSource !== (consumerSourceChanged ? "changed" : "unchanged")
365
+ || receipt.mutationClasses.consumerIgnoredArtifacts !== (consumerIgnoredChanged
366
+ ? "changed_and_discarded" : "none")
367
+ || receipt.mutationClasses.foreignTarget !== (foreignChanged ? "changed" : "unchanged")) {
368
+ return false;
369
+ }
370
+ const facts = [
371
+ [workspaceSourceChanged, "invalidated_by_command_source_mutation", "source_mutated_during_verification"],
372
+ [boundIgnoredChanged, "invalidated_by_bound_ignored_mutation", "bound_ignored_path_mutated_during_verification"],
373
+ [dependencyChanged, "invalidated_by_dependency_environment_mutation", "dependency_environment_mutated_during_verification"],
374
+ [consumerSourceChanged, "invalidated_by_consumer_source_mutation", "consumer_source_mutated_during_verification"],
375
+ [cleanupFailed, "invalidated_by_isolation_cleanup_failure", "quick_isolation_cleanup_failed"],
376
+ [foreignChanged, "invalidated_by_foreign_workspace_mutation", "foreign_workspace_mutated_during_verification"],
377
+ ].filter(([active]) => active);
378
+ const expectedDecision = facts.length === 0
379
+ ? "source_unchanged"
380
+ : facts.length === 1 ? facts[0][1] : "invalidated_by_multiple_mutations";
381
+ const expectedIssues = facts.map(([, , issue]) => issue).sort();
382
+ return receipt.mutationDecision === expectedDecision
383
+ && JSON.stringify([...receipt.issueCodes].sort()) === JSON.stringify(expectedIssues);
384
+ }
385
+
286
386
  export function validQuickReceiptShape(receipt) {
287
387
  const receiptV1 = receipt?.schemaVersion === "OwlCodaQuickVerificationReceiptV1";
288
388
  const receiptV2 = receipt?.schemaVersion === "OwlCodaQuickVerificationReceiptV2";
289
389
  const receiptV3 = receipt?.schemaVersion === "OwlCodaQuickVerificationReceiptV3";
290
- const requiredKeys = receiptV3
390
+ const receiptV4 = receipt?.schemaVersion === "OwlCodaQuickVerificationReceiptV4";
391
+ const requiredKeys = receiptV4
392
+ ? [...RECEIPT_REQUIRED_KEYS, "controllerWorkspaceRoot", "sourceWorkspaceRoot", "executionIsolation", "mutationClasses", "foreignWorkspace"]
393
+ : receiptV3
291
394
  ? [...RECEIPT_REQUIRED_KEYS, "sourceWorkspaceRoot", "executionIsolation", "mutationClasses"]
292
395
  : receiptV2
293
396
  ? [...RECEIPT_REQUIRED_KEYS, "inputArtifacts"]
294
397
  : RECEIPT_REQUIRED_KEYS;
295
- const optionalKeys = receiptV3 ? ["inputArtifacts", "signatureRef"] : ["signatureRef"];
296
- if (!(receiptV1 || receiptV2 || receiptV3) || !hasExactKeys(receipt, requiredKeys, optionalKeys)) return false;
398
+ const optionalKeys = receiptV3 || receiptV4 ? ["inputArtifacts", "signatureRef"] : ["signatureRef"];
399
+ if (!(receiptV1 || receiptV2 || receiptV3 || receiptV4) || !hasExactKeys(receipt, requiredKeys, optionalKeys)) return false;
297
400
  if (
298
401
  typeof receipt.receiptId !== "string"
299
402
  || receipt.receiptId.length === 0
@@ -320,13 +423,15 @@ export function validQuickReceiptShape(receipt) {
320
423
  || !hasExactKeys(receipt.outputArtifacts, ["stdout", "stderr"])
321
424
  || !validOutputArtifact(receipt.outputArtifacts.stdout)
322
425
  || !validOutputArtifact(receipt.outputArtifacts.stderr)
323
- || !(receiptV3
426
+ || !(receiptV4
427
+ ? V4_MUTATION_DECISIONS.has(receipt.mutationDecision)
428
+ : receiptV3
324
429
  ? V3_MUTATION_DECISIONS.has(receipt.mutationDecision)
325
430
  : ["source_unchanged", "invalidated_by_command_source_mutation"].includes(receipt.mutationDecision))
326
431
  || !Array.isArray(receipt.issueCodes)
327
432
  || new Set(receipt.issueCodes).size !== receipt.issueCodes.length
328
433
  || !receipt.issueCodes.every((entry) => typeof entry === "string"
329
- && (receiptV3 ? V3_RECEIPT_ISSUES : KNOWN_RECEIPT_ISSUES).has(entry))
434
+ && (receiptV4 ? V4_RECEIPT_ISSUES : receiptV3 ? V3_RECEIPT_ISSUES : KNOWN_RECEIPT_ISSUES).has(entry))
330
435
  ) {
331
436
  return false;
332
437
  }
@@ -348,6 +453,22 @@ export function validQuickReceiptShape(receipt) {
348
453
  )) {
349
454
  return false;
350
455
  }
456
+ if (receiptV4 && (
457
+ typeof receipt.controllerWorkspaceRoot !== "string"
458
+ || receipt.controllerWorkspaceRoot.length === 0
459
+ || typeof receipt.sourceWorkspaceRoot !== "string"
460
+ || receipt.sourceWorkspaceRoot.length === 0
461
+ || receipt.controllerWorkspaceRoot === receipt.sourceWorkspaceRoot
462
+ || !validForeignMutationClasses(receipt.mutationClasses)
463
+ || !validExecutionIsolation(receipt.executionIsolation, receipt)
464
+ || !validForeignWorkspace(receipt.foreignWorkspace, receipt.sourceWorkspaceRoot)
465
+ || receipt.inputArtifacts !== undefined
466
+ && (!hasExactKeys(receipt.inputArtifacts, ["stdin"])
467
+ || !validOutputArtifact(receipt.inputArtifacts.stdin))
468
+ || !validV4MutationTruth(receipt)
469
+ )) {
470
+ return false;
471
+ }
351
472
  if (receipt.signatureRef !== undefined) {
352
473
  if (!hasExactKeys(receipt.signatureRef, ["path", "sha256"])
353
474
  || typeof receipt.signatureRef.path !== "string"
@@ -15,10 +15,24 @@ import {
15
15
  } from "./quick-receipt-contract.mjs";
16
16
  import { captureDependencyEnvironment } from "./dependency-environment.mjs";
17
17
  import { captureWorkspaceSnapshot } from "./workspace-snapshot.mjs";
18
+ import {
19
+ captureCanonicalCandidateIdentityV1,
20
+ captureForeignWorkspaceFilesystemIdentityV1,
21
+ } from "./candidate-identity.mjs";
18
22
 
19
23
  export { validQuickReceiptShape } from "./quick-receipt-contract.mjs";
20
24
 
21
25
  export const SUPPORTED_QUICK_CORE_IDENTITIES = Object.freeze([
26
+ {
27
+ contractVersion: "0.2",
28
+ coreVersion: "0.21.0",
29
+ coreManifestSha256: "sha256:f85b9bf8c32705d5f5dfebdb653e83ac8d1ac0468214c17f230cbd2de04246fd",
30
+ },
31
+ {
32
+ contractVersion: "0.2",
33
+ coreVersion: "0.20.1",
34
+ coreManifestSha256: "sha256:8af2b9792731efa37f596255a7677dcec6e2fd3cc079dfdb0e6ff29e8017e784",
35
+ },
22
36
  {
23
37
  contractVersion: "0.2",
24
38
  coreVersion: "0.20.0",
@@ -271,19 +285,25 @@ function attestQuickReceiptDetailsFromBytesWithCatalog({
271
285
  const selectedWorkspaceRoot = workspaceRoot === undefined
272
286
  ? undefined
273
287
  : realpathSync(workspaceRoot);
288
+ const foreignReceipt = receipt.schemaVersion === "OwlCodaQuickVerificationReceiptV4";
274
289
  if (selectedWorkspaceRoot === undefined) {
275
290
  issues.push("current_workspace_not_checked");
276
291
  }
277
292
  let receiptWorkspaceRoot;
293
+ let receiptSourceRoot;
278
294
  if (selectedWorkspaceRoot !== undefined) {
279
295
  try {
280
- receiptWorkspaceRoot = realpathSync(
281
- receipt.schemaVersion === "OwlCodaQuickVerificationReceiptV3"
296
+ receiptWorkspaceRoot = realpathSync(foreignReceipt
297
+ ? receipt.controllerWorkspaceRoot
298
+ : receipt.schemaVersion === "OwlCodaQuickVerificationReceiptV3"
282
299
  ? receipt.sourceWorkspaceRoot
283
- : receipt.exactCommand.cwd,
284
- );
300
+ : receipt.exactCommand.cwd);
301
+ receiptSourceRoot = realpathSync(foreignReceipt
302
+ ? receipt.sourceWorkspaceRoot
303
+ : receiptWorkspaceRoot);
285
304
  } catch {
286
305
  receiptWorkspaceRoot = undefined;
306
+ receiptSourceRoot = undefined;
287
307
  }
288
308
  }
289
309
  const commandWorkspaceMatches = selectedWorkspaceRoot !== undefined
@@ -317,10 +337,25 @@ function attestQuickReceiptDetailsFromBytesWithCatalog({
317
337
  const ignoredPaths = receipt.workspaceAfter.ignoredPathsBound === true
318
338
  ? receipt.workspaceAfter.ignoredPathBindings.map(entry => entry.path)
319
339
  : [];
320
- const currentSourceValid = selectedWorkspaceRoot === undefined
321
- || commandWorkspaceMatches
322
- && captureWorkspaceSnapshot(selectedWorkspaceRoot, { ignoredPaths }).sourceFingerprint
323
- === receipt.workspaceAfter.sourceFingerprint;
340
+ let currentSourceValid = selectedWorkspaceRoot === undefined;
341
+ if (selectedWorkspaceRoot !== undefined && commandWorkspaceMatches && receiptSourceRoot !== undefined) {
342
+ try {
343
+ currentSourceValid = captureWorkspaceSnapshot(receiptSourceRoot, { ignoredPaths }).sourceFingerprint
344
+ === receipt.workspaceAfter.sourceFingerprint;
345
+ if (foreignReceipt) {
346
+ const currentCandidate = captureCanonicalCandidateIdentityV1(receiptSourceRoot);
347
+ const currentFilesystem = captureForeignWorkspaceFilesystemIdentityV1(receiptSourceRoot);
348
+ currentSourceValid = currentSourceValid
349
+ && receipt.foreignWorkspace.zeroWriteObserved === true
350
+ && currentCandidate.candidateFingerprint
351
+ === receipt.foreignWorkspace.candidateAfter.candidateFingerprint
352
+ && currentFilesystem.filesystemFingerprint
353
+ === receipt.foreignWorkspace.filesystemAfter.filesystemFingerprint;
354
+ }
355
+ } catch {
356
+ currentSourceValid = false;
357
+ }
358
+ }
324
359
  const dependencyEnvironmentValid = dependencyEnvironmentCurrent(
325
360
  receipt.executionIsolation?.dependencyEnvironment,
326
361
  materials,
@@ -1,8 +1,8 @@
1
1
  {
2
- "schemaVersion": "OwlCodaRunKitRegistryReleasePolicyV1",
3
- "status": "release_candidate_unpublished",
2
+ "schemaVersion": "OwlCodaRunKitRegistryReleasePolicyV2",
3
+ "status": "release_artifact_registry_gated",
4
4
  "packageName": "owlrunkit",
5
- "candidateVersion": "0.20.0",
5
+ "artifactVersion": "0.21.0",
6
6
  "registry": "https://registry.npmjs.org",
7
7
  "registryRequiredBeforeAdoption": true,
8
8
  "exactVersionRequired": true,
@@ -21,14 +21,13 @@
21
21
  "symlink",
22
22
  "workspace"
23
23
  ],
24
- "currentPublishedRelease": {
24
+ "rollbackRelease": {
25
25
  "packageName": "owlrunkit",
26
- "version": "0.19.2",
27
- "shasum": "f9b0f797fe9f79878374380db0756223accd61dc",
28
- "integrity": "sha512-rFEnbOtPuybztz8EZbcQSY3tGycCAuTkg+qGDwcKaTPjdJRhsXS4OB2HLwDBiILIV6BFyRPSQ7zanObT4jd58g==",
29
- "tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.19.2.tgz"
26
+ "version": "0.20.0",
27
+ "shasum": "b123f5ea33a4f500961a0df3226ed0ca409d111d",
28
+ "integrity": "sha512-VcXUh+q8DwR6RoO9JDoUMEzFrpFRBpSvpqgHvIY15Z+Oo+A31Ij2kFO5wCFki80nd6Tl/YT70t7UV2aG0TZ0GQ==",
29
+ "tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.20.0.tgz"
30
30
  },
31
- "registryRelease": null,
32
31
  "registryEvidenceMustBeExternal": true,
33
32
  "registryEvidenceSchemaVersion": "OwlCodaRunKitRegistryReleaseEvidenceV1",
34
33
  "embeddedAttestComponentVersion": "0.2.0",
package/sbom.spdx.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "owlrunkit-0.20.0",
6
- "documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.20.0",
5
+ "name": "owlrunkit-0.21.0",
6
+ "documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.21.0",
7
7
  "creationInfo": {
8
8
  "created": "2026-07-29T00:00:00Z",
9
9
  "creators": [
@@ -14,7 +14,7 @@
14
14
  {
15
15
  "name": "owlrunkit",
16
16
  "SPDXID": "SPDXRef-Package-OwlRunKit",
17
- "versionInfo": "0.20.0",
17
+ "versionInfo": "0.21.0",
18
18
  "downloadLocation": "NOASSERTION",
19
19
  "filesAnalyzed": false,
20
20
  "licenseConcluded": "GPL-3.0-or-later",
@@ -24,7 +24,7 @@
24
24
  {
25
25
  "referenceCategory": "PACKAGE-MANAGER",
26
26
  "referenceType": "purl",
27
- "referenceLocator": "pkg:npm/owlrunkit@0.20.0"
27
+ "referenceLocator": "pkg:npm/owlrunkit@0.21.0"
28
28
  }
29
29
  ]
30
30
  }
@@ -14,7 +14,7 @@ import { fileURLToPath } from "node:url";
14
14
  import { parseProjectControlState } from "./project-control-parser.mjs";
15
15
 
16
16
  export const CONTRACT_VERSION = "0.2";
17
- export const CORE_VERSION = "0.20.0";
17
+ export const CORE_VERSION = "0.21.0";
18
18
  export const RUNTIME_ROOT = ".owlcoda/runkit";
19
19
 
20
20
  const CORE_FILES = [
@@ -28,6 +28,7 @@ const CORE_FILES = [
28
28
  "deployment-workflow.mjs",
29
29
  "efficiency-metrics.mjs",
30
30
  "fleet-discovery.mjs",
31
+ "fleet-skill-plan.mjs",
31
32
  "finalize.mjs",
32
33
  "formal-workflow.mjs",
33
34
  "formal-preflight.mjs",
@@ -107,11 +108,13 @@ const CORE_FILES = [
107
108
  "schemas/fleet-discovery-v1.schema.json",
108
109
  "schemas/fleet-manifest-v1.schema.json",
109
110
  "schemas/fleet-root-registry-v1.schema.json",
111
+ "schemas/fleet-skill-upgrade-plan-v1.schema.json",
110
112
  "schemas/formal-check-v2.schema.json",
111
113
  "schemas/formal-envelope-preflight-v1.schema.json",
112
114
  "schemas/formal-evidence-summary-v1.schema.json",
113
115
  "schemas/formal-supplemental-evidence-v1.schema.json",
114
116
  "schemas/human-status-v1.schema.json",
117
+ "schemas/inspect-compact-v1.schema.json",
115
118
  "schemas/onboarding-bootstrap-plan-v1.schema.json",
116
119
  "schemas/onboarding-bootstrap-receipt-v1.schema.json",
117
120
  "schemas/outcome-summary-v1.schema.json",
@@ -150,6 +153,7 @@ const CORE_FILES = [
150
153
  "schemas/candidate-transfer-packet-v1.schema.json",
151
154
  "schemas/team-acceptance-packet-v2.schema.json",
152
155
  "schemas/team-delivery-status-v1.schema.json",
156
+ "schemas/team-delivery-status-v2.schema.json",
153
157
  "schemas/team-packet-validation-v1.schema.json",
154
158
  "schemas/team-recommendation-v1.schema.json",
155
159
  "schemas/team-task-packet-v2.schema.json",
@@ -162,10 +166,15 @@ const CORE_FILES = [
162
166
  "schemas/team-project-event-v3.schema.json",
163
167
  "schemas/team-project-event-v4.schema.json",
164
168
  "schemas/team-project-event-v5.schema.json",
169
+ "schemas/team-project-event-v6.schema.json",
170
+ "schemas/team-project-event-v7.schema.json",
165
171
  "schemas/team-project-successor-receipt-v1.schema.json",
166
172
  "schemas/team-project-status-v1.schema.json",
167
173
  "schemas/team-project-status-v2.schema.json",
168
174
  "schemas/team-project-status-v3.schema.json",
175
+ "schemas/team-project-status-v4.schema.json",
176
+ "schemas/external-gate-v1.schema.json",
177
+ "schemas/delivery-lifecycle-v1.schema.json",
169
178
  "schemas/usage-mode-recommendation-v1.schema.json",
170
179
  "schemas/usage-mode-recommendation-v2.schema.json",
171
180
  "schemas/verification-envelope-v1.schema.json",
@@ -199,10 +208,14 @@ const CORE_FILES = [
199
208
  ];
200
209
 
201
210
  const CORE_DEPENDENCY_FILES = [
211
+ "packages/attest/src/candidate-identity.mjs",
202
212
  "packages/attest/src/dependency-environment.mjs",
213
+ "packages/attest/schemas/canonical-candidate-identity-v1.schema.json",
214
+ "packages/attest/schemas/foreign-workspace-filesystem-identity-v1.schema.json",
203
215
  "packages/attest/schemas/workspace-snapshot-v1.schema.json",
204
216
  "packages/attest/schemas/workspace-snapshot-v2.schema.json",
205
217
  "packages/attest/schemas/quick-verification-receipt-v3.schema.json",
218
+ "packages/attest/schemas/quick-verification-receipt-v4.schema.json",
206
219
  "packages/attest/src/formal.mjs",
207
220
  "packages/attest/src/offline-bundle.mjs",
208
221
  "packages/attest/src/quick-receipt-contract.mjs",
@@ -0,0 +1,223 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import {
5
+ currentCoreIdentity,
6
+ validateProjectConfigV2,
7
+ } from "./core-contract.mjs";
8
+ import { discoverFleet } from "./fleet-discovery.mjs";
9
+ import { inspectInstalledSkillCompatibility } from "./install-codex-skill.mjs";
10
+ import { inspectProjectControlState } from "./project-control-state.mjs";
11
+
12
+ function shellQuote(value) {
13
+ return `'${String(value).replaceAll("'", `'"'"'`)}'`;
14
+ }
15
+
16
+ function fleetSourceArguments({
17
+ workspaceRoots,
18
+ fleetManifestPath,
19
+ fleetRoots,
20
+ fleetRegistryPath,
21
+ }, { install = false } = {}) {
22
+ if (Array.isArray(workspaceRoots)) {
23
+ const flag = install ? "--workspace" : "--workspace-root";
24
+ return workspaceRoots.flatMap(root => [flag, shellQuote(root)]).join(" ");
25
+ }
26
+ if (Array.isArray(fleetRoots)) {
27
+ return fleetRoots.flatMap(root => ["--fleet-root", shellQuote(root)]).join(" ");
28
+ }
29
+ if (typeof fleetManifestPath === "string") {
30
+ return `--fleet-manifest ${shellQuote(fleetManifestPath)}`;
31
+ }
32
+ return typeof fleetRegistryPath === "string"
33
+ ? `--registry ${shellQuote(fleetRegistryPath)}`
34
+ : "";
35
+ }
36
+
37
+ function validLegacyConfigV1(config) {
38
+ return config?.schemaVersion === "OwlCodaRunKitConfigV1"
39
+ && config?.core?.contractVersion === "0.1"
40
+ && config?.authorizationPolicy === "external_explicit_authority_required";
41
+ }
42
+
43
+ async function inspectAffectedProject(workspaceRoot) {
44
+ const blockers = [];
45
+ const control = inspectProjectControlState({ workspaceRoot }).upgradeSafety;
46
+ for (const artifactId of control.activeRunIds) {
47
+ blockers.push({ code: "active_execution", workspaceRoot, artifactId });
48
+ }
49
+ for (const artifactId of control.activeLeaseIds) {
50
+ blockers.push({ code: "active_lease", workspaceRoot, artifactId });
51
+ }
52
+ for (const issue of control.issues) {
53
+ blockers.push({ code: "control_state_invalid", workspaceRoot, detail: issue });
54
+ }
55
+
56
+ const configPath = path.join(workspaceRoot, ".owlcoda/runkit/config.json");
57
+ let config = null;
58
+ try {
59
+ config = JSON.parse((await readFile(configPath)).toString("utf8"));
60
+ } catch (error) {
61
+ blockers.push({
62
+ code: "project_config_invalid",
63
+ workspaceRoot,
64
+ detail: error instanceof Error ? error.message : String(error),
65
+ });
66
+ }
67
+ if (config !== null) {
68
+ const validation = config.schemaVersion === "OwlCodaRunKitConfigV2"
69
+ ? validateProjectConfigV2(config)
70
+ : null;
71
+ if ((validation !== null && !validation.valid)
72
+ || (validation === null && !validLegacyConfigV1(config))) {
73
+ blockers.push({
74
+ code: "project_config_invalid",
75
+ workspaceRoot,
76
+ detail: validation?.issues?.join(",") ?? "unsupported_config",
77
+ });
78
+ }
79
+ }
80
+
81
+ return {
82
+ project: {
83
+ workspaceRoot,
84
+ configPath,
85
+ configCoreVersion: config?.core?.coreVersion ?? null,
86
+ activeRunIds: [...control.activeRunIds],
87
+ activeLeaseIds: [...control.activeLeaseIds],
88
+ upgradeSafe: blockers.length === 0,
89
+ },
90
+ blockers,
91
+ };
92
+ }
93
+
94
+ export async function planFleetSkillUpgradeV1({
95
+ repositoryRoot,
96
+ targetRoot,
97
+ archiveRoot,
98
+ workspaceRoots = null,
99
+ fleetManifestPath = null,
100
+ fleetRoots = null,
101
+ fleetRegistryPath = null,
102
+ } = {}) {
103
+ for (const [name, value] of Object.entries({ repositoryRoot, targetRoot, archiveRoot })) {
104
+ if (typeof value !== "string" || value.length === 0) {
105
+ throw new Error(`${name} is required`);
106
+ }
107
+ }
108
+ const resolvedRepositoryRoot = path.resolve(repositoryRoot);
109
+ const resolvedTargetRoot = path.resolve(targetRoot);
110
+ const resolvedArchiveRoot = path.resolve(archiveRoot);
111
+ const source = { workspaceRoots, fleetManifestPath, fleetRoots, fleetRegistryPath };
112
+ const blockers = [];
113
+ let discovery = null;
114
+ try {
115
+ discovery = await discoverFleet(source);
116
+ } catch (error) {
117
+ blockers.push({
118
+ code: error?.message === "fleet_registry_missing"
119
+ ? "fleet_registry_missing"
120
+ : "fleet_discovery_failed",
121
+ detail: error instanceof Error ? error.message : String(error),
122
+ });
123
+ }
124
+ if (discovery !== null && !discovery.complete) {
125
+ for (const workspaceRoot of discovery.unreachableRoots) {
126
+ blockers.push({ code: "fleet_root_unreachable", workspaceRoot });
127
+ }
128
+ }
129
+
130
+ const affectedProjects = [];
131
+ for (const workspaceRoot of discovery?.workspaceRoots ?? []) {
132
+ const inspected = await inspectAffectedProject(workspaceRoot);
133
+ affectedProjects.push(inspected.project);
134
+ blockers.push(...inspected.blockers);
135
+ }
136
+ affectedProjects.sort((left, right) => (
137
+ left.workspaceRoot < right.workspaceRoot ? -1 : left.workspaceRoot > right.workspaceRoot ? 1 : 0
138
+ ));
139
+
140
+ const sharedSkill = await inspectInstalledSkillCompatibility({
141
+ targetRoot: resolvedTargetRoot,
142
+ });
143
+ if (new Set(["unmanaged", "drifted"]).has(sharedSkill.status)) {
144
+ blockers.push({ code: "shared_skill_integrity_invalid", detail: sharedSkill.status });
145
+ }
146
+ blockers.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right), "en"));
147
+
148
+ const planSourceArgs = fleetSourceArguments(source);
149
+ const installSourceArgs = fleetSourceArguments(source, { install: true });
150
+ const commonPlan = [
151
+ "npx --no-install owlrunkit fleet skill-plan",
152
+ `--skill-root ${shellQuote(resolvedTargetRoot)}`,
153
+ `--archive-root ${shellQuote(resolvedArchiveRoot)}`,
154
+ planSourceArgs,
155
+ ].filter(Boolean).join(" ");
156
+ const installerPath = path.join(
157
+ resolvedRepositoryRoot,
158
+ "scripts/runkit-contract/install-codex-skill.mjs",
159
+ );
160
+ const installCommand = [
161
+ `node ${shellQuote(installerPath)} install`,
162
+ `--repository ${shellQuote(resolvedRepositoryRoot)}`,
163
+ `--target ${shellQuote(resolvedTargetRoot)}`,
164
+ `--archive ${shellQuote(resolvedArchiveRoot)}`,
165
+ installSourceArgs,
166
+ ].filter(Boolean).join(" ");
167
+ const rollbackCommand = [
168
+ `node ${shellQuote(installerPath)} restore`,
169
+ `--target ${shellQuote(resolvedTargetRoot)}`,
170
+ `--archive ${shellQuote(resolvedArchiveRoot)}`,
171
+ "--receipt <upgrade-receipt.json>",
172
+ ].join(" ");
173
+
174
+ return {
175
+ schemaVersion: "OwlCodaRunKitFleetSkillUpgradePlanV1",
176
+ status: blockers.length === 0 ? "ready" : "blocked",
177
+ expectedCore: currentCoreIdentity(),
178
+ sharedSkill: {
179
+ targetRoot: resolvedTargetRoot,
180
+ status: sharedSkill.status,
181
+ installedSkillVersion: sharedSkill.installedSkillVersion ?? null,
182
+ installedConfigCoreVersion: sharedSkill.installedConfigCoreVersion ?? null,
183
+ issues: sharedSkill.issues ?? [],
184
+ },
185
+ discovery: discovery === null ? null : {
186
+ source: discovery.source,
187
+ complete: discovery.complete,
188
+ workspaceCount: discovery.workspaceRoots.length,
189
+ unreachableRoots: discovery.unreachableRoots,
190
+ },
191
+ affectedProjects,
192
+ blockers,
193
+ commands: {
194
+ dryRun: commonPlan,
195
+ install: installCommand,
196
+ rollback: rollbackCommand,
197
+ },
198
+ authorizationGranted: false,
199
+ };
200
+ }
201
+
202
+ export function formatFleetSkillUpgradePlanHumanV1(plan) {
203
+ const lines = [
204
+ `Shared Skill fleet plan: ${plan.status}.`,
205
+ `Expected Core: ${plan.expectedCore.coreVersion} (${plan.expectedCore.coreManifestSha256}).`,
206
+ `Installed Skill: ${plan.sharedSkill.status} (${plan.sharedSkill.installedSkillVersion ?? "unknown"}).`,
207
+ `Affected projects: ${plan.affectedProjects.length}.`,
208
+ ];
209
+ if (plan.blockers.length > 0) {
210
+ lines.push("Blockers:");
211
+ for (const blocker of plan.blockers) {
212
+ lines.push(`- ${blocker.code}${blocker.workspaceRoot ? `: ${blocker.workspaceRoot}` : ""}${blocker.artifactId ? ` (${blocker.artifactId})` : ""}`);
213
+ }
214
+ }
215
+ lines.push(
216
+ `Dry run: ${plan.commands.dryRun}`,
217
+ `Install after blockers clear: ${plan.commands.install}`,
218
+ `Rollback after installation: ${plan.commands.rollback}`,
219
+ "Authority: not granted; no shared Skill or project was modified.",
220
+ "",
221
+ );
222
+ return lines.join("\n");
223
+ }
@@ -1394,7 +1394,9 @@ export function resumeCompletedFormalFinishV1({
1394
1394
  };
1395
1395
  }
1396
1396
  if (
1397
- new Set(["0.19.2", "0.20.0"]).has(closeout.artifact.core?.coreVersion)
1397
+ new Set(["0.19.2", "0.20.0", "0.20.1", "0.21.0"]).has(
1398
+ closeout.artifact.core?.coreVersion,
1399
+ )
1398
1400
  && (
1399
1401
  !hasExactKeys(formalEvidenceBinding, [
1400
1402
  "schemaVersion",