@cassiomc1/forgeloop 1.5.0 → 1.6.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 (126) hide show
  1. package/DOCS_INDEX.md +13 -8
  2. package/EXECUTION_STATE.md +20 -0
  3. package/LOOP_ENGINEERING.md +81 -0
  4. package/LOOP_SYSTEM_DESIGN.md +32 -0
  5. package/PROTOCOL_INTEGRATION.md +46 -0
  6. package/QUALITY_SCORECARD.md +2 -0
  7. package/README.md +31 -9
  8. package/THIRD_PARTY_NOTICES.md +15 -0
  9. package/THREAT_MODEL.md +39 -0
  10. package/docs/ARTIFACT_REFERENCE.md +140 -0
  11. package/docs/CLI_REFERENCE.md +294 -3
  12. package/docs/DIAGNOSTIC_MODEL.md +181 -0
  13. package/docs/DOCUMENTATION_GUIDE.md +22 -13
  14. package/docs/EXECUTION_TRACE.md +76 -0
  15. package/docs/MCP.md +33 -0
  16. package/docs/RECIPES.md +67 -0
  17. package/docs/TROUBLESHOOTING.md +106 -2
  18. package/docs/assets/diagrams/forgeloop-engineering-flow.html +13797 -0
  19. package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +37 -0
  20. package/docs/assets/diagrams/forgeloop-engineering-flow.svg +5002 -0
  21. package/docs/diagrams/README.md +55 -0
  22. package/docs/diagrams/forgeloop-engineering-flow.workflow.json +122 -0
  23. package/docs/diagrams/manifest.json +42 -0
  24. package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +20 -0
  25. package/package.json +8 -6
  26. package/schemas/action.schema.json +100 -0
  27. package/schemas/approval.schema.json +51 -0
  28. package/schemas/capability-policy.schema.json +41 -0
  29. package/schemas/diagnostic-case.schema.json +85 -0
  30. package/schemas/execution-receipt.schema.json +16 -0
  31. package/schemas/hypothesis-disposition.schema.json +16 -0
  32. package/schemas/intervention.schema.json +27 -0
  33. package/schemas/policy-lock.schema.json +1 -0
  34. package/schemas/policy-snapshot.schema.json +2 -0
  35. package/schemas/trajectory-evaluation.schema.json +64 -0
  36. package/schemas/trajectory-scenario.schema.json +42 -0
  37. package/src/cli.js +94 -0
  38. package/src/commands/action-authorize.js +41 -0
  39. package/src/commands/action-propose.js +10 -0
  40. package/src/commands/action-reconcile.js +10 -0
  41. package/src/commands/action-record.js +47 -0
  42. package/src/commands/action-show.js +10 -0
  43. package/src/commands/action-verify.js +10 -0
  44. package/src/commands/advance.js +7 -2
  45. package/src/commands/approval-request.js +64 -0
  46. package/src/commands/approval-resolve.js +10 -0
  47. package/src/commands/baseline.js +3 -3
  48. package/src/commands/eval.js +6 -0
  49. package/src/commands/history.js +18 -0
  50. package/src/commands/init.js +2 -2
  51. package/src/commands/inspect.js +49 -0
  52. package/src/commands/metrics.js +7 -0
  53. package/src/commands/next.js +8 -2
  54. package/src/commands/policy-discover.js +2 -2
  55. package/src/commands/record-diagnosis.js +37 -1
  56. package/src/commands/record-hypothesis-disposition.js +45 -0
  57. package/src/commands/record-intervention.js +35 -0
  58. package/src/commands/reflect.js +38 -0
  59. package/src/commands/report.js +9 -1
  60. package/src/commands/run-action.js +18 -0
  61. package/src/commands/trace.js +34 -0
  62. package/src/commands/validate-protocol.js +21 -13
  63. package/src/core/action-authorization.js +106 -0
  64. package/src/core/action-constants.js +86 -0
  65. package/src/core/action-execution.js +105 -0
  66. package/src/core/action-ledger-projection.js +302 -0
  67. package/src/core/action-model.js +581 -0
  68. package/src/core/action-readiness.js +141 -0
  69. package/src/core/action-reconciliation-policy.js +49 -0
  70. package/src/core/action-reconciliation.js +66 -0
  71. package/src/core/action-verification.js +111 -0
  72. package/src/core/actions.js +462 -0
  73. package/src/core/approvals.js +405 -0
  74. package/src/core/artifact-registry.js +48 -0
  75. package/src/core/audit.js +25 -0
  76. package/src/core/bundles.js +15 -0
  77. package/src/core/capability-policy.js +226 -0
  78. package/src/core/cli-command-definitions.js +210 -1
  79. package/src/core/command-executors.js +171 -15
  80. package/src/core/command-runtime.js +12 -1
  81. package/src/core/completion-artifacts.js +37 -12
  82. package/src/core/completion-recovery-rebind.js +194 -0
  83. package/src/core/completion.js +70 -0
  84. package/src/core/continuity-reconciliation.js +24 -5
  85. package/src/core/diagnostic-model.js +396 -0
  86. package/src/core/diagnostic-projection.js +51 -0
  87. package/src/core/diagnostic-record.js +360 -0
  88. package/src/core/error-codes.js +343 -0
  89. package/src/core/events.js +41 -1
  90. package/src/core/execution-prerequisites.js +4 -1
  91. package/src/core/execution.js +26 -188
  92. package/src/core/failure-signature.js +70 -0
  93. package/src/core/failure-surface.js +57 -0
  94. package/src/core/history.js +110 -0
  95. package/src/core/hypothesis-projection.js +85 -0
  96. package/src/core/information-gain-projection.js +283 -0
  97. package/src/core/information-gain.js +138 -0
  98. package/src/core/inspect.js +105 -7
  99. package/src/core/integration-invocation-policy.js +47 -0
  100. package/src/core/integration-resources.js +51 -0
  101. package/src/core/next-action-model.js +35 -1
  102. package/src/core/next-action.js +459 -3
  103. package/src/core/phase.js +40 -21
  104. package/src/core/policy-engine.js +113 -6
  105. package/src/core/preflight-consistency.js +31 -5
  106. package/src/core/preflight.js +19 -2
  107. package/src/core/prepared-execution.js +227 -0
  108. package/src/core/progress.js +41 -4
  109. package/src/core/protocol-info.js +48 -0
  110. package/src/core/protocol.js +14 -0
  111. package/src/core/receipt.js +1 -0
  112. package/src/core/reconcile-closure.js +15 -12
  113. package/src/core/reflection.js +305 -0
  114. package/src/core/resumability.js +57 -3
  115. package/src/core/schema-validation.js +8 -0
  116. package/src/core/strategy-analysis.js +97 -0
  117. package/src/core/task-paths.js +28 -0
  118. package/src/core/task-snapshot.js +53 -0
  119. package/src/core/templates.js +8 -0
  120. package/src/core/trace.js +548 -0
  121. package/src/core/trajectory-evaluation.js +71 -0
  122. package/src/core/trajectory-metrics.js +80 -0
  123. package/src/core/transaction.js +8 -0
  124. package/src/core/work-state.js +10 -5
  125. package/docs/assets/forgeloop-flow.svg +0 -1
  126. package/docs/forgeloop-flow.mmd +0 -51
