perttool 0.8.1 → 0.9.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 (131) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/README.md +73 -26
  3. package/dist/application/cli-facade.d.ts +10 -6
  4. package/dist/application/cli-facade.d.ts.map +1 -1
  5. package/dist/application/cli-facade.js +14 -6
  6. package/dist/application/cli-facade.js.map +1 -1
  7. package/dist/application/contract8-milestone-acceptance.d.ts +74 -0
  8. package/dist/application/contract8-milestone-acceptance.d.ts.map +1 -0
  9. package/dist/application/contract8-milestone-acceptance.js +185 -0
  10. package/dist/application/contract8-milestone-acceptance.js.map +1 -0
  11. package/dist/application/editor-milestone-acceptance.d.ts +75 -0
  12. package/dist/application/editor-milestone-acceptance.d.ts.map +1 -0
  13. package/dist/application/editor-milestone-acceptance.js +161 -0
  14. package/dist/application/editor-milestone-acceptance.js.map +1 -0
  15. package/dist/application/target-governance-init.d.ts +1 -1
  16. package/dist/application/target-governance-init.d.ts.map +1 -1
  17. package/dist/application/target-governance-init.js +3 -5
  18. package/dist/application/target-governance-init.js.map +1 -1
  19. package/dist/application/target-governance-project.d.ts +2 -2
  20. package/dist/application/target-governance-project.d.ts.map +1 -1
  21. package/dist/application/target-historical-graph.d.ts +3 -1
  22. package/dist/application/target-historical-graph.d.ts.map +1 -1
  23. package/dist/application/target-historical-graph.js +85 -2
  24. package/dist/application/target-historical-graph.js.map +1 -1
  25. package/dist/cli.js +348 -28
  26. package/dist/cli.js.map +1 -1
  27. package/dist/command/assurance-discovery.d.ts +4 -3
  28. package/dist/command/assurance-discovery.d.ts.map +1 -1
  29. package/dist/command/assurance-discovery.js +96 -9
  30. package/dist/command/assurance-discovery.js.map +1 -1
  31. package/dist/command/assurance-usage.js +2 -2
  32. package/dist/command/assurance-usage.js.map +1 -1
  33. package/dist/command/discovery.js +4 -4
  34. package/dist/command/discovery.js.map +1 -1
  35. package/dist/command/registry.d.ts +1 -1
  36. package/dist/command/registry.d.ts.map +1 -1
  37. package/dist/command/registry.js +2 -2
  38. package/dist/command/registry.js.map +1 -1
  39. package/dist/command/usage.d.ts.map +1 -1
  40. package/dist/command/usage.js +12 -4
  41. package/dist/command/usage.js.map +1 -1
  42. package/dist/core/index.d.ts +1 -1
  43. package/dist/core/index.d.ts.map +1 -1
  44. package/dist/help/assurance-guide.d.ts +1 -1
  45. package/dist/help/assurance-guide.d.ts.map +1 -1
  46. package/dist/help/assurance-guide.js +45 -19
  47. package/dist/help/assurance-guide.js.map +1 -1
  48. package/dist/help/guide.d.ts +1 -1
  49. package/dist/help/guide.d.ts.map +1 -1
  50. package/dist/help/registry.js +4 -4
  51. package/dist/help/registry.js.map +1 -1
  52. package/dist/history/historical-graph.d.ts +2 -0
  53. package/dist/history/historical-graph.d.ts.map +1 -1
  54. package/dist/history/historical-graph.js +98 -24
  55. package/dist/history/historical-graph.js.map +1 -1
  56. package/dist/history/milestone-acceptance-history.d.ts +59 -0
  57. package/dist/history/milestone-acceptance-history.d.ts.map +1 -0
  58. package/dist/history/milestone-acceptance-history.js +332 -0
  59. package/dist/history/milestone-acceptance-history.js.map +1 -0
  60. package/dist/index.d.ts +10 -9
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +7 -6
  63. package/dist/index.js.map +1 -1
  64. package/dist/migration/grammar-boundary.d.ts +1 -1
  65. package/dist/migration/grammar-boundary.d.ts.map +1 -1
  66. package/dist/migration/grammar-boundary.js +7 -3
  67. package/dist/migration/grammar-boundary.js.map +1 -1
  68. package/dist/milestone-acceptance/advance.d.ts +39 -0
  69. package/dist/milestone-acceptance/advance.d.ts.map +1 -0
  70. package/dist/milestone-acceptance/advance.js +112 -0
  71. package/dist/milestone-acceptance/advance.js.map +1 -0
  72. package/dist/milestone-acceptance/evaluate.d.ts +51 -0
  73. package/dist/milestone-acceptance/evaluate.d.ts.map +1 -0
  74. package/dist/milestone-acceptance/evaluate.js +114 -0
  75. package/dist/milestone-acceptance/evaluate.js.map +1 -0
  76. package/dist/milestone-acceptance/migration.d.ts +25 -0
  77. package/dist/milestone-acceptance/migration.d.ts.map +1 -0
  78. package/dist/milestone-acceptance/migration.js +76 -0
  79. package/dist/milestone-acceptance/migration.js.map +1 -0
  80. package/dist/milestone-acceptance/mutation.d.ts +49 -0
  81. package/dist/milestone-acceptance/mutation.d.ts.map +1 -0
  82. package/dist/milestone-acceptance/mutation.js +136 -0
  83. package/dist/milestone-acceptance/mutation.js.map +1 -0
  84. package/dist/milestone-acceptance/source.d.ts +83 -0
  85. package/dist/milestone-acceptance/source.d.ts.map +1 -0
  86. package/dist/milestone-acceptance/source.js +301 -0
  87. package/dist/milestone-acceptance/source.js.map +1 -0
  88. package/dist/mutation/advance-deletion.d.ts.map +1 -1
  89. package/dist/mutation/advance-deletion.js +6 -1
  90. package/dist/mutation/advance-deletion.js.map +1 -1
  91. package/dist/perttool-vscode-private-0.0.0-d1578b9.vsix +0 -0
  92. package/dist/recommendation/override-types.d.ts +2 -2
  93. package/dist/recommendation/override.d.ts +1 -1
  94. package/dist/recommendation/override.js +2 -2
  95. package/dist/schema/registry.d.ts +1 -1
  96. package/dist/schema/registry.d.ts.map +1 -1
  97. package/dist/schema/registry.js +8 -6
  98. package/dist/schema/registry.js.map +1 -1
  99. package/dist/semantic/validator.d.ts.map +1 -1
  100. package/dist/semantic/validator.js +14 -3
  101. package/dist/semantic/validator.js.map +1 -1
  102. package/dist/session/document-session.d.ts +5 -0
  103. package/dist/session/document-session.d.ts.map +1 -1
  104. package/dist/session/document-session.js +25 -2
  105. package/dist/session/document-session.js.map +1 -1
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/package.json +1 -1
  109. package/schemas/{Perttool.AdvanceResult.v2.schema.json → Perttool.AdvanceResult.v3.schema.json} +36 -5
  110. package/schemas/Perttool.AgentGuidanceResult.v1.schema.json +1 -1
  111. package/schemas/{Perttool.AnalysisResult.v5.schema.json → Perttool.AnalysisResult.v6.schema.json} +12 -5
  112. package/schemas/{Perttool.CheckResult.v4.schema.json → Perttool.CheckResult.v5.schema.json} +12 -5
  113. package/schemas/Perttool.CliError.v1.schema.json +1 -1
  114. package/schemas/Perttool.CommandHelpResult.v1.schema.json +3 -3
  115. package/schemas/Perttool.ExportResult.v1.schema.json +1 -1
  116. package/schemas/Perttool.FormatResult.v1.schema.json +1 -1
  117. package/schemas/Perttool.GuideResult.v1.schema.json +1 -1
  118. package/schemas/Perttool.HistoricalGraphResult.v1.schema.json +100 -2
  119. package/schemas/Perttool.ImportResult.v1.schema.json +1 -1
  120. package/schemas/Perttool.InitResult.v1.schema.json +1 -1
  121. package/schemas/Perttool.MilestoneAcceptanceMigrationResult.v1.schema.json +24 -0
  122. package/schemas/Perttool.MilestoneAcceptanceResult.v1.schema.json +79 -0
  123. package/schemas/{Perttool.MutationResult.v4.schema.json → Perttool.MutationResult.v5.schema.json} +4 -4
  124. package/schemas/{Perttool.NextResult.v6.schema.json → Perttool.NextResult.v7.schema.json} +12 -5
  125. package/schemas/Perttool.OverrideDecision.v1.schema.json +1 -1
  126. package/schemas/Perttool.PlanAssuranceResult.v1.schema.json +1 -1
  127. package/schemas/Perttool.ProjectHistoryResult.v1.schema.json +1 -1
  128. package/schemas/Perttool.ProjectResult.v4.schema.json +2 -2
  129. package/schemas/Perttool.SchemaResult.v1.schema.json +1 -1
  130. package/schemas/Perttool.UnitMigrationResult.v3.schema.json +5 -3
  131. package/schemas/Perttool.VelocityObservationResult.v1.schema.json +1 -1
