owlrunkit 0.19.1 → 0.20.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 (42) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +107 -3
  3. package/docs/architecture/OWLCODA_RUNKIT_0191_PROFILE_RECONCILE_PATCH_PRODUCT_DECISION_20260813.md +11 -5
  4. package/docs/architecture/OWLCODA_RUNKIT_0192_FORMAL_USABILITY_PRODUCT_DECISION_20260813.md +141 -0
  5. package/docs/architecture/OWLCODA_RUNKIT_020_TEAM_DELIVERY_PHASE1_PRODUCT_DECISION_20260813.md +296 -0
  6. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +74 -9
  7. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  8. package/package.json +1 -1
  9. package/packages/attest/distribution-manifest-v1.json +10 -0
  10. package/packages/attest/src/quick.mjs +42 -4
  11. package/registry-release-policy-v1.json +5 -5
  12. package/sbom.spdx.json +5 -5
  13. package/scripts/runkit-contract/core-contract.mjs +42 -2
  14. package/scripts/runkit-contract/efficiency-metrics.mjs +9 -7
  15. package/scripts/runkit-contract/formal-preflight.mjs +352 -0
  16. package/scripts/runkit-contract/formal-supplemental-evidence.mjs +713 -0
  17. package/scripts/runkit-contract/formal-workflow.mjs +529 -59
  18. package/scripts/runkit-contract/onboarding-doctor.mjs +32 -13
  19. package/scripts/runkit-contract/project-cli-resolver.mjs +33 -3
  20. package/scripts/runkit-contract/project-external-delivery.mjs +16 -9
  21. package/scripts/runkit-contract/quick-attest.mjs +24 -0
  22. package/scripts/runkit-contract/runkit-cli.mjs +445 -52
  23. package/scripts/runkit-contract/schemas/candidate-transfer-packet-v1.schema.json +98 -0
  24. package/scripts/runkit-contract/schemas/formal-check-v2.schema.json +231 -0
  25. package/scripts/runkit-contract/schemas/formal-envelope-preflight-v1.schema.json +212 -0
  26. package/scripts/runkit-contract/schemas/formal-evidence-summary-v1.schema.json +114 -0
  27. package/scripts/runkit-contract/schemas/formal-supplemental-evidence-v1.schema.json +103 -0
  28. package/scripts/runkit-contract/schemas/team-acceptance-packet-v2.schema.json +109 -0
  29. package/scripts/runkit-contract/schemas/team-delivery-status-v1.schema.json +72 -0
  30. package/scripts/runkit-contract/schemas/team-packet-validation-v1.schema.json +33 -0
  31. package/scripts/runkit-contract/schemas/team-project-event-v5.schema.json +89 -0
  32. package/scripts/runkit-contract/schemas/team-project-status-v3.schema.json +173 -0
  33. package/scripts/runkit-contract/schemas/team-recommendation-v1.schema.json +121 -0
  34. package/scripts/runkit-contract/schemas/team-task-packet-v2.schema.json +228 -0
  35. package/scripts/runkit-contract/snapshot.mjs +125 -5
  36. package/scripts/runkit-contract/source-candidate.mjs +271 -69
  37. package/scripts/runkit-contract/sync-release-identity.mjs +39 -4
  38. package/scripts/runkit-contract/team-delivery.mjs +906 -0
  39. package/scripts/runkit-contract/team-project-successor.mjs +7 -4
  40. package/scripts/runkit-contract/team-project.mjs +440 -28
  41. package/scripts/runkit-contract/usage-mode.mjs +9 -3
  42. package/scripts/runkit-contract/verification-envelope.mjs +425 -37
@@ -28,10 +28,12 @@ const MAX_JSON_DEPTH = 64;
28
28
  const MAX_JSON_NODES = 50_000;
29
29
 