@@ -14,6 +14,8 @@ export const INTEGRATION_RISK_CLASSES = Object.freeze({
14
14
  LOOP_MUTATION: "LOOP_MUTATION",
15
15
  CLAIM_REACQUISITION: "CLAIM_REACQUISITION",
16
16
  EXTERNAL_EXECUTION: "EXTERNAL_EXECUTION",
17
+ AUTHORITY_MUTATION: "AUTHORITY_MUTATION",
18
+ EXTERNAL_STATE_ATTESTATION: "EXTERNAL_STATE_ATTESTATION",
17
19
  MAINTENANCE: "MAINTENANCE",
18
20
  CLAIM_RELEASE_RECOVERY: "CLAIM_RELEASE_RECOVERY",
19
21
  LEGACY_MIGRATION: "LEGACY_MIGRATION",
@@ -25,6 +27,7 @@ const READ_ONLY_COMMANDS = Object.freeze(new Set([
25
27
  "task-list", "task-show", "task-lock-status", "progress", "audit", "report",
26
28
  "inspect", "validate-state", "validate-protocol", "validate-receipt",
27
29
  "policy-status", "policy-diff", "rule-verify", "policy",
30
+ "history", "trace", "reflect",
28
31
  ]));
29
32
 
30
33
  const LOOP_MUTATION_COMMANDS = Object.freeze(new Set([
@@ -32,6 +35,7 @@ const LOOP_MUTATION_COMMANDS = Object.freeze(new Set([
32
35
  "record-continuity", "clear-continuity", "prepare-completion",
33
36
  "record-check", "record-diagnosis", "record-decision-criterion",
34
37
  "record-terminal-result", "complete",
38
+ "record-intervention", "record-hypothesis-disposition",
35
39
  ]));
36
40
 
37
41
  const STATIC_RISK_CLASSES = Object.freeze({
@@ -39,7 +43,18 @@ const STATIC_RISK_CLASSES = Object.freeze({
39
43
  ...Object.fromEntries([...LOOP_MUTATION_COMMANDS].map((name) => [name, INTEGRATION_RISK_CLASSES.LOOP_MUTATION])),
40
44
  "task-resume": INTEGRATION_RISK_CLASSES.CLAIM_REACQUISITION,
41
45
  "run-check": INTEGRATION_RISK_CLASSES.EXTERNAL_EXECUTION,
46
+ "run-action": INTEGRATION_RISK_CLASSES.EXTERNAL_EXECUTION,
42
47
  "reconcile-closure": INTEGRATION_RISK_CLASSES.EXTERNAL_EXECUTION,
48
+ "action-propose": INTEGRATION_RISK_CLASSES.LOOP_MUTATION,
49
+ "action-authorize": INTEGRATION_RISK_CLASSES.LOOP_MUTATION,
50
+ "action-record": INTEGRATION_RISK_CLASSES.LOOP_MUTATION,
51
+ "action-verify": INTEGRATION_RISK_CLASSES.LOOP_MUTATION,
52
+ "action-reconcile": INTEGRATION_RISK_CLASSES.LOOP_MUTATION,
53
+ "approval-request": INTEGRATION_RISK_CLASSES.LOOP_MUTATION,
54
+ "approval-resolve": INTEGRATION_RISK_CLASSES.AUTHORITY_MUTATION,
55
+ eval: INTEGRATION_RISK_CLASSES.LOOP_MUTATION,
56
+ "action-show": INTEGRATION_RISK_CLASSES.READ_ONLY,
57
+ metrics: INTEGRATION_RISK_CLASSES.READ_ONLY,
43
58
  init: INTEGRATION_RISK_CLASSES.MAINTENANCE,
44
59
  update: INTEGRATION_RISK_CLASSES.MAINTENANCE,
45
60
  activate: INTEGRATION_RISK_CLASSES.MAINTENANCE,
@@ -63,6 +78,15 @@ function refineRiskClass(command, input) {
63
78
  if (command === "task-unlock" && input?.force === true) {
64
79
  return INTEGRATION_RISK_CLASSES.FORCE_DESTRUCTIVE;
65
80
  }
81
+ // Settling external commit state is independently gated: recording an
82
+ // UNKNOWN observation stays LOOP_MUTATION, while COMMITTED / NOT_COMMITTED
83
+ // settlements attest external state and require their own capability.
84
+ if (
85
+ command === "action-reconcile"
86
+ && ["COMMITTED", "NOT_COMMITTED"].includes(input?.reconciliationOutcome)
87
+ ) {
88
+ return INTEGRATION_RISK_CLASSES.EXTERNAL_STATE_ATTESTATION;
89
+ }
66
90
  // Fail closed: every canonical command must be explicitly classified.
67
91
  return baseRiskClass(command);
68
92
  }
@@ -99,6 +123,16 @@ export function getForgeLoopCapabilities({ packageVersion = null } = {}) {
99
123
  explicitResume: true,
100
124
  validatedClaimProjection: true,
101
125
  },
126
+ durableActions: {
127
+ version: 1,
128
+ readOnlyResources: true,
129
+ externalExecutionOverMcp: false,
130
+ },
131
+ trajectoryEvaluation: {
132
+ version: 1,
133
+ readOnlyMetrics: true,
134
+ projectLocalReference: true,
135
+ },
102
136
  },
103
137
  commands,
104
138
  resources: [
@@ -108,6 +142,12 @@ export function getForgeLoopCapabilities({ packageVersion = null } = {}) {
108
142
  { name: "task/ownership", scope: "TASK" },
109
143
  { name: "task/contract", scope: "TASK" },
110
144
  { name: "task/continuity", scope: "TASK" },
145
+ { name: "task/actions", scope: "TASK" },
146
+ { name: "task/action", scope: "TASK" },
147
+ { name: "task/approvals", scope: "TASK" },
148
+ { name: "task/metrics", scope: "TASK" },
149
+ { name: "task/evaluations", scope: "TASK" },
150
+ { name: "project/capability-policy", scope: "PROJECT" },
111
151
  ],
112
152
  };
113
153
  }
@@ -128,6 +168,10 @@ export function classifyForgeLoopInvocation(command, input = {}) {
128
168
  switch (riskClass) {
129
169
  case INTEGRATION_RISK_CLASSES.EXTERNAL_EXECUTION:
130
170
  return "allowExternalExecution";
171
+ case INTEGRATION_RISK_CLASSES.AUTHORITY_MUTATION:
172
+ return "allowApprovalResolution";
173
+ case INTEGRATION_RISK_CLASSES.EXTERNAL_STATE_ATTESTATION:
174
+ return "allowActionReconciliationSettlement";
131
175
  case INTEGRATION_RISK_CLASSES.MAINTENANCE:
132
176
  return "allowMaintenance";
133
177
  case INTEGRATION_RISK_CLASSES.CLAIM_RELEASE_RECOVERY:
@@ -148,6 +192,8 @@ export function classifyForgeLoopInvocation(command, input = {}) {
148
192
  INTEGRATION_RISK_CLASSES.LOOP_MUTATION,
149
193
  INTEGRATION_RISK_CLASSES.CLAIM_REACQUISITION,
150
194
  INTEGRATION_RISK_CLASSES.EXTERNAL_EXECUTION,
195
+ INTEGRATION_RISK_CLASSES.AUTHORITY_MUTATION,
196
+ INTEGRATION_RISK_CLASSES.EXTERNAL_STATE_ATTESTATION,
151
197
  INTEGRATION_RISK_CLASSES.MAINTENANCE,
152
198
  INTEGRATION_RISK_CLASSES.CLAIM_RELEASE_RECOVERY,
153
199
  INTEGRATION_RISK_CLASSES.LEGACY_MIGRATION,
@@ -160,6 +206,7 @@ export function classifyForgeLoopInvocation(command, input = {}) {
160
206
  "task-create", "task-scope", "complete",
161
207
  ].includes(command),
162
208
  destructive: [
209
+ INTEGRATION_RISK_CLASSES.AUTHORITY_MUTATION,
163
210
  INTEGRATION_RISK_CLASSES.FORCE_DESTRUCTIVE,
164
211
  INTEGRATION_RISK_CLASSES.CLAIM_RELEASE_RECOVERY,
165
212
  INTEGRATION_RISK_CLASSES.LEGACY_MIGRATION,
@@ -1,9 +1,17 @@
1
+ import path from "node:path";
1
2
  import { runProtocolInfo } from "../commands/protocol-info.js";
2
3
  import { readContract } from "./contract.js";
3
4
  import { discoverTasks } from "./task-discovery.js";
4
5
  import { resolveTaskClaimState } from "./task-claim-state.js";
5
6
  import { runStatus } from "../commands/status.js";
6
7
  import { runContinuity } from "../commands/continuity.js";
8
+ import { listActions, readAction } from "./actions.js";
9
+ import { listApprovals } from "./approvals.js";
10
+ import { buildTrajectoryMetrics } from "./trajectory-metrics.js";
11
+ import { loadCapabilityPolicy } from "./capability-policy.js";
12
+ import { readdir } from "node:fs/promises";
13
+ import { readJsonArtifact } from "./artifacts.js";
14
+ import { taskDirectory } from "./task-paths.js";
7
15
 
8
16
  /**
9
17
  * Canonical integration resource allowlist.
@@ -43,6 +51,12 @@ export const INTEGRATION_RESOURCE_DEFINITIONS = Object.freeze({
43
51
  scope: "TASK",
44
52
  description: "Cross-harness continuity state for one task.",
45
53
  }),
54
+ "task/actions": Object.freeze({ scope: "TASK", description: "Canonical durable action summaries for one task." }),
55
+ "task/action": Object.freeze({ scope: "TASK", description: "One canonical durable action artifact." }),
56
+ "task/approvals": Object.freeze({ scope: "TASK", description: "Durable approval artifacts for one task." }),
57
+ "task/metrics": Object.freeze({ scope: "TASK", description: "Read-only trajectory metrics for one task." }),
58
+ "task/evaluations": Object.freeze({ scope: "TASK", description: "Persisted trajectory evaluations for one task." }),
59
+ "project/capability-policy": Object.freeze({ scope: "PROJECT", description: "Project capability policy, never host authority." }),
46
60
  });
47
61
 
48
62
  function ownershipProjection(projection) {
@@ -64,6 +78,7 @@ export async function readForgeLoopIntegrationResource(uri, {
64
78
  packageRoot = undefined,
65
79
  packageVersion = null,
66
80
  taskId = null,
81
+ actionId = null,
67
82
  } = {}) {
68
83
  const resource = INTEGRATION_RESOURCE_DEFINITIONS[uri];
69
84
  if (!resource) {
@@ -102,12 +117,48 @@ export async function readForgeLoopIntegrationResource(uri, {
102
117
  }
103
118
  break;
104
119
  }
120
+ case "task/actions":
121
+ case "task/action":
122
+ case "task/approvals":
123
+ case "task/metrics":
124
+ case "task/evaluations": {
125
+ if (typeof taskId !== "string" || !taskId) {
126
+ const error = new Error(`Resource ${uri} requires a taskId`); error.code = "E_TASK_REQUIRED"; throw error;
127
+ }
128
+ break;
129
+ }
105
130
  }
106
131
 
107
132
  if (uri === "task/ownership") {
108
133
  const projection = await resolveTaskClaimState(projectPath, { taskId, packageRoot });
109
134
  return { uri, taskId, data: ownershipProjection(projection) };
110
135
  }
136
+ if (uri === "task/actions") {
137
+ const actions = await listActions(projectPath, { packageRoot, taskId });
138
+ return { uri, taskId, data: { actions } };
139
+ }
140
+ if (uri === "task/action") {
141
+ if (!actionId) { const error = new Error("Resource task/action requires actionId"); error.code = "E_ACTION_INVALID"; throw error; }
142
+ return { uri, taskId, data: await readAction(projectPath, { packageRoot, taskId, actionId }) };
143
+ }
144
+ if (uri === "task/approvals") {
145
+ return { uri, taskId, data: { approvals: await listApprovals(projectPath, { packageRoot, taskId }) } };
146
+ }
147
+ if (uri === "task/metrics") {
148
+ return { uri, taskId, data: await buildTrajectoryMetrics({ target: projectPath, packageRoot, taskId }) };
149
+ }
150
+ if (uri === "task/evaluations") {
151
+ const dir = path.join(projectPath, taskDirectory(taskId), "evaluations");
152
+ let names = []; try { names = await readdir(dir); } catch { /* absent is an empty projection */ }
153
+ const evaluations = [];
154
+ for (const name of names.filter((entry) => /^eval-[A-Za-z0-9_-]+\.json$/.test(entry)).sort()) {
155
+ evaluations.push((await readJsonArtifact(projectPath, `${taskDirectory(taskId)}/evaluations/${name}`, "trajectory-evaluation", packageRoot)).value);
156
+ }
157
+ return { uri, taskId, data: { evaluations } };
158
+ }
159
+ if (uri === "project/capability-policy") {
160
+ return { uri, data: await loadCapabilityPolicy(projectPath, packageRoot) };
161
+ }
111
162
  if (uri === "task/status") {
112
163
  const result = await runStatus({ target: projectPath, packageRoot, taskId });
113
164
  return { uri, taskId, data: result };
@@ -16,6 +16,9 @@ export const NEXT_ACTIONS = Object.freeze({
16
16
  RECORD_DIAGNOSIS: "RECORD_DIAGNOSIS",
17
17
  CORRECT: "CORRECT",
18
18
  CHANGE_STRATEGY: "CHANGE_STRATEGY",
19
+ REQUIRE_NEW_DIAGNOSTIC_INFORMATION: "REQUIRE_NEW_DIAGNOSTIC_INFORMATION",
20
+ INTRODUCE_NEW_OBSERVATION: "INTRODUCE_NEW_OBSERVATION",
21
+ RECORD_INTERVENTION: "RECORD_INTERVENTION",
19
22
  ENTER_REVIEWING: "ENTER_REVIEWING",
20
23
  RECORD_TERMINAL_RESULT: "RECORD_TERMINAL_RESULT",
21
24
  PREPARE_COMPLETION: "PREPARE_COMPLETION",
@@ -32,13 +35,18 @@ export const NEXT_ACTIONS = Object.freeze({
32
35
  RESTORE_BASELINE: "RESTORE_BASELINE",
33
36
  CONTINUE_WITH_EXISTING_BASELINE: "CONTINUE_WITH_EXISTING_BASELINE",
34
37
  RECONCILE_CLOSURE: "RECONCILE_CLOSURE",
38
+ RECONCILE_ACTION: "RECONCILE_ACTION",
39
+ AUTHORIZE_ACTION: "AUTHORIZE_ACTION",
40
+ REQUEST_ACTION_APPROVAL: "REQUEST_ACTION_APPROVAL",
41
+ RESOLVE_ACTION_APPROVAL: "RESOLVE_ACTION_APPROVAL",
42
+ VERIFY_EXTERNAL_ACTION: "VERIFY_EXTERNAL_ACTION",
35
43
  RECOVER_TASK: "RECOVER_TASK",
36
44
  RESUME_RECOVERED_TASK: "RESUME_RECOVERED_TASK",
37
45
  RESOLVE_RECOVERY_INCONSISTENCY: "RESOLVE_RECOVERY_INCONSISTENCY",
38
46
  NONE: "NONE",
39
47
  });
40
48
 
41
- function directCommandSpec(commandId, taskId, requiredInputs = []) {
49
+ export function directCommandSpec(commandId, taskId, requiredInputs = []) {
42
50
  return {
43
51
  commandId,
44
52
  executable: "forgeloop",
@@ -104,6 +112,12 @@ export function result({
104
112
  requiredArtifacts = [],
105
113
  missingArtifacts = [],
106
114
  progress = undefined,
115
+ diagnosticGuidance = undefined,
116
+ authorityRequired = undefined,
117
+ hostActionRequired = undefined,
118
+ approvalRequired = undefined,
119
+ capabilityDecision = undefined,
120
+ reconciliationAuthorityRequired = undefined,
107
121
  }) {
108
122
  const normalizedReasons = reasons
109
123
  .map((reason) => {
@@ -136,6 +150,14 @@ export function result({
136
150
  requiredArtifacts: uniqueSorted(requiredArtifacts),
137
151
  missingArtifacts: uniqueSorted(missingArtifacts),
138
152
  ...(progress ? { progress: structuredClone(progress) } : {}),
153
+ ...(diagnosticGuidance ? { diagnosticGuidance: structuredClone(diagnosticGuidance) } : {}),
154
+ ...(authorityRequired ? { authorityRequired: structuredClone(authorityRequired) } : {}),
155
+ ...(hostActionRequired ? { hostActionRequired: structuredClone(hostActionRequired) } : {}),
156
+ ...(approvalRequired ? { approvalRequired: structuredClone(approvalRequired) } : {}),
157
+ ...(capabilityDecision ? { capabilityDecision: structuredClone(capabilityDecision) } : {}),
158
+ ...(reconciliationAuthorityRequired
159
+ ? { reconciliationAuthorityRequired: structuredClone(reconciliationAuthorityRequired) }
160
+ : {}),
139
161
  };
140
162
  }
141
163
 
@@ -186,6 +208,18 @@ export function recordDiagnosisCommandSpec() {
186
208
  };
187
209
  }
188
210
 
211
+ export function recordInterventionCommandSpec(taskId = null) {
212
+ return {
213
+ commandId: "record-intervention",
214
+ executable: "forgeloop",
215
+ subcommand: "record-intervention",
216
+ argv: ["record-intervention", ...(taskId ? [`--task=${taskId}`] : [])],
217
+ requiredInputs: [
218
+ { name: "file", option: "--file=<intervention-json-path>" },
219
+ ],
220
+ };
221
+ }
222
+
189
223
  export function recordTerminalResultCommandSpec(requirement) {
190
224
  const reqId = requirement.id ?? requirement;
191
225
  const type = requirement.type ?? "PUBLICATION";