@cassiomc1/forgeloop 1.13.0 → 1.14.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 (211) hide show
  1. package/AGENT_COMPATIBILITY.md +8 -0
  2. package/DOCS_INDEX.md +35 -3
  3. package/ENG/nodejs-backend-development-eng.md +2 -2
  4. package/ENG/sec-code-eng.md +7 -7
  5. package/EXECUTION_STATE.md +12 -0
  6. package/LOOP_ENGINEERING.md +28 -2
  7. package/ORCHESTRATOR_INTEGRATION.md +9 -5
  8. package/PROTOCOL_INTEGRATION.md +55 -2
  9. package/README.md +40 -25
  10. package/TERMINOLOGY.md +2 -0
  11. package/THREAT_MODEL.md +140 -1
  12. package/completions/_forgeloop +19 -1
  13. package/completions/forgeloop.bash +37 -1
  14. package/completions/forgeloop.fish +123 -1
  15. package/docs/ADVISORY_CONTEXT.md +25 -0
  16. package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
  17. package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
  18. package/docs/AGENT_PROTOCOL_SUMMARY.md +27 -2
  19. package/docs/AGENT_SKILL.md +66 -0
  20. package/docs/ARTIFACT_REFERENCE.md +123 -0
  21. package/docs/AUDIT_UX.md +46 -0
  22. package/docs/BROWSER_VERIFICATION.md +136 -0
  23. package/docs/CLI_REFERENCE.md +366 -6
  24. package/docs/CODE_ATTESTATION.md +2 -2
  25. package/docs/DOCUMENTATION_GUIDE.md +32 -11
  26. package/docs/JEV_BENCHMARKS.md +31 -0
  27. package/docs/MODEL_ROUTING.md +37 -0
  28. package/docs/OPENSRC_ADAPTER.md +241 -0
  29. package/docs/PACKAGE_CONTENTS.md +35 -8
  30. package/docs/PROVIDERS.md +126 -0
  31. package/docs/PROVIDER_ARCHITECTURE.md +199 -0
  32. package/docs/RECIPES.md +9 -0
  33. package/docs/RELEASE_CHECKLIST.md +38 -5
  34. package/docs/SECURITY_REVIEW.md +71 -0
  35. package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
  36. package/docs/TEST_INTELLIGENCE.md +29 -0
  37. package/docs/TEST_PRUNING.md +14 -0
  38. package/docs/TROUBLESHOOTING.md +198 -1
  39. package/docs/UNIVERSAL_INTEGRATION.md +31 -0
  40. package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
  41. package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
  42. package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
  43. package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
  44. package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
  45. package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
  46. package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
  47. package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
  48. package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
  49. package/docs/diagrams/README.md +13 -9
  50. package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
  51. package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
  52. package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
  53. package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
  54. package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
  55. package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
  56. package/docs/documentation-manifest.json +750 -5
  57. package/docs/protocol-requirements.json +24 -0
  58. package/package.json +30 -3
  59. package/schemas/config.schema.json +14 -0
  60. package/schemas/context-plan.schema.json +18 -0
  61. package/schemas/semantic-decision.schema.json +46 -0
  62. package/schemas/test-utility.schema.json +44 -0
  63. package/scripts/CI_VALIDATORS.md +6 -6
  64. package/scripts/benchmark-jev.mjs +5 -0
  65. package/scripts/benchmark-test-intelligence.mjs +4 -0
  66. package/scripts/generate-agent-protocol-summary.mjs +4 -1
  67. package/scripts/generate-forgeloop-skill.mjs +133 -0
  68. package/scripts/jev-smoke.mjs +19 -0
  69. package/skills/forgeloop/README.md +9 -0
  70. package/skills/forgeloop/SKILL.md +77 -0
  71. package/skills/forgeloop/references/lifecycle.md +9 -0
  72. package/skills/forgeloop/references/recovery.md +7 -0
  73. package/skills/forgeloop/references/verification.md +7 -0
  74. package/src/adapters/agent-browser/assertions.js +47 -0
  75. package/src/adapters/agent-browser/commands.js +54 -0
  76. package/src/adapters/agent-browser/index.js +3 -0
  77. package/src/adapters/agent-browser/locator.js +40 -0
  78. package/src/adapters/agent-browser/process.js +215 -0
  79. package/src/adapters/agent-browser/provider.js +313 -0
  80. package/src/adapters/emulated-services/constants.js +24 -0
  81. package/src/adapters/emulated-services/index.js +7 -0
  82. package/src/adapters/emulated-services/process.js +162 -0
  83. package/src/adapters/emulated-services/provider.js +282 -0
  84. package/src/adapters/opensrc/normalize.js +90 -0
  85. package/src/adapters/opensrc/process.js +248 -0
  86. package/src/adapters/opensrc/provider.js +338 -0
  87. package/src/adapters/opensrc/search.js +264 -0
  88. package/src/adapters/typesafe/client.js +28 -0
  89. package/src/adapters/typesafe/engine.js +63 -0
  90. package/src/adapters/typesafe/normalize.js +41 -0
  91. package/src/cli.js +108 -0
  92. package/src/commands/checkpoint-revalidate.js +176 -0
  93. package/src/commands/context-plan.js +38 -0
  94. package/src/commands/contract-create.js +264 -0
  95. package/src/commands/contract-revise.js +236 -0
  96. package/src/commands/decision-show.js +14 -0
  97. package/src/commands/decision-status.js +22 -0
  98. package/src/commands/discover.js +41 -0
  99. package/src/commands/doctor.js +15 -0
  100. package/src/commands/gate-record.js +205 -0
  101. package/src/commands/gate-revalidate.js +137 -0
  102. package/src/commands/model-route.js +32 -0
  103. package/src/commands/route.js +146 -18
  104. package/src/commands/semantic-plan.js +17 -0
  105. package/src/commands/task-abandon.js +224 -0
  106. package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
  107. package/src/commands/task-repair-contract-bootstrap.js +263 -0
  108. package/src/commands/test-inventory.js +5 -0
  109. package/src/commands/test-prune-plan.js +5 -0
  110. package/src/commands/test-prune-probe.js +5 -0
  111. package/src/commands/test-utility.js +5 -0
  112. package/src/commands/validate-protocol.js +10 -1
  113. package/src/core/artifact-registry.js +24 -0
  114. package/src/core/audit-ux.js +514 -0
  115. package/src/core/browser-verification/constants.js +149 -0
  116. package/src/core/browser-verification/normalize.js +254 -0
  117. package/src/core/browser-verification/provider.js +519 -0
  118. package/src/core/browser-verification/service.js +115 -0
  119. package/src/core/checkpoint-revalidation.js +319 -0
  120. package/src/core/cli-command-definitions.js +241 -0
  121. package/src/core/command-executors.js +110 -0
  122. package/src/core/command-input.js +115 -43
  123. package/src/core/completion-artifacts.js +14 -5
  124. package/src/core/completion.js +4 -6
  125. package/src/core/config.js +3 -0
  126. package/src/core/context-compiler/budget.js +9 -0
  127. package/src/core/context-compiler/candidates.js +39 -0
  128. package/src/core/context-compiler/compiler.js +63 -0
  129. package/src/core/context-compiler/fingerprint.js +11 -0
  130. package/src/core/context-compiler/policy.js +13 -0
  131. package/src/core/context-compiler/result.js +23 -0
  132. package/src/core/contract-bootstrap-recovery.js +655 -0
  133. package/src/core/contract-revision.js +210 -0
  134. package/src/core/decision/artifact.js +69 -0
  135. package/src/core/decision/benchmarks.js +103 -0
  136. package/src/core/decision/cache.js +27 -0
  137. package/src/core/decision/constants.js +58 -0
  138. package/src/core/decision/cutover.js +34 -0
  139. package/src/core/decision/engine.js +22 -0
  140. package/src/core/decision/errors.js +68 -0
  141. package/src/core/decision/events.js +101 -0
  142. package/src/core/decision/freshness.js +19 -0
  143. package/src/core/decision/normalizers/index.js +115 -0
  144. package/src/core/decision/policy.js +18 -0
  145. package/src/core/decision/projection.js +16 -0
  146. package/src/core/decision/question-registry.js +201 -0
  147. package/src/core/decision/request.js +26 -0
  148. package/src/core/decision/resolver.js +130 -0
  149. package/src/core/decision/result.js +58 -0
  150. package/src/core/decision/service.js +156 -0
  151. package/src/core/decision/state-builder.js +65 -0
  152. package/src/core/decision/task-bindings.js +30 -0
  153. package/src/core/decision/test-provider.js +32 -0
  154. package/src/core/decision/thresholds.js +15 -0
  155. package/src/core/error-codes.js +278 -0
  156. package/src/core/events.js +226 -57
  157. package/src/core/evidence-readiness.js +9 -0
  158. package/src/core/execution-prerequisites.js +14 -0
  159. package/src/core/execution-profile.js +63 -38
  160. package/src/core/gate-provenance.js +124 -0
  161. package/src/core/integration-invocation-policy.js +27 -4
  162. package/src/core/integration-resources.js +86 -61
  163. package/src/core/model-router/constants.js +10 -0
  164. package/src/core/model-router/policy.js +103 -0
  165. package/src/core/model-router/router.js +37 -0
  166. package/src/core/next-action-model.js +58 -0
  167. package/src/core/next-action-phases.js +130 -42
  168. package/src/core/next-action-refresh.js +43 -9
  169. package/src/core/next-action-review-phase.js +7 -2
  170. package/src/core/next-action.js +35 -7
  171. package/src/core/phase.js +128 -10
  172. package/src/core/preflight-consistency.js +23 -9
  173. package/src/core/preflight-loaders.js +37 -5
  174. package/src/core/protocol-info.js +65 -0
  175. package/src/core/protocol.js +20 -0
  176. package/src/core/reconcile-closure.js +128 -52
  177. package/src/core/recovery-history.js +1 -0
  178. package/src/core/resumability.js +154 -44
  179. package/src/core/route-artifact.js +15 -1
  180. package/src/core/router.js +67 -1
  181. package/src/core/runtime-context.js +118 -61
  182. package/src/core/schema-validation.js +3 -0
  183. package/src/core/security-review/constants.js +64 -0
  184. package/src/core/security-review/normalize.js +245 -0
  185. package/src/core/security-review/provider.js +204 -0
  186. package/src/core/security-review/service.js +134 -0
  187. package/src/core/semantic-planning/constants.js +19 -0
  188. package/src/core/semantic-planning/projection.js +94 -0
  189. package/src/core/semantic-planning/service.js +15 -0
  190. package/src/core/sources.js +37 -0
  191. package/src/core/task-claim-state.js +201 -1
  192. package/src/core/task-conflict-inspection.js +31 -5
  193. package/src/core/task-paths.js +13 -0
  194. package/src/core/task-recovery.js +1 -0
  195. package/src/core/templates.js +3 -0
  196. package/src/core/test-intelligence/benchmarks.js +68 -0
  197. package/src/core/test-intelligence/inventory.js +73 -0
  198. package/src/core/test-intelligence/prune.js +90 -0
  199. package/src/core/test-intelligence/semantic-state.js +15 -0
  200. package/src/core/test-intelligence/service.js +40 -0
  201. package/src/core/test-intelligence/utility.js +50 -0
  202. package/src/core/trace.js +11 -7
  203. package/src/core/transaction.js +1 -0
  204. package/src/integration.d.ts +492 -0
  205. package/src/integration.js +54 -0
  206. package/src/providers/README.md +47 -0
  207. package/src/providers/capabilities.js +46 -0
  208. package/src/providers/errors.js +15 -0
  209. package/src/providers/index.js +29 -0
  210. package/src/providers/json-snapshot.js +105 -0
  211. package/src/providers/registry.js +152 -0
