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.
- package/CHANGELOG.md +48 -0
- package/README.md +63 -10
- package/docs/architecture/OWLCODA_RUNKIT_0201_RELEASE_TRUTH_AND_PROFILE_NORMALIZATION_PATCH_DECISION_20260813.md +95 -0
- package/docs/architecture/OWLCODA_RUNKIT_021_TEAM_DELIVERY_PHASE2_PRODUCT_DECISION_20260813.md +249 -0
- package/integrations/codex/skills/owlcoda-runkit/SKILL.md +92 -12
- package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
- package/package.json +1 -1
- package/packages/attest/README.md +7 -1
- package/packages/attest/consumer-surface-v3.json +275 -0
- package/packages/attest/distribution-manifest-v1.json +14 -0
- package/packages/attest/schemas/canonical-candidate-identity-v1.schema.json +112 -0
- package/packages/attest/schemas/foreign-workspace-filesystem-identity-v1.schema.json +32 -0
- package/packages/attest/schemas/quick-verification-receipt-v4.schema.json +226 -0
- package/packages/attest/src/candidate-identity.mjs +454 -0
- package/packages/attest/src/index.mjs +11 -0
- package/packages/attest/src/quick-receipt-contract.mjs +126 -5
- package/packages/attest/src/quick.mjs +43 -8
- package/{registry-release-policy-v1.json → registry-release-policy-v2.json} +8 -9
- package/sbom.spdx.json +4 -4
- package/scripts/runkit-contract/core-contract.mjs +14 -1
- package/scripts/runkit-contract/fleet-skill-plan.mjs +223 -0
- package/scripts/runkit-contract/formal-workflow.mjs +3 -1
- package/scripts/runkit-contract/inspect-presentation.mjs +56 -0
- package/scripts/runkit-contract/install-codex-skill.mjs +1 -0
- package/scripts/runkit-contract/onboarding-bootstrap.mjs +15 -0
- package/scripts/runkit-contract/onboarding-doctor.mjs +201 -7
- package/scripts/runkit-contract/profile-onboarding.mjs +6 -0
- package/scripts/runkit-contract/project-cli-resolver.mjs +9 -1
- package/scripts/runkit-contract/quick-metrics.mjs +9 -5
- package/scripts/runkit-contract/quick-verify.mjs +108 -24
- package/scripts/runkit-contract/registry-adoption-gate.mjs +12 -3
- package/scripts/runkit-contract/registry-adoption.mjs +10 -5
- package/scripts/runkit-contract/runkit-cli.mjs +289 -19
- package/scripts/runkit-contract/schemas/delivery-lifecycle-v1.schema.json +91 -0
- package/scripts/runkit-contract/schemas/external-gate-v1.schema.json +68 -0
- package/scripts/runkit-contract/schemas/fleet-skill-upgrade-plan-v1.schema.json +140 -0
- package/scripts/runkit-contract/schemas/inspect-compact-v1.schema.json +93 -0
- package/scripts/runkit-contract/schemas/team-delivery-status-v2.schema.json +219 -0
- package/scripts/runkit-contract/schemas/team-project-event-v6.schema.json +82 -0
- package/scripts/runkit-contract/schemas/team-project-event-v7.schema.json +80 -0
- package/scripts/runkit-contract/schemas/team-project-status-v4.schema.json +208 -0
- package/scripts/runkit-contract/sync-release-identity.mjs +87 -0
- package/scripts/runkit-contract/team-delivery.mjs +128 -3
- 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
|
|
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
|
-
|| !(
|
|
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.
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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": "
|
|
3
|
-
"status": "
|
|
2
|
+
"schemaVersion": "OwlCodaRunKitRegistryReleasePolicyV2",
|
|
3
|
+
"status": "release_artifact_registry_gated",
|
|
4
4
|
"packageName": "owlrunkit",
|
|
5
|
-
"
|
|
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
|
-
"
|
|
24
|
+
"rollbackRelease": {
|
|
25
25
|
"packageName": "owlrunkit",
|
|
26
|
-
"version": "0.
|
|
27
|
-
"shasum": "
|
|
28
|
-
"integrity": "sha512-
|
|
29
|
-
"tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.
|
|
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.
|
|
6
|
-
"documentNamespace": "https://owlcoda.com/spdx/owlrunkit/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.
|
|
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.
|
|
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.
|
|
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(
|
|
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",
|