perttool 0.9.4 → 0.10.1

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 (230) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +39 -17
  3. package/dist/application/cli-facade.d.ts +33 -8
  4. package/dist/application/cli-facade.d.ts.map +1 -1
  5. package/dist/application/cli-facade.js +1 -2
  6. package/dist/application/cli-facade.js.map +1 -1
  7. package/dist/application/contract9-assurance-mutation.d.ts +35 -0
  8. package/dist/application/contract9-assurance-mutation.d.ts.map +1 -0
  9. package/dist/application/contract9-assurance-mutation.js +146 -0
  10. package/dist/application/contract9-assurance-mutation.js.map +1 -0
  11. package/dist/application/contract9-assurance.d.ts +23 -0
  12. package/dist/application/contract9-assurance.d.ts.map +1 -0
  13. package/dist/application/contract9-assurance.js +114 -0
  14. package/dist/application/contract9-assurance.js.map +1 -0
  15. package/dist/application/contract9-candidate.d.ts +33 -0
  16. package/dist/application/contract9-candidate.d.ts.map +1 -0
  17. package/dist/application/contract9-candidate.js +39 -0
  18. package/dist/application/contract9-candidate.js.map +1 -0
  19. package/dist/application/contract9-format-migration.d.ts +22 -0
  20. package/dist/application/contract9-format-migration.d.ts.map +1 -0
  21. package/dist/application/contract9-format-migration.js +52 -0
  22. package/dist/application/contract9-format-migration.js.map +1 -0
  23. package/dist/application/contract9-mixed-mutation.d.ts +14 -0
  24. package/dist/application/contract9-mixed-mutation.d.ts.map +1 -0
  25. package/dist/application/contract9-mixed-mutation.js +88 -0
  26. package/dist/application/contract9-mixed-mutation.js.map +1 -0
  27. package/dist/application/contract9-project.d.ts +15 -0
  28. package/dist/application/contract9-project.d.ts.map +1 -0
  29. package/dist/application/contract9-project.js +24 -0
  30. package/dist/application/contract9-project.js.map +1 -0
  31. package/dist/application/contract9-projection.d.ts +23 -0
  32. package/dist/application/contract9-projection.d.ts.map +1 -0
  33. package/dist/application/contract9-projection.js +89 -0
  34. package/dist/application/contract9-projection.js.map +1 -0
  35. package/dist/application/contract9-runtime.d.ts +43 -0
  36. package/dist/application/contract9-runtime.d.ts.map +1 -0
  37. package/dist/application/contract9-runtime.js +36 -0
  38. package/dist/application/contract9-runtime.js.map +1 -0
  39. package/dist/application/contract9-temporal-context.d.ts +15 -0
  40. package/dist/application/contract9-temporal-context.d.ts.map +1 -0
  41. package/dist/application/contract9-temporal-context.js +127 -0
  42. package/dist/application/contract9-temporal-context.js.map +1 -0
  43. package/dist/application/contract9-temporal-mutation.d.ts +20 -0
  44. package/dist/application/contract9-temporal-mutation.d.ts.map +1 -0
  45. package/dist/application/contract9-temporal-mutation.js +78 -0
  46. package/dist/application/contract9-temporal-mutation.js.map +1 -0
  47. package/dist/application/contract9-temporal.d.ts +17 -0
  48. package/dist/application/contract9-temporal.d.ts.map +1 -0
  49. package/dist/application/contract9-temporal.js +65 -0
  50. package/dist/application/contract9-temporal.js.map +1 -0
  51. package/dist/application/contract9-write.d.ts +28 -0
  52. package/dist/application/contract9-write.d.ts.map +1 -0
  53. package/dist/application/contract9-write.js +25 -0
  54. package/dist/application/contract9-write.js.map +1 -0
  55. package/dist/application/editor-milestone-acceptance.d.ts +4 -0
  56. package/dist/application/editor-milestone-acceptance.d.ts.map +1 -1
  57. package/dist/application/editor-milestone-acceptance.js +90 -0
  58. package/dist/application/editor-milestone-acceptance.js.map +1 -1
  59. package/dist/application/editor-repair.d.ts +12 -0
  60. package/dist/application/editor-repair.d.ts.map +1 -0
  61. package/dist/application/editor-repair.js +74 -0
  62. package/dist/application/editor-repair.js.map +1 -0
  63. package/dist/application/target-postdue-analysis.d.ts +18 -0
  64. package/dist/application/target-postdue-analysis.d.ts.map +1 -0
  65. package/dist/application/target-postdue-analysis.js +26 -0
  66. package/dist/application/target-postdue-analysis.js.map +1 -0
  67. package/dist/application/target-postdue-check.d.ts +10 -0
  68. package/dist/application/target-postdue-check.d.ts.map +1 -0
  69. package/dist/application/target-postdue-check.js +18 -0
  70. package/dist/application/target-postdue-check.js.map +1 -0
  71. package/dist/application/target-postdue-next.d.ts +10 -0
  72. package/dist/application/target-postdue-next.d.ts.map +1 -0
  73. package/dist/application/target-postdue-next.js +13 -0
  74. package/dist/application/target-postdue-next.js.map +1 -0
  75. package/dist/application/target-postdue-projection.d.ts +11 -0
  76. package/dist/application/target-postdue-projection.d.ts.map +1 -0
  77. package/dist/application/target-postdue-projection.js +17 -0
  78. package/dist/application/target-postdue-projection.js.map +1 -0
  79. package/dist/assurance/canonical.d.ts +3 -3
  80. package/dist/assurance/canonical.d.ts.map +1 -1
  81. package/dist/assurance/canonical.js +19 -6
  82. package/dist/assurance/canonical.js.map +1 -1
  83. package/dist/assurance/evaluate.d.ts.map +1 -1
  84. package/dist/assurance/evaluate.js +10 -2
  85. package/dist/assurance/evaluate.js.map +1 -1
  86. package/dist/assurance/types.d.ts +11 -1
  87. package/dist/assurance/types.d.ts.map +1 -1
  88. package/dist/cli.js +184 -85
  89. package/dist/cli.js.map +1 -1
  90. package/dist/command/contract9-discovery.d.ts +17 -0
  91. package/dist/command/contract9-discovery.d.ts.map +1 -0
  92. package/dist/command/contract9-discovery.js +130 -0
  93. package/dist/command/contract9-discovery.js.map +1 -0
  94. package/dist/command/contract9-usage.d.ts +24 -0
  95. package/dist/command/contract9-usage.d.ts.map +1 -0
  96. package/dist/command/contract9-usage.js +23 -0
  97. package/dist/command/contract9-usage.js.map +1 -0
  98. package/dist/core/index.d.ts +4 -3
  99. package/dist/core/index.d.ts.map +1 -1
  100. package/dist/core/index.js +1 -1
  101. package/dist/editor/repair.d.ts +95 -0
  102. package/dist/editor/repair.d.ts.map +1 -0
  103. package/dist/editor/repair.js +232 -0
  104. package/dist/editor/repair.js.map +1 -0
  105. package/dist/editor/semantic-fingerprint.d.ts +8 -0
  106. package/dist/editor/semantic-fingerprint.d.ts.map +1 -0
  107. package/dist/editor/semantic-fingerprint.js +177 -0
  108. package/dist/editor/semantic-fingerprint.js.map +1 -0
  109. package/dist/help/assurance-guide.js +7 -7
  110. package/dist/help/assurance-guide.js.map +1 -1
  111. package/dist/help/contract9-guide.d.ts +10 -0
  112. package/dist/help/contract9-guide.d.ts.map +1 -0
  113. package/dist/help/contract9-guide.js +32 -0
  114. package/dist/help/contract9-guide.js.map +1 -0
  115. package/dist/help/guide.d.ts +1 -1
  116. package/dist/help/guide.d.ts.map +1 -1
  117. package/dist/index.d.ts +10 -8
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +4 -4
  120. package/dist/index.js.map +1 -1
  121. package/dist/mutation/advance.d.ts.map +1 -1
  122. package/dist/mutation/advance.js.map +1 -1
  123. package/dist/recommendation/override-types.d.ts +2 -2
  124. package/dist/recommendation/override.js +2 -2
  125. package/dist/schema/registry.d.ts +1 -1
  126. package/dist/schema/registry.js +8 -8
  127. package/dist/session/document-session.d.ts +23 -0
  128. package/dist/session/document-session.d.ts.map +1 -1
  129. package/dist/session/document-session.js +104 -2
  130. package/dist/session/document-session.js.map +1 -1
  131. package/dist/temporal-schedule/alert-types.d.ts +109 -0
  132. package/dist/temporal-schedule/alert-types.d.ts.map +1 -0
  133. package/dist/temporal-schedule/alert-types.js +2 -0
  134. package/dist/temporal-schedule/alert-types.js.map +1 -0
  135. package/dist/temporal-schedule/alert.d.ts +4 -0
  136. package/dist/temporal-schedule/alert.d.ts.map +1 -0
  137. package/dist/temporal-schedule/alert.js +214 -0
  138. package/dist/temporal-schedule/alert.js.map +1 -0
  139. package/dist/temporal-schedule/calendar-mutation.d.ts +11 -0
  140. package/dist/temporal-schedule/calendar-mutation.d.ts.map +1 -0
  141. package/dist/temporal-schedule/calendar-mutation.js +59 -0
  142. package/dist/temporal-schedule/calendar-mutation.js.map +1 -0
  143. package/dist/temporal-schedule/calendar.d.ts +16 -0
  144. package/dist/temporal-schedule/calendar.d.ts.map +1 -0
  145. package/dist/temporal-schedule/calendar.js +179 -0
  146. package/dist/temporal-schedule/calendar.js.map +1 -0
  147. package/dist/temporal-schedule/constraint-types.d.ts +47 -0
  148. package/dist/temporal-schedule/constraint-types.d.ts.map +1 -0
  149. package/dist/temporal-schedule/constraint-types.js +2 -0
  150. package/dist/temporal-schedule/constraint-types.js.map +1 -0
  151. package/dist/temporal-schedule/constraint.d.ts +7 -0
  152. package/dist/temporal-schedule/constraint.d.ts.map +1 -0
  153. package/dist/temporal-schedule/constraint.js +224 -0
  154. package/dist/temporal-schedule/constraint.js.map +1 -0
  155. package/dist/temporal-schedule/entity-mutation.d.ts +31 -0
  156. package/dist/temporal-schedule/entity-mutation.d.ts.map +1 -0
  157. package/dist/temporal-schedule/entity-mutation.js +107 -0
  158. package/dist/temporal-schedule/entity-mutation.js.map +1 -0
  159. package/dist/temporal-schedule/format.d.ts +9 -0
  160. package/dist/temporal-schedule/format.d.ts.map +1 -0
  161. package/dist/temporal-schedule/format.js +183 -0
  162. package/dist/temporal-schedule/format.js.map +1 -0
  163. package/dist/temporal-schedule/required-types.d.ts +68 -0
  164. package/dist/temporal-schedule/required-types.d.ts.map +1 -0
  165. package/dist/temporal-schedule/required-types.js +2 -0
  166. package/dist/temporal-schedule/required-types.js.map +1 -0
  167. package/dist/temporal-schedule/required.d.ts +5 -0
  168. package/dist/temporal-schedule/required.d.ts.map +1 -0
  169. package/dist/temporal-schedule/required.js +183 -0
  170. package/dist/temporal-schedule/required.js.map +1 -0
  171. package/dist/temporal-schedule/schedule-graph.d.ts +8 -0
  172. package/dist/temporal-schedule/schedule-graph.d.ts.map +1 -0
  173. package/dist/temporal-schedule/schedule-graph.js +33 -0
  174. package/dist/temporal-schedule/schedule-graph.js.map +1 -0
  175. package/dist/temporal-schedule/scheduler-types.d.ts +115 -0
  176. package/dist/temporal-schedule/scheduler-types.d.ts.map +1 -0
  177. package/dist/temporal-schedule/scheduler-types.js +2 -0
  178. package/dist/temporal-schedule/scheduler-types.js.map +1 -0
  179. package/dist/temporal-schedule/scheduler.d.ts +12 -0
  180. package/dist/temporal-schedule/scheduler.d.ts.map +1 -0
  181. package/dist/temporal-schedule/scheduler.js +584 -0
  182. package/dist/temporal-schedule/scheduler.js.map +1 -0
  183. package/dist/temporal-schedule/source-lexical.d.ts +30 -0
  184. package/dist/temporal-schedule/source-lexical.d.ts.map +1 -0
  185. package/dist/temporal-schedule/source-lexical.js +166 -0
  186. package/dist/temporal-schedule/source-lexical.js.map +1 -0
  187. package/dist/temporal-schedule/source-types.d.ts +124 -0
  188. package/dist/temporal-schedule/source-types.d.ts.map +1 -0
  189. package/dist/temporal-schedule/source-types.js +2 -0
  190. package/dist/temporal-schedule/source-types.js.map +1 -0
  191. package/dist/temporal-schedule/source-values.d.ts +17 -0
  192. package/dist/temporal-schedule/source-values.d.ts.map +1 -0
  193. package/dist/temporal-schedule/source-values.js +138 -0
  194. package/dist/temporal-schedule/source-values.js.map +1 -0
  195. package/dist/temporal-schedule/source.d.ts +17 -0
  196. package/dist/temporal-schedule/source.d.ts.map +1 -0
  197. package/dist/temporal-schedule/source.js +520 -0
  198. package/dist/temporal-schedule/source.js.map +1 -0
  199. package/dist/temporal-schedule/tzdb-2026c.d.ts +7 -0
  200. package/dist/temporal-schedule/tzdb-2026c.d.ts.map +1 -0
  201. package/dist/temporal-schedule/tzdb-2026c.js +611 -0
  202. package/dist/temporal-schedule/tzdb-2026c.js.map +1 -0
  203. package/dist/version.d.ts +1 -1
  204. package/dist/version.d.ts.map +1 -1
  205. package/dist/version.js +1 -1
  206. package/dist/version.js.map +1 -1
  207. package/package.json +1 -1
  208. package/schemas/Perttool.AdvanceResult.v3.schema.json +1 -1
  209. package/schemas/Perttool.AgentGuidanceResult.v1.schema.json +1 -1
  210. package/schemas/{Perttool.AnalysisResult.v6.schema.json → Perttool.AnalysisResult.v7.schema.json} +178 -6
  211. package/schemas/{Perttool.CheckResult.v5.schema.json → Perttool.CheckResult.v6.schema.json} +10 -6
  212. package/schemas/Perttool.CliError.v1.schema.json +1 -1
  213. package/schemas/Perttool.CommandHelpResult.v1.schema.json +2 -2
  214. package/schemas/Perttool.ExportResult.v1.schema.json +1 -1
  215. package/schemas/Perttool.FormatResult.v1.schema.json +1 -1
  216. package/schemas/Perttool.GuideResult.v1.schema.json +1 -1
  217. package/schemas/Perttool.HistoricalGraphResult.v1.schema.json +1 -1
  218. package/schemas/Perttool.ImportResult.v1.schema.json +1 -1
  219. package/schemas/Perttool.InitResult.v1.schema.json +1 -1
  220. package/schemas/Perttool.MilestoneAcceptanceMigrationResult.v1.schema.json +1 -1
  221. package/schemas/Perttool.MilestoneAcceptanceResult.v1.schema.json +1 -1
  222. package/schemas/{Perttool.MutationResult.v5.schema.json → Perttool.MutationResult.v6.schema.json} +4 -4
  223. package/schemas/{Perttool.NextResult.v7.schema.json → Perttool.NextResult.v8.schema.json} +10 -6
  224. package/schemas/Perttool.OverrideDecision.v1.schema.json +1 -1
  225. package/schemas/{Perttool.PlanAssuranceResult.v1.schema.json → Perttool.PlanAssuranceResult.v2.schema.json} +5 -5
  226. package/schemas/Perttool.ProjectHistoryResult.v1.schema.json +1 -1
  227. package/schemas/{Perttool.ProjectResult.v4.schema.json → Perttool.ProjectResult.v5.schema.json} +70 -7
  228. package/schemas/Perttool.SchemaResult.v1.schema.json +1 -1
  229. package/schemas/{Perttool.UnitMigrationResult.v3.schema.json → Perttool.UnitMigrationResult.v4.schema.json} +5 -5
  230. package/schemas/Perttool.VelocityObservationResult.v1.schema.json +1 -1
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 { getAssuranceGuide, renderAssuranceGuideResult, serializeAssuranceGuideResult, } from "./help/assurance-guide.js";
10
+ import { getContract9Guide as getAssuranceGuide, renderContract9GuideResult as renderAssuranceGuideResult, serializeContract9GuideResult as serializeAssuranceGuideResult, } from "./help/contract9-guide.js";
11
11
  import { commandOptionSets, } from "./command/registry.js";