@@ -2,6 +2,7 @@ import { runDoctor } from "../commands/doctor.js";
2
2
  import { runStatus } from "../commands/status.js";
3
3
  import { runValidateState } from "../commands/validate-state.js";
4
4
  import { runClearState } from "../commands/clear-state.js";
5
+ import { runCheckpointRevalidate } from "../commands/checkpoint-revalidate.js";
5
6
  import { inspectTarget } from "../commands/inspect.js";
6
7
  import { runInit } from "../commands/init.js";
7
8
  import { runRoute } from "../commands/route.js";
@@ -57,6 +58,11 @@ import { runRecordContinuity } from "../commands/record-continuity.js";
57
58
  import { runReconcileContinuity } from "../commands/reconcile-continuity.js";
58
59
  import { runClearContinuity } from "../commands/clear-continuity.js";
59
60
  import { runTaskCreate } from "../commands/task-create.js";
61
+ import { runDiscover } from "../commands/discover.js";
62
+ import { runContractCreate } from "../commands/contract-create.js";
63
+ import { runContractRevise } from "../commands/contract-revise.js";
64
+ import { runGateRecord } from "../commands/gate-record.js";
65
+ import { runGateRevalidate } from "../commands/gate-revalidate.js";
60
66
  import { runTaskList } from "../commands/task-list.js";
