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
@@ -63,12 +63,21 @@ import {
63
63
  runHighLevelVerify,
64
64
  } from "./lifecycle-orchestration.mjs";
65
65
  import {
66
- finalizeFormalChecksV1,
66
+ finalizeFormalChecksWithinControlTransaction,
67
67
  recordFormalCheckV1,
68
68
  recordFormalEnvelopeCheckV1,
69
69
  resumeCompletedFormalFinishV1,
70
70
  validateLegacyVerificationSideEffectsV1,
71
71
  } from "./formal-workflow.mjs";
72
+ import {
73
+ formatFormalEnvelopePreflightHumanV1,
74
+ preflightFormalEnvelopeV1,
75
+ } from "./formal-preflight.mjs";
76
+ import {
77
+ attachFormalSupplementalEvidenceV1,
78
+ reattestFormalEvidenceSummaryV1,
79
+ summarizeFormalEvidenceWithinControlTransaction,
80
+ } from "./formal-supplemental-evidence.mjs";
72
81
  import {
73
82
  freezeSourceCandidateV1,
74
83
  freezeSourceCandidateV2,
@@ -162,7 +171,7 @@ import { OFFICIAL_NPM_REGISTRY } from "./registry-adoption-gate.mjs";
162
171
  import {
163
172
  appendTeamProjectEventV1,
164
173
  assignTeamProjectV1,
165
- buildTeamProjectTakeoverV2,
174
+ buildTeamProjectTakeoverV3,
166
175
  checkpointTeamProjectV1,
167
176
  closeTeamProjectVerificationV1,
168
177
  deferTeamProjectVerificationV1,
@@ -173,9 +182,11 @@ import {
173
182
  integrateTeamProjectV1,
174
183
  openTeamProjectDecisionV1,
175
184
  readTeamProjectStatusV2,
185
+ readTeamProjectStatusV3,
176
186
  rejectAndReturnTeamProjectV1,
177
187
  reopenUpstreamTeamProjectV1,
178
188
  resolveTeamProjectDecisionV1,
189
+ reviseTeamProjectWorkItemScopeV1,
179
190
  transferTeamProjectV1,
180
191
  } from "./team-project.mjs";
181
192
  import {
@@ -186,6 +197,14 @@ import {
186
197
  captureTargetWorkspaceSnapshotV1,
187
198
  importExternalDeliveryV1,
188
199
  } from "./project-external-delivery.mjs";
200
+ import {
201
+ formatTeamDeliveryRecommendationHumanV1,
202
+ formatTeamDeliveryStatusHumanV1,
203
+ formatTeamPacketValidationHumanV1,
204
+ readTeamDeliveryStatusV1,
205
+ recommendTeamDeliveryV1,
206
+ validateTeamPacketFileV1,
207
+ } from "./team-delivery.mjs";
189
208
 
190
209
  const TOP_LEVEL_HELP = `OwlRunKit ${CORE_VERSION}
191
210
 
@@ -205,7 +224,7 @@ Quick Verification
205
224
  Low-risk, source-bound reusable evidence without writer leases or acceptance.
206
225
 
207
226
  Formal Delivery
208
- npx --no-install owlrunkit formal <start|check|finish> --workspace . --run-id <id> [...]
227
+ npx --no-install owlrunkit formal <start|preflight|check|attach-evidence|finish> --workspace . --run-id <id> [...]
209
228
  Use for multi-writer, permissions, security, funds, irreversible change,
210
229
  uncertain rollback, schema/data migration, or explicit Formal acceptance.
211
230
  Frozen dirty source
@@ -222,11 +241,11 @@ Fleet and status
222
241
  npx --no-install owlrunkit fleet discover; npx --no-install owlrunkit status --workspace .
223
242
 
224
243
  Agent team projects
225
- npx --no-install owlrunkit project <init|assign|checkpoint|handoff|reject-and-return|reopen-upstream|transfer|decision|verification|capture|target-snapshot|import-delivery|status|takeover|successor> [options]
226
- Durable Agent work, dependencies, decisions, gates, progress, and handoffs.
244
+ npx --no-install owlrunkit project <init|assign|checkpoint|handoff|reject-and-return|reopen-upstream|transfer|work-item revise-scope|decision|verification|capture|target-snapshot|import-delivery|status|takeover|successor> [options]
245
+ npx --no-install owlrunkit team <recommend|status|packet validate> [options]
246
+ Durable project truth plus read-only Team recommendation and packet validation. No Agent dispatch.
227
247
  Core successor
228
248
  npx --no-install owlrunkit core-successor <plan|apply|resume> --workspace . [...]
229
-
230
249
  Other onboarding commands:
231
250
  npx --no-install owlrunkit profiles validate --workspace .; npx --no-install owlrunkit profiles impact --workspace . --changed <path>
232
251
  npx --no-install owlrunkit inspect --workspace . --json
@@ -297,6 +316,34 @@ Persisted mode preferences are not part of this release.
297
316
  npx --no-install owlrunkit mode status --workspace <directory> [--json]
298
317
 
299
318
  Reads the current mode preference source without creating project state.
319
+ `,
320
+ team: `Usage:
321
+ npx --no-install owlrunkit team recommend --workspace <directory> [--json]
322
+ npx --no-install owlrunkit team status --workspace <directory> [--json]
323
+ npx --no-install owlrunkit team packet validate --workspace <directory>
324
+ --packet <packet.json> [--json]
325
+
326
+ Projects existing Project Driver truth into a read-only Team Delivery view and
327
+ validates portable Team packets. It never dispatches an Agent or grants Git,
328
+ release, deployment, production, business, automation, or money authority.
329
+ `,
330
+ "team recommend": `Usage:
331
+ npx --no-install owlrunkit team recommend --workspace <directory> [--json]
332
+
333
+ Recommends Team coordination only when current Project Driver facts require it.
334
+ Single ordinary lanes and uninitialized projects remain off. This is read-only.
335
+ `,
336
+ "team status": `Usage:
337
+ npx --no-install owlrunkit team status --workspace <directory> [--json]
338
+
339
+ Reads a Team Delivery projection from Project Driver. No second graph is stored.
340
+ `,
341
+ "team packet validate": `Usage:
342
+ npx --no-install owlrunkit team packet validate --workspace <directory>
343
+ --packet <packet.json> [--json]
344
+
345
+ Validates a TeamTaskPacketV2, TeamAcceptancePacketV2, or
346
+ CandidateTransferPacketV1 against current project truth without writing state.
300
347
  `,
301
348
  "quick-attest": `Usage:
302
349
  npx --no-install owlrunkit quick-attest --workspace <directory> --receipt <receipt.json> [--json]
@@ -431,7 +478,9 @@ high-confidence unambiguous profile.
431
478
  `,
432
479
  formal: `Usage:
433
480
  npx --no-install owlrunkit formal start --workspace <directory> --run-id <id> [...]
481
+ npx --no-install owlrunkit formal preflight --workspace <directory> --envelope <file>
434
482
  npx --no-install owlrunkit formal check --workspace <directory> --run-id <id> -- <command>
483
+ npx --no-install owlrunkit formal attach-evidence --workspace <directory> --run-id <id> [...]
435
484
  npx --no-install owlrunkit formal finish --workspace <directory> --run-id <id>
436
485
  `,
437
486
  "formal start": `Usage:
@@ -439,18 +488,38 @@ high-confidence unambiguous profile.
439
488
  --goal <goal.json> --work-item <id> --owned-path <path>
440
489
 
441
490
  Creates the execution and exact writer lease.
491
+ `,
492
+ "formal preflight": `Usage:
493
+ npx --no-install owlrunkit formal preflight --workspace <directory>
494
+ --envelope <verification-envelope.json> [--json]
495
+
496
+ Reads the envelope, enforcement backend, known subprocess requirements, temporary
497
+ directory needs, and protected RunKit runtime scan conflicts without executing
498
+ the command or writing Formal evidence. It grants no authorization.
442
499
  `,
443
500
  "formal check": `Usage:
444
501
  npx --no-install owlrunkit formal check --workspace <directory> --run-id <id>
445
- --work-item <id> --check-id <id> --envelope <verification-envelope.json>
502
+ (--work-item <id> | --from-lease <id>) --check-id <id>
503
+ --envelope <verification-envelope.json>
446
504
  npx --no-install owlrunkit formal check --workspace <directory> --run-id <id>
447
- --work-item <id> --check-id <id> --cwd <directory> -- <built-in-command> [args...]
505
+ (--work-item <id> | --from-lease <id>) --check-id <id>
506
+ --cwd <directory> -- <built-in-command> [args...]
448
507
 
449
508
  Verification Envelopes admit real project commands only when file, network,
450
509
  process, environment, output, timeout, and cleanup constraints are enforced.
510
+ `,
511
+ "formal attach-evidence": `Usage:
512
+ npx --no-install owlrunkit formal attach-evidence --workspace <directory>
513
+ --run-id <id> --evidence-id <id> --kind supplemental-local|networked
514
+ --receipt <quick-receipt.json> [--json]
515
+
516
+ Attests one passing Quick receipt and binds it to the current Formal source
517
+ candidate as non-gating supplemental evidence. It cannot replace a Formal check
518
+ or grant Git, release, deployment, production, or business authorization.
451
519
  `,
452
520
  "formal finish": `Usage:
453
521
  npx --no-install owlrunkit formal finish --workspace <directory> --run-id <id>
522
+ [--decision accepted|rejected|blocked] [--finalize-id <id>]
454
523
 
455
524
  Runs the final source, evidence, permission, closeout, and lease-release path.
456
525
  `,
@@ -579,6 +648,13 @@ No self-reported percentage is accepted.
579
648
  Measured WorkItems require --completed-units on every checkpoint. A completed
580
649
  checkpoint must use the WorkItem's declared total. Example:
581
650
  npx --no-install owlrunkit project checkpoint --workspace . --checkpoint-id checkpoint-x --at 2026-08-11T00:00:00.000Z --assignment-id assign-x --work-item x --state completed --summary 'Completed x.' --completed-units 5 --evidence receipt:quick
651
+ `,
652
+ "project init": `Usage:
653
+ npx --no-install owlrunkit project init --workspace <directory>
654
+ --definition <project-definition.json> [--json]
655
+
656
+ Creates one project-owned definition and empty immutable event journal. It does
657
+ not grant Git, release, deployment, production, or business authorization.
582
658
  `,
583
659
  "project assign": `Usage:
584
660
  npx --no-install owlrunkit project assign --workspace <directory>
@@ -588,6 +664,55 @@ checkpoint must use the WorkItem's declared total. Example:
588
664
 
589
665
  Assigns one current WorkItem owner without granting Git, release, deployment,
590
666
  production, business, or other authorization.
667
+ `,
668
+ "project handoff": `Usage:
669
+ npx --no-install owlrunkit project handoff --workspace <directory>
670
+ --handoff-id <id> --at <ISO-UTC> --assignment-id <current>
671
+ --work-item <id> --from-agent <id> --to-agent <id>
672
+ --summary <text> --next <text> --evidence <ref> [--evidence <ref> ...] [--json]
673
+
674
+ Records an immutable handoff without assigning successor authority or granting
675
+ Git, release, deployment, production, or business authorization.
676
+ `,
677
+ "project decision": `Usage:
678
+ npx --no-install owlrunkit project decision --workspace <directory>
679
+ --open --decision-id <id> --at <ISO-UTC> --title <text> --question <text>
680
+ --owner-agent <id> [--blocking-work-item <id> ...]
681
+ --option <text> [--option <text> ...] [--json]
682
+ npx --no-install owlrunkit project decision --workspace <directory>
683
+ --resolve --decision-id <id> --at <ISO-UTC> --resolution <text>
684
+ --rationale <text> --evidence <ref> [--evidence <ref> ...] [--json]
685
+
686
+ Opens or resolves one durable project decision. Resolution records truth but
687
+ does not grant Git, release, deployment, production, or business authorization.
688
+ `,
689
+ "project verification": `Usage:
690
+ npx --no-install owlrunkit project verification --workspace <directory>
691
+ --defer --verification-id <id> --at <ISO-UTC> --work-item <id>
692
+ --owner-agent <id> --check <check-id> [--check <check-id> ...]
693
+ --reason <text> --due-gate <gate-id> [--json]
694
+ npx --no-install owlrunkit project verification --workspace <directory>
695
+ --close --verification-id <id> --at <ISO-UTC>
696
+ --disposition <verified|no_longer_required> --summary <text>
697
+ [--evidence <ref> ...] [--decision <resolved-decision-id> ...] [--json]
698
+
699
+ Records an intentionally deferred check or closes it with evidence. It does not
700
+ execute the check and grants no additional authorization.
701
+ `,
702
+ "project integrate": `Usage:
703
+ npx --no-install owlrunkit project integrate --workspace <directory>
704
+ --gate <gate-id> --at <ISO-UTC> --summary <text>
705
+ --evidence <ref> [--evidence <ref> ...] [--json]
706
+
707
+ Records one passed integration gate after its dependencies and deferred checks
708
+ are satisfied. It does not perform Git integration or grant release authority.
709
+ `,
710
+ "project capture": `Usage:
711
+ npx --no-install owlrunkit project capture --workspace <directory>
712
+ --request <legacy-event.json> [--json]
713
+
714
+ Compatibility-only raw event capture. External source delivery must use
715
+ project import-delivery. This action grants no repository or business authority.
591
716
  `,
592
717
  "project reject-and-return": `Usage:
593
718
  npx --no-install owlrunkit project reject-and-return --workspace <directory> --rework-id <id> --at <ISO-UTC>
@@ -622,6 +747,19 @@ authority is granted.
622
747
  Atomically records checkpoint, handoff, and successor-assignment facts inside one
623
748
  immutable Event V4 envelope. Terminal WorkItems cannot transfer. No Git, release,
624
749
  deployment, production, or business authority is granted.
750
+ `,
751
+ "project work-item revise-scope": `Usage:
752
+ npx --no-install owlrunkit project work-item revise-scope --workspace <directory>
753
+ --revision-id <id> --at <ISO-UTC> --assignment-id <current>
754
+ --work-item <id> --owner-agent <current-owner>
755
+ [--owned-path <path> ...]
756
+ [--measurable-unit <unit> --measurable-total <positive-int> | --unmeasured]
757
+ --reason <text> [--evidence <ref> ...] [--json]
758
+
759
+ Records an immutable Event V5 that supersedes the WorkItem's prior scope. Omitted
760
+ ownedPaths or measurable fields retain their current values. The event never
761
+ rewrites the project definition and grants no Git, release, deployment,
762
+ production, or business authority.
625
763
  `,
626
764
  "project target-snapshot": `Usage:
627
765
  npx --no-install owlrunkit project target-snapshot --workspace <controller>
@@ -843,7 +981,7 @@ function formatTeamProjectIntegrationHuman(result) {
843
981
  : String(result.nextAction).replace(/\s+/gu, " ").trim();
844
982
  return [
845
983
  `${disposition} project integration gate ${result.gateId}.`,
846
- `Project state: ${result.overall}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
984
+ `Work ledger: ${result.overall}; delivery: ${result.deliveryDisposition}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
847
985
  "Git/release not performed.",
848
986
  "",
849
987
  ].join("\n");
@@ -857,6 +995,9 @@ function formatTeamProjectCheckpointHuman(result) {
857
995
  return [
858
996
  `${disposition} checkpoint ${result.checkpointId} for WorkItem ${result.workItemId}: ${result.state}.`,
859
997
  `Project state: ${result.overall}; next: ${nextAction}${result.nextActorId ? ` (owner ${result.nextActorId})` : ""}`,
998
+ ...(result.warnings?.length > 0
999
+ ? [`Warning: ${result.warnings.map(row => row.code).join(", ")}.`]
1000
+ : []),
860
1001
  "",
861
1002
  ].join("\n");
862
1003
  }
@@ -1912,7 +2053,7 @@ function inspect(options) {
1912
2053
  const onboarding = onboardingProjection(root, recovery);
1913
2054
  const projectDefinitionPath = runtimePath(root, "project", "definition.json");
1914
2055
  const projectDriver = pathEntryExists(projectDefinitionPath)
1915
- ? readTeamProjectStatusV2({ workspaceRoot: root })
2056
+ ? readTeamProjectStatusV3({ workspaceRoot: root })
1916
2057
  : null;
1917
2058
  const summary = buildInspectSummary(result, {
1918
2059
  maintenanceNextAction: onboarding.maintenanceNextAction ?? null,
@@ -2014,6 +2155,20 @@ function closeout(options) {
2014
2155
  releasedLeaseIds,
2015
2156
  };
2016
2157
  }
2158
+ const formalEvidenceSummary = options["formal-evidence-summary"] ?? null;
2159
+ if (
2160
+ formalEvidenceSummary !== null
2161
+ && (
2162
+ decision !== "accepted"
2163
+ || formalEvidenceSummary.status !== "formal_evidence_summarized"
2164
+ || typeof formalEvidenceSummary.evidenceSummaryPath !== "string"
2165
+ || !/^[a-f0-9]{64}$/u.test(
2166
+ formalEvidenceSummary.evidenceSummarySha256 ?? "",
2167
+ )
2168
+ )
2169
+ ) {
2170
+ throw new Error("Formal evidence summary binding is invalid for closeout.");
2171
+ }
2017
2172
  const created = createCoreArtifact({
2018
2173
  core: pin,
2019
2174
  producer: { adapterKind: "codex", adapterVersion: "0.1.0" },
@@ -2023,7 +2178,24 @@ function closeout(options) {
2023
2178
  authorizationGranted: false,
2024
2179
  ...(acceptedVerification ? { verification: acceptedVerification } : {}),
2025
2180
  },
2026
- extensions: { "dev.owlcoda.adapter.codex": {} },
2181
+ extensions: {
2182
+ "dev.owlcoda.adapter.codex": {},
2183
+ ...(formalEvidenceSummary === null
2184
+ ? {}
2185
+ : {
2186
+ "dev.owlcoda.formal-evidence": {
2187
+ schemaVersion: "OwlCodaRunKitFormalEvidenceCloseoutBindingV1",
2188
+ summaryPath: formalEvidenceSummary.evidenceSummaryPath,
2189
+ summarySha256: formalEvidenceSummary.evidenceSummarySha256,
2190
+ formalCheckCount: formalEvidenceSummary.formalCheckCount,
2191
+ supplementalEvidenceCount:
2192
+ formalEvidenceSummary.supplementalEvidenceCount,
2193
+ staleSupplementalEvidenceCount:
2194
+ formalEvidenceSummary.staleSupplementalEvidenceCount,
2195
+ authorizationGranted: false,
2196
+ },
2197
+ }),
2198
+ },
2027
2199
  });
2028
2200
  const closeoutPath = path.join(executionRoot, "closeout-receipt.json");
2029
2201
  writeJsonExclusiveAtomically(closeoutPath, created);
@@ -2038,15 +2210,16 @@ function closeout(options) {
2038
2210
  return { status: "closed", exitCode: 0, runId, decision, authorizationGranted: false, ...created };
2039
2211
  }
2040
2212
 
2041
- function finishExecution(options) {
2213
+ function finishExecutionWithinControlTransaction(options, {
2214
+ formalEvidenceSummary = null,
2215
+ } = {}) {
2042
2216
  const root = workspace(options);
2043
2217
  const runId = safeRunId(requireOption(options, "run-id"));
2044
2218
  const decision = requireOption(options, "decision");
2045
2219
  if (!new Set(["accepted", "rejected", "blocked"]).has(decision)) {
2046
2220
  throw new Error("decision must be accepted, rejected, or blocked.");
2047
2221
  }
2048
- return withControlTransaction(root, () => {
2049
- const executionRoot = runtimePath(root, "executions", runId);
2222
+ const executionRoot = runtimePath(root, "executions", runId);
2050
2223
  const closeoutPath = path.join(executionRoot, "closeout-receipt.json");
2051
2224
  if (pathEntryExists(closeoutPath)) {
2052
2225
  if (lstatSync(closeoutPath).isSymbolicLink()) {
@@ -2090,6 +2263,9 @@ function finishExecution(options) {
2090
2263
  closed = closeout({
2091
2264
  ...options,
2092
2265
  ...(gate ? { "gate-input": gate.gateInputPath } : {}),
2266
+ ...(formalEvidenceSummary === null
2267
+ ? {}
2268
+ : { "formal-evidence-summary": formalEvidenceSummary }),
2093
2269
  });
2094
2270
  if (closed.status !== "closed") {
2095
2271
  rollbackReleasedLeases();
@@ -2109,7 +2285,14 @@ function finishExecution(options) {
2109
2285
  closeoutArtifactSha256: closed.artifactSha256,
2110
2286
  authorizationGranted: false,
2111
2287
  };
2112
- });
2288
+ }
2289
+
2290
+ function finishExecution(options) {
2291
+ const root = workspace(options);
2292
+ return withControlTransaction(
2293
+ root,
2294
+ () => finishExecutionWithinControlTransaction(options),
2295
+ );
2113
2296
  }
2114
2297
 
2115
2298
  function requestCommand(options, handler) {
@@ -2160,8 +2343,19 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2160
2343
  "mode",
2161
2344
  "profiles",
2162
2345
  "project",
2346
+ "team",
2163
2347
  ]).has(command);
2164
- const [action, ...nestedOptions] = nested ? optionValues : [null, ...optionValues];
2348
+ let [action, ...nestedOptions] = nested ? optionValues : [null, ...optionValues];
2349
+ if (command === "project" && action === "work-item"
2350
+ && nestedOptions[0] === "revise-scope") {
2351
+ action = "work-item revise-scope";
2352
+ nestedOptions = nestedOptions.slice(1);
2353
+ }
2354
+ if (command === "team" && action === "packet"
2355
+ && nestedOptions[0] === "validate") {
2356
+ action = "packet validate";
2357
+ nestedOptions = nestedOptions.slice(1);
2358
+ }
2165
2359
  const helpRequested = optionValues.includes("--help")
2166
2360
  || optionValues.includes("-h");
2167
2361
  if (helpRequested) {
@@ -2213,6 +2407,8 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2213
2407
  ? ["evidence", "blocker", "decision"]
2214
2408
  : command === "project" && action === "decision"
2215
2409
  ? ["blocking-work-item", "option", "evidence"]
2410
+ : command === "project" && action === "work-item revise-scope"
2411
+ ? ["owned-path", "evidence"]
2216
2412
  : command === "efficiency" && action === "record"
2217
2413
  ? ["evidence"]
2218
2414
  : [],
@@ -2236,17 +2432,23 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2236
2432
  ]
2237
2433
  : command === "mode" && action === "status"
2238
2434
  ? ["json"]
2435
+ : command === "team"
2436
+ ? ["json"]
2239
2437
  : command === "inspect"
2240
2438
  ? ["json", "verbose", "history"]
2241
2439
  : command === "init"
2242
2440
  ? ["json"]
2243
2441
  : command === "bootstrap"
2244
2442
  ? ["json", "dry-run", "apply"]
2443
+ : command === "formal" && new Set(["preflight", "attach-evidence"]).has(action)
2444
+ ? ["json"]
2245
2445
  : command === "project" && action === "decision"
2246
2446
  ? ["json", "open", "resolve"]
2247
2447
  : command === "project" && action === "verification"
2248
2448
  ? ["json", "defer", "close"]
2249
- : command === "project" && new Set(["assign", "handoff", "reject-and-return", "reopen-upstream", "transfer", "checkpoint", "integrate", "status", "takeover", "successor"]).has(action)
2449
+ : command === "project" && action === "work-item revise-scope"
2450
+ ? ["json", "unmeasured"]
2451
+ : command === "project" && new Set(["init", "assign", "handoff", "reject-and-return", "reopen-upstream", "transfer", "checkpoint", "integrate", "capture", "status", "takeover", "successor"]).has(action)
2250
2452
  ? ["json"]
2251
2453
  : command === "project" && new Set(["target-snapshot", "import-delivery"]).has(action)
2252
2454
  ? ["json", "dry-run", "apply"]
@@ -2361,6 +2563,10 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2361
2563
  ]);
2362
2564
  const recommendation = recommendUsageModeV2({
2363
2565
  workspaceRoot: root,
2566
+ projectDriverPresent: existsSync(path.join(
2567
+ root,
2568
+ ".owlcoda/runkit/project/definition.json",
2569
+ )),
2364
2570
  requestedMode: options["requested-mode"] ?? "auto",
2365
2571
  needsDurableEvidence: options["needs-evidence"] === true,
2366
2572
  exactCommandCount: parseCanonicalNonnegativeSafeInteger(
@@ -2394,6 +2600,10 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2394
2600
  assertOnlyOptions(options, ["workspace", "json"]);
2395
2601
  const recommendation = recommendUsageModeV2({
2396
2602
  workspaceRoot: root,
2603
+ projectDriverPresent: existsSync(path.join(
2604
+ root,
2605
+ ".owlcoda/runkit/project/definition.json",
2606
+ )),
2397
2607
  requestedMode: "auto",
2398
2608
  needsDurableEvidence: false,
2399
2609
  exactCommandCount: 0,
@@ -2425,6 +2635,39 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2425
2635
  }
2426
2636
  throw new Error("Usage: npx --no-install owlrunkit mode <recommend|status> --workspace <directory>");
2427
2637
  }
2638
+ if (command === "team") {
2639
+ const root = workspace(options);
2640
+ if (action === "recommend") {
2641
+ assertOnlyOptions(options, ["workspace", "json"]);
2642
+ const recommendation = recommendTeamDeliveryV1({ workspaceRoot: root });
2643
+ return options.json === true
2644
+ ? recommendation
2645
+ : withHumanOutput(
2646
+ recommendation,
2647
+ formatTeamDeliveryRecommendationHumanV1(recommendation),
2648
+ );
2649
+ }
2650
+ if (action === "status") {
2651
+ assertOnlyOptions(options, ["workspace", "json"]);
2652
+ const status = readTeamDeliveryStatusV1({ workspaceRoot: root });
2653
+ return options.json === true
2654
+ ? status
2655
+ : withHumanOutput(status, formatTeamDeliveryStatusHumanV1(status));
2656
+ }
2657
+ if (action === "packet validate") {
2658
+ assertOnlyOptions(options, ["workspace", "packet", "json"]);
2659
+ const validation = validateTeamPacketFileV1({
2660
+ workspaceRoot: root,
2661
+ packetPath: requireOption(options, "packet"),
2662
+ });
2663
+ return options.json === true
2664
+ ? validation
2665
+ : withHumanOutput(validation, formatTeamPacketValidationHumanV1(validation));
2666
+ }
2667
+ throw new Error(
2668
+ "Usage: npx --no-install owlrunkit team <recommend|status|packet validate> --workspace <directory>",
2669
+ );
2670
+ }
2428
2671
  if (command === "fleet") {
2429
2672
  if (action === "register-root") {
2430
2673
  const registered = await registerFleetCoverageRoot({
@@ -2974,12 +3217,37 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2974
3217
  throw new Error("Usage: npx --no-install owlrunkit deployment <prepare|execute> [options]");
2975
3218
  }
2976
3219
  if (command === "formal") {
3220
+ const allowedFormalOptions = {
3221
+ start: ["workspace", "run-id", "goal", "work-item", "owned-path"],
3222
+ preflight: ["workspace", "envelope", "json"],
3223
+ check: ["workspace", "run-id", "work-item", "from-lease", "check-id", "envelope", "cwd"],
3224
+ "attach-evidence": ["workspace", "run-id", "evidence-id", "kind", "receipt", "json"],
3225
+ finish: ["workspace", "run-id", "decision", "finalize-id"],
3226
+ };
3227
+ if (!Object.hasOwn(allowedFormalOptions, action)) {
3228
+ throw new Error("Usage: npx --no-install owlrunkit formal <start|preflight|check|attach-evidence|finish> [options]");
3229
+ }
3230
+ assertOnlyOptions(options, allowedFormalOptions[action]);
2977
3231
  if (action === "start") {
2978
3232
  return startExecution({
2979
3233
  ...options,
2980
3234
  "work-item": options["work-item"] ?? "delivery",
2981
3235
  });
2982
3236
  }
3237
+ if (action === "preflight") {
3238
+ const root = workspace(options);
3239
+ const envelope = readJson(realpathSync(requireOption(options, "envelope")));
3240
+ const preflight = preflightFormalEnvelopeV1({
3241
+ workspaceRoot: root,
3242
+ envelope,
3243
+ });
3244
+ return options.json === true
3245
+ ? preflight
3246
+ : withHumanOutput(
3247
+ preflight,
3248
+ formatFormalEnvelopePreflightHumanV1(preflight),
3249
+ );
3250
+ }
2983
3251
  if (action === "check") {
2984
3252
  const workItemId = options["work-item"] ?? options["from-lease"] ?? "delivery";
2985
3253
  if (
@@ -2993,12 +3261,17 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2993
3261
  if (commandArgv.length > 0) {
2994
3262
  throw new Error("formal check accepts either --envelope or an exact built-in command, not both.");
2995
3263
  }
3264
+ if (options.cwd !== undefined) {
3265
+ throw new Error("formal check --cwd is only valid with an exact built-in command.");
3266
+ }
3267
+ const root = workspace(options);
3268
+ const envelope = readJson(realpathSync(requireOption(options, "envelope")));
2996
3269
  return await recordFormalEnvelopeCheckV1({
2997
- workspaceRoot: workspace(options),
3270
+ workspaceRoot: root,
2998
3271
  runId: safeRunId(requireOption(options, "run-id")),
2999
3272
  workItemId,
3000
3273
  checkId: requireOption(options, "check-id"),
3001
- envelope: readJson(realpathSync(requireOption(options, "envelope"))),
3274
+ envelope,
3002
3275
  });
3003
3276
  }
3004
3277
  return recordFormalCheckV1({
@@ -3010,6 +3283,15 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3010
3283
  commandArgv,
3011
3284
  });
3012
3285
  }
3286
+ if (action === "attach-evidence") {
3287
+ return attachFormalSupplementalEvidenceV1({
3288
+ workspaceRoot: workspace(options),
3289
+ runId: safeRunId(requireOption(options, "run-id")),
3290
+ evidenceId: requireOption(options, "evidence-id"),
3291
+ kind: requireOption(options, "kind"),
3292
+ receiptPath: requireOption(options, "receipt"),
3293
+ });
3294
+ }
3013
3295
  if (action === "finish") {
3014
3296
  const decision = options.decision ?? "accepted";
3015
3297
  if (!new Set(["accepted", "rejected", "blocked"]).has(decision)) {
@@ -3024,36 +3306,92 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3024
3306
  finalizeId,
3025
3307
  decision,
3026
3308
  });
3027
- if (resumed !== null) return resumed;
3028
- let finalized = null;
3029
- if (decision === "accepted") {
3030
- finalized = finalizeFormalChecksV1({
3031
- workspaceRoot: root,
3032
- runId,
3033
- finalizeId,
3034
- });
3035
- if (finalized.status !== "accepted_passed") return finalized;
3309
+ if (resumed !== null) {
3310
+ const evidenceSummary = decision === "accepted"
3311
+ ? reattestFormalEvidenceSummaryV1({
3312
+ workspaceRoot: root,
3313
+ runId,
3314
+ summaryId: `${finalizeId}-evidence`,
3315
+ })
3316
+ : null;
3317
+ if (
3318
+ resumed.formalEvidenceBinding !== null
3319
+ && (
3320
+ evidenceSummary === null
3321
+ || evidenceSummary.evidenceSummaryPath
3322
+ !== resumed.formalEvidenceBinding.summaryPath
3323
+ || evidenceSummary.evidenceSummarySha256
3324
+ !== resumed.formalEvidenceBinding.summarySha256
3325
+ || evidenceSummary.formalCheckCount
3326
+ !== resumed.formalEvidenceBinding.formalCheckCount
3327
+ || evidenceSummary.supplementalEvidenceCount
3328
+ !== resumed.formalEvidenceBinding.supplementalEvidenceCount
3329
+ || evidenceSummary.staleSupplementalEvidenceCount
3330
+ !== resumed.formalEvidenceBinding.staleSupplementalEvidenceCount
3331
+ )
3332
+ ) {
3333
+ throw new Error(
3334
+ "Existing closeout does not match its Formal evidence summary.",
3335
+ );
3336
+ }
3337
+ const { formalEvidenceBinding: _formalEvidenceBinding, ...resumedResult } = resumed;
3338
+ return {
3339
+ ...resumedResult,
3340
+ supplementalEvidenceCount:
3341
+ evidenceSummary?.supplementalEvidenceCount ?? 0,
3342
+ staleSupplementalEvidenceCount:
3343
+ evidenceSummary?.staleSupplementalEvidenceCount ?? 0,
3344
+ evidenceSummaryPath: evidenceSummary?.evidenceSummaryPath,
3345
+ evidenceSummarySha256: evidenceSummary?.evidenceSummarySha256,
3346
+ };
3036
3347
  }
3037
- const finished = finishExecution({
3038
- ...options,
3039
- decision,
3348
+ return withControlTransaction(root, () => {
3349
+ let finalized = null;
3350
+ let evidenceSummary = null;
3351
+ if (decision === "accepted") {
3352
+ finalized = finalizeFormalChecksWithinControlTransaction({
3353
+ workspaceRoot: root,
3354
+ runId,
3355
+ finalizeId,
3356
+ });
3357
+ if (finalized.status !== "accepted_passed") return finalized;
3358
+ evidenceSummary = summarizeFormalEvidenceWithinControlTransaction({
3359
+ workspaceRoot: root,
3360
+ runId,
3361
+ summaryId: `${finalizeId}-evidence`,
3362
+ });
3363
+ if (evidenceSummary.status !== "formal_evidence_summarized") {
3364
+ return evidenceSummary;
3365
+ }
3366
+ }
3367
+ const finished = finishExecutionWithinControlTransaction({
3368
+ ...options,
3369
+ decision,
3370
+ }, { formalEvidenceSummary: evidenceSummary });
3371
+ if (finished.status !== "finished") return finished;
3372
+ return {
3373
+ status: "formal_finished",
3374
+ exitCode: 0,
3375
+ runId: finished.runId,
3376
+ decision,
3377
+ snapshotCount: finalized?.snapshotCount ?? 0,
3378
+ staleCheckCount: finalized?.staleCheckCount ?? 0,
3379
+ supplementalEvidenceCount:
3380
+ evidenceSummary?.supplementalEvidenceCount ?? 0,
3381
+ staleSupplementalEvidenceCount:
3382
+ evidenceSummary?.staleSupplementalEvidenceCount ?? 0,
3383
+ evidenceSummaryPath: evidenceSummary?.evidenceSummaryPath ?? null,
3384
+ evidenceSummarySha256:
3385
+ evidenceSummary?.evidenceSummarySha256 ?? null,
3386
+ sourceFingerprint: finalized?.sourceFingerprint ?? null,
3387
+ activeReceiptSha256: finished.activeReceiptSha256,
3388
+ closeoutArtifactSha256: finished.closeoutArtifactSha256,
3389
+ releasedLeaseIds: finished.releasedLeaseIds,
3390
+ authorizationGranted: false,
3391
+ };
3040
3392
  });
3041
- if (finished.status !== "finished") return finished;
3042
- return {
3043
- status: "formal_finished",
3044
- exitCode: 0,
3045
- runId: finished.runId,
3046
- decision,
3047
- snapshotCount: finalized?.snapshotCount ?? 0,
3048
- staleCheckCount: finalized?.staleCheckCount ?? 0,
3049
- sourceFingerprint: finalized?.sourceFingerprint ?? null,
3050
- activeReceiptSha256: finished.activeReceiptSha256,
3051
- closeoutArtifactSha256: finished.closeoutArtifactSha256,
3052
- releasedLeaseIds: finished.releasedLeaseIds,
3053
- authorizationGranted: false,
3054
- };
3055
3393
  }
3056
- throw new Error("Usage: npx --no-install owlrunkit formal <start|check|finish> [options]");
3394
+ throw new Error("Usage: npx --no-install owlrunkit formal <start|preflight|check|attach-evidence|finish> [options]");
3057
3395
  }
3058
3396
  if (command === "candidate") {
3059
3397
  if (action === "freeze") {
@@ -3123,7 +3461,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3123
3461
  }
3124
3462
  if (command === "project") {
3125
3463
  const allowedProjectOptions = {
3126
- init: ["workspace", "definition"],
3464
+ init: ["workspace", "definition", "json"],
3127
3465
  assign: [
3128
3466
  "workspace", "request", "assignment-id", "at", "work-item", "agent",
3129
3467
  "supersedes", "execution-run-id", "execution-work-item", "json",
@@ -3145,6 +3483,11 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3145
3483
  "from-agent", "to-agent", "state", "summary", "completed-units",
3146
3484
  "evidence", "blocker", "decision", "next", "source-fingerprint", "json",
3147
3485
  ],
3486
+ "work-item revise-scope": [
3487
+ "workspace", "revision-id", "at", "assignment-id", "work-item",
3488
+ "owner-agent", "owned-path", "measurable-unit", "measurable-total",
3489
+ "unmeasured", "reason", "evidence", "json",
3490
+ ],
3148
3491
  decision: [
3149
3492
  "workspace", "request", "open", "resolve", "decision-id", "at", "title",
3150
3493
  "question", "owner-agent", "blocking-work-item", "option", "resolution",
@@ -3161,7 +3504,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3161
3504
  "disposition", "summary", "evidence", "decision", "json",
3162
3505
  ],
3163
3506
  integrate: ["workspace", "request", "gate", "at", "summary", "evidence", "json"],
3164
- capture: ["workspace", "request"],
3507
+ capture: ["workspace", "request", "json"],
3165
3508
  "target-snapshot": [
3166
3509
  "workspace", "snapshot-id", "at", "work-item", "target-workspace",
3167
3510
  "allowed-path", "dry-run", "apply", "json",
@@ -3371,6 +3714,56 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3371
3714
  ? transferred
3372
3715
  : withHumanOutput(transferred, formatTeamProjectTransferHuman(transferred));
3373
3716
  }
3717
+ if (action === "work-item revise-scope") {
3718
+ const currentStatus = readTeamProjectStatusV3({ workspaceRoot: root });
3719
+ const workItemId = requireOption(options, "work-item");
3720
+ const currentWorkItem = currentStatus.workItems.find(
3721
+ row => row.workItemId === workItemId,
3722
+ );
3723
+ if (!currentWorkItem) throw new Error(`Unknown team project WorkItem: ${workItemId}.`);
3724
+ const hasUnit = options["measurable-unit"] !== undefined;
3725
+ const hasTotal = options["measurable-total"] !== undefined;
3726
+ if (options.unmeasured === true && (hasUnit || hasTotal)) {
3727
+ throw new Error("--unmeasured cannot be combined with measurable-unit or measurable-total.");
3728
+ }
3729
+ if (hasUnit !== hasTotal) {
3730
+ throw new Error("measurable-unit and measurable-total must be supplied together.");
3731
+ }
3732
+ const measurable = options.unmeasured === true
3733
+ ? null
3734
+ : hasUnit
3735
+ ? {
3736
+ unit: requireOption(options, "measurable-unit"),
3737
+ total: parseCanonicalNonnegativeSafeInteger(
3738
+ requireOption(options, "measurable-total"),
3739
+ "measurable-total",
3740
+ ),
3741
+ }
3742
+ : currentWorkItem.measurable;
3743
+ if (measurable?.total === 0) {
3744
+ throw new Error("measurable-total must be a positive safe integer.");
3745
+ }
3746
+ const revised = reviseTeamProjectWorkItemScopeV1({
3747
+ workspaceRoot: root,
3748
+ revisionId: requireOption(options, "revision-id"),
3749
+ occurredAt: requireOption(options, "at"),
3750
+ assignmentId: requireOption(options, "assignment-id"),
3751
+ workItemId,
3752
+ ownerAgentId: requireOption(options, "owner-agent"),
3753
+ ownedPaths: options["owned-path"] ?? currentWorkItem.ownedPaths,
3754
+ measurable,
3755
+ reason: requireOption(options, "reason"),
3756
+ evidenceRefs: options.evidence ?? [],
3757
+ });
3758
+ return options.json === true
3759
+ ? revised
3760
+ : withHumanOutput(revised, [
3761
+ `Revised WorkItem ${revised.workItemId} scope as ${revised.revisionId}.`,
3762
+ `Owned paths: ${revised.ownedPaths.join(", ")}.`,
3763
+ "Project definition remains immutable; no Git or release authority was granted.",
3764
+ "",
3765
+ ].join("\n"));
3766
+ }
3374
3767
  if (action === "decision") {
3375
3768
  const directDecisionFields = [
3376
3769
  "open",
@@ -3667,13 +4060,13 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3667
4060
  });
3668
4061
  }
3669
4062
  if (action === "status") {
3670
- const status = readTeamProjectStatusV2({ workspaceRoot: root });
4063
+ const status = readTeamProjectStatusV3({ workspaceRoot: root });
3671
4064
  return options.json === true
3672
4065
  ? status
3673
4066
  : withHumanOutput(status, formatTeamProjectStatusHumanV2(status));
3674
4067
  }
3675
4068
  if (action === "takeover") {
3676
- const takeover = buildTeamProjectTakeoverV2({
4069
+ const takeover = buildTeamProjectTakeoverV3({
3677
4070
  workspaceRoot: root,
3678
4071
  agentId: requireOption(options, "agent"),
3679
4072
  });
@@ -3694,7 +4087,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3694
4087
  ? successor
3695
4088
  : withHumanOutput(successor, formatTeamProjectSuccessorHumanV1(successor));
3696
4089
  }
3697
- throw new Error("Usage: npx --no-install owlrunkit project <init|assign|checkpoint|handoff|reject-and-return|reopen-upstream|transfer|decision|verification|integrate|capture|target-snapshot|import-delivery|status|takeover|successor> [options]");
4090
+ throw new Error("Usage: npx --no-install owlrunkit project <init|assign|checkpoint|handoff|reject-and-return|reopen-upstream|transfer|work-item revise-scope|decision|verification|integrate|capture|target-snapshot|import-delivery|status|takeover|successor> [options]");
3698
4091
  }
3699
4092
  if (command === "profiles") {
3700
4093
  const root = requireOption(options, "workspace");
@@ -3937,7 +4330,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3937
4330
  return withControlTransaction(root, () => closeout(options));
3938
4331
  }
3939
4332
  if (command === "finish") return finishExecution(options);
3940
- throw new Error("Usage: npx --no-install owlrunkit <bootstrap|init|doctor|adopt|mode|assurance|fleet|profiles|project|status|formal|candidate|deployment|core-successor|start|verify|repair|offline-export|offline-import|quick-verify|quick-reuse|quick-runtime-verify|quick-attest|quick-metrics|efficiency|finish|plan|inspect|lease|delivery|coverage-adopt|resume|verify-plan|resource-preflight|snapshot|visual-smoke|finalize|ready-for-commit|closeout> [options]");
4333
+ throw new Error("Usage: npx --no-install owlrunkit <bootstrap|init|doctor|adopt|mode|team|assurance|fleet|profiles|project|status|formal|candidate|deployment|core-successor|start|verify|repair|offline-export|offline-import|quick-verify|quick-reuse|quick-runtime-verify|quick-attest|quick-metrics|efficiency|finish|plan|inspect|lease|delivery|coverage-adopt|resume|verify-plan|resource-preflight|snapshot|visual-smoke|finalize|ready-for-commit|closeout> [options]");
3941
4334
  } catch (error) {
3942
4335
  return {
3943
4336
  status: "invalid_input",