12
- import { ASSURANCE_COMMAND_REGISTRY, getAssuranceCommandDiscovery, renderAssuranceCommandHelpResult, serializeAssuranceCommandHelpResult, } from "./command/assurance-discovery.js";
12
+ import { CONTRACT9_COMMAND_REGISTRY as ASSURANCE_COMMAND_REGISTRY, getContract9CommandDiscovery as getAssuranceCommandDiscovery, renderContract9CommandHelpResult as renderAssuranceCommandHelpResult, serializeContract9CommandHelpResult as serializeAssuranceCommandHelpResult, } from "./command/contract9-discovery.js";
13
13
  import { handlerCommandUsageError, } from "./command/usage.js";
14
- import { renderAssuranceCommandUsageError, serializeAssuranceCommandUsageError, validateAssuranceCommandInvocation, } from "./command/assurance-usage.js";
14
+ import { renderContract9CommandUsageError as renderAssuranceCommandUsageError, serializeContract9CommandUsageError as serializeAssuranceCommandUsageError, validateContract9CommandInvocation as validateAssuranceCommandInvocation, } from "./command/contract9-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";
@@ -27,8 +27,13 @@ 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/contract8-milestone-acceptance.js";
31
- import { persistMilestoneAcceptanceMutation, planAcceptanceReceiptMutation, planCriterionSetReplacement, showMilestoneAcceptance, } from "./milestone-acceptance/mutation.js";
30
+ import { analyzeDocument as analyzeContract8Document, checkDocument as checkContract8Document, selectNextTasks as selectContract8NextTasks, } from "./application/contract9-temporal.js";
31
+ import { contract9CheckResultToJson, contract9ProjectResultToJson, liftContract9AnalysisResultJson, liftContract9NextResultJson, renderContract9ScheduleAlerts, contract9WireJson, } from "./application/contract9-projection.js";
32
+ import { planContract9GrammarMigration } from "./application/contract9-format-migration.js";
33
+ import { planContract9TemporalMutation } from "./application/contract9-temporal-mutation.js";
34
+ import { composeContract9MixedMutation, composeContract9TemporalMutation } from "./application/contract9-mixed-mutation.js";
35
+ import { planAcceptanceReceiptMutation, planCriterionSetReplacement, showMilestoneAcceptance, } from "./milestone-acceptance/mutation.js";
36
+ import { scanTemporalDeclarationBlocks, temporalScheduleBaseText, } from "./temporal-schedule/source-lexical.js";
32
37
  import { planMilestoneAcceptanceMigration, recheckCommittedMigrationProof, } from "./milestone-acceptance/migration.js";
