perttool 0.10.5 → 0.11.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 (241) hide show
  1. package/CHANGELOG.md +52 -1
  2. package/README.md +274 -606
  3. package/dist/application/cli-facade.d.ts +4 -10
  4. package/dist/application/cli-facade.d.ts.map +1 -1
  5. package/dist/application/cli-facade.js +1 -1
  6. package/dist/application/cli-facade.js.map +1 -1
  7. package/dist/application/contract10-candidate.d.ts +33 -0
  8. package/dist/application/contract10-candidate.d.ts.map +1 -0
  9. package/dist/application/contract10-candidate.js +38 -0
  10. package/dist/application/contract10-candidate.js.map +1 -0
  11. package/dist/application/contract10-planning-history.d.ts +4 -0
  12. package/dist/application/contract10-planning-history.d.ts.map +1 -0
  13. package/dist/application/contract10-planning-history.js +28 -0
  14. package/dist/application/contract10-planning-history.js.map +1 -0
  15. package/dist/application/contract10-planning.d.ts +61 -0
  16. package/dist/application/contract10-planning.d.ts.map +1 -0
  17. package/dist/application/contract10-planning.js +165 -0
  18. package/dist/application/contract10-planning.js.map +1 -0
  19. package/dist/application/contract10-runtime.d.ts +185 -0
  20. package/dist/application/contract10-runtime.d.ts.map +1 -0
  21. package/dist/application/contract10-runtime.js +236 -0
  22. package/dist/application/contract10-runtime.js.map +1 -0
  23. package/dist/application/contract8-milestone-acceptance.d.ts +6 -22
  24. package/dist/application/contract8-milestone-acceptance.d.ts.map +1 -1
  25. package/dist/application/contract8-milestone-acceptance.js +21 -99
  26. package/dist/application/contract8-milestone-acceptance.js.map +1 -1
  27. package/dist/application/contract8-milestone-read.d.ts +25 -0
  28. package/dist/application/contract8-milestone-read.d.ts.map +1 -0
  29. package/dist/application/contract8-milestone-read.js +111 -0
  30. package/dist/application/contract8-milestone-read.js.map +1 -0
  31. package/dist/application/contract9-assurance-evaluate.d.ts +3 -0
  32. package/dist/application/contract9-assurance-evaluate.d.ts.map +1 -0
  33. package/dist/application/contract9-assurance-evaluate.js +75 -0
  34. package/dist/application/contract9-assurance-evaluate.js.map +1 -0
  35. package/dist/application/contract9-assurance.d.ts +1 -2
  36. package/dist/application/contract9-assurance.d.ts.map +1 -1
  37. package/dist/application/contract9-assurance.js +2 -56
  38. package/dist/application/contract9-assurance.js.map +1 -1
  39. package/dist/application/contract9-candidate.d.ts +8 -0
  40. package/dist/application/contract9-candidate.d.ts.map +1 -1
  41. package/dist/application/contract9-candidate.js +36 -11
  42. package/dist/application/contract9-candidate.js.map +1 -1
  43. package/dist/application/contract9-mixed-mutation.d.ts +3 -0
  44. package/dist/application/contract9-mixed-mutation.d.ts.map +1 -1
  45. package/dist/application/contract9-mixed-mutation.js +5 -4
  46. package/dist/application/contract9-mixed-mutation.js.map +1 -1
  47. package/dist/application/contract9-temporal.js +1 -1
  48. package/dist/application/contract9-temporal.js.map +1 -1
  49. package/dist/application/target-actuals-analysis.d.ts.map +1 -1
  50. package/dist/application/target-actuals-analysis.js +10 -6
  51. package/dist/application/target-actuals-analysis.js.map +1 -1
  52. package/dist/application/target-temporal-analysis.d.ts +1 -0
  53. package/dist/application/target-temporal-analysis.d.ts.map +1 -1
  54. package/dist/application/target-temporal-analysis.js +5 -1
  55. package/dist/application/target-temporal-analysis.js.map +1 -1
  56. package/dist/cli.js +761 -87
  57. package/dist/cli.js.map +1 -1
  58. package/dist/command/contract10-discovery.d.ts +17 -0
  59. package/dist/command/contract10-discovery.d.ts.map +1 -0
  60. package/dist/command/contract10-discovery.js +304 -0
  61. package/dist/command/contract10-discovery.js.map +1 -0
  62. package/dist/command/contract10-usage.d.ts +24 -0
  63. package/dist/command/contract10-usage.d.ts.map +1 -0
  64. package/dist/command/contract10-usage.js +49 -0
  65. package/dist/command/contract10-usage.js.map +1 -0
  66. package/dist/core/index.d.ts +11 -2
  67. package/dist/core/index.d.ts.map +1 -1
  68. package/dist/core/index.js +3 -1
  69. package/dist/core/index.js.map +1 -1
  70. package/dist/help/assurance-guide.js +1 -1
  71. package/dist/help/assurance-guide.js.map +1 -1
  72. package/dist/help/contract10-guide.d.ts +10 -0
  73. package/dist/help/contract10-guide.d.ts.map +1 -0
  74. package/dist/help/contract10-guide.js +244 -0
  75. package/dist/help/contract10-guide.js.map +1 -0
  76. package/dist/index.d.ts +18 -8
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +8 -5
  79. package/dist/index.js.map +1 -1
  80. package/dist/milestone-acceptance/advance.d.ts +9 -0
  81. package/dist/milestone-acceptance/advance.d.ts.map +1 -1
  82. package/dist/milestone-acceptance/advance.js +29 -2
  83. package/dist/milestone-acceptance/advance.js.map +1 -1
  84. package/dist/milestone-acceptance/mutation.d.ts +2 -0
  85. package/dist/milestone-acceptance/mutation.d.ts.map +1 -1
  86. package/dist/milestone-acceptance/mutation.js +60 -20
  87. package/dist/milestone-acceptance/mutation.js.map +1 -1
  88. package/dist/model/source-result.d.ts +12 -0
  89. package/dist/model/source-result.d.ts.map +1 -0
  90. package/dist/model/source-result.js +16 -0
  91. package/dist/model/source-result.js.map +1 -0
  92. package/dist/mutation/advance-deletion.d.ts +1 -0
  93. package/dist/mutation/advance-deletion.d.ts.map +1 -1
  94. package/dist/mutation/advance-deletion.js +4 -1
  95. package/dist/mutation/advance-deletion.js.map +1 -1
  96. package/dist/mutation/validated-source.d.ts +30 -0
  97. package/dist/mutation/validated-source.d.ts.map +1 -0
  98. package/dist/mutation/validated-source.js +58 -0
  99. package/dist/mutation/validated-source.js.map +1 -0
  100. package/dist/node/planning-token-store.d.ts +3 -0
  101. package/dist/node/planning-token-store.d.ts.map +1 -0
  102. package/dist/node/planning-token-store.js +90 -0
  103. package/dist/node/planning-token-store.js.map +1 -0
  104. package/dist/parser/document-parser.d.ts +1 -0
  105. package/dist/parser/document-parser.d.ts.map +1 -1
  106. package/dist/parser/document-parser.js +1 -1
  107. package/dist/parser/document-parser.js.map +1 -1
  108. package/dist/perttool-vscode-private-0.0.0-d1578b9.vsix +0 -0
  109. package/dist/planning-pool/advance.d.ts +10 -0
  110. package/dist/planning-pool/advance.d.ts.map +1 -0
  111. package/dist/planning-pool/advance.js +158 -0
  112. package/dist/planning-pool/advance.js.map +1 -0
  113. package/dist/planning-pool/format.d.ts +12 -0
  114. package/dist/planning-pool/format.d.ts.map +1 -0
  115. package/dist/planning-pool/format.js +199 -0
  116. package/dist/planning-pool/format.js.map +1 -0
  117. package/dist/planning-pool/history-guard.d.ts +19 -0
  118. package/dist/planning-pool/history-guard.d.ts.map +1 -0
  119. package/dist/planning-pool/history-guard.js +123 -0
  120. package/dist/planning-pool/history-guard.js.map +1 -0
  121. package/dist/planning-pool/history-types.d.ts +174 -0
  122. package/dist/planning-pool/history-types.d.ts.map +1 -0
  123. package/dist/planning-pool/history-types.js +2 -0
  124. package/dist/planning-pool/history-types.js.map +1 -0
  125. package/dist/planning-pool/history.d.ts +11 -0
  126. package/dist/planning-pool/history.d.ts.map +1 -0
  127. package/dist/planning-pool/history.js +977 -0
  128. package/dist/planning-pool/history.js.map +1 -0
  129. package/dist/planning-pool/human.d.ts +9 -0
  130. package/dist/planning-pool/human.d.ts.map +1 -0
  131. package/dist/planning-pool/human.js +305 -0
  132. package/dist/planning-pool/human.js.map +1 -0
  133. package/dist/planning-pool/intent-types.d.ts +76 -0
  134. package/dist/planning-pool/intent-types.d.ts.map +1 -0
  135. package/dist/planning-pool/intent-types.js +2 -0
  136. package/dist/planning-pool/intent-types.js.map +1 -0
  137. package/dist/planning-pool/intent.d.ts +7 -0
  138. package/dist/planning-pool/intent.d.ts.map +1 -0
  139. package/dist/planning-pool/intent.js +590 -0
  140. package/dist/planning-pool/intent.js.map +1 -0
  141. package/dist/planning-pool/observation-types.d.ts +143 -0
  142. package/dist/planning-pool/observation-types.d.ts.map +1 -0
  143. package/dist/planning-pool/observation-types.js +2 -0
  144. package/dist/planning-pool/observation-types.js.map +1 -0
  145. package/dist/planning-pool/observation.d.ts +8 -0
  146. package/dist/planning-pool/observation.d.ts.map +1 -0
  147. package/dist/planning-pool/observation.js +582 -0
  148. package/dist/planning-pool/observation.js.map +1 -0
  149. package/dist/planning-pool/projection.d.ts +28 -0
  150. package/dist/planning-pool/projection.d.ts.map +1 -0
  151. package/dist/planning-pool/projection.js +148 -0
  152. package/dist/planning-pool/projection.js.map +1 -0
  153. package/dist/planning-pool/public-core.d.ts +32 -0
  154. package/dist/planning-pool/public-core.d.ts.map +1 -0
  155. package/dist/planning-pool/public-core.js +122 -0
  156. package/dist/planning-pool/public-core.js.map +1 -0
  157. package/dist/planning-pool/reshape-normalize.d.ts +15 -0
  158. package/dist/planning-pool/reshape-normalize.d.ts.map +1 -0
  159. package/dist/planning-pool/reshape-normalize.js +688 -0
  160. package/dist/planning-pool/reshape-normalize.js.map +1 -0
  161. package/dist/planning-pool/reshape-token.d.ts +20 -0
  162. package/dist/planning-pool/reshape-token.d.ts.map +1 -0
  163. package/dist/planning-pool/reshape-token.js +193 -0
  164. package/dist/planning-pool/reshape-token.js.map +1 -0
  165. package/dist/planning-pool/reshape-types.d.ts +183 -0
  166. package/dist/planning-pool/reshape-types.d.ts.map +1 -0
  167. package/dist/planning-pool/reshape-types.js +2 -0
  168. package/dist/planning-pool/reshape-types.js.map +1 -0
  169. package/dist/planning-pool/reshape.d.ts +13 -0
  170. package/dist/planning-pool/reshape.d.ts.map +1 -0
  171. package/dist/planning-pool/reshape.js +1434 -0
  172. package/dist/planning-pool/reshape.js.map +1 -0
  173. package/dist/planning-pool/source-lexical.d.ts +30 -0
  174. package/dist/planning-pool/source-lexical.d.ts.map +1 -0
  175. package/dist/planning-pool/source-lexical.js +158 -0
  176. package/dist/planning-pool/source-lexical.js.map +1 -0
  177. package/dist/planning-pool/source-types.d.ts +169 -0
  178. package/dist/planning-pool/source-types.d.ts.map +1 -0
  179. package/dist/planning-pool/source-types.js +2 -0
  180. package/dist/planning-pool/source-types.js.map +1 -0
  181. package/dist/planning-pool/source-values.d.ts +16 -0
  182. package/dist/planning-pool/source-values.d.ts.map +1 -0
  183. package/dist/planning-pool/source-values.js +120 -0
  184. package/dist/planning-pool/source-values.js.map +1 -0
  185. package/dist/planning-pool/source.d.ts +18 -0
  186. package/dist/planning-pool/source.d.ts.map +1 -0
  187. package/dist/planning-pool/source.js +811 -0
  188. package/dist/planning-pool/source.js.map +1 -0
  189. package/dist/planning-pool/window-types.d.ts +133 -0
  190. package/dist/planning-pool/window-types.d.ts.map +1 -0
  191. package/dist/planning-pool/window-types.js +2 -0
  192. package/dist/planning-pool/window-types.js.map +1 -0
  193. package/dist/planning-pool/window.d.ts +6 -0
  194. package/dist/planning-pool/window.d.ts.map +1 -0
  195. package/dist/planning-pool/window.js +625 -0
  196. package/dist/planning-pool/window.js.map +1 -0
  197. package/dist/schema/registry.d.ts +1 -1
  198. package/dist/schema/registry.d.ts.map +1 -1
  199. package/dist/schema/registry.js +17 -3
  200. package/dist/schema/registry.js.map +1 -1
  201. package/dist/temporal-schedule/format.d.ts.map +1 -1
  202. package/dist/temporal-schedule/format.js +4 -54
  203. package/dist/temporal-schedule/format.js.map +1 -1
  204. package/dist/temporal-schedule/source-lexical.d.ts +9 -0
  205. package/dist/temporal-schedule/source-lexical.d.ts.map +1 -1
  206. package/dist/temporal-schedule/source-lexical.js +21 -10
  207. package/dist/temporal-schedule/source-lexical.js.map +1 -1
  208. package/dist/temporal-schedule/source.d.ts.map +1 -1
  209. package/dist/temporal-schedule/source.js +3 -13
  210. package/dist/temporal-schedule/source.js.map +1 -1
  211. package/dist/version.d.ts +1 -1
  212. package/dist/version.js +1 -1
  213. package/package.json +1 -1
  214. package/schemas/{Perttool.AdvanceResult.v3.schema.json → Perttool.AdvanceResult.v4.schema.json} +42 -4
  215. package/schemas/Perttool.AgentGuidanceResult.v1.schema.json +1 -1
  216. package/schemas/Perttool.AnalysisResult.v7.schema.json +1 -1
  217. package/schemas/Perttool.CheckResult.v6.schema.json +1 -1
  218. package/schemas/Perttool.CliError.v1.schema.json +1 -1
  219. package/schemas/Perttool.CommandHelpResult.v1.schema.json +2 -2
  220. package/schemas/Perttool.ExportResult.v1.schema.json +1 -1
  221. package/schemas/Perttool.FormatResult.v1.schema.json +1 -1
  222. package/schemas/Perttool.GuideResult.v1.schema.json +1 -1
  223. package/schemas/Perttool.HistoricalGraphResult.v1.schema.json +1 -1
  224. package/schemas/Perttool.ImportResult.v1.schema.json +1 -1
  225. package/schemas/Perttool.InitResult.v1.schema.json +1 -1
  226. package/schemas/Perttool.MilestoneAcceptanceMigrationResult.v1.schema.json +1 -1
  227. package/schemas/Perttool.MilestoneAcceptanceResult.v1.schema.json +1 -1
  228. package/schemas/Perttool.MutationResult.v6.schema.json +1 -1
  229. package/schemas/Perttool.NextResult.v8.schema.json +7 -4
  230. package/schemas/Perttool.PlanAssuranceResult.v2.schema.json +1 -1
  231. package/schemas/Perttool.PlanningMutationResult.v1.schema.json +567 -0
  232. package/schemas/Perttool.PlanningObservationRequest.v1.schema.json +6 -0
  233. package/schemas/Perttool.PlanningPoolResult.v1.schema.json +469 -0
  234. package/schemas/Perttool.PlanningReshapePreflightResult.v1.schema.json +906 -0
  235. package/schemas/Perttool.PlanningReshapeRequest.v1.schema.json +19 -0
  236. package/schemas/Perttool.ProjectHistoryResult.v1.schema.json +1 -1
  237. package/schemas/Perttool.ProjectResult.v5.schema.json +1 -1
  238. package/schemas/Perttool.SchemaResult.v1.schema.json +1 -1
  239. package/schemas/{Perttool.UnitMigrationResult.v4.schema.json → Perttool.UnitMigrationResult.v5.schema.json} +42 -17
  240. package/schemas/Perttool.VelocityObservationResult.v1.schema.json +1 -1
  241. package/schemas/Perttool.WindowMutationRequest.v1.schema.json +6 -0