61
67
  import { runTaskShow } from "../commands/task-show.js";
62
68
  import { runTaskScope } from "../commands/task-scope.js";
@@ -64,10 +70,22 @@ import { runTaskMigrate } from "../commands/task-migrate.js";
64
70
  import { runMigrateProtocol } from "../commands/migrate-protocol.js";
65
71
  import { runTaskUnlock } from "../commands/task-unlock.js";
66
72
  import { runTaskRecover } from "../commands/task-recover.js";
73
+ import { runTaskAbandon } from "../commands/task-abandon.js";
67
74
  import { runTaskResume } from "../commands/task-resume.js";
68
75
  import { runTaskRepairLegacyRecovery } from "../commands/task-repair-legacy-recovery.js";
76
+ import { runTaskRepairContractBootstrap } from "../commands/task-repair-contract-bootstrap.js";
77
+ import { runTaskMigrateContractBootstrapRepair } from "../commands/task-migrate-contract-bootstrap-repair.js";
69
78
  import { runTaskLockStatus } from "../commands/task-lock-status.js";
70
79
  import { runProtocolInfo } from "../commands/protocol-info.js";
80
+ import { runDecisionStatus } from "../commands/decision-status.js";
81
+ import { runDecisionShow } from "../commands/decision-show.js";
82
+ import { runContextPlan } from "../commands/context-plan.js";
83
+ import { runModelRoute } from "../commands/model-route.js";
84
+ import { runSemanticPlan } from "../commands/semantic-plan.js";
85
+ import { runTestInventory } from "../commands/test-inventory.js";
86
+ import { runTestUtility } from "../commands/test-utility.js";
87
+ import { runTestPrunePlan } from "../commands/test-prune-plan.js";
88
+ import { runTestPruneProbe } from "../commands/test-prune-probe.js";
71
89
  import { runWorkspaceBind } from "../commands/workspace-bind.js";
72
90
  import { runWorkspaceStatus } from "../commands/workspace-status.js";
73
91
  import { runHandoffCreate } from "../commands/handoff-create.js";