33
38
  import { MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY, milestoneAcceptanceBaseText, parseMilestoneAcceptanceSource } from "./milestone-acceptance/source.js";
34
39
  import { coalesceMilestoneAcceptanceDeletionOverlaps, planMilestoneAcceptanceAdvance, preserveMilestoneAcceptanceRecords, } from "./milestone-acceptance/advance.js";
@@ -36,11 +41,11 @@ const { analyzeDocument: _analyzeContract7Document, checkDocument: _checkContrac
36
41
  const analyzeDocument = analyzeContract8Document;
37
42
  const checkDocument = checkContract8Document;
38
43
  const selectNextTasks = selectContract8NextTasks;
39
- function contract8MutationResultToJson(result, ...args) {
44
+ function contract9MutationResultToJson(result, ...args) {
40
45
  return Object.freeze({
41
46
  ...contract7MutationResultToJson(result, ...args),
42
- schema_version: "Perttool.MutationResult.v5",
43
- cli_contract_version: 8,
47
+ schema_version: "Perttool.MutationResult.v6",
48
+ cli_contract_version: 9,
44
49
  });
45
50
  }
46
51
  class UsageError extends Error {
@@ -216,7 +221,7 @@ async function readStdin() {
216
221
  function writeJson(value) {
217
222
  const contract8Value = typeof value === "object" && value !== null && !Array.isArray(value) &&
218
223
  "cli_contract_version" in value
219
- ? { ...value, cli_contract_version: 8 }
224
+ ? { ...value, cli_contract_version: 9 }
220
225
  : value;
221
226
  process.stdout.write(`${JSON.stringify(contract8Value)}\n`);
222
227
  }
@@ -289,30 +294,7 @@ async function runCheck(args) {
289
294
  const warningFailure = warningsAsErrors && result.summary.warnings > 0;
290
295
  const ok = result.ok && !warningFailure;
291
296
  if (format === "json") {
292
- writeJson({
293
- schema_version: result.schemaVersion,
294
- cli_contract_version: 8,
295
- tool_version: TOOL_VERSION,
296
- operation: "document.check",
297
- ok,
298
- document_id: result.documentId,
299
- source,
300
- source_digest: input.digest,
301
- diagnostics: result.diagnostics.map(jsonDiagnostic),
302
- diagnostics_truncated: result.diagnosticsTruncated,
303
- grammar_version: result.grammarVersion,
304
- summary: result.summary,
305
- temporal_inputs: snakeJson(result.temporalInputs),
306
- actuals_inputs: result.actualsInputs === null
307
- ? null
308
- : {
309
- model_version: result.actualsInputs.modelVersion,
310
- events: result.actualsInputs.events.map(contract6WorkEventToJson),
311
- },
312
- assurance: contract7SnakeJson(result.assurance),
313
- assurance_state_counts: contract7SnakeJson(result.assuranceStateCounts),
314
- acceptance: snakeJson(result.acceptance),
315
- });
297
+ writeJson(contract9CheckResultToJson(result, { source, sourceDigest: input.digest, ok }));
316
298
  }
317
299
  else {
318
300
  if (ok) {
@@ -321,6 +303,7 @@ async function runCheck(args) {
321
303
  for (const diagnostic of result.diagnostics) {
322
304
  process.stderr.write(`${renderDiagnostic(diagnostic, source, color)}\n`);
323
305
  }
306
+ process.stdout.write(renderContract9ScheduleAlerts(result.scheduleAlerts));
324
307
  if (result.diagnosticsTruncated) {
325
308
  process.stderr.write(`DIAGNOSTICS_TRUNCATED true limit=${maxDiagnostics}\n`);
326
309
  }
@@ -350,7 +333,7 @@ async function runProjectShow(args) {
350
333
  result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
351
334
  const ok = result.ok && !warningFailure;
352
335
  if (format === "json") {
353
- writeJson(contract7ProjectResultToJson(result, source, input.digest, ok));
336
+ writeJson(contract9ProjectResultToJson(result, { source, sourceDigest: input.digest, ok }));
354
337
  }
355
338
  else {
356
339
  if (ok && result.project !== null) {
@@ -549,10 +532,15 @@ async function persistContract8CandidateResult(result, request) {
549
532
  if (!result.ok || !result.governance?.writeAuthorized || result.updatedText === null) {
550
533
  throw new TypeError("authorized Contract 8 result does not contain a digest-bound candidate");
551
534
  }
552
- const validator = (candidate) => {
553
- const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
554
- return { ok: parsed.ok, diagnostics: [] };
555
- };
535
+ const validator = /^ version 8$/mu.test(result.updatedText)
536
+ ? (candidate) => {
537
+ const checked = checkDocument(candidate);
538
+ return { ok: checked.ok, diagnostics: checked.diagnostics };
539
+ }
540
+ : (candidate) => {
541
+ const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
542
+ return { ok: parsed.ok, diagnostics: [] };
543
+ };
556
544
  if (request.mode === "in_place") {
557
545
  await replaceValidatedDocumentFile(request.target, result.updatedText, {
558
546
  initialDigest: result.originalDigest,
@@ -575,6 +563,20 @@ async function commitCandidate(request, candidateText, initialDigest) {
575
563
  if (candidateText === null) {
576
564
  throw new SafeWriteVerificationError("invalid_candidate", "successful editing result has no candidate text");
577
565
  }
566
+ if (/^ version 8$/mu.test(candidateText)) {
567
+ const validator = (candidate) => {
568
+ const checked = checkDocument(candidate);
569
+ return { ok: checked.ok, diagnostics: checked.diagnostics };
570
+ };
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);
579
+ }
578
580
  const acceptanceSource = parseMilestoneAcceptanceSource(candidateText, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
579
581
  if (acceptanceSource.grammarVersion === 7) {
580
582
  const validator = (candidate) => {
@@ -614,6 +616,26 @@ function renderWriteSummary(operation, result) {
614
616
  function renderGovernanceWriteSummary(operation, result, digest) {
615
617
  return `WRITE ${operation} mode=${result.mode} target=${result.target ?? "-"} digest=${digest ?? "-"} written=${result.written}\n`;
616
618
  }
619
+ async function runContract9DocumentMigration(args) {
620
+ const parsed = parseCommandOptions("document.migrate", args);
621
+ if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "8")
622
+ throw new UsageError("document migrate requires <file> --target-grammar 8");
623
+ const sourceOperand = parsed.positionals[0];
624
+ const format = outputFormat(parsed.values.get("format"));
625
+ const input = await readDocument(sourceOperand);
626
+ const result = planContract9GrammarMigration(input.text);
627
+ if (result.ok && result.updatedText !== null && parsed.flags.has("write")) {
628
+ if (sourceOperand === "-")
629
+ throw new UsageError("document migrate --write requires a file");
630
+ 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: [] }));
631
+ }
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);
637
+ return result.ok ? 0 : 1;
638
+ }
617
639
  async function runFormat(args) {
618
640
  const parsed = parseCommandOptions("document.format", args);
619
641
  if (parsed.positionals.length !== 1) {
@@ -657,7 +679,7 @@ async function runFormat(args) {
657
679
  if (format === "json") {
658
680
  writeJson({
659
681
  schema_version: "Perttool.FormatResult.v1",
660
- cli_contract_version: 8,
682
+ cli_contract_version: 9,
661
683
  tool_version: TOOL_VERSION,
662
684
  operation: "document.format",
663
685
  ok,
@@ -1241,11 +1263,21 @@ async function runMutation(resource, action, args) {
1241
1263
  updatedLabel: "candidate",
1242
1264
  governance: governanceRequest(parsed, writeRequest),
1243
1265
  };
1244
- const result = lifecycleMutation !== null
1245
- ? planFinishActuals(input.text, lifecycleMutation, mutationOptions)
1266
+ const legacyPlanner = (text) => lifecycleMutation !== null
1267
+ ? planFinishActuals(text, lifecycleMutation, mutationOptions)
1246
1268
  : resource === "batch"
1247
- ? planBatchMutation(input.text, mutation, mutationOptions)
1248
- : planMutation(input.text, mutation, mutationOptions);
1269
+ ? planBatchMutation(text, mutation, mutationOptions)
1270
+ : planMutation(text, mutation, mutationOptions);
1271
+ const contract9Invocation = validateAssuranceCommandInvocation([resource, action, ...args]);
1272
+ const temporalRequest = contract9Invocation.ok
1273
+ ? planContract9TemporalMutation(input.text, contract9Invocation, { maxDiagnostics })
1274
+ : null;
1275
+ const legacyPreview = legacyPlanner(input.text);
1276
+ const result = temporalRequest === null
1277
+ ? legacyPreview
1278
+ : !legacyPreview.ok
1279
+ ? composeContract9TemporalMutation(input.text, (candidate) => planContract9TemporalMutation(candidate, contract9Invocation, { maxDiagnostics }), { originalLabel: source, updatedLabel: "candidate" })
1280
+ : composeContract9MixedMutation(input.text, (base) => legacyPlanner(base), (candidate) => planContract9TemporalMutation(candidate, contract9Invocation, { maxDiagnostics }), { originalLabel: source, updatedLabel: "candidate" });
1249
1281
  const warningFailure = parsed.flags.has("warnings-as-errors") &&
1250
1282
  (result.diagnosticsTruncated ||
1251
1283
  result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
@@ -1266,7 +1298,7 @@ async function runMutation(resource, action, args) {
1266
1298
  }
1267
1299
  }
1268
1300
  if (format === "json") {
1269
- writeJson(contract8MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1301
+ writeJson(contract9MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1270
1302
  }
1271
1303
  else {
1272
1304
  if (ok) {
@@ -1349,7 +1381,7 @@ async function runLifecycleMutation(action, args) {
1349
1381
  }
1350
1382
  }
1351
1383
  if (format === "json") {
1352
- writeJson(contract8MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1384
+ writeJson(contract9MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1353
1385
  }
1354
1386
  else {
1355
1387
  if (ok) {
@@ -1388,7 +1420,7 @@ function unitMigrationJson(result, source, sourceDigest, ok) {
1388
1420
  });
1389
1421
  return {
1390
1422
  schema_version: result.schemaVersion,
1391
- cli_contract_version: 8,
1423
+ cli_contract_version: 9,
1392
1424
  tool_version: TOOL_VERSION,
1393
1425
  operation: "project.migrate-unit",
1394
1426
  ok,
@@ -2261,8 +2293,8 @@ async function runAnalyze(args) {
2261
2293
  result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
2262
2294
  const ok = result.ok && !warningFailure;
2263
2295
  if (format === "json") {
2264
- writeJson({
2265
- schema_version: result.schemaVersion,
2296
+ writeJson(liftContract9AnalysisResultJson({
2297
+ schema_version: "Perttool.AnalysisResult.v6",
2266
2298
  cli_contract_version: 8,
2267
2299
  tool_version: TOOL_VERSION,
2268
2300
  operation: "dag.analyze",
@@ -2297,7 +2329,7 @@ async function runAnalyze(args) {
2297
2329
  temporal: snakeJson(result.temporal),
2298
2330
  assurance: contract7SnakeJson(result.assurance),
2299
2331
  acceptance: snakeJson(result.acceptance),
2300
- });
2332
+ }, result));
2301
2333
  }
2302
2334
  else {
2303
2335
  if (ok)
@@ -2833,7 +2865,7 @@ async function runNext(args) {
2833
2865
  if (format === "json") {
2834
2866
  writeJson({
2835
2867
  schema_version: "Perttool.CliError.v1",
2836
- cli_contract_version: 8,
2868
+ cli_contract_version: 9,
2837
2869
  tool_version: TOOL_VERSION,
2838
2870
  operation: "dag.next",
2839
2871
  ok: false,
@@ -2852,8 +2884,8 @@ async function runNext(args) {
2852
2884
  result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
2853
2885
  const ok = result.ok && !warningFailure;
2854
2886
  if (format === "json") {
2855
- writeJson({
2856
- schema_version: result.schemaVersion,
2887
+ writeJson(liftContract9NextResultJson({
2888
+ schema_version: "Perttool.NextResult.v7",
2857
2889
  cli_contract_version: 8,
2858
2890
  recommendation_interface_version: 1,
2859
2891
  tool_version: TOOL_VERSION,
@@ -2869,7 +2901,7 @@ async function runNext(args) {
2869
2901
  temporal: snakeJson(result.temporal),
2870
2902
  assurance: contract7SnakeJson(result.assurance),
2871
2903
  acceptance: snakeJson(result.acceptance),
2872
- });
2904
+ }, result));
2873
2905
  }
2874
2906
  else {
2875
2907
  if (ok)
@@ -2883,6 +2915,49 @@ async function runNext(args) {
2883
2915
  }
2884
2916
  return ok ? 0 : 1;
2885
2917
  }
2918
+ function parseMilestoneAcceptanceCriteria(values) {
2919
+ return values.map((value) => {
2920
+ const [criterionId, requiredText, evidenceKind, ...description] = value.split(":");
2921
+ if (criterionId === undefined || !["required", "optional"].includes(requiredText ?? "") || !["test", "command", "artifact", "observation", "owner"].includes(evidenceKind ?? "") || description.length === 0)
2922
+ throw new UsageError("--criterion must be ID:required|optional:kind:description");
2923
+ return {
2924
+ criterionId,
2925
+ required: requiredText === "required",
2926
+ evidenceKind: evidenceKind,
2927
+ description: description.join(":"),
2928
+ };
2929
+ });
2930
+ }
2931
+ function planContract9AcceptanceMutation(text, planner) {
2932
+ if (!/^ version 8$/mu.test(text))
2933
+ return planner(text);
2934
+ const base = temporalScheduleBaseText(text, scanTemporalDeclarationBlocks(text));
2935
+ const planned = planner(base);
2936
+ const originalDigest = sha256DigestUtf8(text);
2937
+ if (!planned.ok || planned.updatedText === null) {
2938
+ return Object.freeze({ ...planned, originalDigest });
2939
+ }
2940
+ let prefix = 0;
2941
+ while (prefix < base.length &&
2942
+ prefix < planned.updatedText.length &&
2943
+ base[prefix] === planned.updatedText[prefix])
2944
+ prefix += 1;
2945
+ let suffix = 0;
2946
+ while (suffix < base.length - prefix &&
2947
+ suffix < planned.updatedText.length - prefix &&
2948
+ base[base.length - 1 - suffix] ===
2949
+ planned.updatedText[planned.updatedText.length - 1 - suffix])
2950
+ suffix += 1;
2951
+ const candidate = text.slice(0, prefix) +
2952
+ planned.updatedText.slice(prefix, planned.updatedText.length - suffix) +
2953
+ text.slice(text.length - suffix);
2954
+ const checked = checkDocument(candidate);
2955
+ if (!checked.ok)
2956
+ return Object.freeze({ ...planned, ok: false, changed: false,
2957
+ originalDigest, updatedDigest: null, updatedText: null });
2958
+ return Object.freeze({ ...planned, originalDigest, changed: candidate !== text,
2959
+ updatedDigest: sha256DigestUtf8(candidate), updatedText: candidate });
2960
+ }
2886
2961
  async function runMilestoneAcceptance(action, args) {
2887
2962
  const operation = `milestone-acceptance.${action}`;
2888
2963
  const parsed = parseCommandOptions(operation, args);
@@ -2909,16 +2984,11 @@ async function runMilestoneAcceptance(action, args) {
2909
2984
  const governance = governanceRequest(parsed, request);
2910
2985
  let result;
2911
2986
  if (action === "replace") {
2912
- const criteria = (parsed.repeatedValues.get("criterion") ?? []).map((value) => {
2913
- const [criterionId, requiredText, evidenceKind, ...description] = value.split(":");
2914
- if (criterionId === undefined || !["required", "optional"].includes(requiredText ?? "") || !["test", "command", "artifact", "observation", "owner"].includes(evidenceKind ?? "") || description.length === 0)
2915
- throw new UsageError("--criterion must be ID:required|optional:kind:description");
2916
- return { criterionId, required: requiredText === "required", evidenceKind: evidenceKind, description: description.join(":") };
2917
- });
2918
- result = planCriterionSetReplacement(input.text, { milestoneId: parsed.positionals[1], setId: parsed.positionals[2], revisionId: parsed.positionals[3], criteria }, { governance });
2987
+ const criteria = parseMilestoneAcceptanceCriteria(parsed.repeatedValues.get("criterion") ?? []);
2988
+ result = planContract9AcceptanceMutation(input.text, (text) => planCriterionSetReplacement(text, { milestoneId: parsed.positionals[1], setId: parsed.positionals[2], revisionId: parsed.positionals[3], criteria }, { governance }));
2919
2989
  }
2920
2990
  else {
2921
- result = planAcceptanceReceiptMutation(input.text, {
2991
+ result = planContract9AcceptanceMutation(input.text, (text) => planAcceptanceReceiptMutation(text, {
2922
2992
  setId: parsed.positionals[1], criterionId: parsed.positionals[2], receiptId: parsed.positionals[3], action: action,
2923
2993
  ...(parsed.values.get("evidence-kind") === undefined ? {} : { evidenceKind: parsed.values.get("evidence-kind") }),
2924
2994
  ...(parsed.values.get("evidence-reference") === undefined ? {} : { evidenceReference: parsed.values.get("evidence-reference") }),
@@ -2927,16 +2997,16 @@ async function runMilestoneAcceptance(action, args) {
2927
2997
  ...(parsed.values.get("occurred-at") === undefined ? {} : { occurredAt: parsed.values.get("occurred-at") }),
2928
2998
  ...(parsed.values.get("reason") === undefined ? {} : { reason: parsed.values.get("reason") }),
2929
2999
  ...(parsed.values.get("revokes") === undefined ? {} : { revokes: parsed.values.get("revokes") }),
2930
- }, { governance });
3000
+ }, { governance }));
2931
3001
  }
2932
3002
  let written = false;
2933
3003
  if (result.ok && request.mode === "in_place" && result.changed) {
2934
- await persistMilestoneAcceptanceMutation(sourceOperand, result, request.expectedDigest);
3004
+ await commitCandidate(request, result.updatedText, input.digest);
2935
3005
  written = true;
2936
3006
  }
2937
3007
  if (format === "json")
2938
3008
  writeJson({
2939
- schema_version: "Perttool.MutationResult.v5",
3009
+ schema_version: "Perttool.MutationResult.v6",
2940
3010
  cli_contract_version: 8,
2941
3011
  tool_version: TOOL_VERSION,
2942
3012
  operation,
@@ -2972,39 +3042,36 @@ async function runMilestoneAcceptance(action, args) {
2972
3042
  return result.ok ? 0 : 1;
2973
3043
  }
2974
3044
  async function runDocumentMigration(args) {
3045
+ const target = args.includes("--target-grammar")
3046
+ ? args[args.indexOf("--target-grammar") + 1]
3047
+ : args.find((value) => value.startsWith("--target-grammar="))?.slice("--target-grammar=".length);
3048
+ if (target === "8")
3049
+ return runContract9DocumentMigration(args);
2975
3050
  const parsed = parseCommandOptions("document.migrate", args);
2976
3051
  if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "7")
2977
- throw new UsageError("document migrate requires <file> --target-grammar 7");
3052
+ throw new UsageError("document migrate requires <file> --target-grammar 7 or 8");
2978
3053
  const sourceOperand = parsed.positionals[0];
2979
3054
  if (sourceOperand === "-")
2980
3055
  throw new UsageError("document migrate requires a repository file");
2981
3056
  const format = outputFormat(parsed.values.get("format"));
2982
3057
  const input = await readDocument(sourceOperand);
2983
3058
  const baseline = await captureAdvanceHistoryBaseline({ targetPath: sourceOperand, expectedSourceDigest: input.digest });
2984
- const toProof = (value) => value.status === "complete" && value.repositorySnapshotId !== null &&
2985
- value.repositoryRelativePath !== null && value.objectFormat !== null &&
2986
- value.headCommitId !== null && value.headBlobId !== null &&
3059
+ const toProof = (value) => value.status === "complete" && value.repositorySnapshotId !== null && value.repositoryRelativePath !== null &&
3060
+ value.objectFormat !== null && value.headCommitId !== null && value.headBlobId !== null &&
2987
3061
  value.indexBlobId !== null && value.currentSourceDigest !== null
2988
- ? {
2989
- repositoryId: value.repositorySnapshotId,
2990
- repositoryRelativePath: value.repositoryRelativePath,
2991
- objectFormat: value.objectFormat,
2992
- headCommit: value.headCommitId,
2993
- headBlob: value.headBlobId,
2994
- stage0Blob: value.indexBlobId,
2995
- sourceDigest: value.currentSourceDigest,
2996
- }
3062
+ ? { repositoryId: value.repositorySnapshotId, repositoryRelativePath: value.repositoryRelativePath,
3063
+ objectFormat: value.objectFormat, headCommit: value.headCommitId, headBlob: value.headBlobId,
3064
+ stage0Blob: value.indexBlobId, sourceDigest: value.currentSourceDigest }
2997
3065
  : null;
2998
3066
  const proof = toProof(baseline);
2999
3067
  let result = proof === null
3000
- ? { 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"]) }
3068
+ ? { ok: false, modelVersion: 1, changed: false, sourceGrammarVersion: null, targetGrammarVersion: null,
3069
+ sourceDigest: input.digest, candidateDigest: null, grandfatheredMilestoneIds: Object.freeze([]),
3070
+ candidateText: null, diagnostics: Object.freeze(["PTMAC-109"]) }
3001
3071
  : planMilestoneAcceptanceMigration(input.text, proof);
3002
3072
  let race = false;
3003
3073
  if (result.ok && result.changed && result.candidateText !== null && parsed.flags.has("write")) {
3004
- const current = toProof(await captureAdvanceHistoryBaseline({
3005
- targetPath: sourceOperand,
3006
- expectedSourceDigest: input.digest,
3007
- }));
3074
+ const current = toProof(await captureAdvanceHistoryBaseline({ targetPath: sourceOperand, expectedSourceDigest: input.digest }));
3008
3075
  if (proof === null || current === null || !recheckCommittedMigrationProof(proof, current)) {
3009
3076
  result = Object.freeze({ ...result, ok: false, diagnostics: Object.freeze(["PTMAC-110"]) });
3010
3077
  race = true;
@@ -3014,7 +3081,8 @@ async function runDocumentMigration(args) {
3014
3081
  }
3015
3082
  }
3016
3083
  if (format === "json")
3017
- writeJson({ schema_version: "Perttool.MilestoneAcceptanceMigrationResult.v1", cli_contract_version: 8, tool_version: TOOL_VERSION, operation: "document.migrate", ...snakeJson(result) });
3084
+ writeJson({ schema_version: "Perttool.MilestoneAcceptanceMigrationResult.v1", cli_contract_version: 9,
3085
+ tool_version: TOOL_VERSION, operation: "document.migrate", ...snakeJson(result) });
3018
3086
  else if (result.candidateText !== null)
3019
3087
  process.stdout.write(result.candidateText);
3020
3088
  return result.ok ? 0 : race ? 5 : 1;
@@ -3188,7 +3256,8 @@ async function runPlanAssuranceInspection(action, args) {
3188
3256
  (result.diagnosticsTruncated || result.diagnostics.some(({ severity }) => severity === "warning"));
3189
3257
  const ok = result.ok && !warningFailure;
3190
3258
  if (format === "json") {
3191
- writeJson(contract7InspectionResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), source));
3259
+ writeJson({ ...contract9WireJson(ok ? result : Object.freeze({ ...result, ok: false })),
3260
+ source, cli_contract_version: 9 });
3192
3261
  }
3193
3262
  else if (ok) {
3194
3263
  if (action === "hash") {
@@ -3336,7 +3405,7 @@ async function runAssuranceMutation(resource, action, args) {
3336
3405
  }
3337
3406
  }
3338
3407
  if (format === "json") {
3339
- writeJson(contract8MutationResultToJson(result, operation, source, writeResult));
3408
+ writeJson(contract9MutationResultToJson(result, operation, source, writeResult));
3340
3409
  }
3341
3410
  else {
3342
3411
  if (result.ok) {
@@ -3364,6 +3433,32 @@ async function runAssuranceMutation(resource, action, args) {
3364
3433
  }
3365
3434
  return result.ok ? 0 : 1;
3366
3435
  }
3436
+ async function runCalendarMutation(action, args) {
3437
+ const operation = `calendar.${action}`;
3438
+ const validation = validateAssuranceCommandInvocation(["calendar", action, ...args]);
3439
+ if (!validation.ok)
3440
+ return emitCommandUsage(validation.error, jsonRequested(args));
3441
+ const parsed = parseCommandOptions(operation, args);
3442
+ const format = outputFormat(parsed.values.get("format"));
3443
+ const sourceOperand = parsed.positionals[0];
3444
+ const source = sourceOperand === "-" ? "<stdin>" : sourceOperand;
3445
+ const input = await readDocument(sourceOperand);
3446
+ const temporal = (candidate) => planContract9TemporalMutation(candidate, validation);
3447
+ const result = composeContract9TemporalMutation(input.text, temporal, { originalLabel: source, updatedLabel: "candidate" });
3448
+ const writeRequest = editingWriteRequest(parsed, sourceOperand);
3449
+ let writeResult = Object.freeze({ mode: writeRequest.mode, target: writeRequest.target, written: false });
3450
+ if (result.ok && writeRequest.mode !== "preview") {
3451
+ writeResult = await persistContract8CandidateResult(result, writeRequest);
3452
+ }
3453
+ if (format === "json") {
3454
+ writeJson({ ...contract9WireJson(result), operation,
3455
+ source, write: contract9WireJson(writeResult), cli_contract_version: 9 });
3456
+ }
3457
+ else if (result.ok) {
3458
+ process.stdout.write(parsed.flags.has("diff") ? result.diff ?? "" : result.updatedText ?? "");
3459
+ }
3460
+ return result.ok ? 0 : 1;
3461
+ }
3367
3462
  async function dispatchCommand(descriptor, args) {
3368
3463
  switch (descriptor.operation) {
3369
3464
  case "help":
@@ -3402,6 +3497,10 @@ async function dispatchCommand(descriptor, args) {
3402
3497
  return runHistoricalGraph(args);
3403
3498
  case "dag.import":
3404
3499
  return runImport(args);
3500
+ case "calendar.add":
3501
+ case "calendar.set":
3502
+ case "calendar.remove":
3503
+ return runCalendarMutation(descriptor.path[1], args);
3405
3504
  case "task.start":
3406
3505
  return runLifecycleMutation("start", args);
3407
3506
  case "task.suspend":