package/dist/cli.js CHANGED
@@ -7,11 +7,11 @@ import { createNodeHost } from "./node/host.js";
7
7
  import { createHistoricalGraphGitEvidenceHost } from "./node/historical-host.js";
8
8
  import { exportMermaid, } from "./conversion/mermaid.js";
9
9
  import { importMermaid } from "./conversion/mermaid-import.js";
10
- import { getContract9Guide as getAssuranceGuide, renderContract9GuideResult as renderAssuranceGuideResult, serializeContract9GuideResult as serializeAssuranceGuideResult, } from "./help/contract9-guide.js";
10
+ import { getContract10Guide as getAssuranceGuide, renderContract10GuideResult as renderAssuranceGuideResult, serializeContract10GuideResult as serializeAssuranceGuideResult, } from "./help/contract10-guide.js";
11
11
  import { commandOptionSets, } from "./command/registry.js";
12
- import { CONTRACT9_COMMAND_REGISTRY as ASSURANCE_COMMAND_REGISTRY, getContract9CommandDiscovery as getAssuranceCommandDiscovery, renderContract9CommandHelpResult as renderAssuranceCommandHelpResult, serializeContract9CommandHelpResult as serializeAssuranceCommandHelpResult, } from "./command/contract9-discovery.js";
12
+ import { CONTRACT10_COMMAND_REGISTRY as ASSURANCE_COMMAND_REGISTRY, getContract10CommandDiscovery as getAssuranceCommandDiscovery, renderContract10CommandHelpResult as renderAssuranceCommandHelpResult, serializeContract10CommandHelpResult as serializeAssuranceCommandHelpResult, } from "./command/contract10-discovery.js";
13
13
  import { handlerCommandUsageError, } from "./command/usage.js";
14
- import { renderContract9CommandUsageError as renderAssuranceCommandUsageError, serializeContract9CommandUsageError as serializeAssuranceCommandUsageError, validateContract9CommandInvocation as validateAssuranceCommandInvocation, } from "./command/contract9-usage.js";
14
+ import { renderContract10CommandUsageError as renderAssuranceCommandUsageError, serializeContract10CommandUsageError as serializeAssuranceCommandUsageError, validateContract10CommandInvocation as validateAssuranceCommandInvocation, } from "./command/contract10-usage.js";
15
15
  import { agentGuidanceResultToJson } from "./guidance/projection.js";
16
16
  import { agentGuidanceExitCode, renderAgentGuidanceText, } from "./guidance/text.js";
17
17
  import { SafeWriteConflictError, SafeWriteVerificationError, } from "./io/safe-write.js";
@@ -20,14 +20,14 @@ import { formatDecimal } from "./model/rational.js";
20
20
  import { convertWithVelocity, durationSuffix } from "./model/units.js";
21
21
  import { recommendationInvariantExitCode } from "./recommendation/failure.js";
22
22
  import { recommendationAnalysisToJson } from "./recommendation/json.js";
23
- import { applyTextEdits, normalizeTextEdits } from "./mutation/text-edits.js";
23
+ import { applyTextEdits, normalizeTextEdits, } from "./mutation/text-edits.js";
24
24
  import { createUnifiedDiff } from "./editing/unified-diff.js";
25
25
  import { sha256DigestUtf8 } from "./model/sha256.js";
26
26
  import { TARGET_GRAMMAR_6_CAPABILITY, } from "./parser/document-parser.js";
27
27
  import { exportPlanAssuranceMermaid, importPlanAssuranceMermaid, } from "./assurance/mermaid.js";
28
28
  import { getJsonSchemaResult, renderJsonSchemaResult, serializeJsonSchemaResult, } from "./schema/registry.js";
29
29
  import { TOOL_VERSION } from "./version.js";
30
- import { analyzeDocument as analyzeContract8Document, checkDocument as checkContract8Document, selectNextTasks as selectContract8NextTasks, } from "./application/contract9-temporal.js";
30
+ import { analyzeDocument as analyzeContract8Document, checkDocument as checkContract8Document, planGrammarMigration as planContract10GrammarMigration, selectNextTasks as selectContract8NextTasks, } from "./application/contract10-runtime.js";
31
31
  import { contract9CheckResultToJson, contract9ProjectResultToJson, liftContract9AnalysisResultJson, liftContract9NextResultJson, renderContract9ScheduleAlerts, contract9WireJson, } from "./application/contract9-projection.js";
32
32
  import { planContract9GrammarMigration } from "./application/contract9-format-migration.js";
33
33
  import { planContract9TemporalMutation } from "./application/contract9-temporal-mutation.js";
