@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
@@ -24,7 +24,7 @@ export const INTEGRATION_RISK_CLASSES = Object.freeze({
24
24
  });
25
25
 
26
26
  const READ_ONLY_COMMANDS = Object.freeze(new Set([
27
- "protocol-info", "status", "next", "continuity", "reconcile-continuity",
27
+ "protocol-info", "decision-status", "decision-show", "context-plan", "model-route", "semantic-plan", "test-inventory", "status", "next", "continuity", "reconcile-continuity",
28
28
  "task-list", "task-show", "task-lock-status", "progress", "audit", "report",
29
29
  "inspect", "validate-state", "validate-protocol", "validate-receipt",
30
30
  "policy-status", "policy-diff", "rule-verify", "policy",
@@ -37,7 +37,7 @@ const READ_ONLY_COMMANDS = Object.freeze(new Set([
37
37
  ]));
38
38
 
39
39
  const LOOP_MUTATION_COMMANDS = Object.freeze(new Set([
40
- "route", "preflight", "advance", "task-create", "task-scope",
40
+ "discover", "contract-create", "route", "preflight", "advance", "task-create", "task-scope",
41
41
  "record-continuity", "clear-continuity", "prepare-completion",
42
42
  "record-check", "record-diagnosis", "record-decision-criterion",
43
43
  "record-terminal-result", "complete",
@@ -86,7 +86,17 @@ const STATIC_RISK_CLASSES = Object.freeze({
86
86
  bundle: INTEGRATION_RISK_CLASSES.MAINTENANCE,
87
87
  "profile-interview": INTEGRATION_RISK_CLASSES.MAINTENANCE,
88
88
  "task-recover": INTEGRATION_RISK_CLASSES.CLAIM_RELEASE_RECOVERY,
89
+ "task-abandon": INTEGRATION_RISK_CLASSES.CLAIM_RELEASE_RECOVERY,
89
90
  "task-repair-legacy-recovery": INTEGRATION_RISK_CLASSES.LEGACY_MIGRATION,
91
+ "gate-record": INTEGRATION_RISK_CLASSES.MAINTENANCE,
92
+ "gate-revalidate": INTEGRATION_RISK_CLASSES.MAINTENANCE,
93
+ "test-utility": INTEGRATION_RISK_CLASSES.MAINTENANCE,
94
+ "test-prune-plan": INTEGRATION_RISK_CLASSES.READ_ONLY,
95
+ "test-prune-probe": INTEGRATION_RISK_CLASSES.EXTERNAL_EXECUTION,
96
+ "task-repair-contract-bootstrap": INTEGRATION_RISK_CLASSES.LEGACY_MIGRATION,
97
+ "task-migrate-contract-bootstrap-repair": INTEGRATION_RISK_CLASSES.LEGACY_MIGRATION,
98
+ "checkpoint-revalidate": INTEGRATION_RISK_CLASSES.MAINTENANCE,
99
+ "contract-revise": INTEGRATION_RISK_CLASSES.MAINTENANCE,
90
100
  });
91
101
 
92
102
  // Sparse input-dependent refinements over the static table.
@@ -169,6 +179,18 @@ export function getForgeLoopCapabilities({ packageVersion = null } = {}) {
169
179
  commands: ["next", "task-show"],
170
180
  preservesDefaultOutput: true,
171
181
  },
182
+ auditUx: {
183
+ version: 1,
184
+ supported: true,
185
+ readOnly: true,
186
+ resource: "task/audit-view",
187
+ timeline: true,
188
+ lifecycleAuthority: false,
189
+ evidenceAuthority: false,
190
+ completionAuthority: false,
191
+ mutationAuthority: false,
192
+ externalExecution: false,
193
+ },
172
194
  usageTelemetry: {
173
195
  version: 1,
174
196
  supported: true,
@@ -295,6 +317,7 @@ export function getForgeLoopCapabilities({ packageVersion = null } = {}) {
295
317
  { name: "task/approvals", scope: "TASK" },
296
318
  { name: "task/metrics", scope: "TASK" },
297
319
  { name: "task/context", scope: "TASK" },
320
+ { name: "task/audit-view", scope: "TASK" },
298
321
  { name: "task/evaluations", scope: "TASK" },
299
322
  { name: "project/capability-policy", scope: "PROJECT" },
300
323
  { name: "repository/index-status", scope: "PROJECT" },
@@ -352,8 +375,8 @@ export function classifyForgeLoopInvocation(command, input = {}) {
352
375
  removesArtifacts: definition.removes.length > 0,
353
376
  executesExternalProcess: definition.mayExecuteExternalProcess === true,
354
377
  affectsClaimAuthority: [
355
- "task-resume", "task-recover", "task-repair-legacy-recovery",
356
- "task-create", "task-scope", "complete",
378
+ "task-resume", "task-recover", "task-repair-legacy-recovery", "task-repair-contract-bootstrap",
379
+ "task-create", "task-scope", "complete", "task-migrate-contract-bootstrap-repair",
357
380
  ].includes(command),
358
381
  destructive: [
359
382
  INTEGRATION_RISK_CLASSES.AUTHORITY_MUTATION,
@@ -21,6 +21,12 @@ import { resolveAttestationStatus } from "./attestation.js";
21
21
  import { buildExecutionProfileContext } from "./execution-profile-context.js";
22
22
  import { projectStructuralQualityStatus } from "./structural-quality/service.js";
23
23
  import { getRepositoryIndexStatus } from "../repository-index/status.js";
24
+ import { buildAuditUxView } from "./audit-ux.js";
25
+ import { runContextPlan } from "../commands/context-plan.js";
26
+ import { runModelRoute } from "../commands/model-route.js";
27
+ import { readPersistedRoute } from "./route-artifact.js";
28
+ import { readWorkState } from "./work-state.js";
29
+ import { readTestUtility } from "./test-intelligence/service.js";
24
30
 
25
31
  /**
26
32
  * Canonical integration resource allowlist.
@@ -86,11 +92,18 @@ export const INTEGRATION_RESOURCE_DEFINITIONS = Object.freeze({
86
92
  "task/approvals": Object.freeze({ scope: "TASK", description: "Durable approval artifacts for one task." }),
87
93
  "task/metrics": Object.freeze({ scope: "TASK", description: "Read-only trajectory metrics for one task." }),
88
94
  "task/context": Object.freeze({ scope: "TASK", description: "Read-only profile-aware task context with bounded presentation policy." }),
95
+ "task/audit-view": Object.freeze({ scope: "TASK", description: "Bounded read-only Audit UX projection composed from canonical task resolvers." }),
89
96
  "task/evaluations": Object.freeze({ scope: "TASK", description: "Persisted trajectory evaluations for one task." }),
97
+ "task/decisions": Object.freeze({ scope: "TASK", description: "Persisted, fingerprint-bound semantic decisions without lifecycle or evidence authority." }),
98
+ "task/context-plan": Object.freeze({ scope: "TASK", description: "Bounded non-authoritative semantic context-plan projection." }),
99
+ "task/model-route": Object.freeze({ scope: "TASK", description: "Deterministic model-routing floor with advisory semantic escalation." }),
100
+ "task/test-utility": Object.freeze({ scope: "TASK", description: "Non-evidence test inventory and utility analysis; never deletion authority." }),
90
101
  "project/capability-policy": Object.freeze({ scope: "PROJECT", description: "Project capability policy, never host authority." }),
91
102
  "repository/index-status": Object.freeze({ scope: "PROJECT", description: "Provider-neutral repository-index health and owned-server status." }),
92
103
  });
93
104
 
105
+ const TASK_RESOURCE_URIS = new Set(Object.keys(INTEGRATION_RESOURCE_DEFINITIONS).filter((uri) => uri.startsWith("task/")));
106
+
94
107
  function ownershipProjection(projection) {
95
108
  return {
96
109
  taskId: projection.taskId,
@@ -120,67 +133,20 @@ async function readForgeLoopIntegrationResourceCore(uri, {
120
133
  throw error;
121
134
  }
122
135
 
123
- switch (uri) {
124
- case "protocol/info": {
125
- return { uri, data: await runProtocolInfo({ packageVersion }) };
126
- }
127
- case "project/tasks": {
128
- const tasks = await discoverTasks(projectPath, packageRoot);
129
- return {
130
- uri,
131
- data: {
132
- count: tasks.length,
133
- tasks: tasks.map((task) => ({
134
- taskId: task.taskId,
135
- healthy: task.healthy !== false,
136
- phase: task.phase ?? null,
137
- mutationAllowed: task.mutationAllowed !== false,
138
- })),
139
- },
140
- };
141
- }
142
- case "task/status":
143
- case "task/ownership":
144
- case "task/contract":
145
- case "task/continuity": {
146
- if (typeof taskId !== "string" || !taskId) {
147
- const error = new Error(`Resource ${uri} requires a taskId`);
148
- error.code = "E_TASK_REQUIRED";
149
- throw error;
150
- }
151
- break;
152
- }
153
- case "task/workspace-binding":
154
- case "task/handoffs":
155
- case "task/responsibility":
156
- case "task/verification-scope":
157
- case "task/attestation": {
158
- if (typeof taskId !== "string" || !taskId) {
159
- const error = new Error(`Resource ${uri} requires a taskId`);
160
- error.code = "E_TASK_REQUIRED";
161
- throw error;
162
- }
163
- break;
164
- }
165
- case "task/structural-quality": {
166
- if (typeof taskId !== "string" || !taskId) {
167
- const error = new Error(`Resource ${uri} requires a taskId`);
168
- error.code = "E_TASK_REQUIRED";
169
- throw error;
170
- }
171
- break;
172
- }
173
- case "task/actions":
174
- case "task/action":
175
- case "task/approvals":
176
- case "task/metrics":
177
- case "task/context":
178
- case "task/evaluations": {
179
- if (typeof taskId !== "string" || !taskId) {
180
- const error = new Error(`Resource ${uri} requires a taskId`); error.code = "E_TASK_REQUIRED"; throw error;
181
- }
182
- break;
183
- }
136
+ if (uri === "protocol/info") return { uri, data: await runProtocolInfo({ packageVersion }) };
137
+ if (uri === "project/tasks") {
138
+ const tasks = await discoverTasks(projectPath, packageRoot);
139
+ return { uri, data: { count: tasks.length, tasks: tasks.map((task) => ({
140
+ taskId: task.taskId,
141
+ healthy: task.healthy !== false,
142
+ phase: task.phase ?? null,
143
+ mutationAllowed: task.mutationAllowed !== false,
144
+ })) } };
145
+ }
146
+ if (TASK_RESOURCE_URIS.has(uri) && (typeof taskId !== "string" || !taskId)) {
147
+ const error = new Error(`Resource ${uri} requires a taskId`);
148
+ error.code = "E_TASK_REQUIRED";
149
+ throw error;
184
150
  }
185
151
 
186
152
  if (uri === "task/ownership") {
@@ -270,6 +236,45 @@ async function readForgeLoopIntegrationResourceCore(uri, {
270
236
  }
271
237
  return { uri, taskId, data: { evaluations } };
272
238
  }
239
+ if (uri === "task/decisions") {
240
+ const dir = path.join(projectPath, taskDirectory(taskId), "decisions");
241
+ let names = []; try { names = await readdir(dir); } catch { /* absent is an empty projection */ }
242
+ const decisions = [];
243
+ for (const name of names.filter((entry) => /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}\.json$/.test(entry)).sort()) {
244
+ decisions.push((await readJsonArtifact(projectPath, `${taskDirectory(taskId)}/decisions/${name}`, "semantic-decision", packageRoot)).value);
245
+ }
246
+ return { uri, taskId, data: { taskId, decisions } };
247
+ }
248
+ if (uri === "task/context-plan") {
249
+ return { uri, taskId, data: await runContextPlan({ target: projectPath, packageRoot, taskId, profile: runtimeContext?.contextProfile ?? "balanced", readOnly: true }) };
250
+ }
251
+ if (uri === "task/model-route") {
252
+ const state = await readWorkState(projectPath, { packageRoot, taskId });
253
+ const route = await readPersistedRoute(projectPath, packageRoot, { taskId });
254
+ return {
255
+ uri,
256
+ taskId,
257
+ data: await runModelRoute({
258
+ target: projectPath,
259
+ packageRoot,
260
+ taskId,
261
+ workType: route.value.input?.workType,
262
+ surfaces: route.value.input?.surfaces,
263
+ risks: route.value.input?.risks,
264
+ platforms: route.value.input?.platforms,
265
+ behaviorChange: route.value.input?.behaviorChange,
266
+ executableChange: route.value.input?.executableChange,
267
+ generationRequired: route.value.input?.generationRequired,
268
+ architectureChange: route.value.input?.architectureChange,
269
+ ambiguity: route.value.input?.ambiguity,
270
+ contract: { phase: state.phase },
271
+ }),
272
+ };
273
+ }
274
+ if (uri === "task/test-utility") {
275
+ const artifact = await readTestUtility({ target: projectPath, packageRoot, taskId });
276
+ return { uri, taskId, data: artifact.value };
277
+ }
273
278
  if (uri === "project/capability-policy") {
274
279
  return { uri, data: await loadCapabilityPolicy(projectPath, packageRoot) };
275
280
  }
@@ -292,6 +297,26 @@ async function readForgeLoopIntegrationResourceCore(uri, {
292
297
  }
293
298
 
294
299
  export async function readForgeLoopIntegrationResource(uri, options = {}) {
300
+ if (uri === "task/audit-view") {
301
+ if (typeof options.taskId !== "string" || !options.taskId) {
302
+ const error = new Error("Resource task/audit-view requires a taskId"); error.code = "E_TASK_REQUIRED"; throw error;
303
+ }
304
+ return {
305
+ uri,
306
+ taskId: options.taskId,
307
+ data: await buildAuditUxView({
308
+ target: options.projectPath ?? ".",
309
+ packageRoot: options.packageRoot,
310
+ taskId: options.taskId,
311
+ limit: options.limit,
312
+ beforeSequence: options.beforeSequence,
313
+ afterSequence: options.afterSequence,
314
+ categories: options.categories,
315
+ authorityContext: options.runtimeContext?.authorityContext,
316
+ runtimeContext: options.runtimeContext,
317
+ }),
318
+ };
319
+ }
295
320
  if (uri === "repository/index-status") {
296
321
  return {
297
322
  uri,
@@ -0,0 +1,10 @@
1
+ import { DECISION_AUTHORITY, DECISION_EVIDENCE_AUTHORITY, PINNED_JEV_MODEL } from "../decision/constants.js";
2
+
3
+ export const MODEL_ROUTE_TIERS = Object.freeze(["NONE", "FAST", "STANDARD", "PRIMARY"]);
4
+ export const MODEL_ROUTE_POLICY_VERSION = 1;
5
+ export const MODEL_ROUTE_PROJECTION_AUTHORITY = DECISION_AUTHORITY;
6
+ export const MODEL_ROUTE_PROJECTION_EVIDENCE_AUTHORITY = DECISION_EVIDENCE_AUTHORITY;
7
+ export const MODEL_ROUTE_JEV_MODEL = PINNED_JEV_MODEL;
8
+
9
+ export const MODEL_ROUTE_RANK = Object.freeze({ NONE: 0, FAST: 1, STANDARD: 2, PRIMARY: 3 });
10
+
@@ -0,0 +1,103 @@
1
+ import { MODEL_ROUTE_RANK, MODEL_ROUTE_TIERS } from "./constants.js";
2
+
3
+ const GENERATION_WORK_TYPES = new Set([
4
+ "code", "bug", "refactor", "backend", "api", "infrastructure", "security-review", "release",
5
+ ]);
6
+ const PRIMARY_WORK_TYPES = new Set(["infrastructure", "security-review", "release"]);
7
+ const PRIMARY_RISKS = new Set(["secrets", "personal-data", "publication", "critical-path", "destructive", "irreversible", "migration", "credentials", "payment"]);
8
+ const PRIMARY_SURFACES = new Set(["auth", "critical-path", "database"]);
9
+
10
+ function text(value) {
11
+ return typeof value === "string" ? value.toLowerCase() : "";
12
+ }
13
+
14
+ function array(value) {
15
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
16
+ }
17
+
18
+ function contractText(contract) {
19
+ if (!contract || typeof contract !== "object" || Array.isArray(contract)) return "";
20
+ const values = [contract.objective, contract.summary, ...(contract.deliverables ?? []), ...(contract.successCriteria ?? []), ...(contract.risks ?? []), ...(contract.constraints ?? [])];
21
+ return values.map((value) => value && typeof value === "object" ? value.text : value).filter((value) => typeof value === "string").join(" ").toLowerCase();
22
+ }
23
+
24
+ function normalizedInput(input = {}) {
25
+ return {
26
+ workType: text(input.workType),
27
+ surfaces: array(input.surfaces).map(text),
28
+ risks: array(input.risks).map(text),
29
+ platforms: array(input.platforms).map(text),
30
+ behaviorChange: input.behaviorChange === true,
31
+ executableChange: input.executableChange === true,
32
+ generationRequired: input.generationRequired === true,
33
+ architectureChange: input.architectureChange === true,
34
+ ambiguity: input.ambiguity === true,
35
+ contract: input.contract,
36
+ };
37
+ }
38
+
39
+ function deterministicFloor(input) {
40
+ const normalized = normalizedInput(input);
41
+ const reasons = [];
42
+ const combined = `${contractText(normalized.contract)} ${normalized.workType} ${normalized.surfaces.join(" ")} ${normalized.risks.join(" ")}`;
43
+ const generationRequired = normalized.generationRequired
44
+ || normalized.behaviorChange
45
+ || normalized.executableChange
46
+ || GENERATION_WORK_TYPES.has(normalized.workType)
47
+ || /\b(implement|fix|refactor|change|build|generate|write|modify|code)\b/.test(combined);
48
+ const primary = normalized.architectureChange
49
+ || normalized.ambiguity
50
+ || PRIMARY_WORK_TYPES.has(normalized.workType)
51
+ || normalized.risks.some((risk) => PRIMARY_RISKS.has(risk))
52
+ || normalized.surfaces.some((surface) => PRIMARY_SURFACES.has(surface))
53
+ || /\b(architecture|architectural|security boundary|migration|ambiguous|unknown requirements)\b/.test(combined);
54
+
55
+ if (!generationRequired) {
56
+ reasons.push("NO_GENERATION_REQUIRED");
57
+ return { floor: "NONE", reasons };
58
+ }
59
+ reasons.push("GENERATION_REQUIRED");
60
+ if (primary) {
61
+ reasons.push("PRIMARY_COMPLEXITY_OR_RISK");
62
+ return { floor: "PRIMARY", reasons };
63
+ }
64
+ reasons.push("STANDARD_GENERATION_FLOOR");
65
+ return { floor: "STANDARD", reasons };
66
+ }
67
+
68
+ function normalizeRecommendation(recommendation) {
69
+ if (recommendation === null || recommendation === undefined) return null;
70
+ if (typeof recommendation === "string") {
71
+ return MODEL_ROUTE_TIERS.includes(recommendation) ? { tier: recommendation, confidence: null, requiresEscalation: false } : null;
72
+ }
73
+ if (!recommendation || typeof recommendation !== "object" || Array.isArray(recommendation)) return null;
74
+ const tier = typeof recommendation.tier === "string" && MODEL_ROUTE_TIERS.includes(recommendation.tier) ? recommendation.tier : null;
75
+ if (!tier) return null;
76
+ return {
77
+ tier,
78
+ confidence: typeof recommendation.confidence === "number" && Number.isFinite(recommendation.confidence) ? recommendation.confidence : null,
79
+ requiresEscalation: recommendation.requiresEscalation === true,
80
+ };
81
+ }
82
+
83
+ export function resolveModelRoute({ input = {}, semanticRecommendation = null } = {}) {
84
+ const deterministic = deterministicFloor(input);
85
+ const recommendation = normalizeRecommendation(semanticRecommendation);
86
+ let resolved = deterministic.floor;
87
+ const reasons = [...deterministic.reasons];
88
+ if (recommendation?.requiresEscalation) {
89
+ if (MODEL_ROUTE_RANK[resolved] < MODEL_ROUTE_RANK.PRIMARY) resolved = "PRIMARY";
90
+ reasons.push("JEV_LOW_CONFIDENCE_ESCALATION");
91
+ } else if (recommendation && MODEL_ROUTE_RANK[recommendation.tier] > MODEL_ROUTE_RANK[resolved]) {
92
+ resolved = recommendation.tier;
93
+ reasons.push("JEV_ESCALATION_ONLY");
94
+ }
95
+ return {
96
+ floor: deterministic.floor,
97
+ resolved,
98
+ reasons: [...new Set(reasons)],
99
+ semanticRecommendation: recommendation,
100
+ generationRequired: deterministic.floor !== "NONE",
101
+ };
102
+ }
103
+
@@ -0,0 +1,37 @@
1
+ import {
2
+ MODEL_ROUTE_JEV_MODEL,
3
+ MODEL_ROUTE_POLICY_VERSION,
4
+ MODEL_ROUTE_PROJECTION_AUTHORITY,
5
+ MODEL_ROUTE_PROJECTION_EVIDENCE_AUTHORITY,
6
+ MODEL_ROUTE_RANK,
7
+ MODEL_ROUTE_TIERS,
8
+ } from "./constants.js";
9
+ import { resolveModelRoute } from "./policy.js";
10
+
11
+ export function projectModelRoute({ input = {}, semanticRecommendation = null } = {}) {
12
+ const route = resolveModelRoute({ input, semanticRecommendation });
13
+ if (!MODEL_ROUTE_TIERS.includes(route.floor) || !MODEL_ROUTE_TIERS.includes(route.resolved)
14
+ || MODEL_ROUTE_RANK[route.resolved] < MODEL_ROUTE_RANK[route.floor]) {
15
+ const error = new Error("Model route violates its deterministic safety floor.");
16
+ error.code = "E_MODEL_ROUTE_SAFETY_FLOOR_INVALID";
17
+ throw error;
18
+ }
19
+ return {
20
+ schemaVersion: 1,
21
+ policyVersion: MODEL_ROUTE_POLICY_VERSION,
22
+ engine: "typesafe-jev",
23
+ model: MODEL_ROUTE_JEV_MODEL,
24
+ floor: route.floor,
25
+ resolved: route.resolved,
26
+ reasons: route.reasons,
27
+ generationRequired: route.generationRequired,
28
+ semanticRecommendation: route.semanticRecommendation,
29
+ authority: MODEL_ROUTE_PROJECTION_AUTHORITY,
30
+ evidenceAuthority: MODEL_ROUTE_PROJECTION_EVIDENCE_AUTHORITY,
31
+ lifecycleAuthority: false,
32
+ completionAuthority: false,
33
+ ownershipAuthority: false,
34
+ installationAuthority: false,
35
+ };
36
+ }
37
+
@@ -6,6 +6,7 @@ export const NEXT_ACTIONS = Object.freeze({
6
6
  CREATE_CONTRACT: "CREATE_CONTRACT",
7
7
  ROUTE: "ROUTE",
8
8
  SATISFY_GATES: "SATISFY_GATES",
9
+ REVALIDATE_GATES: "REVALIDATE_GATES",
9
10
  RUN_PREFLIGHT: "RUN_PREFLIGHT",
10
11
  PLAN: "PLAN",
11
12
  START_EXECUTION: "START_EXECUTION",
@@ -47,6 +48,9 @@ export const NEXT_ACTIONS = Object.freeze({
47
48
  RECOVER_TASK: "RECOVER_TASK",
48
49
  RESUME_RECOVERED_TASK: "RESUME_RECOVERED_TASK",
49
50
  RESOLVE_RECOVERY_INCONSISTENCY: "RESOLVE_RECOVERY_INCONSISTENCY",
51
+ REPAIR_CONTRACT_BOOTSTRAP: "REPAIR_CONTRACT_BOOTSTRAP",
52
+ MIGRATE_CONTRACT_BOOTSTRAP_REPAIR: "MIGRATE_CONTRACT_BOOTSTRAP_REPAIR",
53
+ REVALIDATE_CHECKPOINT: "REVALIDATE_CHECKPOINT",
50
54
  NONE: "NONE",
51
55
  });
52
56
 
@@ -60,6 +64,33 @@ export function directCommandSpec(commandId, taskId, requiredInputs = []) {
60
64
  };
61
65
  }
62
66
 
67
+ export function routeCommandSpec(taskId) {
68
+ return {
69
+ commandId: "route",
70
+ executable: "forgeloop",
71
+ subcommand: "route",
72
+ argv: ["route", `--task=${taskId}`, "--json"],
73
+ requiredInputs: [
74
+ { name: "workType", option: "--work=<type>" },
75
+ { name: "surface", option: "--surface=<value>", repeatable: true, optional: true },
76
+ { name: "risk", option: "--risk=<value>", repeatable: true, optional: true },
77
+ { name: "platform", option: "--platform=<value>", repeatable: true, optional: true },
78
+ ],
79
+ };
80
+ }
81
+
82
+ export function gateRevalidationCommandSpec(taskId, gate) {
83
+ return {
84
+ commandId: "gate-revalidate",
85
+ executable: "forgeloop",
86
+ subcommand: "gate-revalidate",
87
+ argv: ["gate-revalidate", `--task=${taskId}`, `--gate=${gate}`, "--acknowledge-stale", "--json"],
88
+ requiredInputs: [
89
+ { name: "acknowledgeStale", option: "--acknowledge-stale" },
90
+ ],
91
+ };
92
+ }
93
+
63
94
  export function recoveryGuidanceForClassification(classification, taskId) {
64
95
  if (classification === "RECOVERABLE") {
65
96
  return {
@@ -167,8 +198,35 @@ export function result({
167
198
  };
168
199
  }
169
200
 
201
+ export function contractBootstrapRepairGuidance(taskId, reason = null) {
202
+ const command = `forgeloop task-repair-contract-bootstrap --task ${taskId} --acknowledge-repair --json`;
203
+ return {
204
+ nextAction: NEXT_ACTIONS.REPAIR_CONTRACT_BOOTSTRAP,
205
+ commands: [command],
206
+ commandSpecs: [directCommandSpec("task-repair-contract-bootstrap", taskId, [
207
+ { name: "acknowledgeRepair", option: "--acknowledge-repair", description: "Explicit caller acknowledgement of the exact repair signature." },
208
+ ])],
209
+ reason: reason ?? { code: "E_CONTRACT_BOOTSTRAP_REPAIR_AVAILABLE", message: "The exact duplicate contract bootstrap defect is repairable through the official append-only command." },
210
+ };
211
+ }
212
+
213
+ export function contractBootstrapRepairMigrationGuidance(taskId, reason = null) {
214
+ const command = `forgeloop task-migrate-contract-bootstrap-repair --task ${taskId} --acknowledge-migration --json`;
215
+ return {
216
+ nextAction: NEXT_ACTIONS.MIGRATE_CONTRACT_BOOTSTRAP_REPAIR,
217
+ commands: [command],
218
+ commandSpecs: [directCommandSpec("task-migrate-contract-bootstrap-repair", taskId, [
219
+ { name: "acknowledgeMigration", option: "--acknowledge-migration", description: "Fresh explicit caller acknowledgement of the exact legacy marker migration." },
220
+ ])],
221
+ reason: reason ?? { code: "E_CONTRACT_BOOTSTRAP_REPAIR_MIGRATION_AVAILABLE", message: "The exact legacy contract bootstrap repair marker can be migrated through the official append-only command." },
222
+ };
223
+ }
224
+
170
225
  export function commandFor(action) {
171
226
  return {
227
+ [NEXT_ACTIONS.ROUTE]: "forgeloop route --task <id> --work <type> --json",
228
+ [NEXT_ACTIONS.RESOLVE_STALE_ROUTE]: "forgeloop route --task <id> --work <type> --json",
229
+ [NEXT_ACTIONS.REVALIDATE_GATES]: "forgeloop gate-revalidate --task <id> --gate <name> --acknowledge-stale --json",
172
230
  [NEXT_ACTIONS.PLAN]: "forgeloop advance --to PLANNED",
173
231
  [NEXT_ACTIONS.RUN_PREFLIGHT]: "forgeloop preflight --json",
174
232
  [NEXT_ACTIONS.START_EXECUTION]: "forgeloop advance --to EXECUTING",