package/dist/cli.js CHANGED
@@ -19,11 +19,29 @@ import { formatDecimal } from "./model/rational.js";
19
19
  import { convertWithVelocity, durationSuffix } from "./model/units.js";
20
20
  import { recommendationInvariantExitCode } from "./recommendation/failure.js";
21
21
  import { recommendationAnalysisToJson } from "./recommendation/json.js";
22
+ import { applyTextEdits, normalizeTextEdits } from "./mutation/text-edits.js";
23
+ import { createUnifiedDiff } from "./editing/unified-diff.js";
24
+ import { sha256DigestUtf8 } from "./model/sha256.js";
22
25
  import { TARGET_GRAMMAR_6_CAPABILITY, } from "./parser/document-parser.js";
23
26
  import { exportPlanAssuranceMermaid, importPlanAssuranceMermaid, } from "./assurance/mermaid.js";
24
27
  import { getJsonSchemaResult, renderJsonSchemaResult, serializeJsonSchemaResult, } from "./schema/registry.js";
25
28
  import { TOOL_VERSION } from "./version.js";
26
- const { analyzeDocument, checkDocument, selectNextTasks, planFormat, planProjectInit, projectInitResultToJson, renderProjectInitResult, withProjectInitOutput, planUnitMigration, withUnitMigrationWrite, getProjectMetadata, contract7ProjectResultToJson, renderContract7ProjectText, planAdvance, planBatchMutation, planFinishActuals, planLifecycle, planMutation, planAssuranceMutation, renderTargetGovernanceDecision, contract7InspectionResultToJson, contract7MutationResultToJson, contract7SnakeJson, contract6WorkEventToJson, renderAdvanceHistoryGuard, prepareTargetPlanAssuranceAdvanceHistory, withTargetPlanAssuranceAdvanceHistoryRace, persistTargetPlanAssuranceResult, inspectTargetPlanAssurance, inspectTargetProjectHistoryFile, renderTargetProjectHistoryText, targetProjectHistoryResultToJson, observeTargetProjectVelocity, renderTargetVelocityObservationText, targetVelocityObservationResultToJson, getAgentHelp, documentContentFromBytes, readDocumentContent, readBytes, recheckAdvanceHistoryBaseline, createArtifactFile, createTargetGrammar6DocumentFile, replaceTargetGrammar6DocumentFile, inspectTargetHistoricalGraphFile, renderTargetHistoricalGraphText, targetHistoricalGraphResultToJson, } = createCliApplicationFacade(createNodeHost(), createHistoricalGraphGitEvidenceHost());
29
+ import { analyzeDocument as analyzeContract8Document, checkDocument as checkContract8Document, selectNextTasks as selectContract8NextTasks, } from "./application/contract8-milestone-acceptance.js";
30
+ import { persistMilestoneAcceptanceMutation, planAcceptanceReceiptMutation, planCriterionSetReplacement, showMilestoneAcceptance, } from "./milestone-acceptance/mutation.js";
31
+ import { planMilestoneAcceptanceMigration, recheckCommittedMigrationProof, } from "./milestone-acceptance/migration.js";
32
+ import { MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY, milestoneAcceptanceBaseText, parseMilestoneAcceptanceSource } from "./milestone-acceptance/source.js";
33
+ import { planMilestoneAcceptanceAdvance } from "./milestone-acceptance/advance.js";
34
+ const { analyzeDocument: _analyzeContract7Document, checkDocument: _checkContract7Document, selectNextTasks: _selectContract7NextTasks, planFormat, planProjectInit, projectInitResultToJson, renderProjectInitResult, withProjectInitOutput, planUnitMigration, withUnitMigrationWrite, getProjectMetadata, contract7ProjectResultToJson, renderContract7ProjectText, planAdvance, planBatchMutation, planFinishActuals, planLifecycle, planMutation, planAssuranceMutation, renderTargetGovernanceDecision, contract7InspectionResultToJson, contract7MutationResultToJson, contract7SnakeJson, contract6WorkEventToJson, renderAdvanceHistoryGuard, prepareTargetPlanAssuranceAdvanceHistory, prepareAdvanceHistory, withAdvanceHistoryRace, withTargetPlanAssuranceAdvanceHistoryRace, persistTargetPlanAssuranceResult, inspectTargetPlanAssurance, inspectTargetProjectHistoryFile, renderTargetProjectHistoryText, targetProjectHistoryResultToJson, observeTargetProjectVelocity, renderTargetVelocityObservationText, targetVelocityObservationResultToJson, getAgentHelp, documentContentFromBytes, readDocumentContent, readBytes, recheckAdvanceHistoryBaseline, captureAdvanceHistoryBaseline, createArtifactFile, createValidatedDocumentFile, createTargetGrammar6DocumentFile, replaceTargetGrammar6DocumentFile, replaceValidatedDocumentFile, inspectTargetHistoricalGraphFile, renderTargetHistoricalGraphText, targetHistoricalGraphResultToJson, } = createCliApplicationFacade(createNodeHost(), createHistoricalGraphGitEvidenceHost());
35
+ const analyzeDocument = analyzeContract8Document;
36
+ const checkDocument = checkContract8Document;
37
+ const selectNextTasks = selectContract8NextTasks;
38
+ function contract8MutationResultToJson(result, ...args) {
39
+ return Object.freeze({
40
+ ...contract7MutationResultToJson(result, ...args),
41
+ schema_version: "Perttool.MutationResult.v5",
42
+ cli_contract_version: 8,
43
+ });
44
+ }
27
45
  class UsageError extends Error {
28
46
  code = "PTCLI-001";
29
47
  }