30
30
  class StrictJsonParser {
31
- constructor(text) {
31
+ constructor(text, { maxDepth = MAX_JSON_DEPTH, maxNodes = MAX_JSON_NODES } = {}) {
32
32
  this.text = text;
33
33
  this.index = 0;
34
34
  this.nodes = 0;
35
+ this.maxDepth = maxDepth;
36
+ this.maxNodes = maxNodes;
35
37
  }
36
38
 
37
39
  parse() {
@@ -44,7 +46,7 @@ class StrictJsonParser {
44
46
  parseValue(depth) {
45
47
  this.skipWhitespace();
46
48
  this.nodes += 1;
47
- if (this.nodes > MAX_JSON_NODES) throw new Error("JSON input exceeds the node limit");
49
+ if (this.nodes > this.maxNodes) throw new Error("JSON input exceeds the node limit");
48
50
  const character = this.text[this.index];
49
51
  if (character === "{") return this.parseObject(depth);
50
52
  if (character === "[") return this.parseArray(depth);
@@ -165,7 +167,7 @@ class StrictJsonParser {
165
167
 
166
168
  enter(depth) {
167
169
  const nextDepth = depth + 1;
168
- if (nextDepth > MAX_JSON_DEPTH) throw new Error("JSON input exceeds the nesting limit");
170
+ if (nextDepth > this.maxDepth) throw new Error("JSON input exceeds the nesting limit");
169
171
  return nextDepth;
170
172
  }
171
173
 
@@ -180,11 +182,15 @@ class StrictJsonParser {
180
182
  }
181
183
  }
182
184
 
183
- function parseJsonStrict(text) {
184
- if (typeof text !== "string" || Buffer.byteLength(text, "utf8") > MAX_JSON_BYTES) {
185
+ function parseJsonStrict(text, {
186
+ maxBytes = MAX_JSON_BYTES,
187
+ maxDepth = MAX_JSON_DEPTH,
188
+ maxNodes = MAX_JSON_NODES,
189
+ } = {}) {
190
+ if (typeof text !== "string" || Buffer.byteLength(text, "utf8") > maxBytes) {
185
191
  throw new Error("JSON input exceeds the input-byte limit");
186
192
  }
187
- return new StrictJsonParser(text).parse();
193
+ return new StrictJsonParser(text, { maxDepth, maxNodes }).parse();
188
194
  }
189
195
 
190
196
  export function resolveBoundedWorkspaceRoot(workspaceRoot) {
@@ -212,7 +218,10 @@ function identityMatches(left, right) {
212
218
  && left.mtimeMs === right.mtimeMs;
213
219
  }
214
220
 
215
- export function readWorkspaceFileBounded(root, relativePath, { optional = false } = {}) {
221
+ export function readWorkspaceBytesBounded(root, relativePath, {
222
+ optional = false,
223
+ maxBytes = MAX_JSON_BYTES,
224
+ } = {}) {
216
225
  const target = path.resolve(root, relativePath);
217
226
  if (!strictDescendant(root, target)) throw new Error("workspace file escaped the workspace root");
218
227
  const segments = path.relative(root, target).split(path.sep);
@@ -238,17 +247,16 @@ export function readWorkspaceFileBounded(root, relativePath, { optional = false
238
247
  const descriptor = openSync(target, "r");
239
248
  try {
240
249
  const before = fstatSync(descriptor);
241
- if (!before.isFile() || before.size > MAX_JSON_BYTES) {
250
+ if (!before.isFile() || before.size > maxBytes) {
242
251
  throw new Error("workspace file exceeds the input-byte limit");
243
252
  }
244
- const buffer = Buffer.allocUnsafe(MAX_JSON_BYTES + 1);
253
+ const buffer = Buffer.allocUnsafe(before.size);
245
254
  let offset = 0;
246
- while (offset <= MAX_JSON_BYTES) {
255
+ while (offset < buffer.length) {
247
256
  const bytesRead = readSync(descriptor, buffer, offset, buffer.length - offset, offset);
248
257
  if (bytesRead === 0) break;
249
258
  offset += bytesRead;
250
259
  }
251
- if (offset > MAX_JSON_BYTES) throw new Error("workspace file exceeds the input-byte limit");
252
260
  const after = fstatSync(descriptor);
253
261
  const currentStat = lstatSync(target);
254
262
  if (
@@ -260,15 +268,22 @@ export function readWorkspaceFileBounded(root, relativePath, { optional = false
260
268
  ) {
261
269
  throw new Error("workspace file identity changed while reading");
262
270
  }
263
- return new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(0, offset));
271
+ return buffer.subarray(0, offset);
264
272
  } finally {
265
273
  closeSync(descriptor);
266
274
  }
267
275
  }
268
276
 
277
+ export function readWorkspaceFileBounded(root, relativePath, options) {
278
+ const bytes = readWorkspaceBytesBounded(root, relativePath, options);
279
+ return bytes === null
280
+ ? null
281
+ : new TextDecoder("utf-8", { fatal: true }).decode(bytes);
282
+ }
283
+
269
284
  export function readWorkspaceJsonBounded(root, relativePath, options) {
270
285
  const text = readWorkspaceFileBounded(root, relativePath, options);
271
- return text === null ? null : parseJsonStrict(text);
286
+ return text === null ? null : parseJsonStrict(text, options);
272
287
  }
273
288
 
274
289
  async function readResponseJsonBounded(response) {
@@ -549,6 +564,10 @@ function runtimeIsolationCheck(root) {
549
564
  };
550
565
  }
551
566
 
567
+ export function inspectRuntimeIsolationV1({ workspaceRoot } = {}) {
568
+ return runtimeIsolationCheck(resolveBoundedWorkspaceRoot(workspaceRoot));
569
+ }
570
+
552
571
  function configCheck(root) {
553
572
  try {
554
573
  const config = readWorkspaceJsonBounded(
@@ -15,9 +15,16 @@ const MAX_CORE_TOTAL_BYTES = 67_108_864;
15
15
  const PACKAGE_NAME = "owlrunkit";
16
16
  const OFFICIAL_CLI_ENTRYPOINT =
17
17
  "scripts/runkit-contract/runkit-bootstrap.mjs";
18
+ const SELF_NORMALIZED_QUICK_CORE_VERSIONS = new Set(["0.19.2", "0.20.0"]);
18
19
  const EXACT_VERSION = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
19
20
  const SHA256_REF = /^sha256:[a-f0-9]{64}$/;
20
21
  const TRUSTED_PRIOR_CORE_IDENTITIES = new Map([
22
+ ["0.19.2", new Set([
23
+ "sha256:c46ae9d8ed0572e5636ab5725f922f8db3ee5bf0f966b200bce7b2287c9267c8",
24
+ ])],
25
+ ["0.19.1", new Set([
26
+ "sha256:291ef97c93a513eed24a29f75c400b61cefd6a8c0ab228401cf2c6a73ea9e622",
27
+ ])],
21
28
  ["0.19.0", new Set([
22
29
  "sha256:803fb7de76a6ccffd1ec5e0164eeff15a580209fa6dfbef9e561345ab616b403",
23
30
  ])],
@@ -523,7 +530,28 @@ function coreFileList(coreContractSource, identifier) {
523
530
  return values;
524
531
  }
525
532
 
526
- function installedCoreManifestSha256(packageRoot) {
533
+ function coreDependencyBytes(target, relativePath, version) {
534
+ const bytes = readFileSync(target);
535
+ if (relativePath !== "packages/attest/src/quick.mjs"
536
+ || !SELF_NORMALIZED_QUICK_CORE_VERSIONS.has(version)) return bytes;
537
+ const source = bytes.toString("utf8");
538
+ const escapedVersion = version.replaceAll(".", "\\.");
539
+ const currentIdentity = new RegExp(
540
+ `(coreVersion:\\s*"${escapedVersion}",\\s*coreManifestSha256:\\s*")`
541
+ + "sha256:[a-f0-9]{64}(\")",
542
+ "gu",
543
+ );
544
+ const matches = [...source.matchAll(currentIdentity)];
545
+ if (matches.length !== 1) {
546
+ throw new Error("project_cli_core_contract_invalid");
547
+ }
548
+ return Buffer.from(source.replace(
549
+ currentIdentity,
550
+ `$1sha256:${"0".repeat(64)}$2`,
551
+ ));
552
+ }
553
+
554
+ function installedCoreManifestSha256(packageRoot, version) {
527
555
  const coreRoot = path.join(packageRoot, "scripts", "runkit-contract");
528
556
  const coreContractPath = path.join(coreRoot, "core-contract.mjs");
529
557
  assertRegularDescendant(
@@ -570,7 +598,9 @@ function installedCoreManifestSha256(packageRoot) {
570
598
  ) {
571
599
  throw new Error("project_cli_core_closure_too_large");
572
600
  }
573
- return `${relativePath}\tsha256:${sha256(readFileSync(target))}\n`;
601
+ return `${relativePath}\tsha256:${sha256(
602
+ coreDependencyBytes(target, relativePath, version),
603
+ )}\n`;
574
604
  }).join("");
575
605
  return `sha256:${sha256(stream)}`;
576
606
  }
@@ -629,7 +659,7 @@ function verifyInstalledCoreBinding(root, packageRoot, version) {
629
659
  }
630
660
 
631
661
  function verifyInstalledCoreClosure(packageRoot, version) {
632
- const actualCoreManifestSha256 = installedCoreManifestSha256(packageRoot);
662
+ const actualCoreManifestSha256 = installedCoreManifestSha256(packageRoot, version);
633
663
  const trusted = trustedCoreManifestHashes(version);
634
664
  if (!trusted.hashes.has(actualCoreManifestSha256)) {
635
665
  throw new Error("project_cli_untrusted_core_identity");
@@ -30,6 +30,7 @@ import {
30
30
  appendTeamProjectEventV1,
31
31
  normalizeTeamProjectDefinitionV1,
32
32
  readTeamProjectStatusV2,
33
+ readTeamProjectStatusV3,
33
34
  teamProjectDefinitionBindingV1,
34
35
  withTeamProjectControlLockV1,
35
36
  } from "./team-project.mjs";
@@ -85,11 +86,14 @@ function artifactSha256(value) {
85
86
 
86
87
  function validateTimestamp(value, label) {
87
88
  if (typeof value !== "string"
88
- || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value)
89
+ || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/u.test(value)
89
90
  || Number.isNaN(Date.parse(value))) {
90
- throw new Error(`${label} must be an ISO-8601 UTC timestamp.`);
91
+ throw new Error(
92
+ `${label} must be an ISO-8601 UTC timestamp `
93
+ + "(YYYY-MM-DDTHH:mm:ssZ or YYYY-MM-DDTHH:mm:ss.sssZ).",
94
+ );
91
95
  }
92
- return value;
96
+ return new Date(value).toISOString();
93
97
  }
94
98
 
95
99
  function compareIdentifiers(left, right) {
@@ -256,12 +260,13 @@ export function captureTargetWorkspaceSnapshotV1({
256
260
  apply = false,
257
261
  }) {
258
262
  safeIdentifier(snapshotId, "snapshotId");
259
- validateTimestamp(occurredAt, "Target snapshot capturedAt");
263
+ occurredAt = validateTimestamp(occurredAt, "Target snapshot capturedAt");
260
264
  const controllerRoot = canonicalControllerRoot(controllerWorkspaceRoot);
261
265
  const targetRoot = canonicalTargetRoot(targetWorkspaceRoot);
262
266
  assertDisjointWorkspaces(controllerRoot, targetRoot);
263
267
  const definition = readProjectDefinition(controllerRoot);
264
- const workItem = definition.workItems.find(row => row.id === workItemId);
268
+ const workItem = readTeamProjectStatusV3({ workspaceRoot: controllerRoot })
269
+ .workItems.find(row => row.workItemId === workItemId);
265
270
  if (!workItem) throw new Error(`Unknown team project WorkItem: ${workItemId}.`);
266
271
  const projectBinding = teamProjectDefinitionBindingV1(definition);
267
272
  const selectedAllowedPaths = resolveAllowedPaths(workItem, allowedPaths);
@@ -293,11 +298,12 @@ export function captureTargetWorkspaceSnapshotV1({
293
298
 
294
299
  const persisted = withTeamProjectControlLockV1({
295
300
  workspaceRoot: controllerRoot,
296
- operation({ definition: currentDefinition, definitionBinding }) {
301
+ operation({ definitionBinding }) {
297
302
  if (canonical(definitionBinding) !== canonical(projectBinding)) {
298
303
  throw new Error("Team project identity changed before target snapshot persistence.");
299
304
  }
300
- const currentWorkItem = currentDefinition.workItems.find(row => row.id === workItemId);
305
+ const currentWorkItem = readTeamProjectStatusV3({ workspaceRoot: controllerRoot })
306
+ .workItems.find(row => row.workItemId === workItemId);
301
307
  if (!currentWorkItem
302
308
  || canonical(resolveAllowedPaths(currentWorkItem, selectedAllowedPaths))
303
309
  !== canonical(selectedAllowedPaths)) {
@@ -549,12 +555,13 @@ export function importExternalDeliveryV1({
549
555
  }) {
550
556
  safeIdentifier(deliveryId, "deliveryId");
551
557
  safeIdentifier(producerId, "producerId");
552
- validateTimestamp(occurredAt, "External delivery occurredAt");
558
+ occurredAt = validateTimestamp(occurredAt, "External delivery occurredAt");
553
559
  const controllerRoot = canonicalControllerRoot(controllerWorkspaceRoot);
554
560
  const targetRoot = canonicalTargetRoot(targetWorkspaceRoot);
555
561
  assertDisjointWorkspaces(controllerRoot, targetRoot);
556
562
  const definition = readProjectDefinition(controllerRoot);
557
- const workItem = definition.workItems.find(row => row.id === workItemId);
563
+ const workItem = readTeamProjectStatusV3({ workspaceRoot: controllerRoot })
564
+ .workItems.find(row => row.workItemId === workItemId);
558
565
  if (!workItem) throw new Error(`Unknown team project WorkItem: ${workItemId}.`);
559
566
  const projectBinding = teamProjectDefinitionBindingV1(definition);
560
567
  validateCurrentAssignment(controllerRoot, workItemId, assignmentId);
@@ -1,5 +1,29 @@
1
+ import {
2
+ SUPPORTED_QUICK_CORE_IDENTITIES,
3
+ attestQuickReceiptDetailsFromBytesWithCoreCatalog,
4
+ } from "../../packages/attest/src/quick.mjs";
5
+ import { currentCoreIdentity } from "./core-contract.mjs";
6
+
1
7
  export {
2
8
  attestQuickReceipt,
3
9
  attestQuickReceiptDetails,
10
+ attestQuickReceiptDetailsFromBytes,
4
11
  validQuickReceiptShape,
5
12
  } from "../../packages/attest/src/quick.mjs";
13
+
14
+ function coreBoundCatalog() {
15
+ const current = currentCoreIdentity();
16
+ return [
17
+ current,
18
+ ...SUPPORTED_QUICK_CORE_IDENTITIES.filter((identity) => (
19
+ identity.coreVersion !== current.coreVersion
20
+ )),
21
+ ];
22
+ }
23
+
24
+ export function attestCoreBoundQuickReceiptDetailsFromBytes(options) {
25
+ return attestQuickReceiptDetailsFromBytesWithCoreCatalog(
26
+ options,
27
+ coreBoundCatalog(),
28
+ );
29
+ }