@@ -36,8 +36,18 @@ import { planAcceptanceReceiptMutation, planCriterionSetReplacement, showMilesto
36
36
  import { scanTemporalDeclarationBlocks, temporalScheduleBaseText, } from "./temporal-schedule/source-lexical.js";
37
37
  import { planMilestoneAcceptanceMigration, recheckCommittedMigrationProof, } from "./milestone-acceptance/migration.js";
38
38
  import { MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY, milestoneAcceptanceBaseText, parseMilestoneAcceptanceSource } from "./milestone-acceptance/source.js";
39
- import { coalesceMilestoneAcceptanceDeletionOverlaps, planMilestoneAcceptanceAdvance, preserveMilestoneAcceptanceRecords, } from "./milestone-acceptance/advance.js";
40
- 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, inspectTargetCurrentProjectActuals, inspectTargetProjectHistoryFile, renderTargetProjectHistoryText, targetProjectHistoryResultToJson, observeTargetProjectVelocity, renderTargetVelocityObservationText, targetVelocityObservationResultToJson, getAgentHelp, documentContentFromBytes, readDocumentContent, readBytes, recheckAdvanceHistoryBaseline, captureAdvanceHistoryBaseline, createArtifactFile, createValidatedDocumentFile, createTargetGrammar6DocumentFile, replaceTargetGrammar6DocumentFile, replaceValidatedDocumentFile, inspectTargetHistoricalGraphFile, renderTargetHistoricalGraphText, targetHistoricalGraphResultToJson, } = createCliApplicationFacade(createNodeHost(), createHistoricalGraphGitEvidenceHost());
39
+ import { planMilestoneAcceptanceAdvance, prepareMilestoneAcceptanceAdvanceEdits, preserveMilestoneAcceptanceRecords, } from "./milestone-acceptance/advance.js";
40
+ import { beginPlanningPoolReshapeCommit, inspectPlanningPool, observeCurrentPlanningPool, planPlanningWindowMutation, preflightPlanningPoolReshape, preparePlanningPoolReshapeApply, recoverPlanningPoolReshapeCommit, settlePlanningPoolReshapeCommit, } from "./application/contract10-planning.js";
41
+ import { observeHistoricalPlanningPool } from "./application/contract10-planning-history.js";
42
+ import { parsePlanningPoolSource, PLANNING_POOL_SOURCE_CAPABILITY, } from "./planning-pool/source.js";
43
+ import { planPlanningAdvanceCleanup } from "./planning-pool/advance.js";
44
+ import { planningPoolBaseText, scanPlanningDeclarationBlocks, } from "./planning-pool/source-lexical.js";
45
+ import { assessPlanningHistoryBaseline, planningHistoryNotApplicable, } from "./planning-pool/history-guard.js";
46
+ import { withPlanningReshapeTokenRegistry } from "./node/planning-token-store.js";
47
+ import { compilePlanningIntentRequest, isPlanningIntentRequest, } from "./planning-pool/intent.js";
48
+ import { renderPlanningHistoricalObservationText, renderPlanningObservationText, renderPlanningPoolReadText, renderPlanningReshapePreflightText, } from "./planning-pool/human.js";
49
+ const historicalGitEvidenceHost = createHistoricalGraphGitEvidenceHost();
50
+ 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, inspectTargetCurrentProjectActuals, inspectTargetProjectHistoryFile, renderTargetProjectHistoryText, targetProjectHistoryResultToJson, observeTargetProjectVelocity, renderTargetVelocityObservationText, targetVelocityObservationResultToJson, getAgentHelp, documentContentFromBytes, readDocumentContent, readBytes, recheckAdvanceHistoryBaseline, captureAdvanceHistoryBaseline, createArtifactFile, createValidatedDocumentFile, createTargetGrammar6DocumentFile, replaceTargetGrammar6DocumentFile, replaceValidatedDocumentFile, inspectTargetHistoricalGraphFile, renderTargetHistoricalGraphText, targetHistoricalGraphResultToJson, } = createCliApplicationFacade(createNodeHost(), historicalGitEvidenceHost);
41
51
  const analyzeDocument = analyzeContract8Document;
42
52
  const checkDocument = checkContract8Document;
43
53
  const selectNextTasks = selectContract8NextTasks;