@@ -195,7 +213,11 @@ async function readStdin() {
195
213
  return Buffer.concat(chunks);
196
214
  }
197
215
  function writeJson(value) {
198
- process.stdout.write(`${JSON.stringify(value)}\n`);
216
+ const contract8Value = typeof value === "object" && value !== null && !Array.isArray(value) &&
217
+ "cli_contract_version" in value
218
+ ? { ...value, cli_contract_version: 8 }
219
+ : value;
220
+ process.stdout.write(`${JSON.stringify(contract8Value)}\n`);
199
221
  }
200
222
  function snakeJson(value) {
201
223
  if (typeof value === "bigint")
@@ -232,7 +254,7 @@ function cliError(error, exitCode, operation, json) {
232
254
  if (json) {
233
255
  writeJson({
234
256
  schema_version: "Perttool.CliError.v1",
235
- cli_contract_version: 7,
257
+ cli_contract_version: 8,
236
258
  tool_version: TOOL_VERSION,
237
259
  operation,
238
260
  ok: false,
@@ -268,7 +290,7 @@ async function runCheck(args) {
268
290
  if (format === "json") {
269
291
  writeJson({
270
292
  schema_version: result.schemaVersion,
271
- cli_contract_version: 7,
293
+ cli_contract_version: 8,
272
294
  tool_version: TOOL_VERSION,
273
295
  operation: "document.check",
274
296
  ok,
@@ -288,6 +310,7 @@ async function runCheck(args) {
288
310
  },
289
311
  assurance: contract7SnakeJson(result.assurance),
290
312
  assurance_state_counts: contract7SnakeJson(result.assuranceStateCounts),
313
+ acceptance: snakeJson(result.acceptance),
291
314
  });
292
315
  }
293
316
  else {
@@ -345,7 +368,7 @@ async function runProjectInit(args) {
345
368
  const parsed = parseCommandOptions("project.init", args);
346
369
  const format = outputFormat(parsed.values.get("format"));
347
370
  const color = colorMode(parsed.values.get("color"), format);
348
- const durationUnit = enumOption(requiredOption(parsed, "duration-unit"), "duration-unit", new Set(["day", "hour", "point"]));
371
+ const durationUnit = enumOption(parsed.values.get("duration-unit") ?? "point", "duration-unit", new Set(["day", "hour", "point"]));
349
372
  const version = optionalInteger(parsed, "version", 0, 2_147_483_647);
350
373
  let result = planProjectInit({
351
374
  projectId: parsed.positionals[0],
@@ -518,6 +541,28 @@ async function persistGovernedResult(result, request, sourceOperand) {
518
541
  target: request.target,
519
542
  });
520
543
  }
544
+ async function persistContract8CandidateResult(result, request) {
545
+ if (request.mode === "preview" || !result.changed) {
546
+ return Object.freeze({ mode: request.mode, target: request.target, written: false });
547
+ }
548
+ if (!result.ok || !result.governance?.writeAuthorized || result.updatedText === null) {
549
+ throw new TypeError("authorized Contract 8 result does not contain a digest-bound candidate");
550
+ }
551
+ const validator = (candidate) => {
552
+ const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
553
+ return { ok: parsed.ok, diagnostics: [] };
554
+ };
555
+ if (request.mode === "in_place") {
556
+ await replaceValidatedDocumentFile(request.target, result.updatedText, {
557
+ initialDigest: result.originalDigest,
558
+ ...(request.expectedDigest === undefined ? {} : { expectedDigest: request.expectedDigest }),
559
+ }, validator);
560
+ }
561
+ else {
562
+ await createValidatedDocumentFile(request.target, result.updatedText, validator);
563
+ }
564
+ return Object.freeze({ mode: request.mode, target: request.target, written: true });
565
+ }
521
566
  function assertExpectedDigest(request, initialDigest) {
522
567
  if (request.mode === "in_place" &&
523
568
  request.expectedDigest !== undefined &&
@@ -529,6 +574,21 @@ async function commitCandidate(request, candidateText, initialDigest) {
529
574
  if (candidateText === null) {
530
575
  throw new SafeWriteVerificationError("invalid_candidate", "successful editing result has no candidate text");
531
576
  }
577
+ const acceptanceSource = parseMilestoneAcceptanceSource(candidateText, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
578
+ if (acceptanceSource.grammarVersion === 7) {
579
+ const validator = (candidate) => {
580
+ const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
581
+ return { ok: parsed.ok, diagnostics: [] };
582
+ };
583
+ return request.mode === "in_place"
584
+ ? replaceValidatedDocumentFile(request.target, candidateText, {
585
+ initialDigest,
586
+ ...(request.expectedDigest === undefined
587
+ ? {}
588
+ : { expectedDigest: request.expectedDigest }),
589
+ }, validator)
590
+ : createValidatedDocumentFile(request.target, candidateText, validator);
591
+ }
532
592
  return request.mode === "in_place"
533
593
  ? replaceTargetGrammar6DocumentFile(request.target, candidateText, TARGET_GRAMMAR_6_CAPABILITY, {
534
594
  initialDigest,
@@ -596,7 +656,7 @@ async function runFormat(args) {
596
656
  if (format === "json") {
597
657
  writeJson({
598
658
  schema_version: "Perttool.FormatResult.v1",
599
- cli_contract_version: 7,
659
+ cli_contract_version: 8,
600
660
  tool_version: TOOL_VERSION,
601
661
  operation: "document.format",
602
662
  ok,
@@ -1197,7 +1257,7 @@ async function runMutation(resource, action, args) {
1197
1257
  if (result.ok) {
1198
1258
  try {
1199
1259
  if (ok && writeRequest.mode !== "preview") {
1200
- writeResult = await persistGovernedResult(result, writeRequest, sourceOperand);
1260
+ writeResult = await persistContract8CandidateResult(result, writeRequest);
1201
1261
  }
1202
1262
  }
1203
1263
  catch (error) {
@@ -1205,7 +1265,7 @@ async function runMutation(resource, action, args) {
1205
1265
  }
1206
1266
  }
1207
1267
  if (format === "json") {
1208
- writeJson(contract7MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1268
+ writeJson(contract8MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1209
1269
  }
1210
1270
  else {
1211
1271
  if (ok) {
@@ -1281,14 +1341,14 @@ async function runLifecycleMutation(action, args) {
1281
1341
  });
1282
1342
  if (result.ok && ok && writeRequest.mode !== "preview") {
1283
1343
  try {
1284
- writeResult = await persistGovernedResult(result, writeRequest, sourceOperand);
1344
+ writeResult = await persistContract8CandidateResult(result, writeRequest);
1285
1345
  }
1286
1346
  catch (error) {
1287
1347
  return writeFailureExit(error, operation, format === "json");
1288
1348
  }
1289
1349
  }
1290
1350
  if (format === "json") {
1291
- writeJson(contract7MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1351
+ writeJson(contract8MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1292
1352
  }
1293
1353
  else {
1294
1354
  if (ok) {
@@ -1327,7 +1387,7 @@ function unitMigrationJson(result, source, sourceDigest, ok) {
1327
1387
  });
1328
1388
  return {
1329
1389
  schema_version: result.schemaVersion,
1330
- cli_contract_version: 7,
1390
+ cli_contract_version: 8,
1331
1391
  tool_version: TOOL_VERSION,
1332
1392
  operation: "project.migrate-unit",
1333
1393
  ok,
@@ -1628,16 +1688,94 @@ async function runAdvance(args) {
1628
1688
  catch (error) {
1629
1689
  return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dag.advance", format === "json");
1630
1690
  }
1631
- const planned = planAdvance(input.text, {
1691
+ const acceptancePlan = planMilestoneAcceptanceAdvance(input.text, {
1692
+ maxDiagnostics,
1693
+ originalLabel: source,
1694
+ updatedLabel: "candidate",
1695
+ provisionalPlanner: (baseText) => planAdvance(baseText, {
1696
+ maxDiagnostics,
1697
+ originalLabel: source,
1698
+ updatedLabel: "candidate",
1699
+ }),
1700
+ });
1701
+ if (!acceptancePlan.ok) {
1702
+ if (format === "json")
1703
+ writeJson({
1704
+ schema_version: "Perttool.AdvanceResult.v3",
1705
+ cli_contract_version: 8,
1706
+ tool_version: TOOL_VERSION,
1707
+ operation: "dag.advance",
1708
+ ok: false,
1709
+ document_id: /^project ([A-Za-z][A-Za-z0-9_-]*):$/mu.exec(input.text)?.[1] ?? null,
1710
+ source,
1711
+ source_digest: input.digest,
1712
+ diagnostics: acceptancePlan.diagnostics.map(jsonDiagnostic),
1713
+ diagnostics_truncated: false,
1714
+ changed: acceptancePlan.provisional !== null,
1715
+ original_digest: acceptancePlan.originalDigest,
1716
+ updated_digest: acceptancePlan.provisional?.updatedDigest ?? null,
1717
+ updated_text: acceptancePlan.provisional?.updatedText ?? null,
1718
+ diff: acceptancePlan.provisional?.diff ?? null,
1719
+ edits: snakeJson(acceptancePlan.provisional?.edits ?? []),
1720
+ write: { mode: writeRequest.mode, target: writeRequest.target, written: false },
1721
+ governance: null,
1722
+ lifecycle: null,
1723
+ advance: acceptancePlan.provisional === null ? null : snakeJson({
1724
+ ...acceptancePlan.provisional.advance,
1725
+ removedWorkEventIds: [],
1726
+ removedAssuranceRecordIds: [],
1727
+ updatedAssuranceReceiptIds: [],
1728
+ }),
1729
+ history_guard: null,
1730
+ assurance_guard: null,
1731
+ acceptance_guard: snakeJson(acceptancePlan.acceptanceGuard),
1732
+ });
1733
+ else {
1734
+ if (acceptancePlan.provisional !== null)
1735
+ process.stdout.write(parsed.flags.has("diff") ? acceptancePlan.provisional.diff : acceptancePlan.provisional.updatedText);
1736
+ for (const diagnostic of acceptancePlan.diagnostics)
1737
+ process.stderr.write(`${renderDiagnostic(diagnostic, source, color)}\n`);
1738
+ }
1739
+ return 1;
1740
+ }
1741
+ const contract7BaseText = milestoneAcceptanceBaseText(input.text);
1742
+ const contract7Planned = planAdvance(contract7BaseText, {
1632
1743
  maxDiagnostics,
1633
1744
  originalLabel: source,
1634
1745
  updatedLabel: "candidate",
1635
1746
  governance: governanceRequest(parsed, writeRequest),
1636
1747
  });
1748
+ const combinedEdits = contract7Planned.updatedText === null
1749
+ ? contract7Planned.edits
1750
+ : normalizeTextEdits(input.text, [...contract7Planned.edits, ...acceptancePlan.provisional.edits].filter((edit, index, values) => values.findIndex((candidate) => candidate.startOffset === edit.startOffset &&
1751
+ candidate.endOffset === edit.endOffset &&
1752
+ candidate.replacement === edit.replacement) === index), "Contract 8 acceptance-aware advance");
1753
+ const combinedText = contract7Planned.updatedText === null
1754
+ ? null
1755
+ : applyTextEdits(input.text, combinedEdits);
1756
+ const combinedSource = combinedText === null
1757
+ ? null
1758
+ : parseMilestoneAcceptanceSource(combinedText, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
1759
+ if (combinedSource !== null && !combinedSource.ok) {
1760
+ throw new Error("acceptance-aware assurance advance lost Grammar 7 validation");
1761
+ }
1762
+ const planned = Object.freeze({
1763
+ ...contract7Planned,
1764
+ schemaVersion: "Perttool.AdvanceResult.v3",
1765
+ originalDigest: input.digest,
1766
+ updatedText: combinedText,
1767
+ updatedDigest: combinedText === null ? null : sha256DigestUtf8(combinedText),
1768
+ diff: combinedText === null ? null : createUnifiedDiff(input.text, combinedText, {
1769
+ originalLabel: source,
1770
+ updatedLabel: "candidate",
1771
+ }),
1772
+ edits: combinedEdits,
1773
+ acceptanceGuard: acceptancePlan.acceptanceGuard,
1774
+ });
1637
1775
  const initialWarningFailure = parsed.flags.has("warnings-as-errors") &&
1638
1776
  (planned.diagnosticsTruncated ||
1639
1777
  planned.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
1640
- const prepared = await prepareTargetPlanAssuranceAdvanceHistory(input.text, planned, TARGET_GRAMMAR_6_CAPABILITY, {
1778
+ const preparedBase = await prepareAdvanceHistory(input.text, planned, {
1641
1779
  mode: writeRequest.mode === "out"
1642
1780
  ? "out"
1643
1781
  : writeRequest.mode,
@@ -1649,6 +1787,28 @@ async function runAdvance(args) {
1649
1787
  forceRequested,
1650
1788
  warningDenied: initialWarningFailure,
1651
1789
  maxDiagnostics,
1790
+ documentValidator: (candidateText, candidateMaxDiagnostics) => {
1791
+ const acceptanceSource = parseMilestoneAcceptanceSource(candidateText, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
1792
+ const checked = checkContract8Document(candidateText, { maxDiagnostics: candidateMaxDiagnostics });
1793
+ return {
1794
+ ok: checked.ok && acceptanceSource.ok,
1795
+ document: checked.document,
1796
+ documentId: checked.documentId,
1797
+ diagnostics: checked.diagnostics,
1798
+ diagnosticsTruncated: checked.diagnosticsTruncated,
1799
+ };
1800
+ },
1801
+ });
1802
+ const prepared = Object.freeze({
1803
+ ...preparedBase,
1804
+ result: Object.freeze({
1805
+ ...preparedBase.result,
1806
+ schemaVersion: "Perttool.AdvanceResult.v3",
1807
+ governance: planned.governance,
1808
+ assuranceGuard: planned.assuranceGuard,
1809
+ acceptanceGuard: acceptancePlan.acceptanceGuard,
1810
+ advance: planned.advance,
1811
+ }),
1652
1812
  });
1653
1813
  let result = prepared.result;
1654
1814
  const warningFailure = parsed.flags.has("warnings-as-errors") &&
@@ -1671,13 +1831,20 @@ async function runAdvance(args) {
1671
1831
  result.historyGuard?.status === "forced")) {
1672
1832
  const recheck = await recheckAdvanceHistoryBaseline(prepared.baseline, sourceOperand);
1673
1833
  if (!recheck.ok) {
1674
- result = withTargetPlanAssuranceAdvanceHistoryRace(result, recheck, maxDiagnostics);
1834
+ result = Object.freeze({
1835
+ ...withAdvanceHistoryRace(result, recheck, maxDiagnostics),
1836
+ schemaVersion: "Perttool.AdvanceResult.v3",
1837
+ governance: result.governance,
1838
+ assuranceGuard: result.assuranceGuard,
1839
+ acceptanceGuard: result.acceptanceGuard,
1840
+ advance: result.advance,
1841
+ });
1675
1842
  ok = false;
1676
1843
  historyRace = true;
1677
1844
  }
1678
1845
  }
1679
1846
  if (ok && writeRequest.mode !== "preview") {
1680
- writeResult = await persistGovernedResult(result, writeRequest, sourceOperand);
1847
+ writeResult = await persistContract8CandidateResult(result, writeRequest);
1681
1848
  }
1682
1849
  }
1683
1850
  catch (error) {
@@ -1685,7 +1852,12 @@ async function runAdvance(args) {
1685
1852
  }
1686
1853
  }
1687
1854
  if (format === "json") {
1688
- writeJson(contract7MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), "dag.advance", source, writeResult));
1855
+ writeJson({
1856
+ ...contract7MutationResultToJson((ok ? result : Object.freeze({ ...result, ok: false })), "dag.advance", source, writeResult),
1857
+ schema_version: "Perttool.AdvanceResult.v3",
1858
+ cli_contract_version: 8,
1859
+ acceptance_guard: snakeJson(result.acceptanceGuard),
1860
+ });
1689
1861
  }
1690
1862
  else {
1691
1863
  if (result.advance !== null) {
@@ -2046,7 +2218,7 @@ async function runAnalyze(args) {
2046
2218
  if (format === "json") {
2047
2219
  writeJson({
2048
2220
  schema_version: result.schemaVersion,
2049
- cli_contract_version: 7,
2221
+ cli_contract_version: 8,
2050
2222
  tool_version: TOOL_VERSION,
2051
2223
  operation: "dag.analyze",
2052
2224
  ok,
@@ -2079,6 +2251,7 @@ async function runAnalyze(args) {
2079
2251
  : resourceJson(result.resource, result.durationUnit, result.precision),
2080
2252
  temporal: snakeJson(result.temporal),
2081
2253
  assurance: contract7SnakeJson(result.assurance),
2254
+ acceptance: snakeJson(result.acceptance),
2082
2255
  });
2083
2256
  }
2084
2257
  else {
@@ -2193,7 +2366,7 @@ async function runRender(args) {
2193
2366
  if (format === "json") {
2194
2367
  writeJson({
2195
2368
  schema_version: "Perttool.ExportResult.v1",
2196
- cli_contract_version: 7,
2369
+ cli_contract_version: 8,
2197
2370
  tool_version: TOOL_VERSION,
2198
2371
  operation: "dag.render",
2199
2372
  ok,
@@ -2306,7 +2479,7 @@ async function runImport(args) {
2306
2479
  if (format === "json") {
2307
2480
  writeJson({
2308
2481
  schema_version: "Perttool.ImportResult.v1",
2309
- cli_contract_version: 7,
2482
+ cli_contract_version: 8,
2310
2483
  tool_version: TOOL_VERSION,
2311
2484
  operation: "dag.import",
2312
2485
  ok,
@@ -2615,7 +2788,7 @@ async function runNext(args) {
2615
2788
  if (format === "json") {
2616
2789
  writeJson({
2617
2790
  schema_version: "Perttool.CliError.v1",
2618
- cli_contract_version: 7,
2791
+ cli_contract_version: 8,
2619
2792
  tool_version: TOOL_VERSION,
2620
2793
  operation: "dag.next",
2621
2794
  ok: false,
@@ -2636,7 +2809,7 @@ async function runNext(args) {
2636
2809
  if (format === "json") {
2637
2810
  writeJson({
2638
2811
  schema_version: result.schemaVersion,
2639
- cli_contract_version: 7,
2812
+ cli_contract_version: 8,
2640
2813
  recommendation_interface_version: 1,
2641
2814
  tool_version: TOOL_VERSION,
2642
2815
  operation: "dag.next",
@@ -2650,6 +2823,7 @@ async function runNext(args) {
2650
2823
  ...(result.durationUnit === null ? {} : nextJson(result)),
2651
2824
  temporal: snakeJson(result.temporal),
2652
2825
  assurance: contract7SnakeJson(result.assurance),
2826
+ acceptance: snakeJson(result.acceptance),
2653
2827
  });
2654
2828
  }
2655
2829
  else {
@@ -2664,6 +2838,142 @@ async function runNext(args) {
2664
2838
  }
2665
2839
  return ok ? 0 : 1;
2666
2840
  }
2841
+ async function runMilestoneAcceptance(action, args) {
2842
+ const operation = `milestone-acceptance.${action}`;
2843
+ const parsed = parseCommandOptions(operation, args);
2844
+ const format = outputFormat(parsed.values.get("format"));
2845
+ const sourceOperand = parsed.positionals[0];
2846
+ if (sourceOperand === undefined)
2847
+ throw new UsageError(`${operation} requires <file>`);
2848
+ const input = await readDocument(sourceOperand);
2849
+ if (action === "show") {
2850
+ if (parsed.positionals.length !== 1)
2851
+ throw new UsageError("milestone acceptance show requires exactly one <file>");
2852
+ const result = checkDocument(input.text).acceptance ?? showMilestoneAcceptance(input.text, []);
2853
+ if (format === "json")
2854
+ writeJson({ schema_version: "Perttool.MilestoneAcceptanceResult.v1", cli_contract_version: 8, tool_version: TOOL_VERSION, operation, ok: result.ok, milestones: snakeJson(result.milestones), diagnostics: snakeJson(result.diagnostics) });
2855
+ else
2856
+ process.stdout.write(`${result.milestones.map(({ milestoneId, closure, acceptance }) => `${milestoneId} closure=${closure} acceptance=${acceptance}`).join("\n")}\n`);
2857
+ return result.ok ? 0 : 1;
2858
+ }
2859
+ if (parsed.positionals.length !== 4)
2860
+ throw new UsageError(`${operation} requires four operands`);
2861
+ const request = editingWriteRequest(parsed, sourceOperand);
2862
+ if (request.mode === "out")
2863
+ throw new UsageError(`${operation} does not support --out in Contract 8`);
2864
+ const governance = governanceRequest(parsed, request);
2865
+ let result;
2866
+ if (action === "replace") {
2867
+ const criteria = (parsed.repeatedValues.get("criterion") ?? []).map((value) => {
2868
+ const [criterionId, requiredText, evidenceKind, ...description] = value.split(":");
2869
+ if (criterionId === undefined || !["required", "optional"].includes(requiredText ?? "") || !["test", "command", "artifact", "observation", "owner"].includes(evidenceKind ?? "") || description.length === 0)
2870
+ throw new UsageError("--criterion must be ID:required|optional:kind:description");
2871
+ return { criterionId, required: requiredText === "required", evidenceKind: evidenceKind, description: description.join(":") };
2872
+ });
2873
+ result = planCriterionSetReplacement(input.text, { milestoneId: parsed.positionals[1], setId: parsed.positionals[2], revisionId: parsed.positionals[3], criteria }, { governance });
2874
+ }
2875
+ else {
2876
+ result = planAcceptanceReceiptMutation(input.text, {
2877
+ setId: parsed.positionals[1], criterionId: parsed.positionals[2], receiptId: parsed.positionals[3], action: action,
2878
+ ...(parsed.values.get("evidence-kind") === undefined ? {} : { evidenceKind: parsed.values.get("evidence-kind") }),
2879
+ ...(parsed.values.get("evidence-reference") === undefined ? {} : { evidenceReference: parsed.values.get("evidence-reference") }),
2880
+ ...(parsed.values.get("evidence-revision") === undefined ? {} : { evidenceRevision: parsed.values.get("evidence-revision") }),
2881
+ ...(parsed.values.get("verifier") === undefined ? {} : { verifier: parsed.values.get("verifier") }),
2882
+ ...(parsed.values.get("occurred-at") === undefined ? {} : { occurredAt: parsed.values.get("occurred-at") }),
2883
+ ...(parsed.values.get("reason") === undefined ? {} : { reason: parsed.values.get("reason") }),
2884
+ ...(parsed.values.get("revokes") === undefined ? {} : { revokes: parsed.values.get("revokes") }),
2885
+ }, { governance });
2886
+ }
2887
+ let written = false;
2888
+ if (result.ok && request.mode === "in_place" && result.changed) {
2889
+ await persistMilestoneAcceptanceMutation(sourceOperand, result, request.expectedDigest);
2890
+ written = true;
2891
+ }
2892
+ if (format === "json")
2893
+ writeJson({
2894
+ schema_version: "Perttool.MutationResult.v5",
2895
+ cli_contract_version: 8,
2896
+ tool_version: TOOL_VERSION,
2897
+ operation,
2898
+ ok: result.ok,
2899
+ document_id: /^project ([A-Za-z][A-Za-z0-9_-]*):$/mu.exec(input.text)?.[1] ?? null,
2900
+ source: sourceOperand,
2901
+ source_digest: input.digest,
2902
+ diagnostics: result.diagnostics.map((code) => jsonDiagnostic({
2903
+ code,
2904
+ severity: code === "PTGOV-103" || code === "PTGOV-104" ? "warning" : "error",
2905
+ message: code,
2906
+ helpTopic: "editing",
2907
+ })),
2908
+ diagnostics_truncated: false,
2909
+ changed: result.changed,
2910
+ original_digest: result.originalDigest,
2911
+ updated_digest: result.updatedDigest,
2912
+ updated_text: result.updatedText,
2913
+ diff: result.updatedText === null ? null : createUnifiedDiff(input.text, result.updatedText, { originalLabel: sourceOperand, updatedLabel: "candidate" }),
2914
+ edits: result.changed && result.updatedText !== null ? [{ start_offset: 0, end_offset: input.text.length, replacement: result.updatedText }] : [],
2915
+ write: { mode: request.mode, target: request.target, written },
2916
+ governance: result.governance === null ? null : {
2917
+ ...snakeJson(result.governance),
2918
+ schema_version: "Perttool.GovernanceDecision.v2",
2919
+ governance_interface_version: 2,
2920
+ governance_semantics_version: 2,
2921
+ },
2922
+ lifecycle: null,
2923
+ assurance_impact: null,
2924
+ });
2925
+ else if (result.updatedText !== null)
2926
+ process.stdout.write(result.updatedText);
2927
+ return result.ok ? 0 : 1;
2928
+ }
2929
+ async function runDocumentMigration(args) {
2930
+ const parsed = parseCommandOptions("document.migrate", args);
2931
+ if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "7")
2932
+ throw new UsageError("document migrate requires <file> --target-grammar 7");
2933
+ const sourceOperand = parsed.positionals[0];
2934
+ if (sourceOperand === "-")
2935
+ throw new UsageError("document migrate requires a repository file");
2936
+ const format = outputFormat(parsed.values.get("format"));
2937
+ const input = await readDocument(sourceOperand);
2938
+ const baseline = await captureAdvanceHistoryBaseline({ targetPath: sourceOperand, expectedSourceDigest: input.digest });
2939
+ const toProof = (value) => value.status === "complete" && value.repositorySnapshotId !== null &&
2940
+ value.repositoryRelativePath !== null && value.objectFormat !== null &&
2941
+ value.headCommitId !== null && value.headBlobId !== null &&
2942
+ value.indexBlobId !== null && value.currentSourceDigest !== null
2943
+ ? {
2944
+ repositoryId: value.repositorySnapshotId,
2945
+ repositoryRelativePath: value.repositoryRelativePath,
2946
+ objectFormat: value.objectFormat,
2947
+ headCommit: value.headCommitId,
2948
+ headBlob: value.headBlobId,
2949
+ stage0Blob: value.indexBlobId,
2950
+ sourceDigest: value.currentSourceDigest,
2951
+ }
2952
+ : null;
2953
+ const proof = toProof(baseline);
2954
+ let result = proof === null
2955
+ ? { ok: false, modelVersion: 1, changed: false, sourceGrammarVersion: null, targetGrammarVersion: null, sourceDigest: input.digest, candidateDigest: null, grandfatheredMilestoneIds: Object.freeze([]), candidateText: null, diagnostics: Object.freeze(["PTMAC-109"]) }
2956
+ : planMilestoneAcceptanceMigration(input.text, proof);
2957
+ let race = false;
2958
+ if (result.ok && result.changed && result.candidateText !== null && parsed.flags.has("write")) {
2959
+ const current = toProof(await captureAdvanceHistoryBaseline({
2960
+ targetPath: sourceOperand,
2961
+ expectedSourceDigest: input.digest,
2962
+ }));
2963
+ if (proof === null || current === null || !recheckCommittedMigrationProof(proof, current)) {
2964
+ result = Object.freeze({ ...result, ok: false, diagnostics: Object.freeze(["PTMAC-110"]) });
2965
+ race = true;
2966
+ }
2967
+ else {
2968
+ await replaceValidatedDocumentFile(sourceOperand, result.candidateText, { initialDigest: input.digest, ...(parsed.values.get("expect-digest") === undefined ? {} : { expectedDigest: parsed.values.get("expect-digest") }) }, (candidate) => ({ ok: parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY).ok, diagnostics: [] }));
2969
+ }
2970
+ }
2971
+ if (format === "json")
2972
+ writeJson({ schema_version: "Perttool.MilestoneAcceptanceMigrationResult.v1", cli_contract_version: 8, tool_version: TOOL_VERSION, operation: "document.migrate", ...snakeJson(result) });
2973
+ else if (result.candidateText !== null)
2974
+ process.stdout.write(result.candidateText);
2975
+ return result.ok ? 0 : race ? 5 : 1;
2976
+ }
2667
2977
  function runGuide(args) {
2668
2978
  const parsed = parseCommandOptions("guide", args);
2669
2979
  if (parsed.positionals.length > 2) {
@@ -2690,13 +3000,13 @@ function runGuide(args) {
2690
3000
  }
2691
3001
  function runCommandHelp(args) {
2692
3002
  const parsed = parseCommandOptions("help", args);
2693
- if (parsed.positionals.length > 2) {
2694
- throw new UsageError("help accepts at most <resource> <action>");
3003
+ if (parsed.positionals.length > 3) {
3004
+ throw new UsageError("help accepts at most <resource> <group> <action>");
2695
3005
  }
2696
3006
  const format = outputFormat(parsed.values.get("format"));
2697
3007
  const result = getAssuranceCommandDiscovery({
2698
3008
  resource: parsed.positionals[0] ?? null,
2699
- action: parsed.positionals[1] ?? null,
3009
+ action: parsed.positionals.length < 2 ? null : parsed.positionals.slice(1).join(" "),
2700
3010
  });
2701
3011
  if (format === "json") {
2702
3012
  process.stdout.write(serializeAssuranceCommandHelpResult(result));
@@ -2770,7 +3080,7 @@ function runAgentHelp(args) {
2770
3080
  const { schema_version: schemaVersion, ...payload } = projected;
2771
3081
  writeJson({
2772
3082
  schema_version: schemaVersion,
2773
- cli_contract_version: 7,
3083
+ cli_contract_version: 8,
2774
3084
  ...payload,
2775
3085
  });
2776
3086
  }
@@ -2974,14 +3284,14 @@ async function runAssuranceMutation(resource, action, args) {
2974
3284
  });
2975
3285
  if (result.ok && writeRequest.mode !== "preview") {
2976
3286
  try {
2977
- writeResult = await persistGovernedResult(result, writeRequest, sourceOperand);
3287
+ writeResult = await persistContract8CandidateResult(result, writeRequest);
2978
3288
  }
2979
3289
  catch (error) {
2980
3290
  return writeFailureExit(error, operation, format === "json");
2981
3291
  }
2982
3292
  }
2983
3293
  if (format === "json") {
2984
- writeJson(contract7MutationResultToJson(result, operation, source, writeResult));
3294
+ writeJson(contract8MutationResultToJson(result, operation, source, writeResult));
2985
3295
  }
2986
3296
  else {
2987
3297
  if (result.ok) {
@@ -3021,6 +3331,8 @@ async function dispatchCommand(descriptor, args) {
3021
3331
  return runCheck(args);
3022
3332
  case "document.format":
3023
3333
  return runFormat(args);
3334
+ case "document.migrate":
3335
+ return runDocumentMigration(args);
3024
3336
  case "agent.help":
3025
3337
  return runAgentHelp(args);
3026
3338
  case "project.init":
@@ -3051,6 +3363,14 @@ async function dispatchCommand(descriptor, args) {
3051
3363
  return runLifecycleMutation("suspend", args);
3052
3364
  case "task.resume":
3053
3365
  return runLifecycleMutation("resume", args);
3366
+ case "milestone-acceptance.show":
3367
+ case "milestone-acceptance.replace":
3368
+ case "milestone-acceptance.verify":
3369
+ case "milestone-acceptance.fail":
3370
+ case "milestone-acceptance.unavailable":
3371
+ case "milestone-acceptance.revoke":
3372
+ case "milestone-acceptance.waive":
3373
+ return runMilestoneAcceptance(descriptor.path[2], args);
3054
3374
  case "plan-assurance.show":
3055
3375
  return runPlanAssuranceInspection("show", args);
3056
3376
  case "plan-assurance.hash":
@@ -3069,7 +3389,7 @@ async function dispatchCommand(descriptor, args) {
3069
3389
  const [resource, action] = descriptor.path;
3070
3390
  return runMutation(resource, action, args);
3071
3391
  }
3072
- throw new Error(`no Contract 7 handler for ${descriptor.operation}`);
3392
+ throw new Error(`no Contract 8 handler for ${descriptor.operation}`);
3073
3393
  }
3074
3394
  function emitCommandUsage(error, json) {
3075
3395
  if (json) {