@@ -103,10 +121,81 @@ import {
103
121
  * directly. No ownership, recovery, or lifecycle logic may live here.
104
122
  */
105
123
  export const COMMAND_EXECUTORS = {
124
+ discover: async ({ target, packageRoot, options }) => ({
125
+ result: await runDiscover({ target, packageRoot, taskId: options.taskId }),
126
+ exitCode: 0,
127
+ }),
128
+ "contract-create": async ({ target, packageRoot, options }) => ({
129
+ result: await runContractCreate({ target, packageRoot, taskId: options.taskId, preset: options.preset, contractFile: options.contractFile }),
130
+ exitCode: 0,
131
+ }),
132
+ "contract-revise": async ({ target, packageRoot, options }) => ({
133
+ result: await runContractRevise({ target, packageRoot, taskId: options.taskId, preset: options.preset, contractFile: options.contractFile }),
134
+ exitCode: 0,
135
+ }),
136
+ "gate-record": async ({ target, packageRoot, options }) => ({
137
+ result: await runGateRecord({ target, packageRoot, taskId: options.taskId, gate: options.gate, status: options.gateStatus, artifacts: options.gateArtifacts, decisions: options.gateDecisions, unknowns: options.gateUnknowns, assumptions: options.gateAssumptions, evidenceFile: options.gateEvidenceFile }),
138
+ exitCode: 0,
139
+ }),
140
+ "gate-revalidate": async ({ target, packageRoot, options }) => ({
141
+ result: await runGateRevalidate({ target, packageRoot, taskId: options.taskId, gate: options.gate, acknowledgeStale: options.acknowledgeStale }),
142
+ exitCode: 0,
143
+ }),
106
144
  "protocol-info": async ({ packageVersion }) => ({
107
145
  result: await runProtocolInfo({ packageVersion }),
108
146
  exitCode: 0,
109
147
  }),
148
+ "decision-status": async ({ target, packageRoot, options }) => ({
149
+ result: await runDecisionStatus({ target, packageRoot, health: options.health }),
150
+ exitCode: 0,
151
+ }),
152
+ "decision-show": async ({ target, packageRoot, options }) => ({
153
+ result: await runDecisionShow({ target, packageRoot, taskId: options.taskId, decisionId: options.decisionId }),
154
+ exitCode: 0,
155
+ }),
156
+ "context-plan": async ({ target, packageRoot, options }) => ({
157
+ result: await runContextPlan({ target, packageRoot, taskId: options.taskId, decisionId: options.decisionId, profile: options.profile ?? "balanced" }),
158
+ exitCode: 0,
159
+ }),
160
+ "model-route": async ({ target, packageRoot, options }) => ({
161
+ result: await runModelRoute({
162
+ target, packageRoot, taskId: options.taskId, decisionId: options.decisionId,
163
+ workType: options.workType,
164
+ surfaces: options.surfaces,
165
+ risks: options.risks,
166
+ platforms: options.platforms,
167
+ behaviorChange: options.behaviorChange,
168
+ executableChange: options.executableChange,
169
+ generationRequired: options.generationRequired,
170
+ architectureChange: options.architectureChange,
171
+ ambiguity: options.ambiguity,
172
+ }),
173
+ exitCode: 0,
174
+ }),
175
+ "semantic-plan": async ({ target, packageRoot, options }) => ({
176
+ result: await runSemanticPlan({
177
+ target, packageRoot, taskId: options.taskId, decisionId: options.decisionId,
178
+ kind: options.semanticPlanKind,
179
+ input: options.semanticPlanInput ?? {},
180
+ }),
181
+ exitCode: 0,
182
+ }),
183
+ "test-inventory": async ({ target }) => ({
184
+ result: await runTestInventory({ target }),
185
+ exitCode: 0,
186
+ }),
187
+ "test-utility": async ({ target, packageRoot, options }) => ({
188
+ result: await runTestUtility({ target, packageRoot, taskId: options.taskId }),
189
+ exitCode: 0,
190
+ }),
191
+ "test-prune-plan": async ({ target, packageRoot, options }) => ({
192
+ result: await runTestPrunePlan({ target, packageRoot, taskId: options.taskId }),
193
+ exitCode: 0,
194
+ }),
195
+ "test-prune-probe": async ({ target, packageRoot, options }) => ({
196
+ result: await runTestPruneProbe({ target, packageRoot, taskId: options.taskId, testId: options.testId }),
197
+ exitCode: 0,
198
+ }),
110
199
  init: async ({ target, packageRoot, packageVersion, options }) => ({
111
200
  result: await runInit({ target, dryRun: options.dryRun, packageRoot, packageVersion, repositoryIndex: true }),
112
201
  exitCode: 0,
@@ -593,6 +682,10 @@ export const COMMAND_EXECUTORS = {
593
682
  result: await runClearState({ target, taskId: options.taskId }),
594
683
  exitCode: 0,
595
684
  }),
685
+ "checkpoint-revalidate": async ({ target, packageRoot, options }) => ({
686
+ result: await runCheckpointRevalidate({ target, packageRoot, taskId: options.taskId }),
687
+ exitCode: 0,
688
+ }),
596
689
  "task-create": async ({ target, packageRoot, options }) => ({
597
690
  result: await runTaskCreate({
598
691
  target,
@@ -648,10 +741,27 @@ export const COMMAND_EXECUTORS = {
648
741
  }),
649
742
  exitCode: 0,
650
743
  }),
744
+ "task-abandon": async ({ target, packageRoot, options }) => ({
745
+ result: await runTaskAbandon({
746
+ target,
747
+ packageRoot,
748
+ taskId: options.taskId,
749
+ acknowledgeAbandonment: options.acknowledgeAbandonment,
750
+ }),
751
+ exitCode: 0,
752
+ }),
651
753
  "task-resume": async ({ target, packageRoot, options }) => ({
652
754
  result: await runTaskResume({ target, packageRoot, taskId: options.taskId, claims: options.claims }),
653
755
  exitCode: 0,
654
756
  }),
757
+ "task-repair-contract-bootstrap": async ({ target, packageRoot, options }) => ({
758
+ result: await runTaskRepairContractBootstrap({ target, packageRoot, taskId: options.taskId, acknowledgeRepair: options.acknowledgeRepair }),
759
+ exitCode: 0,
760
+ }),
761
+ "task-migrate-contract-bootstrap-repair": async ({ target, packageRoot, options }) => ({
762
+ result: await runTaskMigrateContractBootstrapRepair({ target, packageRoot, taskId: options.taskId, acknowledgeMigration: options.acknowledgeMigration }),
763
+ exitCode: 0,
764
+ }),
655
765
  "task-repair-legacy-recovery": async ({ target, packageRoot, options }) => ({
656
766
  result: await runTaskRepairLegacyRecovery({
657
767
  target,
@@ -19,10 +19,17 @@ function validatePolicyInput(command, options) {
19
19
  if (command !== "policy" && options.policy) throw inputError(`Policy name is not valid for ${command}`);
20
20
  }
21
21
 
22
- function validateTaskCreationInput(command, options) {
22
+ function validateContractBootstrapRepairMigrationInput(command, options) {
23
+ if (command !== "task-migrate-contract-bootstrap-repair") return;
24
+ if (!options.taskId) throw inputError("task-migrate-contract-bootstrap-repair requires --task");
25
+ if (!options.acknowledgeMigration) throw inputError("task-migrate-contract-bootstrap-repair requires --acknowledge-migration");
26
+ }
27
+
28
+ function validateTaskCreationInput(command, options, help = false) {
29
+ if (help) return;
23
30
  if (command === "bundle" && !options.taskId) throw inputError("bundle requires --task");
24
31
  if (command === "task-create" && !options.taskId) throw inputError("task-create requires --task");
25
- if (command !== "task-create" && (options.preset || options.preview)) {
32
+ if (!["task-create", "contract-create", "contract-revise"].includes(command) && (options.preset || options.preview)) {
26
33
  throw inputError(`preset/preview options are not valid for ${command}`);
27
34
  }
28
35
  if (command === "task-create" && options.preview && !options.preset && !options.contractFile) {
@@ -31,6 +38,15 @@ function validateTaskCreationInput(command, options) {
31
38
  if (command === "task-create" && options.preset && options.contractFile) {
32
39
  throw inputError("task-create accepts either --preset or --contract-file, not both");
33
40
  }
41
+ if (command === "contract-create" && !options.taskId) throw inputError("contract-create requires --task");
42
+ if (command === "contract-create" && !options.preset && !options.contractFile) throw inputError("contract-create requires --preset or --contract-file");
43
+ if (command === "contract-create" && options.preset && options.contractFile) throw inputError("contract-create accepts either --preset or --contract-file, not both");
44
+ if (command === "contract-revise" && !options.taskId) throw inputError("contract-revise requires --task");
45
+ if (command === "contract-revise" && !options.preset && !options.contractFile) throw inputError("contract-revise requires --preset or --contract-file");
46
+ if (command === "contract-revise" && options.preset && options.contractFile) throw inputError("contract-revise accepts either --preset or --contract-file, not both");
47
+ if (command === "task-repair-contract-bootstrap" && !options.taskId) throw inputError("task-repair-contract-bootstrap requires --task");
48
+ if (command === "task-repair-contract-bootstrap" && !options.acknowledgeRepair) throw inputError("task-repair-contract-bootstrap requires --acknowledge-repair");
49
+ validateContractBootstrapRepairMigrationInput(command, options);
34
50
  const hasTaskListFilter = Boolean(
35
51
  options.phase
36
52
  || options.active
@@ -42,6 +58,15 @@ function validateTaskCreationInput(command, options) {
42
58
  }
43
59
  }
44
60
 
61
+ function validateGateRecordInput(command, options, help) {
62
+ if (command !== "gate-record" || help) return;
63
+ if (!options.taskId) throw inputError("gate-record requires --task");
64
+ if (!options.gate) throw inputError("gate-record requires --gate");
65
+ if (!["satisfied", "unverified", "blocked"].includes(options.gateStatus)) {
66
+ throw inputError("gate-record --status must be satisfied, unverified, or blocked");
67
+ }
68
+ }
69
+
45
70
  function validateExecutionProfileInput(command, options) {
46
71
  if (options.executionProfile !== null && options.executionProfile !== undefined) {
47
72
  if (command !== "route") throw inputError(`executionProfile is not valid for ${command}`);
@@ -91,54 +116,91 @@ function validateOutputInput(command, options) {
91
116
  if (command !== "next" && options.explain === true) throw inputError(`explain output is not valid for ${command}`);
92
117
  }
93
118
 
94
- function validateTaskSelectorsInput(command, options, help) {
95
- const taskCommands = ["workspace-bind", "workspace-status", "handoff-create", "handoff-list", "handoff-show", "handoff-accept", "responsibility-set", "responsibility-status", "verify-scope", "attestation-create", "attestation-status", "attestation-verify"];
96
- if (taskCommands.includes(command) && !options.taskId) throw inputError(`${command} requires --task`);
97
- if (command === "handoff-show" && !help && !options.handoffId) throw inputError("handoff-show requires --id");
98
- if (command === "handoff-accept" && !help) {
99
- if (!options.handoffId) throw inputError("handoff-accept requires --handoff");
100
- if (!options.consumerId) throw inputError("handoff-accept requires --consumer-id");
119
+ const TASK_SELECTOR_COMMANDS = new Set([
120
+ "context-plan",
121
+ "model-route",
122
+ "semantic-plan",
123
+ "test-utility",
124
+ "checkpoint-revalidate",
125
+ "workspace-bind",
126
+ "workspace-status",
127
+ "handoff-create",
128
+ "handoff-list",
129
+ "handoff-show",
130
+ "handoff-accept",
131
+ "responsibility-set",
132
+ "responsibility-status",
133
+ "verify-scope",
134
+ "attestation-create",
135
+ "attestation-status",
136
+ "attestation-verify",
137
+ ]);
138
+
139
+ function validateRequiredTaskSelector(command, options, help) {
140
+ if (TASK_SELECTOR_COMMANDS.has(command) && !help && !options.taskId) {
141
+ throw inputError(`${command} requires --task`);
101
142
  }
143
+ }
144
+
145
+ function validateHandoffShowInput(command, options, help) {
146
+ if (command === "handoff-show" && !help && !options.handoffId) throw inputError("handoff-show requires --id");
147
+ }
148
+
149
+ function validateHandoffAcceptInput(command, options, help) {
150
+ if (command !== "handoff-accept" || help) return;
151
+ if (!options.handoffId) throw inputError("handoff-accept requires --handoff");
152
+ if (!options.consumerId) throw inputError("handoff-accept requires --consumer-id");
153
+ }
154
+
155
+ function validateResponsibilityInput(command, options, help) {
102
156
  if (command === "responsibility-set" && !help && !options.responsibilityLabel) {
103
157
  throw inputError("responsibility-set requires --label");
104
158
  }
105
- if (command === "verify-scope" && !help) {
106
- const mode = String(options.verificationScopeMode ?? "AUTO").toUpperCase();
107
- if (!["AUTO", "CHANGED", "CLAIMED", "FULL"].includes(mode)) throw inputError("verify-scope --mode must be AUTO, CHANGED, CLAIMED, or FULL");
108
- }
109
- if (command === "attestation-verify-range" && !help) {
110
- if (!options.baseRevision) throw inputError("attestation-verify-range requires --base");
111
- if (!options.headRevision) throw inputError("attestation-verify-range requires --head");
159
+ }
160
+
161
+ function validateVerificationScopeInput(command, options, help) {
162
+ if (command !== "verify-scope" || help) return;
163
+ const mode = String(options.verificationScopeMode ?? "AUTO").toUpperCase();
164
+ if (!["AUTO", "CHANGED", "CLAIMED", "FULL"].includes(mode)) throw inputError("verify-scope --mode must be AUTO, CHANGED, CLAIMED, or FULL");
165
+ }
166
+
167
+ function validateAttestationRangeInput(command, options, help) {
168
+ if (command !== "attestation-verify-range" || help) return;
169
+ if (!options.baseRevision) throw inputError("attestation-verify-range requires --base");
170
+ if (!options.headRevision) throw inputError("attestation-verify-range requires --head");
171
+ }
172
+
173
+ function validateTaskSelectorsInput(command, options, help) {
174
+ validateRequiredTaskSelector(command, options, help);
175
+ validateHandoffShowInput(command, options, help);
176
+ validateHandoffAcceptInput(command, options, help);
177
+ validateResponsibilityInput(command, options, help);
178
+ validateVerificationScopeInput(command, options, help);
179
+ validateAttestationRangeInput(command, options, help);
180
+ }
181
+
182
+ function validateRecordCheckInput(options) {
183
+ if (!options.checkId) throw inputError("record-check requires --id");
184
+ if (!options.checkRequirement) throw inputError("record-check requires --requirement");
185
+ if (!options.checkStatus) throw inputError("record-check requires --status");
186
+ if (!options.checkEvidenceKind) throw inputError("record-check requires --evidence-kind");
187
+ if (!options.checkCommand && !options.checkResult) throw inputError("record-check requires --command or --result");
188
+ }
189
+
190
+ function validateCommandCheckInput(options, command) {
191
+ if (!options.checkId) throw inputError(`${command} requires --id`);
192
+ if (!options.checkRequirement) throw inputError(`${command} requires --requirement`);
193
+ if (options.checkKind || options.checkStatus || options.checkEvidenceKind || options.checkCommand
194
+ || options.checkResult || options.checkExitCode !== null || options.checkExecutionRef || options.checkProvenance) {
195
+ throw inputError(`${command} accepts only --id, --requirement, --details,${command === "run-check" ? " --timeout-ms, --scope-ref," : ""} and -- <argv>`);
112
196
  }
197
+ if (!Array.isArray(options.commandArgv) || options.commandArgv.length === 0) throw inputError(`${command} requires -- followed by an exact command argv`);
113
198
  }
114
199
 
115
200
  function validateCheckInput(command, options, help) {
116
- if (command === "record-check" && !help) {
117
- if (!options.checkId) throw inputError("record-check requires --id");
118
- if (!options.checkRequirement) throw inputError("record-check requires --requirement");
119
- if (!options.checkStatus) throw inputError("record-check requires --status");
120
- if (!options.checkEvidenceKind) throw inputError("record-check requires --evidence-kind");
121
- if (!options.checkCommand && !options.checkResult) throw inputError("record-check requires --command or --result");
122
- }
123
- if (command === "run-check" && !help) {
124
- if (!options.checkId) throw inputError("run-check requires --id");
125
- if (!options.checkRequirement) throw inputError("run-check requires --requirement");
126
- if (options.checkKind || options.checkStatus || options.checkEvidenceKind || options.checkCommand
127
- || options.checkResult || options.checkExitCode !== null || options.checkExecutionRef || options.checkProvenance) {
128
- throw inputError("run-check accepts only --id, --requirement, --details, --timeout-ms, --scope-ref, and -- <argv>");
129
- }
130
- if (!Array.isArray(options.commandArgv) || options.commandArgv.length === 0) throw inputError("run-check requires -- followed by an exact command argv");
131
- }
132
- if (command === "reconcile-closure" && !help) {
133
- if (!options.taskId) throw inputError("reconcile-closure requires --task");
134
- if (!options.checkId) throw inputError("reconcile-closure requires --id");
135
- if (!options.checkRequirement) throw inputError("reconcile-closure requires --requirement");
136
- if (options.checkKind || options.checkStatus || options.checkEvidenceKind || options.checkCommand
137
- || options.checkResult || options.checkExitCode !== null || options.checkExecutionRef || options.checkProvenance) {
138
- throw inputError("reconcile-closure accepts only --id, --requirement, --details, and -- <argv>");
139
- }
140
- if (!Array.isArray(options.commandArgv) || options.commandArgv.length === 0) throw inputError("reconcile-closure requires -- followed by an exact command argv");
141
- }
201
+ if (help) return;
202
+ if (command === "record-check") validateRecordCheckInput(options);
203
+ if (command === "run-check" || command === "reconcile-closure") validateCommandCheckInput(options, command);
142
204
  }
143
205
 
144
206
  /**
@@ -172,6 +234,8 @@ export function defaultCommandInputValues() {
172
234
  assetPath: null,
173
235
  binaryPath: null,
174
236
  force: false,
237
+ acknowledgeRepair: false,
238
+ acknowledgeMigration: false,
175
239
  workType: null,
176
240
  surfaces: [],
177
241
  risks: [],
@@ -193,6 +257,13 @@ export function defaultCommandInputValues() {
193
257
  file: null,
194
258
  contractFile: null,
195
259
  preset: null,
260
+ gate: null,
261
+ gateStatus: null,
262
+ gateArtifacts: [],
263
+ gateDecisions: [],
264
+ gateUnknowns: [],
265
+ gateAssumptions: [],
266
+ gateEvidenceFile: null,
196
267
  preview: false,
197
268
  phase: null,
198
269
  active: false,
@@ -263,7 +334,8 @@ export function validateForgeLoopCommandInput({ command, input, help = false } =
263
334
  if (!command) return;
264
335
 
265
336
  validatePolicyInput(command, options);
266
- validateTaskCreationInput(command, options);
337
+ validateTaskCreationInput(command, options, help);
338
+ validateGateRecordInput(command, options, help);
267
339
  validateSearchCommandInput(command, options, help);
268
340
  validateProfileAndUsageInput(command, options, help);
269
341
  validateOutputInput(command, options);
@@ -18,7 +18,7 @@ import { readPersistedRoute } from "./route-artifact.js";
18
18
  import { createReceipt, validateReceipt } from "./receipt.js";
19
19
  import { readWorkState, mutateWorkState } from "./work-state.js";
20
20
  import { assertExecutionPrerequisites, hasExecutionStarted } from "./execution-prerequisites.js";
21
- import { normalizeRequirements } from "./evidence-readiness.js";
21
+ import { normalizeRequirements, terminalRequirementsForContract } from "./evidence-readiness.js";
22
22
  import { classifyCommandResolution, validateVerificationAuthority } from "./verification-capability.js";
23
23
  import { readExecutionArtifact, validateExecutionBinding } from "./execution.js";
24
24
  import { taskArtifactPath, taskExecutionPath } from "./task-paths.js";
@@ -478,10 +478,15 @@ export async function assertRecordCheckPrerequisites({
478
478
  const requested = normalizeRequirements(requiredEvidence).find((item) => (
479
479
  item.id === requirement || item.text === requirement
480
480
  ));
481
- if (requested?.terminalOwned && status === "passed" && evidenceKind === "OBSERVED") {
481
+ const terminalRequested = terminalRequirementsForContract(contract.value, {
482
+ additionalEvidence: preflight.policy?.requiredEvidence ?? [],
483
+ }).find((item) => (
484
+ item.id === requirement || item.text === requirement
485
+ ));
486
+ if ((requested?.terminalOwned || terminalRequested) && status === "passed" && evidenceKind === "OBSERVED") {
482
487
  throw artifactError(
483
488
  "E_FUTURE_LIFECYCLE_EVIDENCE",
484
- `Terminal-owned requirement cannot be recorded before its authoritative result: ${requested.text}`,
489
+ `Terminal-owned requirement cannot be recorded before its authoritative result: ${(requested ?? terminalRequested).text}`,
485
490
  [stateRel, eventsRel],
486
491
  );
487
492
  }
@@ -827,8 +832,12 @@ export async function recordTerminalResult({
827
832
  additionalEvidence: preflight.policy?.requiredEvidence ?? [],
828
833
  });
829
834
 
830
- const normalized = normalizeRequirements(requiredEvidence);
831
- const requested = normalized.find((item) => (
835
+ const terminalRequirements = terminalRequirementsForContract(contract.value, {
836
+ additionalEvidence: preflight.policy?.requiredEvidence ?? [],
837
+ });
838
+ const requested = terminalRequirements.find((item) => (
839
+ item.id === requirement || item.text === requirement
840
+ )) ?? normalizeRequirements(requiredEvidence).find((item) => (
832
841
  item.id === requirement || item.text === requirement
833
842
  ));
834
843
 
@@ -10,7 +10,7 @@ import { completionRelationshipErrors } from "./completion-relationships.js";
10
10
  import { assertSafePath, ensureWithin, fileExists } from "./filesystem.js";
11
11
  import { evaluateStartExecutionPrerequisites, hasExecutionStarted } from "./execution-prerequisites.js";
12
12
  import { isRecoverableCompletionEvidenceCode } from "./completion-recovery.js";
13
- import { evaluateTerminalRequirements } from "./evidence-readiness.js";
13
+ import { evaluateTerminalRequirements, terminalRequirementsForContract } from "./evidence-readiness.js";
14
14
  import { PROJECT_ARTIFACT_PATHS, taskArtifactPath, taskCodeManifestPath } from "./task-paths.js";
15
15
  import { detectPolicyCapability, evaluateTargetPolicy } from "./policy-engine.js";
16
16
  import { listActions } from "./actions.js";
@@ -500,12 +500,10 @@ export async function evaluateCompletion({
500
500
  const publication = receiptValue ? publicationStatus(receiptValue) : "not-published";
501
501
 
502
502
  if (contract) {
503
- const allContractReqs = [
504
- ...(contract.value.verification ?? []),
505
- ...(contract.value.successCriteria ?? []),
506
- ];
507
503
  const terminalEval = evaluateTerminalRequirements({
508
- requirements: allContractReqs,
504
+ requirements: terminalRequirementsForContract(contract.value, {
505
+ additionalEvidence: preflight.policy?.requiredEvidence ?? [],
506
+ }),
509
507
  receipt: receiptValue,
510
508
  });
511
509
  for (const termErr of terminalEval.errors) {
@@ -4,6 +4,7 @@ import { E_ATTESTATION_CONFIGURATION_INVALID } from "./error-codes.js";
4
4
  import { normalizeVerificationConfiguration } from "./verification-scope-capability.js";
5
5
  import { EXECUTION_PROFILE_REQUESTS } from "./execution-profile.js";
6
6
  import { normalizeStructuralQualityConfig } from "./structural-quality/policy.js";
7
+ import { normalizeDecisionPolicy } from "./decision/policy.js";
7
8
 
8
9
  export const CONFIG_SCHEMA_VERSION = 1;
9
10
  export const COMPLIANCE_MODES = Object.freeze(["advisory", "standard", "strict"]);
@@ -82,6 +83,7 @@ export function createConfig(input = {}) {
82
83
  executionProfile = input.executionProfile;
83
84
  }
84
85
  const structuralQuality = normalizeStructuralQualityConfig(input.structuralQuality);
86
+ const decisionEngine = normalizeDecisionPolicy(input.decisionEngine);
85
87
  return {
86
88
  schemaVersion: CONFIG_SCHEMA_VERSION,
87
89
  protocolVersion: PROTOCOL_VERSION,
@@ -93,6 +95,7 @@ export function createConfig(input = {}) {
93
95
  ...(attestation ? { attestation } : {}),
94
96
  ...(executionProfile ? { executionProfile } : {}),
95
97
  ...(structuralQuality !== undefined ? { structuralQuality } : {}),
98
+ decisionEngine,
96
99
  };
97
100
  }
98
101
 
@@ -0,0 +1,9 @@
1
+ export const CONTEXT_BUDGETS = Object.freeze({
2
+ light: Object.freeze({ maxItems: 12, maxChars: 24_000 }),
3
+ balanced: Object.freeze({ maxItems: 32, maxChars: 64_000 }),
4
+ full: Object.freeze({ maxItems: 96, maxChars: 160_000 }),
5
+ });
6
+
7
+ export function contextBudget(profile = "balanced") {
8
+ return CONTEXT_BUDGETS[profile] ?? CONTEXT_BUDGETS.balanced;
9
+ }
@@ -0,0 +1,39 @@
1
+ import { canonicalFingerprint } from "../artifacts.js";
2
+ import { buildDecisionState } from "../decision/state-builder.js";
3
+
4
+ const INJECTION_PATTERN = /(ignore|disregard|override)\s+(?:all|previous|forge|system|developer)|exfiltrat|reveal\s+(?:the|all)\s+(?:secret|token|key)|execute\s+(?:this|the)\s+command/i;
5
+
6
+ export function normalizeContextCandidate(input = {}) {
7
+ const safe = buildDecisionState({
8
+ id: input.id ?? null,
9
+ sourceRef: input.sourceRef ?? null,
10
+ kind: input.kind ?? "UNKNOWN",
11
+ summary: input.summary ?? "",
12
+ required: input.required === true,
13
+ mandatory: input.mandatory === true,
14
+ risk: input.risk ?? "NORMAL",
15
+ trust: input.trust ?? "UNTRUSTED",
16
+ });
17
+ const summary = typeof safe.summary === "string" ? safe.summary : "";
18
+ const id = typeof safe.id === "string" && safe.id ? safe.id : `candidate-${canonicalFingerprint(safe).slice(0, 16)}`;
19
+ return {
20
+ ...safe,
21
+ id,
22
+ summary,
23
+ chars: summary.length,
24
+ promptInjection: INJECTION_PATTERN.test(summary),
25
+ };
26
+ }
27
+
28
+ export function normalizeContextCandidates(candidates = []) {
29
+ const seen = new Set();
30
+ const normalized = [];
31
+ for (const candidate of candidates) {
32
+ const value = normalizeContextCandidate(candidate);
33
+ const identity = `${value.id}:${value.sourceRef ?? ""}`;
34
+ if (seen.has(identity)) continue;
35
+ seen.add(identity);
36
+ normalized.push(value);
37
+ }
38
+ return normalized;
39
+ }
@@ -0,0 +1,63 @@
1
+ import { contextBudget } from "./budget.js";
2
+ import { normalizeContextCandidates } from "./candidates.js";
3
+ import { contextPlanFingerprint } from "./fingerprint.js";
4
+ import { canonicalFingerprint } from "../artifacts.js";
5
+ import { assertContextCompilerPolicy, candidatePriority } from "./policy.js";
6
+ import { contextPlanResult } from "./result.js";
7
+
8
+ function orderCandidates(candidates, rankedIds = []) {
9
+ const ranks = new Map(rankedIds.map((id, index) => [id, rankedIds.length - index]));
10
+ return [...candidates].sort((a, b) => (b.mandatory - a.mandatory)
11
+ || (b.required - a.required)
12
+ || ((ranks.get(b.id) ?? 0) - (ranks.get(a.id) ?? 0))
13
+ || (candidatePriority(b) - candidatePriority(a))
14
+ || a.id.localeCompare(b.id));
15
+ }
16
+
17
+ export function compileContext({ candidates = [], profile = "balanced", mandatoryIds = [], semanticRanker = null } = {}) {
18
+ const policy = assertContextCompilerPolicy({ profile, mandatoryIds });
19
+ const normalized = normalizeContextCandidates(candidates);
20
+ const candidateSetFingerprint = canonicalFingerprint(normalized.map((candidate) => ({
21
+ id: candidate.id,
22
+ sourceRef: candidate.sourceRef,
23
+ summary: candidate.summary,
24
+ required: candidate.required,
25
+ mandatory: candidate.mandatory,
26
+ })));
27
+ const mandatory = new Set(policy.mandatoryIds);
28
+ const marked = normalized.map((candidate) => ({ ...candidate, mandatory: candidate.mandatory || mandatory.has(candidate.id) }));
29
+ const semantic = typeof semanticRanker === "function" ? semanticRanker(marked.filter((item) => !item.promptInjection).map((item) => ({ id: item.id, summary: item.summary }))) : [];
30
+ const rankedIds = Array.isArray(semantic) ? semantic : (semantic?.rankedIds ?? []);
31
+ const excludedIds = new Set(Array.isArray(semantic) ? [] : (semantic?.excludedIds ?? []));
32
+ const ordered = orderCandidates(marked, Array.isArray(rankedIds) ? rankedIds : []);
33
+ const budget = contextBudget(profile);
34
+ const selected = [];
35
+ const omitted = [];
36
+ let chars = 0;
37
+ for (const candidate of ordered) {
38
+ const mustKeep = candidate.mandatory || candidate.required;
39
+ if (excludedIds.has(candidate.id) && !mustKeep) {
40
+ omitted.push(candidate);
41
+ continue;
42
+ }
43
+ const fits = selected.length < budget.maxItems && chars + candidate.chars <= budget.maxChars;
44
+ if (fits || mustKeep) {
45
+ selected.push(candidate);
46
+ chars += candidate.chars;
47
+ } else omitted.push(candidate);
48
+ }
49
+ const promptInjectionIds = marked.filter((item) => item.promptInjection).map((item) => item.id).sort();
50
+ const result = contextPlanResult({
51
+ profile,
52
+ candidates: marked,
53
+ selected,
54
+ omitted,
55
+ mandatoryIds: [...new Set([...policy.mandatoryIds, ...marked.filter((item) => item.mandatory).map((item) => item.id)])].sort(),
56
+ promptInjectionIds,
57
+ fingerprint: null,
58
+ budget,
59
+ candidateSetFingerprint,
60
+ });
61
+ result.decisionFingerprint = contextPlanFingerprint(result);
62
+ return result;
63
+ }
@@ -0,0 +1,11 @@
1
+ import { canonicalFingerprint } from "../artifacts.js";
2
+
3
+ export function contextPlanFingerprint(plan) {
4
+ return canonicalFingerprint({
5
+ profile: plan.profile,
6
+ selectedIds: plan.selected.map((item) => item.id),
7
+ omittedIds: plan.omitted.map((item) => item.id),
8
+ mandatoryIds: plan.mandatoryIds,
9
+ promptInjectionIds: plan.promptInjectionIds,
10
+ });
11
+ }
@@ -0,0 +1,13 @@
1
+ import { decisionError, DECISION_ERROR_CODES } from "../decision/errors.js";
2
+
3
+ const RISK_ORDER = Object.freeze({ CRITICAL: 4, HIGH: 3, NORMAL: 2, LOW: 1 });
4
+
5
+ export function assertContextCompilerPolicy({ profile = "balanced", mandatoryIds = [] } = {}) {
6
+ if (!["light", "balanced", "full"].includes(profile)) throw decisionError(DECISION_ERROR_CODES.POLICY_INVALID, "Context compiler profile is invalid.");
7
+ if (!Array.isArray(mandatoryIds) || mandatoryIds.some((id) => typeof id !== "string" || !id)) throw decisionError(DECISION_ERROR_CODES.POLICY_INVALID, "Context compiler mandatory IDs are invalid.");
8
+ return { profile, mandatoryIds: [...new Set(mandatoryIds)] };
9
+ }
10
+
11
+ export function candidatePriority(candidate) {
12
+ return (candidate.mandatory || candidate.required ? 100 : 0) + (candidate.promptInjection ? -50 : 0) + (RISK_ORDER[candidate.risk] ?? 0);
13
+ }
@@ -0,0 +1,23 @@
1
+ export function contextPlanResult({ profile, candidates, selected, omitted, mandatoryIds, promptInjectionIds, fingerprint, budget, candidateSetFingerprint }) {
2
+ return {
3
+ schemaVersion: 1,
4
+ protocolVersion: 1,
5
+ profile,
6
+ budget,
7
+ candidateItems: candidates.length,
8
+ selectedItems: selected.length,
9
+ candidateChars: candidates.reduce((total, item) => total + item.chars, 0),
10
+ selectedChars: selected.reduce((total, item) => total + item.chars, 0),
11
+ selected,
12
+ omitted,
13
+ mandatoryIds,
14
+ promptInjectionIds,
15
+ candidateSetFingerprint,
16
+ tokenUsage: { inputTokens: null, outputTokens: null, reportedBy: "UNKNOWN" },
17
+ decisionFingerprint: fingerprint,
18
+ authority: "SEMANTIC_DECISION",
19
+ evidenceAuthority: "NONE",
20
+ lifecycleAuthority: false,
21
+ completionAuthority: false,
22
+ };
23
+ }