@@ -221,7 +231,7 @@ async function readStdin() {
221
231
  function writeJson(value) {
222
232
  const contract8Value = typeof value === "object" && value !== null && !Array.isArray(value) &&
223
233
  "cli_contract_version" in value
224
- ? { ...value, cli_contract_version: 9 }
234
+ ? { ...value, cli_contract_version: 10 }
225
235
  : value;
226
236
  process.stdout.write(`${JSON.stringify(contract8Value)}\n`);
227
237
  }
@@ -532,15 +542,20 @@ async function persistContract8CandidateResult(result, request) {
532
542
  if (!result.ok || !result.governance?.writeAuthorized || result.updatedText === null) {
533
543
  throw new TypeError("authorized Contract 8 result does not contain a digest-bound candidate");
534
544
  }
535
- const validator = /^ version 8$/mu.test(result.updatedText)
545
+ const validator = /^ version 9$/mu.test(result.updatedText)
536
546
  ? (candidate) => {
537
- const checked = checkDocument(candidate);
538
- return { ok: checked.ok, diagnostics: checked.diagnostics };
547
+ const parsed = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
548
+ return { ok: parsed.ok, diagnostics: parsed.diagnostics };
539
549
  }
540
- : (candidate) => {
541
- const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
542
- return { ok: parsed.ok, diagnostics: [] };
543
- };
550
+ : /^ version 8$/mu.test(result.updatedText)
551
+ ? (candidate) => {
552
+ const checked = checkDocument(candidate);
553
+ return { ok: checked.ok, diagnostics: checked.diagnostics };
554
+ }
555
+ : (candidate) => {
556
+ const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
557
+ return { ok: parsed.ok, diagnostics: [] };
558
+ };
544
559
  if (request.mode === "in_place") {
545
560
  await replaceValidatedDocumentFile(request.target, result.updatedText, {
546
561
  initialDigest: result.originalDigest,
@@ -563,19 +578,19 @@ async function commitCandidate(request, candidateText, initialDigest) {
563
578
  if (candidateText === null) {
564
579
  throw new SafeWriteVerificationError("invalid_candidate", "successful editing result has no candidate text");
565
580
  }
581
+ if (/^ version 9$/mu.test(candidateText)) {
582
+ const validator = (candidate) => {
583
+ const parsed = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
584
+ return { ok: parsed.ok, diagnostics: parsed.diagnostics };
585
+ };
586
+ return commitValidatedCandidate(request, candidateText, initialDigest, validator);
587
+ }
566
588
  if (/^ version 8$/mu.test(candidateText)) {
567
589
  const validator = (candidate) => {
568
590
  const checked = checkDocument(candidate);
569
591
  return { ok: checked.ok, diagnostics: checked.diagnostics };
570
592
  };
571
- return request.mode === "in_place"
572
- ? replaceValidatedDocumentFile(request.target, candidateText, {
573
- initialDigest,
574
- ...(request.expectedDigest === undefined
575
- ? {}
576
- : { expectedDigest: request.expectedDigest }),
577
- }, validator)
578
- : createValidatedDocumentFile(request.target, candidateText, validator);
593
+ return commitValidatedCandidate(request, candidateText, initialDigest, validator);
579
594
  }
580
595
  const acceptanceSource = parseMilestoneAcceptanceSource(candidateText, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
581
596
  if (acceptanceSource.grammarVersion === 7) {
@@ -583,14 +598,7 @@ async function commitCandidate(request, candidateText, initialDigest) {
583
598
  const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
584
599
  return { ok: parsed.ok, diagnostics: [] };
585
600
  };
586
- return request.mode === "in_place"
587
- ? replaceValidatedDocumentFile(request.target, candidateText, {
588
- initialDigest,
589
- ...(request.expectedDigest === undefined
590
- ? {}
591
- : { expectedDigest: request.expectedDigest }),
592
- }, validator)
593
- : createValidatedDocumentFile(request.target, candidateText, validator);
601
+ return commitValidatedCandidate(request, candidateText, initialDigest, validator);
594
602
  }
595
603
  return request.mode === "in_place"
596
604
  ? replaceTargetGrammar6DocumentFile(request.target, candidateText, TARGET_GRAMMAR_6_CAPABILITY, {
@@ -601,6 +609,17 @@ async function commitCandidate(request, candidateText, initialDigest) {
601
609
  })
602
610
  : createTargetGrammar6DocumentFile(request.target, candidateText, TARGET_GRAMMAR_6_CAPABILITY);
603
611
  }
612
+ function commitValidatedCandidate(request, candidateText, initialDigest, validator) {
613
+ if (request.mode === "out") {
614
+ return createValidatedDocumentFile(request.target, candidateText, validator);
615
+ }
616
+ return replaceValidatedDocumentFile(request.target, candidateText, {
617
+ initialDigest,
618
+ ...(request.expectedDigest === undefined
619
+ ? {}
620
+ : { expectedDigest: request.expectedDigest }),
621
+ }, validator);
622
+ }
604
623
  function writeFailureExit(error, operation, json) {
605
624
  const normalized = error instanceof Error ? error : new Error(String(error));
606
625
  const exitCode = normalized instanceof SafeWriteConflictError
@@ -616,6 +635,39 @@ function renderWriteSummary(operation, result) {
616
635
  function renderGovernanceWriteSummary(operation, result, digest) {
617
636
  return `WRITE ${operation} mode=${result.mode} target=${result.target ?? "-"} digest=${digest ?? "-"} written=${result.written}\n`;
618
637
  }
638
+ function grammarMigrationResultJson(result, source, sourceDigest, write) {
639
+ return Object.freeze({
640
+ schema_version: "Perttool.UnitMigrationResult.v5",
641
+ cli_contract_version: 10,
642
+ tool_version: TOOL_VERSION,
643
+ operation: "document.migrate",
644
+ ok: result.ok,
645
+ document_id: result.documentId,
646
+ source,
647
+ source_digest: sourceDigest,
648
+ diagnostics: planningDiagnosticsJson(result.diagnostics),
649
+ diagnostics_truncated: result.diagnosticsTruncated,
650
+ source_grammar_version: result.sourceGrammarVersion,
651
+ target_grammar_version: result.targetGrammarVersion,
652
+ changed: result.changed,
653
+ migrated_task_ids: [...result.migratedTaskIds],
654
+ required_action: result.requiredAction,
655
+ original_digest: result.originalDigest,
656
+ updated_digest: result.updatedDigest,
657
+ updated_text: result.updatedText,
658
+ diff: result.diff,
659
+ edits: snakeJson(result.edits),
660
+ write,
661
+ });
662
+ }
663
+ function emitGrammarMigrationResult(format, result, sourceOperand, sourceDigest, write, diffOnly) {
664
+ if (format === "json") {
665
+ writeJson(grammarMigrationResultJson(result, sourceOperand === "-" ? "<stdin>" : sourceOperand, sourceDigest, write));
666
+ }
667
+ else if (result.updatedText !== null) {
668
+ process.stdout.write(diffOnly ? result.diff ?? "" : result.updatedText);
669
+ }
670
+ }
619
671
  async function runContract9DocumentMigration(args) {
620
672
  const parsed = parseCommandOptions("document.migrate", args);
621
673
  if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "8")
@@ -624,16 +676,49 @@ async function runContract9DocumentMigration(args) {
624
676
  const format = outputFormat(parsed.values.get("format"));
625
677
  const input = await readDocument(sourceOperand);
626
678
  const result = planContract9GrammarMigration(input.text);
679
+ let written = false;
627
680
  if (result.ok && result.updatedText !== null && parsed.flags.has("write")) {
628
681
  if (sourceOperand === "-")
629
682
  throw new UsageError("document migrate --write requires a file");
630
683
  await replaceValidatedDocumentFile(sourceOperand, result.updatedText, { initialDigest: input.digest, ...(parsed.values.get("expect-digest") === undefined ? {} : { expectedDigest: parsed.values.get("expect-digest") }) }, (candidate) => ({ ok: checkDocument(candidate).ok, diagnostics: [] }));
684
+ written = result.changed;
631
685
  }
632
- if (format === "json")
633
- writeJson({ schema_version: "Perttool.UnitMigrationResult.v4", cli_contract_version: 9,
634
- tool_version: TOOL_VERSION, operation: "document.migrate", ...snakeJson(result) });
635
- else if (result.updatedText !== null)
636
- process.stdout.write(parsed.flags.has("diff") ? result.diff ?? "" : result.updatedText);
686
+ emitGrammarMigrationResult(format, result, sourceOperand, input.digest, Object.freeze({
687
+ mode: parsed.flags.has("write") ? "in_place" : "preview",
688
+ target: parsed.flags.has("write") ? sourceOperand : null,
689
+ written,
690
+ }), parsed.flags.has("diff"));
691
+ return result.ok ? 0 : 1;
692
+ }
693
+ async function runContract10DocumentMigration(args) {
694
+ const parsed = parseCommandOptions("document.migrate", args);
695
+ if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "9") {
696
+ throw new UsageError("document migrate requires <file> --target-grammar 9");
697
+ }
698
+ const sourceOperand = parsed.positionals[0];
699
+ const format = outputFormat(parsed.values.get("format"));
700
+ const input = await readDocument(sourceOperand);
701
+ const result = planContract10GrammarMigration(input.text);
702
+ let written = false;
703
+ if (result.ok && result.updatedText !== null && parsed.flags.has("write")) {
704
+ if (sourceOperand === "-")
705
+ throw new UsageError("document migrate --write requires a file");
706
+ await replaceValidatedDocumentFile(sourceOperand, result.updatedText, {
707
+ initialDigest: input.digest,
708
+ ...(parsed.values.get("expect-digest") === undefined
709
+ ? {}
710
+ : { expectedDigest: parsed.values.get("expect-digest") }),
711
+ }, (candidate) => {
712
+ const checked = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
713
+ return { ok: checked.ok, diagnostics: checked.diagnostics };
714
+ });
715
+ written = result.changed;
716
+ }
717
+ emitGrammarMigrationResult(format, result, sourceOperand, input.digest, Object.freeze({
718
+ mode: parsed.flags.has("write") ? "in_place" : "preview",
719
+ target: parsed.flags.has("write") ? sourceOperand : null,
720
+ written,
721
+ }), parsed.flags.has("diff"));
637
722
  return result.ok ? 0 : 1;
638
723
  }
639
724
  async function runFormat(args) {
@@ -1420,7 +1505,7 @@ function unitMigrationJson(result, source, sourceDigest, ok) {
1420
1505
  });
1421
1506
  return {
1422
1507
  schema_version: result.schemaVersion,
1423
- cli_contract_version: 9,
1508
+ cli_contract_version: 10,
1424
1509
  tool_version: TOOL_VERSION,
1425
1510
  operation: "project.migrate-unit",
1426
1511
  ok,
@@ -1714,6 +1799,7 @@ function renderAdvanceSummary(details) {
1714
1799
  const list = (ids) => ids.join(",") || "-";
1715
1800
  return [
1716
1801
  `ADVANCE removed_tasks=${list(details.removedTaskIds)} removed_gates=${list(details.removedGateIds)} removed_milestones=${list(details.removedMilestoneIds)} removed_work_events=${list("removedWorkEventIds" in details ? details.removedWorkEventIds : [])}`,
1802
+ `ADVANCE removed_planning_links=${list("removedPlanningLinks" in details ? details.removedPlanningLinks : [])} archived_works=${list("archivedWorkIds" in details ? details.archivedWorkIds : [])}`,
1717
1803
  `ADVANCE frontier_before=${list(details.frontierBefore)} frontier_after=${list(details.frontierAfter)} ready_before=${list(details.readyBefore)} ready_after=${list(details.readyAfter)}`,
1718
1804
  "",
1719
1805
  ].join("\n");
@@ -1765,7 +1851,14 @@ async function runAdvance(args) {
1765
1851
  catch (error) {
1766
1852
  return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dag.advance", format === "json");
1767
1853
  }
1768
- const acceptancePlan = planMilestoneAcceptanceAdvance(input.text, {
1854
+ const grammar9 = /^ version 9$/mu.test(input.text);
1855
+ const strictInputText = grammar9
1856
+ ? planningPoolBaseText(input.text, scanPlanningDeclarationBlocks(input.text))
1857
+ : input.text;
1858
+ const acceptanceInputText = /^ version 8$/mu.test(strictInputText)
1859
+ ? temporalScheduleBaseText(strictInputText, scanTemporalDeclarationBlocks(strictInputText))
1860
+ : strictInputText;
1861
+ const acceptancePlan = planMilestoneAcceptanceAdvance(acceptanceInputText, {
1769
1862
  maxDiagnostics,
1770
1863
  originalLabel: source,
1771
1864
  updatedLabel: "candidate",
@@ -1778,8 +1871,8 @@ async function runAdvance(args) {
1778
1871
  if (!acceptancePlan.ok) {
1779
1872
  if (format === "json")
1780
1873
  writeJson({
1781
- schema_version: "Perttool.AdvanceResult.v3",
1782
- cli_contract_version: 8,
1874
+ schema_version: "Perttool.AdvanceResult.v4",
1875
+ cli_contract_version: 10,
1783
1876
  tool_version: TOOL_VERSION,
1784
1877
  operation: "dag.advance",
1785
1878
  ok: false,
@@ -1802,6 +1895,8 @@ async function runAdvance(args) {
1802
1895
  removedWorkEventIds: [],
1803
1896
  removedAssuranceRecordIds: [],
1804
1897
  updatedAssuranceReceiptIds: [],
1898
+ removedPlanningLinks: [],
1899
+ archivedWorkIds: [],
1805
1900
  }),
1806
1901
  history_guard: null,
1807
1902
  assurance_guard: null,
@@ -1815,25 +1910,38 @@ async function runAdvance(args) {
1815
1910
  }
1816
1911
  return 1;
1817
1912
  }
1818
- const contract7BaseText = milestoneAcceptanceBaseText(input.text);
1913
+ const contract7BaseText = milestoneAcceptanceBaseText(acceptanceInputText);
1819
1914
  const contract7Planned = planAdvance(contract7BaseText, {
1820
1915
  maxDiagnostics,
1821
1916
  originalLabel: source,
1822
1917
  updatedLabel: "candidate",
1823
1918
  governance: governanceRequest(parsed, writeRequest),
1824
1919
  });
1825
- const combinedEdits = contract7Planned.updatedText === null
1920
+ const strictCombinedEdits = contract7Planned.updatedText === null
1826
1921
  ? contract7Planned.edits
1827
- : normalizeTextEdits(input.text, coalesceMilestoneAcceptanceDeletionOverlaps([
1828
- ...preserveMilestoneAcceptanceRecords(input.text, contract7Planned.edits, acceptancePlan.provisional.advance.keptMilestoneIds),
1922
+ : normalizeTextEdits(acceptanceInputText, prepareMilestoneAcceptanceAdvanceEdits(acceptanceInputText, [
1923
+ ...preserveMilestoneAcceptanceRecords(acceptanceInputText, contract7Planned.edits, acceptancePlan.provisional.advance.keptMilestoneIds),
1829
1924
  ...acceptancePlan.provisional.edits,
1830
1925
  ]), "Contract 8 acceptance-aware advance");
1926
+ const planningCleanup = grammar9 && contract7Planned.updatedText !== null
1927
+ ? planPlanningAdvanceCleanup(input.text, contract7Planned.advance?.removedMilestoneIds ?? [], contract7Planned.advance?.removedTaskIds ?? [], parsed.flags.has("archive-empty-work"))
1928
+ : Object.freeze({
1929
+ edits: Object.freeze([]),
1930
+ removedPlanningLinks: Object.freeze([]),
1931
+ archivedWorkIds: Object.freeze([]),
1932
+ destructiveRecords: Object.freeze([]),
1933
+ });
1934
+ const combinedEdits = contract7Planned.updatedText === null
1935
+ ? strictCombinedEdits
1936
+ : normalizeTextEdits(input.text, [...strictCombinedEdits, ...planningCleanup.edits], "Contract 10 planning-aware advance");
1831
1937
  const combinedText = contract7Planned.updatedText === null
1832
1938
  ? null
1833
1939
  : applyTextEdits(input.text, combinedEdits);
1834
1940
  const combinedCheck = combinedText === null
1835
1941
  ? null
1836
- : checkContract8Document(combinedText, { maxDiagnostics });
1942
+ : grammar9
1943
+ ? checkDocument(combinedText, { maxDiagnostics })
1944
+ : checkContract8Document(combinedText, { maxDiagnostics });
1837
1945
  if (combinedCheck !== null && !combinedCheck.ok) {
1838
1946
  throw new Error("acceptance-aware assurance advance lost Contract 8 validation");
1839
1947
  }
@@ -1842,7 +1950,7 @@ async function runAdvance(args) {
1842
1950
  : mergeAdvanceCandidateDiagnostics(combinedCheck.diagnostics, contract7Planned.diagnostics, maxDiagnostics);
1843
1951
  const planned = Object.freeze({
1844
1952
  ...contract7Planned,
1845
- schemaVersion: "Perttool.AdvanceResult.v3",
1953
+ schemaVersion: "Perttool.AdvanceResult.v4",
1846
1954
  originalDigest: input.digest,
1847
1955
  updatedText: combinedText,
1848
1956
  updatedDigest: combinedText === null ? null : sha256DigestUtf8(combinedText),
@@ -1856,6 +1964,13 @@ async function runAdvance(args) {
1856
1964
  (combinedCheck?.diagnosticsTruncated ?? false) ||
1857
1965
  (combinedDiagnostics?.truncated ?? false),
1858
1966
  acceptanceGuard: acceptancePlan.acceptanceGuard,
1967
+ advance: contract7Planned.advance === null
1968
+ ? null
1969
+ : Object.freeze({
1970
+ ...contract7Planned.advance,
1971
+ removedPlanningLinks: planningCleanup.removedPlanningLinks,
1972
+ archivedWorkIds: planningCleanup.archivedWorkIds,
1973
+ }),
1859
1974
  });
1860
1975
  const initialWarningFailure = parsed.flags.has("warnings-as-errors") &&
1861
1976
  (contract7Planned.diagnosticsTruncated ||
@@ -1873,8 +1988,16 @@ async function runAdvance(args) {
1873
1988
  warningDenied: initialWarningFailure,
1874
1989
  maxDiagnostics,
1875
1990
  documentValidator: (candidateText, candidateMaxDiagnostics) => {
1876
- const acceptanceSource = parseMilestoneAcceptanceSource(candidateText, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
1877
- const checked = checkContract8Document(candidateText, { maxDiagnostics: candidateMaxDiagnostics });
1991
+ const planningBase = grammar9
1992
+ ? planningPoolBaseText(candidateText, scanPlanningDeclarationBlocks(candidateText))
1993
+ : candidateText;
1994
+ const acceptanceBase = /^ version 8$/mu.test(planningBase)
1995
+ ? temporalScheduleBaseText(planningBase, scanTemporalDeclarationBlocks(planningBase))
1996
+ : planningBase;
1997
+ const acceptanceSource = parseMilestoneAcceptanceSource(acceptanceBase, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
1998
+ const checked = grammar9
1999
+ ? checkDocument(candidateText, { maxDiagnostics: candidateMaxDiagnostics })
2000
+ : checkContract8Document(candidateText, { maxDiagnostics: candidateMaxDiagnostics });
1878
2001
  return {
1879
2002
  ok: checked.ok && acceptanceSource.ok,
1880
2003
  document: checked.document,
@@ -1884,11 +2007,66 @@ async function runAdvance(args) {
1884
2007
  };
1885
2008
  },
1886
2009
  });
2010
+ const planningAdvanceGuard = planningCleanup.destructiveRecords.length === 0
2011
+ ? planningHistoryNotApplicable([], "no_canonical_records")
2012
+ : writeRequest.mode === "preview"
2013
+ ? planningHistoryNotApplicable(planningCleanup.destructiveRecords, "preview")
2014
+ : writeRequest.mode === "out"
2015
+ ? planningHistoryNotApplicable(planningCleanup.destructiveRecords, "separate_output")
2016
+ : preparedBase.baseline === null
2017
+ ? planningHistoryNotApplicable(planningCleanup.destructiveRecords, "authority_denied")
2018
+ : assessPlanningHistoryBaseline(input.text, planningCleanup.destructiveRecords, preparedBase.baseline, forceRequested);
2019
+ const planningAdvanceBlocked = planningAdvanceGuard.status === "blocked";
2020
+ const baseHistoryGuard = preparedBase.result.historyGuard;
2021
+ const combinedHistoryGuard = baseHistoryGuard === null
2022
+ ? null
2023
+ : planningCleanup.destructiveRecords.length === 0
2024
+ ? baseHistoryGuard
2025
+ : Object.freeze({
2026
+ ...baseHistoryGuard,
2027
+ status: planningAdvanceGuard.status === "blocked"
2028
+ ? "blocked"
2029
+ : planningAdvanceGuard.status === "forced"
2030
+ ? "forced"
2031
+ : baseHistoryGuard.status,
2032
+ cause: planningAdvanceGuard.status === "passed" ||
2033
+ planningAdvanceGuard.status === "not_applicable"
2034
+ ? baseHistoryGuard.cause
2035
+ : planningAdvanceGuard.cause,
2036
+ destructiveEntityIds: Object.freeze([...new Set([
2037
+ ...baseHistoryGuard.destructiveEntityIds,
2038
+ ...planningAdvanceGuard.destructiveEntityIds,
2039
+ ])].sort()),
2040
+ overlappingEntityIds: Object.freeze([...new Set([
2041
+ ...baseHistoryGuard.overlappingEntityIds,
2042
+ ...planningAdvanceGuard.overlappingEntityIds,
2043
+ ])].sort()),
2044
+ });
2045
+ const preparedDiagnostics = planningAdvanceBlocked
2046
+ ? limitDiagnostics(sortDiagnostics([
2047
+ ...preparedBase.result.diagnostics,
2048
+ Object.freeze({
2049
+ code: "PTADV-101",
2050
+ severity: "error",
2051
+ message: "advance history proof is blocked for canonical planning facts",
2052
+ helpTopic: "editing",
2053
+ data: Object.freeze({
2054
+ cause: planningAdvanceGuard.cause,
2055
+ entity_ids: planningAdvanceGuard.overlappingEntityIds,
2056
+ }),
2057
+ }),
2058
+ ]), maxDiagnostics)
2059
+ : null;
1887
2060
  const prepared = Object.freeze({
1888
2061
  ...preparedBase,
1889
2062
  result: Object.freeze({
1890
2063
  ...preparedBase.result,
1891
- schemaVersion: "Perttool.AdvanceResult.v3",
2064
+ schemaVersion: "Perttool.AdvanceResult.v4",
2065
+ ok: preparedBase.result.ok && !planningAdvanceBlocked,
2066
+ diagnostics: preparedDiagnostics?.diagnostics ?? preparedBase.result.diagnostics,
2067
+ diagnosticsTruncated: preparedBase.result.diagnosticsTruncated ||
2068
+ (preparedDiagnostics?.truncated ?? false),
2069
+ historyGuard: combinedHistoryGuard,
1892
2070
  governance: planned.governance,
1893
2071
  assuranceGuard: planned.assuranceGuard,
1894
2072
  acceptanceGuard: acceptancePlan.acceptanceGuard,
@@ -1918,7 +2096,7 @@ async function runAdvance(args) {
1918
2096
  if (!recheck.ok) {
1919
2097
  result = Object.freeze({
1920
2098
  ...withAdvanceHistoryRace(result, recheck, maxDiagnostics),
1921
- schemaVersion: "Perttool.AdvanceResult.v3",
2099
+ schemaVersion: "Perttool.AdvanceResult.v4",
1922
2100
  governance: result.governance,
1923
2101
  assuranceGuard: result.assuranceGuard,
1924
2102
  acceptanceGuard: result.acceptanceGuard,
@@ -1939,9 +2117,10 @@ async function runAdvance(args) {
1939
2117
  if (format === "json") {
1940
2118
  writeJson({
1941
2119
  ...contract7MutationResultToJson((ok ? result : Object.freeze({ ...result, ok: false })), "dag.advance", source, writeResult),
1942
- schema_version: "Perttool.AdvanceResult.v3",
1943
- cli_contract_version: 8,
2120
+ schema_version: "Perttool.AdvanceResult.v4",
2121
+ cli_contract_version: 10,
1944
2122
  acceptance_guard: snakeJson(result.acceptanceGuard),
2123
+ advance: snakeJson(result.advance),
1945
2124
  });
1946
2125
  }
1947
2126
  else {
@@ -2783,10 +2962,13 @@ function renderNextText(result) {
2783
2962
  const unit = result.durationUnit;
2784
2963
  const taskById = new Map(result.tasks.map((task) => [task.id, task]));
2785
2964
  const authority = result.temporal.authority;
2965
+ const runnableNow = new Set(result.groups.runnableNow);
2966
+ const nonRunnableRecommended = authority.rawRecommendedTaskIds.filter((taskId) => !runnableNow.has(taskId));
2786
2967
  const lines = [
2787
2968
  "START AUTHORITY",
2788
2969
  `POLICY ${authority.policy}`,
2789
2970
  `STARTABLE RECOMMENDED ${authority.startableRecommendedTaskIds.join(",") || "-"}`,
2971
+ `NON-RUNNABLE RAW RECOMMENDED ${nonRunnableRecommended.join(",") || "-"}`,
2790
2972
  `DELAYED RECOMMENDED ${authority.delayedRecommendedTaskIds.join(",") || "-"}`,
2791
2973
  `UNAVAILABLE RECOMMENDED ${authority.unavailableRecommendedTaskIds.join(",") || "-"}`,
2792
2974
  "DEADLINE FACTS INFORMATIONAL FOR RANKING v1",
@@ -2936,35 +3118,82 @@ function parseMilestoneAcceptanceCriteria(values) {
2936
3118
  };
2937
3119
  });
2938
3120
  }
3121
+ function liftAcceptanceMutationCandidate(text, base, planned) {
3122
+ const originalDigest = sha256DigestUtf8(text);
3123
+ const rebound = planned.governance === null
3124
+ ? planned
3125
+ : Object.freeze({
3126
+ ...planned,
3127
+ governance: Object.freeze({
3128
+ ...planned.governance,
3129
+ sourceDigest: originalDigest,
3130
+ }),
3131
+ });
3132
+ if (planned.updatedText === null) {
3133
+ return Object.freeze({ ...rebound, originalDigest });
3134
+ }
3135
+ const protectedRanges = maskedSourceLineRanges(text, base);
3136
+ let edits;
3137
+ let candidate;
3138
+ try {
3139
+ edits = normalizeTextEdits(base, planned.edits, "milestone acceptance lift");
3140
+ if (protectedRanges === null ||
3141
+ edits.some((edit) => protectedRanges.some((range) => textEditTouchesRange(edit, range))) ||
3142
+ applyTextEdits(base, edits) !== planned.updatedText)
3143
+ throw new Error("acceptance edits do not preserve the lowered source");
3144
+ candidate = applyTextEdits(text, edits);
3145
+ }
3146
+ catch {
3147
+ return Object.freeze({ ...rebound, ok: false, changed: false,
3148
+ originalDigest, updatedDigest: null, updatedText: null,
3149
+ edits: Object.freeze([]), diagnostics: Object.freeze([
3150
+ ...rebound.diagnostics, "invalid_lifted_candidate",
3151
+ ]) });
3152
+ }
3153
+ const checked = checkDocument(candidate);
3154
+ if (!checked.ok)
3155
+ return Object.freeze({ ...rebound, ok: false, changed: false,
3156
+ originalDigest, updatedDigest: null, updatedText: null,
3157
+ edits: Object.freeze([]), diagnostics: Object.freeze([
3158
+ ...rebound.diagnostics, "invalid_lifted_candidate",
3159
+ ]) });
3160
+ return Object.freeze({ ...rebound, originalDigest, changed: candidate !== text,
3161
+ updatedDigest: sha256DigestUtf8(candidate), updatedText: candidate,
3162
+ edits: Object.freeze(edits) });
3163
+ }
3164
+ function maskedSourceLineRanges(text, base) {
3165
+ if (text.length !== base.length)
3166
+ return null;
3167
+ const ranges = [];
3168
+ let startOffset = 0;
3169
+ while (startOffset < text.length) {
3170
+ const newline = text.indexOf("\n", startOffset);
3171
+ const endOffset = newline < 0 ? text.length : newline + 1;
3172
+ if (text.slice(startOffset, endOffset) !== base.slice(startOffset, endOffset)) {
3173
+ ranges.push(Object.freeze({ startOffset, endOffset }));
3174
+ }
3175
+ startOffset = endOffset;
3176
+ }
3177
+ return Object.freeze(ranges);
3178
+ }
3179
+ function textEditTouchesRange(edit, range) {
3180
+ return edit.startOffset === edit.endOffset
3181
+ ? edit.startOffset > range.startOffset && edit.startOffset < range.endOffset
3182
+ : edit.startOffset < range.endOffset && edit.endOffset > range.startOffset;
3183
+ }
2939
3184
  function planContract9AcceptanceMutation(text, planner) {
2940
3185
  if (!/^ version 8$/mu.test(text))
2941
3186
  return planner(text);
2942
3187
  const base = temporalScheduleBaseText(text, scanTemporalDeclarationBlocks(text));
2943
- const planned = planner(base);
2944
- const originalDigest = sha256DigestUtf8(text);
2945
- if (!planned.ok || planned.updatedText === null) {
2946
- return Object.freeze({ ...planned, originalDigest });
2947
- }
2948
- let prefix = 0;
2949
- while (prefix < base.length &&
2950
- prefix < planned.updatedText.length &&
2951
- base[prefix] === planned.updatedText[prefix])
2952
- prefix += 1;
2953
- let suffix = 0;
2954
- while (suffix < base.length - prefix &&
2955
- suffix < planned.updatedText.length - prefix &&
2956
- base[base.length - 1 - suffix] ===
2957
- planned.updatedText[planned.updatedText.length - 1 - suffix])
2958
- suffix += 1;
2959
- const candidate = text.slice(0, prefix) +
2960
- planned.updatedText.slice(prefix, planned.updatedText.length - suffix) +
2961
- text.slice(text.length - suffix);
2962
- const checked = checkDocument(candidate);
2963
- if (!checked.ok)
2964
- return Object.freeze({ ...planned, ok: false, changed: false,
2965
- originalDigest, updatedDigest: null, updatedText: null });
2966
- return Object.freeze({ ...planned, originalDigest, changed: candidate !== text,
2967
- updatedDigest: sha256DigestUtf8(candidate), updatedText: candidate });
3188
+ return liftAcceptanceMutationCandidate(text, base, planner(base));
3189
+ }
3190
+ function planContract10AcceptanceMutation(text, planner) {
3191
+ if (!/^ version 9$/mu.test(text)) {
3192
+ return planContract9AcceptanceMutation(text, planner);
3193
+ }
3194
+ const base = planningPoolBaseText(text, scanPlanningDeclarationBlocks(text));
3195
+ const planned = planContract9AcceptanceMutation(base, planner);
3196
+ return liftAcceptanceMutationCandidate(text, base, planned);
2968
3197
  }
2969
3198
  async function runMilestoneAcceptance(action, args) {
2970
3199
  const operation = `milestone-acceptance.${action}`;
@@ -2979,7 +3208,7 @@ async function runMilestoneAcceptance(action, args) {
2979
3208
  throw new UsageError("milestone acceptance show requires exactly one <file>");
2980
3209
  const result = checkDocument(input.text).acceptance ?? showMilestoneAcceptance(input.text, []);
2981
3210
  if (format === "json")
2982
- 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) });
3211
+ writeJson({ schema_version: "Perttool.MilestoneAcceptanceResult.v1", cli_contract_version: 10, tool_version: TOOL_VERSION, operation, ok: result.ok, milestones: snakeJson(result.milestones), diagnostics: snakeJson(result.diagnostics) });
2983
3212
  else
2984
3213
  process.stdout.write(`${result.milestones.map(({ milestoneId, closure, acceptance }) => `${milestoneId} closure=${closure} acceptance=${acceptance}`).join("\n")}\n`);
2985
3214
  return result.ok ? 0 : 1;
@@ -2988,15 +3217,15 @@ async function runMilestoneAcceptance(action, args) {
2988
3217
  throw new UsageError(`${operation} requires four operands`);
2989
3218
  const request = editingWriteRequest(parsed, sourceOperand);
2990
3219
  if (request.mode === "out")
2991
- throw new UsageError(`${operation} does not support --out in Contract 8`);
3220
+ throw new UsageError(`${operation} does not support --out in Contract 10`);
2992
3221
  const governance = governanceRequest(parsed, request);
2993
3222
  let result;
2994
3223
  if (action === "replace") {
2995
3224
  const criteria = parseMilestoneAcceptanceCriteria(parsed.repeatedValues.get("criterion") ?? []);
2996
- result = planContract9AcceptanceMutation(input.text, (text) => planCriterionSetReplacement(text, { milestoneId: parsed.positionals[1], setId: parsed.positionals[2], revisionId: parsed.positionals[3], criteria }, { governance }));
3225
+ result = planContract10AcceptanceMutation(input.text, (text) => planCriterionSetReplacement(text, { milestoneId: parsed.positionals[1], setId: parsed.positionals[2], revisionId: parsed.positionals[3], criteria }, { governance }));
2997
3226
  }
2998
3227
  else {
2999
- result = planContract9AcceptanceMutation(input.text, (text) => planAcceptanceReceiptMutation(text, {
3228
+ result = planContract10AcceptanceMutation(input.text, (text) => planAcceptanceReceiptMutation(text, {
3000
3229
  setId: parsed.positionals[1], criterionId: parsed.positionals[2], receiptId: parsed.positionals[3], action: action,
3001
3230
  ...(parsed.values.get("evidence-kind") === undefined ? {} : { evidenceKind: parsed.values.get("evidence-kind") }),
3002
3231
  ...(parsed.values.get("evidence-reference") === undefined ? {} : { evidenceReference: parsed.values.get("evidence-reference") }),
@@ -3009,13 +3238,18 @@ async function runMilestoneAcceptance(action, args) {
3009
3238
  }
3010
3239
  let written = false;
3011
3240
  if (result.ok && request.mode === "in_place" && result.changed) {
3012
- await commitCandidate(request, result.updatedText, input.digest);
3013
- written = true;
3241
+ try {
3242
+ await commitCandidate(request, result.updatedText, input.digest);
3243
+ written = true;
3244
+ }
3245
+ catch (error) {
3246
+ return writeFailureExit(error, operation, format === "json");
3247
+ }
3014
3248
  }
3015
3249
  if (format === "json")
3016
3250
  writeJson({
3017
3251
  schema_version: "Perttool.MutationResult.v6",
3018
- cli_contract_version: 8,
3252
+ cli_contract_version: 10,
3019
3253
  tool_version: TOOL_VERSION,
3020
3254
  operation,
3021
3255
  ok: result.ok,
@@ -3034,7 +3268,7 @@ async function runMilestoneAcceptance(action, args) {
3034
3268
  updated_digest: result.updatedDigest,
3035
3269
  updated_text: result.updatedText,
3036
3270
  diff: result.updatedText === null ? null : createUnifiedDiff(input.text, result.updatedText, { originalLabel: sourceOperand, updatedLabel: "candidate" }),
3037
- edits: result.changed && result.updatedText !== null ? [{ start_offset: 0, end_offset: input.text.length, replacement: result.updatedText }] : [],
3271
+ edits: snakeJson(result.edits),
3038
3272
  write: { mode: request.mode, target: request.target, written },
3039
3273
  governance: result.governance === null ? null : {
3040
3274
  ...snakeJson(result.governance),
@@ -3055,9 +3289,11 @@ async function runDocumentMigration(args) {
3055
3289
  : args.find((value) => value.startsWith("--target-grammar="))?.slice("--target-grammar=".length);
3056
3290
  if (target === "8")
3057
3291
  return runContract9DocumentMigration(args);
3292
+ if (target === "9")
3293
+ return runContract10DocumentMigration(args);
3058
3294
  const parsed = parseCommandOptions("document.migrate", args);
3059
3295
  if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "7")
3060
- throw new UsageError("document migrate requires <file> --target-grammar 7 or 8");
3296
+ throw new UsageError("document migrate requires <file> --target-grammar 7, 8, or 9");
3061
3297
  const sourceOperand = parsed.positionals[0];
3062
3298
  if (sourceOperand === "-")
3063
3299
  throw new UsageError("document migrate requires a repository file");
@@ -3467,6 +3703,420 @@ async function runCalendarMutation(action, args) {
3467
3703
  }
3468
3704
  return result.ok ? 0 : 1;
3469
3705
  }
3706
+ function unknownRecord(value) {
3707
+ return typeof value === "object" && value !== null && !Array.isArray(value)
3708
+ ? value
3709
+ : null;
3710
+ }
3711
+ async function residualDescriptionOption(value) {
3712
+ const separator = value.indexOf("=");
3713
+ if (separator <= 0) {
3714
+ throw new UsageError("--add-residual-description requires WORK_ID=<JSON string> or WORK_ID=@<UTF-8 path>");
3715
+ }
3716
+ const workId = value.slice(0, separator);
3717
+ const source = value.slice(separator + 1);
3718
+ let text;
3719
+ if (source.startsWith("@")) {
3720
+ const bytes = await readBytes(source.slice(1));
3721
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
3722
+ }
3723
+ else {
3724
+ try {
3725
+ text = JSON.parse(source);
3726
+ }
3727
+ catch {
3728
+ throw new UsageError("--add-residual-description inline value must be one JSON string");
3729
+ }
3730
+ }
3731
+ if (typeof text !== "string" || text.length === 0) {
3732
+ throw new UsageError("--add-residual-description value must be a non-empty string");
3733
+ }
3734
+ return Object.freeze({ work_id: workId, text });
3735
+ }
3736
+ async function planningRequestInput(parsed, sourceOperand) {
3737
+ const requestSource = parsed.values.get("request") ?? parsed.values.get("intent-request");
3738
+ if (requestSource === undefined) {
3739
+ throw new UsageError("exactly one of --request or --intent-request is required");
3740
+ }
3741
+ if (sourceOperand === "-" && requestSource === "-") {
3742
+ throw new UsageError("document and planning request cannot both use stdin");
3743
+ }
3744
+ const input = await readMutationRequest(requestSource);
3745
+ const additions = await Promise.all((parsed.repeatedValues.get("add-residual-description") ?? [])
3746
+ .map(residualDescriptionOption));
3747
+ if (additions.length === 0)
3748
+ return input;
3749
+ const request = unknownRecord(input);
3750
+ if (request === null) {
3751
+ throw new UsageError("planning request must be one JSON object");
3752
+ }
3753
+ const existing = request["add_residual_description"];
3754
+ if (!Array.isArray(existing)) {
3755
+ throw new UsageError("planning reshape request add_residual_description must be an array");
3756
+ }
3757
+ return Object.freeze({
3758
+ ...request,
3759
+ add_residual_description: Object.freeze([...existing, ...additions]),
3760
+ });
3761
+ }
3762
+ function planningDiagnosticsJson(diagnostics) {
3763
+ return diagnostics.map((diagnostic) => jsonDiagnostic(diagnostic));
3764
+ }
3765
+ function planningWireJson(value) {
3766
+ const projected = snakeJson(value);
3767
+ function convert(candidate) {
3768
+ if (Array.isArray(candidate))
3769
+ return candidate.map(convert);
3770
+ const record = unknownRecord(candidate);
3771
+ if (record === null)
3772
+ return candidate;
3773
+ const start = unknownRecord(record["start"]);
3774
+ const end = unknownRecord(record["end"]);
3775
+ const sourcePosition = (position) => position !== null &&
3776
+ typeof position["offset"] === "number" &&
3777
+ typeof position["line"] === "number" &&
3778
+ typeof position["column"] === "number";
3779
+ if (sourcePosition(start) && sourcePosition(end)) {
3780
+ const oneBased = (position) => ({
3781
+ offset: position["offset"],
3782
+ line: position["line"] + 1,
3783
+ column: position["column"] + 1,
3784
+ });
3785
+ return { start: oneBased(start), end: oneBased(end) };
3786
+ }
3787
+ return Object.fromEntries(Object.entries(record).map(([key, child]) => [key, convert(child)]));
3788
+ }
3789
+ return convert(projected);
3790
+ }
3791
+ function planningResultJson(operation, source, result, write = null) {
3792
+ const projected = planningWireJson(result);
3793
+ const diagnostics = result["diagnostics"];
3794
+ return {
3795
+ ...projected,
3796
+ ...(Array.isArray(diagnostics)
3797
+ ? { diagnostics: planningDiagnosticsJson(diagnostics) }
3798
+ : {}),
3799
+ cli_contract_version: 10,
3800
+ tool_version: TOOL_VERSION,
3801
+ operation,
3802
+ source,
3803
+ ...(write === null ? {} : { write: snakeJson(write) }),
3804
+ };
3805
+ }
3806
+ function emitPlanningResult(format, operation, sourceOperand, result) {
3807
+ if (format === "json") {
3808
+ writeJson(planningResultJson(operation, sourceOperand === "-" ? "<stdin>" : sourceOperand, result));
3809
+ }
3810
+ else if (operation === "work.observe" || operation === "window.observe") {
3811
+ const historical = "historyCapability" in result;
3812
+ process.stdout.write(historical
3813
+ ? renderPlanningHistoricalObservationText(operation, result)
3814
+ : renderPlanningObservationText(operation, result));
3815
+ }
3816
+ else if (operation === "work.reshape.preflight") {
3817
+ process.stdout.write(renderPlanningReshapePreflightText(result));
3818
+ }
3819
+ }
3820
+ async function runPlanningRead(resource, action, args) {
3821
+ const operation = `${resource}.${action}`;
3822
+ const parsed = parseCommandOptions(operation, args);
3823
+ const format = outputFormat(parsed.values.get("format"));
3824
+ const sourceOperand = parsed.positionals[0];
3825
+ const input = await readDocument(sourceOperand);
3826
+ const result = inspectPlanningPool(input.text, {
3827
+ operation,
3828
+ ...(action === "show" ? { id: parsed.positionals[1] } : {}),
3829
+ });
3830
+ if (format === "json") {
3831
+ writeJson(planningResultJson(operation, sourceOperand === "-" ? "<stdin>" : sourceOperand, result));
3832
+ }
3833
+ else if (result.ok) {
3834
+ process.stdout.write(renderPlanningPoolReadText(result));
3835
+ }
3836
+ if (format !== "json") {
3837
+ for (const diagnostic of result.diagnostics) {
3838
+ process.stderr.write(`${diagnostic.code} ${diagnostic.severity}: ${diagnostic.message}\n`);
3839
+ }
3840
+ }
3841
+ return result.ok ? 0 : 1;
3842
+ }
3843
+ function historicalSelectionAbsent(text, requestInput) {
3844
+ const parsed = parsePlanningPoolSource(text, PLANNING_POOL_SOURCE_CAPABILITY);
3845
+ const request = unknownRecord(requestInput);
3846
+ const selection = unknownRecord(request?.["selection"]);
3847
+ if (!parsed.ok || parsed.model === null || selection === null)
3848
+ return false;
3849
+ if (selection["kind"] === "work" && Array.isArray(selection["work_ids"])) {
3850
+ const available = new Set(parsed.model.works.map(({ qualifiedId }) => qualifiedId));
3851
+ return selection["work_ids"].some((id) => typeof id === "string" && !available.has(id));
3852
+ }
3853
+ if (selection["kind"] === "persisted" && typeof selection["window_id"] === "string") {
3854
+ return !parsed.model.windows.some(({ qualifiedId }) => qualifiedId === selection["window_id"]);
3855
+ }
3856
+ return false;
3857
+ }
3858
+ async function runPlanningObservation(resource, args) {
3859
+ const operation = `${resource}.observe`;
3860
+ const parsed = parseCommandOptions(operation, args);
3861
+ const format = outputFormat(parsed.values.get("format"));
3862
+ const sourceOperand = parsed.positionals[0];
3863
+ const input = await readDocument(sourceOperand);
3864
+ const request = await planningRequestInput(parsed, sourceOperand);
3865
+ let result = observeCurrentPlanningPool(input.text, request);
3866
+ if (!result.ok && sourceOperand !== "-" && historicalSelectionAbsent(input.text, request)) {
3867
+ const evidence = await historicalGitEvidenceHost.probe({
3868
+ targetPath: sourceOperand,
3869
+ expectedSourceDigest: input.digest,
3870
+ });
3871
+ result = observeHistoricalPlanningPool(input.text, request, evidence);
3872
+ }
3873
+ emitPlanningResult(format, operation, sourceOperand, result);
3874
+ return result.ok ? 0 : 1;
3875
+ }
3876
+ async function runPlanningReshapePreflight(args) {
3877
+ const operation = "work.reshape.preflight";
3878
+ const parsed = parseCommandOptions(operation, args);
3879
+ const format = outputFormat(parsed.values.get("format"));
3880
+ const sourceOperand = parsed.positionals[0];
3881
+ const input = await readDocument(sourceOperand);
3882
+ const request = await planningRequestInput(parsed, sourceOperand);
3883
+ const result = await withPlanningReshapeTokenRegistry((registry) => preflightPlanningPoolReshape(input.text, request, registry));
3884
+ emitPlanningResult(format, operation, sourceOperand, result);
3885
+ return result.ok ? 0 : 1;
3886
+ }
3887
+ function planningValidator(candidate) {
3888
+ const checked = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
3889
+ return { ok: checked.ok && checked.grammarVersion === 9, diagnostics: [] };
3890
+ }
3891
+ async function persistPlanningCandidate(request, candidateText, originalDigest) {
3892
+ if (request.mode === "preview") {
3893
+ return Object.freeze({ mode: "preview", target: null, written: false });
3894
+ }
3895
+ if (request.mode === "in_place") {
3896
+ const output = await replaceValidatedDocumentFile(request.target, candidateText, {
3897
+ initialDigest: originalDigest,
3898
+ ...(request.expectedDigest === undefined ? {} : { expectedDigest: request.expectedDigest }),
3899
+ }, planningValidator);
3900
+ return Object.freeze({ mode: "in_place", target: request.target, written: output.written });
3901
+ }
3902
+ const output = await createValidatedDocumentFile(request.target, candidateText, planningValidator);
3903
+ return Object.freeze({ mode: "out", target: request.target, written: output.written });
3904
+ }
3905
+ async function preparePlanningHistory(sourceOperand, sourceDigest, sourceText, writeRequest, records, changed, writeAuthorized) {
3906
+ const canonical = records.filter(({ ownerClass }) => ownerClass === "canonical");
3907
+ const notApplicable = (cause) => Object.freeze({
3908
+ guard: planningHistoryNotApplicable(canonical, cause),
3909
+ baseline: null,
3910
+ });
3911
+ if (writeRequest.mode === "preview")
3912
+ return notApplicable("preview");
3913
+ if (writeRequest.mode === "out")
3914
+ return notApplicable("separate_output");
3915
+ if (!changed)
3916
+ return notApplicable("no_change");
3917
+ if (canonical.length === 0)
3918
+ return notApplicable("no_canonical_records");
3919
+ if (!writeAuthorized)
3920
+ return notApplicable("authority_denied");
3921
+ const baseline = await captureAdvanceHistoryBaseline({
3922
+ targetPath: sourceOperand,
3923
+ expectedSourceDigest: sourceDigest,
3924
+ });
3925
+ const prepared = Object.freeze({
3926
+ guard: assessPlanningHistoryBaseline(sourceText, canonical, baseline),
3927
+ baseline,
3928
+ });
3929
+ if (prepared.guard.status !== "passed" || writeRequest.mode !== "in_place") {
3930
+ return prepared;
3931
+ }
3932
+ const recheck = await recheckAdvanceHistoryBaseline(baseline, sourceOperand);
3933
+ if (recheck.ok)
3934
+ return prepared;
3935
+ return Object.freeze({
3936
+ ...prepared,
3937
+ guard: Object.freeze({
3938
+ ...prepared.guard,
3939
+ status: "blocked",
3940
+ cause: recheck.cause ?? "baseline_race",
3941
+ }),
3942
+ });
3943
+ }
3944
+ function planningHistoryDiagnostic(guard) {
3945
+ return Object.freeze({
3946
+ code: "PTPOOL-113",
3947
+ severity: "error",
3948
+ message: "Canonical planning history proof is blocked",
3949
+ helpTopic: "editing",
3950
+ data: Object.freeze({
3951
+ cause: guard.cause,
3952
+ entity_ids: guard.overlappingEntityIds.length > 0
3953
+ ? guard.overlappingEntityIds
3954
+ : guard.destructiveEntityIds,
3955
+ }),
3956
+ });
3957
+ }
3958
+ async function runPlanningReshapeApply(args) {
3959
+ const operation = "work.reshape.apply";
3960
+ const parsed = parseCommandOptions(operation, args);
3961
+ const format = outputFormat(parsed.values.get("format"));
3962
+ const sourceOperand = parsed.positionals[0];
3963
+ const input = await readDocument(sourceOperand);
3964
+ const requestInput = await planningRequestInput(parsed, sourceOperand);
3965
+ const preflightHash = requiredOption(parsed, "preflight-hash");
3966
+ const preflightToken = requiredOption(parsed, "preflight-token");
3967
+ const writeRequest = editingWriteRequest(parsed, sourceOperand);
3968
+ const output = await withPlanningReshapeTokenRegistry(async (registry) => {
3969
+ const recovered = recoverPlanningPoolReshapeCommit(preflightToken, input.digest, registry);
3970
+ if (recovered.ok && recovered.completed) {
3971
+ const snapshot = registry.snapshots().find(({ tokenDigest }) => tokenDigest === sha256DigestUtf8(preflightToken));
3972
+ if (snapshot === undefined) {
3973
+ throw new Error("completed planning reshape recovery lost its token binding");
3974
+ }
3975
+ return Object.freeze({
3976
+ result: Object.freeze({
3977
+ schemaVersion: "Perttool.PlanningMutationResult.v1",
3978
+ reshapeCapability: "perttool.planning-reshape-core@1",
3979
+ ok: true,
3980
+ documentId: parsePlanningPoolSource(input.text, PLANNING_POOL_SOURCE_CAPABILITY).documentId,
3981
+ sourceDigest: snapshot.binding.sourceDigest,
3982
+ normalizedRequest: null,
3983
+ preflightHash: snapshot.binding.preflightHash,
3984
+ candidateDigest: snapshot.binding.candidateDigest,
3985
+ candidateText: input.text,
3986
+ changed: false,
3987
+ edits: Object.freeze([]),
3988
+ diagnostics: Object.freeze([]),
3989
+ diagnosticsTruncated: false,
3990
+ transfers: Object.freeze([]),
3991
+ destructiveRecords: Object.freeze([]),
3992
+ governance: null,
3993
+ assuranceImpact: null,
3994
+ historyGuard: planningHistoryNotApplicable([], "no_change"),
3995
+ tokenRecovery: recovered,
3996
+ }),
3997
+ write: Object.freeze({
3998
+ mode: writeRequest.mode,
3999
+ target: writeRequest.target,
4000
+ written: false,
4001
+ }),
4002
+ });
4003
+ }
4004
+ const prepared = preparePlanningPoolReshapeApply(input.text, requestInput, preflightHash, preflightToken, registry, { governance: governanceRequest(parsed, writeRequest) });
4005
+ const warningFailure = parsed.flags.has("warnings-as-errors") &&
4006
+ prepared.diagnostics.some(({ severity }) => severity === "warning");
4007
+ const history = await preparePlanningHistory(sourceOperand, input.digest, input.text, writeRequest, prepared.destructiveRecords, prepared.changed, prepared.ok && !warningFailure && (prepared.governance?.writeAuthorized ?? false));
4008
+ const historyBlocked = history.guard.status === "blocked";
4009
+ const effectiveDiagnostics = historyBlocked
4010
+ ? Object.freeze([...prepared.diagnostics, planningHistoryDiagnostic(history.guard)])
4011
+ : prepared.diagnostics;
4012
+ let write = Object.freeze({
4013
+ mode: writeRequest.mode,
4014
+ target: writeRequest.target,
4015
+ written: false,
4016
+ });
4017
+ if (prepared.ok && !warningFailure && !historyBlocked && writeRequest.mode !== "preview") {
4018
+ if (prepared.candidateText === null || prepared.candidateDigest === null) {
4019
+ throw new Error("successful planning reshape has no candidate");
4020
+ }
4021
+ assertExpectedDigest(writeRequest, input.digest);
4022
+ const begun = beginPlanningPoolReshapeCommit(prepared, preflightToken, registry);
4023
+ if (!begun.ok)
4024
+ throw new Error(`planning reshape token cannot enter commit: ${begun.state}`);
4025
+ if (prepared.changed) {
4026
+ write = await persistPlanningCandidate(writeRequest, prepared.candidateText, input.digest);
4027
+ }
4028
+ const settled = settlePlanningPoolReshapeCommit(preflightToken, prepared.candidateDigest, registry);
4029
+ if (!settled.ok || !settled.completed) {
4030
+ throw new Error(`planning reshape token cannot complete: ${settled.state}`);
4031
+ }
4032
+ }
4033
+ return Object.freeze({
4034
+ result: Object.freeze({
4035
+ ...prepared,
4036
+ ok: prepared.ok && !warningFailure && !historyBlocked,
4037
+ diagnostics: effectiveDiagnostics,
4038
+ historyGuard: history.guard,
4039
+ tokenRecovery: recovered,
4040
+ }),
4041
+ write,
4042
+ });
4043
+ });
4044
+ if (format === "json") {
4045
+ writeJson(planningResultJson(operation, sourceOperand === "-" ? "<stdin>" : sourceOperand, output.result, output.write));
4046
+ }
4047
+ else if (output.result.ok && output.result.candidateText !== null) {
4048
+ process.stdout.write(parsed.flags.has("diff")
4049
+ ? createUnifiedDiff(input.text, output.result.candidateText, { originalLabel: sourceOperand, updatedLabel: "candidate" })
4050
+ : output.result.candidateText);
4051
+ }
4052
+ return output.result.ok ? 0 : 1;
4053
+ }
4054
+ async function runPlanningWindowMutation(action, args) {
4055
+ const operation = `window.${action}`;
4056
+ const parsed = parseCommandOptions(operation, args);
4057
+ const format = outputFormat(parsed.values.get("format"));
4058
+ const sourceOperand = parsed.positionals[0];
4059
+ const input = await readDocument(sourceOperand);
4060
+ const requestInput = await planningRequestInput(parsed, sourceOperand);
4061
+ let effectiveRequest = requestInput;
4062
+ if (isPlanningIntentRequest(requestInput)) {
4063
+ const parsedSource = parsePlanningPoolSource(input.text, PLANNING_POOL_SOURCE_CAPABILITY);
4064
+ if (!parsedSource.ok || parsedSource.model === null) {
4065
+ throw new UsageError("Planning intent request requires a valid Grammar 9 document");
4066
+ }
4067
+ const compiled = compilePlanningIntentRequest(requestInput, parsedSource.model);
4068
+ if (!compiled.ok || compiled.windowRequest === null) {
4069
+ throw new UsageError(compiled.reshapeRequest === null
4070
+ ? compiled.diagnostics.map(({ message }) => message).join("; ") || "Planning intent request is invalid"
4071
+ : "Work intent request must use work reshape preflight/apply");
4072
+ }
4073
+ effectiveRequest = compiled.windowRequest;
4074
+ }
4075
+ const request = unknownRecord(effectiveRequest);
4076
+ if (request === null || request["window_id"] !== parsed.positionals[1] &&
4077
+ request["window_id"] !== `${/^project ([A-Za-z][A-Za-z0-9_-]*):$/mu.exec(input.text)?.[1] ?? ""}::${parsed.positionals[1]}`) {
4078
+ throw new UsageError("Window operand and request window_id must identify the same Window");
4079
+ }
4080
+ const writeRequest = editingWriteRequest(parsed, sourceOperand);
4081
+ const result = planPlanningWindowMutation(input.text, effectiveRequest, {
4082
+ governance: governanceRequest(parsed, writeRequest),
4083
+ });
4084
+ const history = await preparePlanningHistory(sourceOperand, input.digest, input.text, writeRequest, result.destructiveRecords, result.changed, result.ok && (result.governance?.writeAuthorized ?? false));
4085
+ const historyBlocked = history.guard.status === "blocked";
4086
+ let write = Object.freeze({
4087
+ mode: writeRequest.mode,
4088
+ target: writeRequest.target,
4089
+ written: false,
4090
+ });
4091
+ if (result.ok && !historyBlocked && result.candidateText !== null && writeRequest.mode !== "preview") {
4092
+ assertExpectedDigest(writeRequest, input.digest);
4093
+ if (result.changed) {
4094
+ write = await persistPlanningCandidate(writeRequest, result.candidateText, input.digest);
4095
+ }
4096
+ }
4097
+ const projected = Object.freeze({
4098
+ ...result,
4099
+ ok: result.ok && !historyBlocked,
4100
+ originalDigest: input.digest,
4101
+ updatedDigest: result.candidateDigest,
4102
+ updatedText: result.candidateText,
4103
+ diff: result.candidateText === null ? null : createUnifiedDiff(input.text, result.candidateText, {
4104
+ originalLabel: sourceOperand,
4105
+ updatedLabel: "candidate",
4106
+ }),
4107
+ diagnostics: historyBlocked
4108
+ ? Object.freeze([...result.diagnostics, planningHistoryDiagnostic(history.guard)])
4109
+ : result.diagnostics,
4110
+ historyGuard: history.guard,
4111
+ });
4112
+ if (format === "json") {
4113
+ writeJson(planningResultJson(operation, sourceOperand === "-" ? "<stdin>" : sourceOperand, projected, write));
4114
+ }
4115
+ else if (result.ok && result.candidateText !== null) {
4116
+ process.stdout.write(parsed.flags.has("diff") ? projected.diff ?? "" : result.candidateText);
4117
+ }
4118
+ return projected.ok ? 0 : 1;
4119
+ }
3470
4120
  async function dispatchCommand(descriptor, args) {
3471
4121
  switch (descriptor.operation) {
3472
4122
  case "help":
@@ -3509,6 +4159,30 @@ async function dispatchCommand(descriptor, args) {
3509
4159
  case "calendar.set":
3510
4160
  case "calendar.remove":
3511
4161
  return runCalendarMutation(descriptor.path[1], args);
4162
+ case "work.list":
4163
+ case "work.show":
4164
+ return runPlanningRead("work", descriptor.path[1], args);
4165
+ case "work.observe":
4166
+ return runPlanningObservation("work", args);
4167
+ case "work.reshape.preflight":
4168
+ return runPlanningReshapePreflight(args);
4169
+ case "work.reshape.apply":
4170
+ return runPlanningReshapeApply(args);
4171
+ case "event.list":
4172
+ case "event.show":
4173
+ return runPlanningRead("event", descriptor.path[1], args);
4174
+ case "activity.list":
4175
+ case "activity.show":
4176
+ return runPlanningRead("activity", descriptor.path[1], args);
4177
+ case "window.list":
4178
+ case "window.show":
4179
+ return runPlanningRead("window", descriptor.path[1], args);
4180
+ case "window.observe":
4181
+ return runPlanningObservation("window", args);
4182
+ case "window.add":
4183
+ case "window.set":
4184
+ case "window.close":
4185
+ return runPlanningWindowMutation(descriptor.path[1], args);
3512
4186
  case "task.start":
3513
4187
  return runLifecycleMutation("start", args);
3514
4188
  case "task.suspend":
@@ -3541,7 +4215,7 @@ async function dispatchCommand(descriptor, args) {
3541
4215
  const [resource, action] = descriptor.path;
3542
4216
  return runMutation(resource, action, args);
3543
4217
  }
3544
- throw new Error(`no Contract 8 handler for ${descriptor.operation}`);
4218
+ throw new Error(`no Contract 10 handler for ${descriptor.operation}`);
3545
4219
  }
3546
4220
  function emitCommandUsage(error, json) {
3547
4221
  if (json) {