loopforge 3.7.0 → 3.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +171 -157
  3. package/dist/audit.d.ts +53 -1
  4. package/dist/audit.d.ts.map +1 -1
  5. package/dist/audit.js +106 -22
  6. package/dist/audit.js.map +1 -1
  7. package/dist/canonical-state.d.ts +75 -69
  8. package/dist/canonical-state.d.ts.map +1 -1
  9. package/dist/canonical-state.js +276 -168
  10. package/dist/canonical-state.js.map +1 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +111 -12
  13. package/dist/cli.js.map +1 -1
  14. package/dist/cognitive-facts.d.ts +13 -0
  15. package/dist/cognitive-facts.d.ts.map +1 -1
  16. package/dist/cognitive-facts.js +30 -16
  17. package/dist/cognitive-facts.js.map +1 -1
  18. package/dist/cognitive-governance.d.ts +30 -6
  19. package/dist/cognitive-governance.d.ts.map +1 -1
  20. package/dist/cognitive-governance.js +74 -18
  21. package/dist/cognitive-governance.js.map +1 -1
  22. package/dist/committed-round.d.ts +109 -24
  23. package/dist/committed-round.d.ts.map +1 -1
  24. package/dist/committed-round.js +235 -52
  25. package/dist/committed-round.js.map +1 -1
  26. package/dist/contract-items.d.ts +55 -0
  27. package/dist/contract-items.d.ts.map +1 -0
  28. package/dist/contract-items.js +180 -0
  29. package/dist/contract-items.js.map +1 -0
  30. package/dist/enforcement-gate.d.ts +43 -20
  31. package/dist/enforcement-gate.d.ts.map +1 -1
  32. package/dist/enforcement-gate.js +269 -378
  33. package/dist/enforcement-gate.js.map +1 -1
  34. package/dist/engine.d.ts +11 -6
  35. package/dist/engine.d.ts.map +1 -1
  36. package/dist/engine.js +102 -67
  37. package/dist/engine.js.map +1 -1
  38. package/dist/evidence-claims.d.ts +4 -4
  39. package/dist/evidence-claims.d.ts.map +1 -1
  40. package/dist/evidence-claims.js +16 -14
  41. package/dist/evidence-claims.js.map +1 -1
  42. package/dist/evidence-provider.d.ts +91 -90
  43. package/dist/evidence-provider.d.ts.map +1 -1
  44. package/dist/evidence-provider.js +349 -160
  45. package/dist/evidence-provider.js.map +1 -1
  46. package/dist/explain.d.ts +76 -0
  47. package/dist/explain.d.ts.map +1 -0
  48. package/dist/explain.js +127 -0
  49. package/dist/explain.js.map +1 -0
  50. package/dist/generate-schema.js +250 -53
  51. package/dist/generate-schema.js.map +1 -1
  52. package/dist/index.d.ts +8 -7
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +7 -6
  55. package/dist/index.js.map +1 -1
  56. package/dist/loop-compiler.d.ts +41 -40
  57. package/dist/loop-compiler.d.ts.map +1 -1
  58. package/dist/loop-compiler.js +275 -515
  59. package/dist/loop-compiler.js.map +1 -1
  60. package/dist/loop-extras-parser.d.ts +0 -1
  61. package/dist/loop-extras-parser.d.ts.map +1 -1
  62. package/dist/loop-extras-parser.js +0 -4
  63. package/dist/loop-extras-parser.js.map +1 -1
  64. package/dist/loop-projection.d.ts.map +1 -1
  65. package/dist/loop-projection.js +3 -1
  66. package/dist/loop-projection.js.map +1 -1
  67. package/dist/mcp/round-lifecycle.d.ts +40 -21
  68. package/dist/mcp/round-lifecycle.d.ts.map +1 -1
  69. package/dist/mcp/round-lifecycle.js +173 -120
  70. package/dist/mcp/round-lifecycle.js.map +1 -1
  71. package/dist/mcp/server.d.ts.map +1 -1
  72. package/dist/mcp/server.js +63 -10
  73. package/dist/mcp/server.js.map +1 -1
  74. package/dist/mcp/session.d.ts +53 -7
  75. package/dist/mcp/session.d.ts.map +1 -1
  76. package/dist/mcp/session.js +240 -139
  77. package/dist/mcp/session.js.map +1 -1
  78. package/dist/mcp/submission-boundary.d.ts +89 -0
  79. package/dist/mcp/submission-boundary.d.ts.map +1 -0
  80. package/dist/mcp/submission-boundary.js +203 -0
  81. package/dist/mcp/submission-boundary.js.map +1 -0
  82. package/dist/mcp/tools.d.ts.map +1 -1
  83. package/dist/mcp/tools.js +377 -125
  84. package/dist/mcp/tools.js.map +1 -1
  85. package/dist/policy-metrics.js +2 -2
  86. package/dist/policy-metrics.js.map +1 -1
  87. package/dist/policy.d.ts +65 -95
  88. package/dist/policy.d.ts.map +1 -1
  89. package/dist/policy.js +151 -39
  90. package/dist/policy.js.map +1 -1
  91. package/dist/prompt-assembler.d.ts +7 -33
  92. package/dist/prompt-assembler.d.ts.map +1 -1
  93. package/dist/prompt-assembler.js +313 -473
  94. package/dist/prompt-assembler.js.map +1 -1
  95. package/dist/prompt-policy.d.ts +1 -4
  96. package/dist/prompt-policy.d.ts.map +1 -1
  97. package/dist/prompt-policy.js +6 -7
  98. package/dist/prompt-policy.js.map +1 -1
  99. package/dist/protocol.d.ts +411 -168
  100. package/dist/protocol.d.ts.map +1 -1
  101. package/dist/protocol.js +23 -69
  102. package/dist/protocol.js.map +1 -1
  103. package/dist/replay.js +2 -2
  104. package/dist/replay.js.map +1 -1
  105. package/dist/round-contract.d.ts +69 -57
  106. package/dist/round-contract.d.ts.map +1 -1
  107. package/dist/round-contract.js +104 -64
  108. package/dist/round-contract.js.map +1 -1
  109. package/dist/round-coordinator.d.ts +55 -16
  110. package/dist/round-coordinator.d.ts.map +1 -1
  111. package/dist/round-coordinator.js +179 -57
  112. package/dist/round-coordinator.js.map +1 -1
  113. package/dist/round-driver.d.ts +7 -5
  114. package/dist/round-driver.d.ts.map +1 -1
  115. package/dist/round-driver.js +2 -1
  116. package/dist/round-driver.js.map +1 -1
  117. package/dist/round-facts.d.ts +96 -0
  118. package/dist/round-facts.d.ts.map +1 -0
  119. package/dist/round-facts.js +216 -0
  120. package/dist/round-facts.js.map +1 -0
  121. package/dist/round-transaction.d.ts +23 -9
  122. package/dist/round-transaction.d.ts.map +1 -1
  123. package/dist/round-transaction.js +99 -22
  124. package/dist/round-transaction.js.map +1 -1
  125. package/dist/self-eval.d.ts +127 -11
  126. package/dist/self-eval.d.ts.map +1 -1
  127. package/dist/self-eval.js +517 -36
  128. package/dist/self-eval.js.map +1 -1
  129. package/dist/subgoal-state.d.ts +77 -0
  130. package/dist/subgoal-state.d.ts.map +1 -0
  131. package/dist/subgoal-state.js +198 -0
  132. package/dist/subgoal-state.js.map +1 -0
  133. package/dist/token-utils.d.ts +52 -19
  134. package/dist/token-utils.d.ts.map +1 -1
  135. package/dist/token-utils.js +83 -72
  136. package/dist/token-utils.js.map +1 -1
  137. package/dist/verification-gate.d.ts +27 -46
  138. package/dist/verification-gate.d.ts.map +1 -1
  139. package/dist/verification-gate.js +308 -557
  140. package/dist/verification-gate.js.map +1 -1
  141. package/dist/version.d.ts +5 -0
  142. package/dist/version.d.ts.map +1 -0
  143. package/dist/version.js +5 -0
  144. package/dist/version.js.map +1 -0
  145. package/dist/workspace.d.ts +9 -0
  146. package/dist/workspace.d.ts.map +1 -1
  147. package/dist/workspace.js +17 -0
  148. package/dist/workspace.js.map +1 -1
  149. package/loop_policy.json +17 -25
  150. package/package.json +7 -7
  151. package/skills/perception/SKILL.md +266 -64
@@ -9,7 +9,6 @@ export declare enum Mode {
9
9
  LOOP_COMPILE = "loop_compile",
10
10
  FEEDBACK = "feedback"
11
11
  }
12
- import type { PresentedStateSnapshot } from "./canonical-state.js";
13
12
  export declare enum AgentStatus {
14
13
  OK = "ok",
15
14
  ERROR = "error",
@@ -22,27 +21,6 @@ export interface ExecutionFeedback {
22
21
  manual_fixes_needed: string;
23
22
  }
24
23
  export declare function makeExecutionFeedback(overrides?: Partial<ExecutionFeedback>): ExecutionFeedback;
25
- /** P4: Structured execution evidence reported by the agent after each round.
26
- * Gives LoopForge visibility into what actually happened — files changed,
27
- * test results, success criteria met, and a subjective progress estimate.
28
- * Enables the compiler to cross-validate agent claims and compute real progress. */
29
- export interface ExecutionEvidence {
30
- /** Files changed in this round. Empty if no files were modified. */
31
- files_changed: string[];
32
- /** Test results. null if no tests were run. */
33
- test_results: {
34
- passed: number;
35
- failed: number;
36
- skipped: number;
37
- } | null;
38
- /** Success criteria from the Loop Objective that were MET this round. */
39
- success_criteria_met: string[];
40
- /** Success criteria from the Loop Objective that REMAIN unmet. */
41
- success_criteria_remaining: string[];
42
- /** Agent's own estimate of overall progress (0.0 to 1.0). */
43
- progress_estimate: number;
44
- }
45
- export declare function makeExecutionEvidence(overrides?: Partial<ExecutionEvidence>): ExecutionEvidence;
46
24
  /** P5: A revision to a success criterion — the old form and the new form.
47
25
  * The agent proposes this when it discovers the original criterion was
48
26
  * wrong, unrealistic, or needs refinement. */
@@ -50,43 +28,6 @@ export interface CriterionRevision {
50
28
  old: string;
51
29
  new: string;
52
30
  }
53
- /** v3.3: Round Contract. v3.4 semantics: the field on a submission is a
54
- * PROPOSAL for the NEXT round — it becomes the ACTIVE contract (rendered
55
- * as the Current Task and checked for execution conformance) only after
56
- * the declaring round commits, and stays active until a committed eval
57
- * lists every done_when item in success_criteria_met (complete) or
58
- * reports outcome="blocked". While active it is restated unchanged each
59
- * round; on completion or block, the next contract is declared instead.
60
- * The ACTIVE contract is machine-derived from committed rounds
61
- * (round-contract.ts) — never read from last_round_result. Optional:
62
- * absent = no contract this round, all contract checks stay silent and
63
- * rendering is identical to a contract-less round.
64
- *
65
- * Every field is machine-checkable:
66
- * - done_when items are claimed satisfied by listing them in
67
- * execution_evidence.success_criteria_met (verified per-round claim
68
- * model); leaving them out while success is claimed is premature_boundary
69
- * against the ACTIVE contract.
70
- * - verification_plan names must reference configured, enabled
71
- * evidence.commands (round_unverifiable otherwise).
72
- * - scope lists the files/directories the round may touch; actual git
73
- * changes outside it trigger round_scope_drift against the ACTIVE
74
- * contract. */
75
- export interface RoundContract {
76
- /** Round focus, one line. Rendered as the Current Task's first line. */
77
- work_item?: string;
78
- /** Completion conditions: cr-XXXXXXXX criterion IDs or free text.
79
- * Claimed met = listed in success_criteria_met; still open = listed in
80
- * success_criteria_remaining. ≤ 20 items. */
81
- done_when: string[];
82
- /** Verification plan: names of configured, enabled evidence commands
83
- * (policy.evidence.commands[].name). ≤ 20 items. */
84
- verification_plan: string[];
85
- /** Files/directories this round may touch (workspace-relative paths,
86
- * forward or back slashes, "./" prefix and trailing slashes accepted).
87
- * Out-of-scope git changes = round_scope_drift. ≤ 50 items. */
88
- scope: string[];
89
- }
90
31
  /** Structured self-evaluation submitted at the round boundary.
91
32
  * The agent outputs this after completing each round.
92
33
  * Every field is consumed by at least one downstream function.
@@ -101,8 +42,8 @@ export interface SelfEvaluation {
101
42
  * computeConstraintRetirement (activity detection), vault lineage. */
102
43
  output_summary: string;
103
44
  /** Constraints the agent actually violated this round.
104
- * Feeds: checkLoopHealth (constraint_integrity),
105
- * buildRollingSummary (recurring_issues), computeConstraintRetirement. */
45
+ * Feeds: deriveRecurringFlags (the constraint_violation kind) and
46
+ * computeConstraintRetirement. */
106
47
  constraint_violations: string[];
107
48
  /** false ONLY when the entire task is complete. Tells the autonomous
108
49
  * runner to stop the loop. Not consumed by the compiler. */
@@ -117,12 +58,22 @@ export interface SelfEvaluation {
117
58
  objective_refinement?: string;
118
59
  /** P2: Sub-problems that surfaced during execution and may need
119
60
  * separate attention. Feed into the next-task suggestion.
120
- * Omit or leave empty if none emerged. */
61
+ * Omit or leave empty if none emerged.
62
+ * v3.7.1: this is the ONLY creation channel. A text matching the
63
+ * sg-XXXXXXXX ID pattern is rejected — creation never accepts an
64
+ * ID reference (that would fabricate a phantom hashed item). */
121
65
  emerged_subtasks?: string[];
66
+ /** v3.7.1: Explicit status transitions for EXISTING sub-goals. Each
67
+ * entry must reference a committed sub-goal ID (sg-XXXXXXXX) and a
68
+ * legal target status; unknown IDs, terminal (done/canceled)
69
+ * references, and illegal migrations are evaluation_invalid before
70
+ * the round advances. in_progress is only reachable through this
71
+ * field — the runtime no longer infers it. */
72
+ subgoal_updates?: SubGoalUpdate[];
122
73
  /** P4: Structured evidence of what was executed this round.
123
74
  * Files changed, test results, criteria met/remaining, progress estimate.
124
75
  * Enables the compiler to validate claims and compute real progress. */
125
- execution_evidence?: ExecutionEvidence;
76
+ execution_report?: ExecutionReport;
126
77
  /** P5: Constraints that the agent now believes are wrong or irrelevant.
127
78
  * Removed from the active constraint set by the compiler.
128
79
  * Omit or leave empty if none. */
@@ -146,28 +97,12 @@ export interface SelfEvaluation {
146
97
  * The engine automatically writes these to the delegation journal.
147
98
  * Omit or leave empty if no delegations occurred. */
148
99
  worker_results?: WorkerResult[];
149
- /** v1.16: Agent's declared next action — what it plans to do in the
150
- * following round. Stored as loop state and rendered in the next prompt
151
- * so the agent's self-planning persists across rounds. Optional —
152
- * no next_action means the compiler generates the next task as before. */
153
- next_action?: string;
154
- /** v2.2: Sub-tasks the agent completed this round. Each entry may be a
155
- * sub-goal ID (e.g. "sg-a3f2b1c0" from the Sub-Goal Dashboard) for
156
- * exact matching, or a natural-language description for Jaccard
157
- * similarity fallback. Omit if none. */
158
- completed_subtasks?: string[];
159
- /** v2.2: Sub-tasks that are now blocked (cannot proceed). Same ID-or-
160
- * description matching as completed_subtasks. Omit if none. */
161
- blocked_subtasks?: string[];
162
- /** v2.2: Sub-tasks the agent is canceling (no longer needed). Same ID-or-
163
- * description matching as completed_subtasks. Omit if none. */
164
- canceled_subtasks?: string[];
165
100
  /** v2.5: Why the agent is stopping. Only meaningful when
166
101
  * should_continue=false and success=false. Defaults to "gave_up"
167
102
  * (current behavior) when absent. "blocked" means work cannot proceed
168
103
  * under current constraints; "needs_human_input" requires intervention. */
169
104
  stop_reason?: "gave_up" | "blocked" | "needs_human_input";
170
- /** v2.12: Declared tri-state outcome. When absent, derived from success
105
+ /** v2.12: Declared outcome (four values). When absent, derived from success
171
106
  * (true → "success", false → "failed"). "partial" and "blocked" can only
172
107
  * be declared explicitly. A declared non-success outcome suppresses the
173
108
  * success-class verification checks even when success=true. */
@@ -187,13 +122,14 @@ export interface SelfEvaluation {
187
122
  * Downgrades the success_without_verified_evidence check from error to
188
123
  * info. Flat string, ≤ 200 chars. */
189
124
  no_change_reason?: string;
190
- /** v2.8: When the previous round's verification flagged intent_drift or
191
- * subgoal_drift, the agent explains why its actions diverged from its
192
- * stated plan. Populated from the self-eval block when the prompt
193
- * injected the field. Empty or absent when no drift was flagged.
194
- * Used by the enforcement gate R7 to distinguish intentional pivots
195
- * from unacknowledged drift. */
196
- drift_clarification?: string;
125
+ /** v3.7.1: gate_opened ids this round's work depended on (returned by
126
+ * loopforge_gate_check). Lenient format — non-string entries are
127
+ * ignored, ≤ 20 entries. Enforced ONLY when policy.gate.enabled: a
128
+ * cited gate that does not exist, is not a user gate, or has no
129
+ * approved gate_decision produces the user_gate_unresolved error and
130
+ * the round is rejected. Safe pre-work (investigation, dry-runs,
131
+ * rollback evidence) never needs a gate. */
132
+ gate_ids?: string[];
197
133
  /** Model's information needs for the next round's prompt.
198
134
  * Consumed by the Compiler — not durable across rounds. */
199
135
  prompt_requests?: PromptRequests;
@@ -202,7 +138,7 @@ export interface SelfEvaluation {
202
138
  * it completes or blocks). Becomes the ACTIVE contract only once this
203
139
  * round commits; it is then derived at compile time from committed
204
140
  * rounds — see round-contract.ts. Optional. */
205
- round_contract?: RoundContract;
141
+ round_contract?: RoundContractProposal;
206
142
  }
207
143
  /** v2.12: Tri-state round outcome. Declared via SelfEvaluation.outcome;
208
144
  * derived from `success` when absent. Shared by the dual gates, the stop
@@ -218,13 +154,15 @@ export interface LoopProjection {
218
154
  what: string;
219
155
  since_round: number;
220
156
  } | null;
221
- /** Suggested next steps: agent-declared intent vs compiler-derived
222
- * pending/blocked sub-goals. Non-authoritative. */
157
+ /** Suggested next steps, derived from the active contract, sub-goals, and
158
+ * open gates/recovery requirements. Non-authoritative. v3.8: the
159
+ * `agent_intent` source was deleted with `next_action` — the agent's own
160
+ * plan is no longer a projection input. */
223
161
  todo: Array<{
224
162
  id: string;
225
163
  item: string;
226
164
  reason: string;
227
- source: "derived" | "agent_intent";
165
+ source: "derived";
228
166
  priority: number;
229
167
  }>;
230
168
  /** Phase boundaries from milestone history. */
@@ -254,6 +192,12 @@ export interface LoopProjection {
254
192
  verified: string[];
255
193
  open_risks: string[];
256
194
  };
195
+ /** v3.8: Sub-goals a machine-verified contract item backs. The machine's
196
+ * separate statement about a `done` sub-goal — it never rewrites
197
+ * `SubGoal.status`. Derived in cognitive-facts.ts, exposed here so the
198
+ * projection carries the same verification view the prompt and state file
199
+ * do. */
200
+ verified_subgoals: VerifiedSubGoalFact[];
257
201
  }
258
202
  export declare function makeLoopProjection(overrides?: Partial<LoopProjection>): LoopProjection;
259
203
  /** v2.12: Structured high-risk action descriptor (internal — audit display
@@ -294,11 +238,11 @@ export declare function makeGateDecision(overrides?: Partial<GateDecision>): Gat
294
238
  * Compiler when assembling the next prompt. Transient — each round's
295
239
  * requests apply to that round only. */
296
240
  export interface PromptRequests {
297
- /** Items to emphasize. Matched against active state via Jaccard
298
- * similarity. Matching items are pulled into a "Critical Context"
299
- * section rendered before optional sections. No content is added —
300
- * only reordered. Max entries: policy-driven (L2: 5, L1: 3).
301
- * L0: ignored. */
241
+ /** Items to emphasize. Matched against active state by stable id or
242
+ * normalized-exact text (v3.8.1 — the Jaccard arm is gone). Matching items
243
+ * are pulled into a "Critical Context" section rendered before optional
244
+ * sections. No content is added — only reordered. An unmatched entry is
245
+ * dropped. Max entries: policy-driven (L2: 5, L1: 3). L0: ignored. */
302
246
  emphasize?: string[];
303
247
  /** Things the model is confused about. Rendered at the prompt top
304
248
  * as "Confusion Alerts" before the Objective section. Compiler
@@ -310,7 +254,7 @@ export interface PromptRequests {
310
254
  * rolling-window eviction. Triggered by three signals in priority order:
311
255
  *
312
256
  * 1. agent_declared — compression_checkpoint === true (agent marks phase complete)
313
- * 2. criteria_milestone — new success_criteria_met detected (semantic dedup)
257
+ * 2. criteria_milestone — a new met criterion_claim detected (semantic dedup)
314
258
  * 3. auto — safety net after N rounds without a milestone
315
259
  *
316
260
  * Built from raw round data in vault entries — no new persistent storage.
@@ -340,16 +284,18 @@ export interface MilestoneSummary {
340
284
  generated_at_round: number;
341
285
  }
342
286
  export declare function makeMilestoneSummary(overrides?: Partial<MilestoneSummary>): MilestoneSummary;
343
- /** A single sub-agent / Worker delegation result (v1.9 — multi-agent). */
287
+ /** A single sub-agent / Worker delegation result (v1.9 — multi-agent).
288
+ * v3.7.1: `outcome` is the single reported fact. `success` is deleted —
289
+ * entries without a valid outcome are dropped by the parser, never
290
+ * derived. The whole array is optional and informational: it buys no
291
+ * machine verdict and an absent/empty array (no delegation this round)
292
+ * is always accepted. */
344
293
  export interface WorkerResult {
345
294
  agentId: string;
346
- subAgentType: string;
295
+ subAgentType?: string;
347
296
  subTask: string;
348
297
  resultSummary: string;
349
- success: boolean;
350
- /** v2.12: Declared worker outcome. When absent, derived from success
351
- * (true → "success", false → "failed"). "partial" is explicit only. */
352
- outcome?: "success" | "partial" | "failed";
298
+ outcome: "success" | "partial" | "failed";
353
299
  discoveredConstraints?: string[];
354
300
  }
355
301
  export declare function makeSelfEvaluation(overrides?: Partial<SelfEvaluation>): SelfEvaluation;
@@ -376,17 +322,23 @@ export interface LoopObjective {
376
322
  refinement_history?: string[];
377
323
  }
378
324
  /** v3.2: Derived per-criterion status for the progress dashboard — the
379
- * "goal → criteria → evidence" vertical view. Zero persistence: derived from
380
- * vault entries each round (met/remaining reports + Jaccard sub-goal links). */
325
+ * "goal → criteria → evidence" vertical view. Zero persistence: derived
326
+ * from committed rounds each round.
327
+ *
328
+ * v3.8 states: `claimed` (the agent claims it met), `remaining` (declared
329
+ * outstanding), `verified` (a verified contract item references it),
330
+ * `contradicted` / `insufficient` (machine evidence denies / cannot back
331
+ * the claim), `unknown` (never mentioned). */
381
332
  export interface CriterionStatus {
382
333
  /** Stable ID derived from the criterion text (cr-XXXXXXXX). */
383
334
  id: string;
384
335
  /** The criterion text as declared in the objective. */
385
336
  text: string;
386
- status: "met" | "remaining" | "unknown";
337
+ status: "unknown" | "claimed" | "remaining" | "insufficient" | "contradicted" | "verified";
387
338
  /** Round when the criterion was first reported met (machine-backed). */
388
339
  met_at_round?: number;
389
- /** Sub-goals whose description matches this criterion (Jaccard). */
340
+ /** Sub-goals an item referencing this criterion also names, via explicit
341
+ * `subgoal_refs` (v3.8.1 — never a text-similarity guess). */
390
342
  related_subgoal_ids: string[];
391
343
  }
392
344
  /** v3.2: A deterministic "lesson learned" — a constraint or verification
@@ -394,30 +346,32 @@ export interface CriterionStatus {
394
346
  * immunize the agent against repeating the same mistakes. Zero persistence:
395
347
  * derived from vault entries each round; presentation only — never feeds
396
348
  * the enforcement gate's decisions. */
397
- export interface Lesson {
398
- /** Constraint text or verification check name. */
399
- text: string;
349
+ /** v3.8.1: a repeated machine fact, keyed by what it is ABOUT.
350
+ *
351
+ * One derivation over the whole committed history replaces the three
352
+ * separate views of "what keeps going wrong" this release removed:
353
+ * `Lesson` (whole history, count >= 2), `rolling_summary.recurring_issues`
354
+ * (the last 5 rounds' raw violation texts, no threshold at all despite the
355
+ * name), and the L1/L2 prompt sections built on top of each. Callers FILTER
356
+ * this list — the state file renders the genuinely recurring set, the prompt
357
+ * renders the recent tail. */
358
+ export interface RecurringFlag {
359
+ /** Constraint text (for a violation) or the verification check id. */
360
+ subject: string;
400
361
  kind: "constraint_violation" | "verification_error" | "verification_warning";
401
- /** How many rounds this lesson occurred in. */
362
+ /** `VerificationFlag.ref` — the command id, `rci-`/`sg-`/`cr-` id or path
363
+ * the flag was about. Empty when the check recorded no subject. */
364
+ ref: string;
365
+ /** Occurrences across the whole committed history. */
402
366
  count: number;
403
- /** The rounds it occurred in, ascending. */
367
+ /** The distinct rounds it occurred in, ascending. */
404
368
  rounds: number[];
405
369
  }
406
370
  export declare function makeLoopObjective(overrides?: Partial<LoopObjective>): LoopObjective;
407
- export interface LoopHealth {
408
- goal_alignment: number;
409
- constraint_integrity: number;
410
- drift_detected: boolean;
411
- strategy_stability: boolean;
412
- task_continuity: number;
413
- escalation_recommended: string;
414
- }
415
- export declare function makeLoopHealth(overrides?: Partial<LoopHealth>): LoopHealth;
416
371
  export interface RollingSummary {
417
372
  /** v1.12: Unified key outcomes — merged from what_worked + key_lessons.
418
373
  * Format: "[R{round}] ✓/✗ ({technique}): {summary}" */
419
374
  key_outcomes: string[];
420
- recurring_issues: string[];
421
375
  rounds_sampled: number;
422
376
  generated_at_round: number;
423
377
  /** v1.7: Detected failure patterns — repeated failed rounds with
@@ -431,14 +385,28 @@ export interface RollingSummary {
431
385
  milestones?: MilestoneSummary[];
432
386
  }
433
387
  export declare function makeRollingSummary(overrides?: Partial<RollingSummary>): RollingSummary;
388
+ /** v3.7.1: One explicit sub-goal status transition. The closed migration
389
+ * matrix (loop-compiler.ts, single source) governs legality:
390
+ * in_progress from pending|blocked; done from pending|in_progress|blocked;
391
+ * blocked|canceled from pending|in_progress; blocked → canceled. done and
392
+ * canceled are terminal — re-opening requires a NEW emerged_subtasks item. */
393
+ export interface SubGoalUpdate {
394
+ /** The sub-goal to transition (sg-XXXXXXXX). Unknown IDs are invalid. */
395
+ id: string;
396
+ status: "in_progress" | "done" | "blocked" | "canceled";
397
+ /** Optional free-text note (≤ 300 chars). Lenient — never validated. */
398
+ note?: string;
399
+ }
434
400
  /** v2.2: A structured sub-goal tracked by the compiler across rounds.
435
- * Declared by the agent via emerged_subtasks (string[]), managed by
436
- * the compiler with derived status. Never creates sub-loops — the
437
- * agent still owns execution; the compiler only tracks state. */
401
+ * Declared by the agent via emerged_subtasks (creation) and
402
+ * subgoal_updates (explicit transitions); statuses are compiler-derived
403
+ * from committed round facts. Never creates sub-loops — the agent still
404
+ * owns execution; the compiler only tracks state. */
438
405
  export interface SubGoal {
439
406
  /** Stable identifier derived from description hash (sg-XXXXXXXX). */
440
407
  id: string;
441
- /** Agent-declared description, deduplicated by similarity. */
408
+ /** Agent-declared description. Exact repeats within one declaration round
409
+ * keep only the first entry (v3.8.1 — no similarity dedup). */
442
410
  description: string;
443
411
  /** Compiler-derived status. */
444
412
  status: "pending" | "in_progress" | "done" | "blocked" | "canceled";
@@ -450,6 +418,9 @@ export interface SubGoal {
450
418
  completed_at_round?: number;
451
419
  /** Priority hint: 0 = highest. Derived from declaration order. */
452
420
  priority: number;
421
+ /** v3.8: The agent's note from the transition that set the current status.
422
+ * Lenient — it never affects validation, only what the agent reads back. */
423
+ status_note?: string;
453
424
  }
454
425
  export declare function makeSubGoal(overrides?: Partial<SubGoal>): SubGoal;
455
426
  /** v2.3: Per-constraint lifecycle metadata for the active constraint set.
@@ -458,8 +429,9 @@ export declare function makeSubGoal(overrides?: Partial<SubGoal>): SubGoal;
458
429
  * was removed — active constraints never auto-demote. */
459
430
  export interface ConstraintMeta {
460
431
  /** v2.11: Stable identifier derived from text hash (c-XXXXXXXX).
461
- * Enables exact ID-first matching by the agent and compiler.
462
- * Eliminates Jaccard false positives/negatives. */
432
+ * The only name an agent can use to refer to this constraint — v3.8.1
433
+ * deleted every similarity fallback, so stable ids and normalized-exact
434
+ * text are the whole matching surface. */
463
435
  id: string;
464
436
  /** Normalized constraint text (the key). */
465
437
  text: string;
@@ -470,13 +442,6 @@ export interface ConstraintMeta {
470
442
  source: "hard" | "plan" | "criteria" | "discovered";
471
443
  }
472
444
  export declare function makeConstraintMeta(overrides?: Partial<ConstraintMeta>): ConstraintMeta;
473
- export interface TaskAlignment {
474
- is_aligned: boolean;
475
- alignment_score: number;
476
- warning: string;
477
- escalation: string;
478
- }
479
- export declare function makeTaskAlignment(overrides?: Partial<TaskAlignment>): TaskAlignment;
480
445
  export interface LoopRoundResult {
481
446
  round: number;
482
447
  success: boolean;
@@ -489,8 +454,11 @@ export interface LoopRoundResult {
489
454
  objective_refinement?: string;
490
455
  /** P2: Sub-problems that emerged during this round. */
491
456
  emerged_subtasks?: string[];
457
+ /** v3.7.1: Explicit sub-goal transitions declared this round.
458
+ * Set from SelfEvaluation.subgoal_updates during buildLoopRequest. */
459
+ subgoal_updates?: SubGoalUpdate[];
492
460
  /** P4: Execution evidence from this round. */
493
- execution_evidence?: ExecutionEvidence;
461
+ execution_report?: ExecutionReport;
494
462
  /** P5: Constraints retracted this round. */
495
463
  retracted_constraints?: string[];
496
464
  /** P5: Success criteria revised this round. */
@@ -504,21 +472,10 @@ export interface LoopRoundResult {
504
472
  compression_checkpoint?: boolean;
505
473
  /** v1.10: Human-readable label for the checkpoint. */
506
474
  checkpoint_label?: string;
507
- /** v1.16: Agent's declared next action for the following round. */
508
- next_action?: string;
509
- /** v2.2: Sub-tasks completed this round. */
510
- completed_subtasks?: string[];
511
- /** v2.2: Sub-tasks blocked this round. */
512
- blocked_subtasks?: string[];
513
- /** v2.2: Sub-tasks canceled this round. */
514
- canceled_subtasks?: string[];
515
- /** v2.8: Agent's explanation for intent/subgoal drift detected in
516
- * the previous round. Carried forward from SelfEvaluation. */
517
- drift_clarification?: string;
518
475
  /** Model's information needs for the next round's prompt.
519
476
  * Carried forward from SelfEvaluation. Consumed by the Compiler. */
520
477
  prompt_requests?: PromptRequests;
521
- /** v2.12: Declared tri-state outcome. Carried forward from SelfEvaluation. */
478
+ /** v2.12: Declared outcome. Carried forward from SelfEvaluation. */
522
479
  outcome?: RoundOutcome;
523
480
  /** v2.12: Flat blocker description (outcome==="blocked" only). */
524
481
  blocker?: string;
@@ -546,7 +503,6 @@ export interface LoopCompileRequest {
546
503
  new_since_last_round: string;
547
504
  last_round_result: LoopRoundResult | null;
548
505
  force_level: string;
549
- health_check_interval: number;
550
506
  /** Optional context supplied explicitly by the embedding Agent. */
551
507
  external_context?: string;
552
508
  /** Maximum rounds for this loop. Used by the state file header to show
@@ -566,18 +522,40 @@ export interface LoopCompileRequest {
566
522
  }
567
523
  export declare function makeLoopCompileRequest(overrides?: Partial<LoopCompileRequest>): LoopCompileRequest;
568
524
  /** Immutable record of the exact prompt delivered for one round attempt. */
525
+ /** v3.8.1: the artifact schema version, next to the type it versions. The
526
+ * transaction envelope parser reads it, so the constant lives here rather
527
+ * than in the renderer. */
528
+ export declare const PROMPT_ARTIFACT_SCHEMA_VERSION: 2;
569
529
  export interface PromptArtifact {
570
- schemaVersion: 1;
530
+ /** v3.8.1: schema 2. Version 1 is a HARD break — a round whose artifact
531
+ * does not parse is not committed history, and `legacyTransactionRounds`
532
+ * reports the loss rather than letting it vanish. */
533
+ schemaVersion: typeof PROMPT_ARTIFACT_SCHEMA_VERSION;
534
+ /** Round identity: `loop:<loopId>:round:<n>`. */
571
535
  roundId: string;
536
+ /** The round number on its own, so a reader does not re-parse roundId. */
537
+ round: number;
572
538
  attempt: number;
573
539
  level: "l0" | "l1" | "l2";
574
540
  renderedPrompt: string;
575
541
  promptHash: string;
576
542
  stateHash: string;
577
- /** v3.2: What the rendered prompt actually presented (L1 only). Persisted
578
- * on the lineage entry as the diff baseline for L1 collapse. Absent for
579
- * L0/L2 compiles. */
580
- presentedState?: PresentedStateSnapshot;
543
+ /** Section ids actually rendered, in render order. */
544
+ sections: string[];
545
+ /** Section ids the deterministic budget rule dropped. */
546
+ droppedSections: string[];
547
+ /** True when the PROTECTED sections alone exceeded the budget. Recorded so
548
+ * an over-budget prompt is visible rather than silently over-long. */
549
+ protectedOverflow: boolean;
550
+ /** The ceiling this render was measured against: the level's configured
551
+ * budget (`lN_max_chars`) minus the fixed footer, which is appended after
552
+ * budgeting because it is never dropped. Measured over the SAME region as
553
+ * `renderedChars`. */
554
+ budget: number;
555
+ /** Characters the budgeted region produced: the fixed header, the confusion
556
+ * alerts and the rendered sections — everything except the footer. NOT the
557
+ * full prompt length; `renderedPrompt` adds the footer on top. */
558
+ renderedChars: number;
581
559
  }
582
560
  export interface LoopCompileResponse {
583
561
  status: AgentStatus;
@@ -592,8 +570,6 @@ export interface LoopCompileResponse {
592
570
  goal_id: string;
593
571
  goal_text_hash: string;
594
572
  loop_objective: LoopObjective | null;
595
- loop_health: LoopHealth | null;
596
- task_alignment: TaskAlignment | null;
597
573
  rolling_summary: RollingSummary | null;
598
574
  /** v2.2: Structured sub-goals tracked across rounds. Compiler-managed
599
575
  * lifecycle with derived status. Rendered as Sub-Goal Dashboard. */
@@ -602,17 +578,16 @@ export interface LoopCompileResponse {
602
578
  constraint_metadata?: ConstraintMeta[];
603
579
  /** v2.5: Current round's agent trust score [0, 1]. Derived from verification
604
580
  * flags: -0.15 per error, -0.03 per warn. Always 1.0 for round 1. */
605
- agent_trust_score?: number;
606
581
  /** v2.5: Trust scores from the last 10 rounds, newest last. Empty for
607
582
  * round 1. Reconstructed from vault entries — zero new persistence. */
608
- agent_trust_trend?: number[];
609
583
  /** v3.2: Derived per-criterion status (goal → criteria → evidence view).
610
584
  * Zero persistence — re-derived from vault entries each round. */
611
585
  criterion_statuses?: CriterionStatus[];
612
- /** v3.2: Deterministic lessons learned (repeated violations / repeated
613
- * verification failures). Presentation only — never feeds enforcement. */
614
- lessons?: Lesson[];
615
- suggested_next_task: string;
586
+ /** v3.8.1: repeated machine facts over the whole committed history, keyed
587
+ * by check id / constraint text and the id they were about. Presentation
588
+ * only — never feeds enforcement. Replaces the former Lessons list; callers
589
+ * filter it (state file: count >= 2, prompt: recent tail). */
590
+ recurring_flags?: RecurringFlag[];
616
591
  plan_source: string | null;
617
592
  warnings: string[];
618
593
  error: string;
@@ -657,7 +632,6 @@ export interface LoopForgeResponse {
657
632
  rolling_summary?: RollingSummary | null;
658
633
  sub_goals?: SubGoal[];
659
634
  criterion_statuses?: CriterionStatus[];
660
- suggested_next_task?: string;
661
635
  }
662
636
  export interface SessionState {
663
637
  task_id: string;
@@ -675,7 +649,11 @@ export interface AgentLoopResult {
675
649
  * `cancelled` is manual stop via loopforge_stop. */
676
650
  export type StopReason = "completed" | "failed" | "blocked" | "cancelled" | "max_rounds" | "stalled" | "enforcement_terminated"
677
651
  /** Loop was paused by user or signal. */
678
- | "paused";
652
+ | "paused"
653
+ /** v3.8: The agent stopped, but machine verification did not close the
654
+ * active contract (or the observations are insufficient to prove the task
655
+ * complete). Never reported as `completed`. */
656
+ | "incomplete";
679
657
  /** Result of round-boundary enforcement. Decides whether to accept the round,
680
658
  * reject it (force the agent to redo the SAME round), or terminate the loop.
681
659
  *
@@ -696,10 +674,10 @@ export interface EnforcementResult {
696
674
  * Used by callers to track consecutive rejections per-rule
697
675
  * so unrelated rejections don't accumulate toward the max. */
698
676
  check?: string;
699
- /** v2.12: True when the enforcement gate accepted the round via
700
- * drift_clarification waiver (R7). The caller uses this to track
701
- * clarification streaks independently of rejection streaks. */
702
- clarification_accepted?: boolean;
677
+ /** v3.8: The stop reason a `terminate` decision must map to. Absent means
678
+ * the historical `enforcement_terminated`; `incomplete` is set by the
679
+ * verification-debt row. */
680
+ stopReason?: StopReason;
703
681
  }
704
682
  export declare function makeEnforcementResult(overrides?: Partial<EnforcementResult>): EnforcementResult;
705
683
  /** Context supplied to an embedding-owned provider before compilation. */
@@ -734,6 +712,12 @@ export interface VerificationFlag {
734
712
  check: string;
735
713
  /** Human-readable description of the inconsistency found. */
736
714
  detail: string;
715
+ /** v3.8.1: the id this flag is ABOUT — a configured command id, an
716
+ * `rci-` / `sg-` / `cr-` id, or a workspace path. Optional: only checks with
717
+ * a concrete subject set it. Recurring-warning grouping keys on
718
+ * `(check, ref)` so it reports WHICH item keeps failing rather than
719
+ * re-parsing `detail` prose. */
720
+ ref?: string;
737
721
  }
738
722
  export declare function makeVerificationFlag(overrides?: Partial<VerificationFlag>): VerificationFlag;
739
723
  /** Result of cross-round self-evaluation verification.
@@ -748,7 +732,266 @@ export declare function makeVerificationFlag(overrides?: Partial<VerificationFla
748
732
  export interface VerificationResult {
749
733
  verdict: "trusted" | "suspect" | "contradicted";
750
734
  flags: VerificationFlag[];
735
+ /** v3.8.1: the round's success claim is MACHINE-backed — a passed
736
+ * after-phase command observed by the runtime (`deriveEvidenceStatus`).
737
+ * Carried as a fact so a consumer never re-derives it; the progress
738
+ * evaluator reads it as "this round is finishing, not churning". */
739
+ machineBackedSuccess: boolean;
751
740
  }
752
741
  export declare function makeVerificationResult(overrides?: Partial<VerificationResult>): VerificationResult;
742
+ /** v3.8: The agent's self-report for a round — renamed from ExecutionReport
743
+ * because these fields are claims, not evidence. The whole object is
744
+ * optional; a mistyped optional field is dropped with a warning and never
745
+ * rejects the round. */
746
+ export interface ExecutionReport {
747
+ /** Files the agent says it changed. Informational — compared against the
748
+ * git observation, never trusted as the observation. */
749
+ files_changed?: string[];
750
+ /** Test counts the agent reports. Informational. */
751
+ tests_reported?: {
752
+ passed: number;
753
+ failed: number;
754
+ skipped: number;
755
+ } | null;
756
+ /** Advisory claims about objective criteria. LENIENT: unknown/duplicate
757
+ * criterion ids and malformed outcomes are dropped with a warning. */
758
+ criterion_claims?: CriterionClaim[];
759
+ /** Claims about ACTIVE contract items. STRICT: an unknown/duplicate item id
760
+ * or an illegal outcome is a structural defect (contract_invalid). */
761
+ contract_item_claims?: ContractItemClaim[];
762
+ /** The agent's own progress estimate (0.0–1.0). Informational. */
763
+ progress_estimate?: number;
764
+ }
765
+ export declare function makeExecutionReport(overrides?: Partial<ExecutionReport>): ExecutionReport;
766
+ /** v3.8: An advisory claim about an objective criterion. Lenient by design —
767
+ * the criterion layer is advisory; the contract item layer is the machine
768
+ * verification skeleton. */
769
+ export interface CriterionClaim {
770
+ /** cr-XXXXXXXX (or the criterion text for plain-text matching). */
771
+ criterion_id: string;
772
+ outcome: "met" | "remaining";
773
+ }
774
+ /** v3.8: A claim about an ACTIVE contract item, cited by the derived
775
+ * rci-XXXXXXXX id the prompt rendered. */
776
+ export interface ContractItemClaim {
777
+ item_id: string;
778
+ outcome: "met" | "remaining";
779
+ }
780
+ /** v3.8: One declared contract item. `verify_with` must name configured,
781
+ * enabled, after-capable evidence commands — the declaration is strict.
782
+ *
783
+ * `subgoal_refs` lives HERE, not on the contract: a machine-verified item
784
+ * backs exactly the sub-goals it names, so "item A verifies SubGoal 1, item B
785
+ * verifies SubGoal 2" is expressible and `VerifiedSubGoalFact` attribution is
786
+ * per-item instead of "every verified item backs every sub-goal". */
787
+ export interface ContractItemProposal {
788
+ description: string;
789
+ /** cr-XXXXXXXX criterion ids this item is evidence for (or free text). */
790
+ criterion_refs: string[];
791
+ /** sg-XXXXXXXX sub-goals this item is evidence for. */
792
+ subgoal_refs: string[];
793
+ /** Evidence command ids (policy.evidence.commands[].name). */
794
+ verify_with: string[];
795
+ }
796
+ /** v3.8: A Round Contract proposal for the NEXT round. It becomes ACTIVE only
797
+ * after the declaring round commits. Identity (rc-/rci-) is derived from
798
+ * CONTENT ONLY — restating an unchanged contract keeps the same identity,
799
+ * unlike a SubGoal whose id includes its declaration round. */
800
+ export interface RoundContractProposal {
801
+ work_item?: string;
802
+ /** Files/directories the round may touch. Empty = no scope constraint. */
803
+ scope: string[];
804
+ items: ContractItemProposal[];
805
+ }
806
+ /** v3.8: The machine's record of what a contract bound at its declaration
807
+ * round. Stamped by the runtime when the declaring round COMMITS (policy is
808
+ * not part of the Vault, so the command configuration in force at
809
+ * declaration could not otherwise be recovered). It is machine-recomputed,
810
+ * never agent-supplied, and adds no second truth. */
811
+ export interface ContractBinding {
812
+ rc_id: string;
813
+ item_ids: string[];
814
+ config_hash_by_command: Record<string, string>;
815
+ }
816
+ /** v3.8: Runtime-derived contract item status. The agent may only claim
817
+ * `met` / `remaining`; the other three are machine-derived. */
818
+ export type ContractItemStatus = "pending" | "insufficient" | "contradicted" | "verified";
819
+ /** v3.8: The round-level verification posture. `trusted` means every claim in
820
+ * the round is machine-backed; `insufficient` means claims are unbacked but
821
+ * not contradicted; `contradicted` means machine facts deny a claim. */
822
+ export type RoundVerificationStatus = "trusted" | "insufficient" | "contradicted";
823
+ /** v3.8: Machine observation status. A configured provider always produces an
824
+ * observation — the failure modes are recorded, not filtered away.
825
+ *
826
+ * Who reports what: `timeout` and `unavailable` are the runtime's own words
827
+ * for "the provider exceeded its deadline" and "the provider yielded
828
+ * nothing" (the collector synthesizes both, so a provider cannot hide a
829
+ * failure by returning nothing). `aborted` is what a PROVIDER reports when
830
+ * its own capture was aborted — a command killed mid-flight, say. A
831
+ * collector deadline aborts the capture AS a timeout, so the round records
832
+ * the runtime's measured cause, not the provider's. */
833
+ export type ObservationStatus = "observed" | "passed" | "failed" | "timeout" | "unavailable" | "error" | "aborted";
834
+ /** v3.8: Common machine-observation fields. Observations are the factual
835
+ * record of what the machine saw; they are persisted with the round and are
836
+ * the only input that can create a `verified` fact. */
837
+ export interface MachineObservationBase {
838
+ schemaVersion: 1;
839
+ providerId: string;
840
+ kind: "git" | "command" | "custom";
841
+ phase: "before" | "after";
842
+ startedAt: number;
843
+ finishedAt: number;
844
+ status: ObservationStatus;
845
+ /** Files this observation reports (git: changed paths; command: resolved
846
+ * entrypoint files). */
847
+ files: string[];
848
+ }
849
+ export interface GitObservationData {
850
+ tracked: string[];
851
+ staged: string[];
852
+ untracked: string[];
853
+ /** path -> "<mode>:<sha256>" (or the literal "missing"). */
854
+ fingerprints: Record<string, string>;
855
+ head?: string;
856
+ }
857
+ export interface GitObservation extends MachineObservationBase {
858
+ kind: "git";
859
+ data: GitObservationData;
860
+ }
861
+ export interface CommandObservationData {
862
+ commandId: string;
863
+ argv: string[];
864
+ cwd: string;
865
+ /** sha256 of the normalized command configuration at capture time. */
866
+ configHash: string;
867
+ required: boolean;
868
+ exitCode: number | null;
869
+ signal: string | null;
870
+ durationMs: number;
871
+ /** Why a non-passed observation did not pass (e.g. "ENOENT", "cwd leaves
872
+ * the workspace"). Free text for the audit trail — never a verdict. */
873
+ failureDetail?: string;
874
+ /** sha256 over the FULL stdout stream — never the truncated excerpt. */
875
+ stdoutSha256: string;
876
+ /** sha256 over the FULL stderr stream. */
877
+ stderrSha256: string;
878
+ stdoutExcerpt: string;
879
+ stderrExcerpt: string;
880
+ truncated: boolean;
881
+ entrypointFiles: string[];
882
+ }
883
+ export interface CommandObservation extends MachineObservationBase {
884
+ kind: "command";
885
+ data: CommandObservationData;
886
+ }
887
+ export interface CustomObservation extends MachineObservationBase {
888
+ kind: "custom";
889
+ data: Record<string, unknown>;
890
+ }
891
+ export type MachineObservation = GitObservation | CommandObservation | CustomObservation;
892
+ /** v3.8: Static, policy-derived verification capability. A pure function of
893
+ * policy — no probing, no filesystem, no provider registry — so it can be
894
+ * hashed into stateHash and reproduced by replay/audit from committed facts.
895
+ * Provider REGISTRATION is code state and is deliberately excluded; it is
896
+ * reported as an unhashed readiness diagnostic instead. */
897
+ export interface ConfiguredCapability {
898
+ schemaVersion: 1;
899
+ providers: Array<{
900
+ providerId: string;
901
+ }>;
902
+ commands: Array<{
903
+ commandId: string;
904
+ enabled: boolean;
905
+ phase: "after" | "both";
906
+ required: boolean;
907
+ configHash: string;
908
+ }>;
909
+ /** policy.evidence.providers is non-empty. */
910
+ observationConfigured: boolean;
911
+ /** At least one enabled, after-capable command. */
912
+ contractVerificationAvailable: boolean;
913
+ }
914
+ /** v3.8: Live observation capability. Rendered only — never hashed, never
915
+ * persisted independently of the observations it is derived from. */
916
+ export interface ObservedCapability {
917
+ providers: Array<{
918
+ providerId: string;
919
+ status: ObservationStatus;
920
+ }>;
921
+ commands: Array<{
922
+ commandId: string;
923
+ status: ObservationStatus;
924
+ configHash: string;
925
+ }>;
926
+ }
927
+ /** v3.8: The single capability fact a prepared round returns — the union of
928
+ * the two halves, split so that only the POLICY half is hashable.
929
+ *
930
+ * `ConfiguredCapability` is a pure function of policy and feeds
931
+ * `stateHash`/`promptHash`; `ObservedCapability` carries live statuses and is
932
+ * rendered only. `provider.available` is provider-REGISTRY state (code, not
933
+ * policy) and therefore never enters the hash either — it is reported here and
934
+ * by `doctor`. Every surface that speaks about capability (MCP start / next /
935
+ * status, the warning list) calls this one function, so they cannot drift
936
+ * apart — and none of them carries a second copy of the fact. */
937
+ export interface EvidenceCapability {
938
+ schemaVersion: 1;
939
+ providers: Array<{
940
+ providerId: string;
941
+ /** A factory for this name is registered in this runtime. */
942
+ available: boolean;
943
+ status: ObservationStatus;
944
+ }>;
945
+ commands: Array<{
946
+ commandId: string;
947
+ enabled: boolean;
948
+ phase: "after" | "both";
949
+ configHash: string;
950
+ /** Enabled and after-capable — i.e. usable as a contract item's evidence. */
951
+ ready: boolean;
952
+ }>;
953
+ contractVerificationAvailable: boolean;
954
+ /** Human-readable capability gaps (the same text start/resume/status show). */
955
+ warnings: string[];
956
+ }
957
+ /** v3.8: A machine-verified sub-goal fact. DERIVED in cognitive-facts.ts,
958
+ * never persisted: it exists only while a committed contract item references
959
+ * the sub-goal AND that item is verified. It never writes SubGoal.status —
960
+ * `done` stays the agent's declaration. */
961
+ export interface VerifiedSubGoalFact {
962
+ subgoal_id: string;
963
+ contract_item_ids: string[];
964
+ verified_at_round: number;
965
+ }
966
+ /** v3.8: The STABLE error codes every tool answers with. A client can branch
967
+ * on these; the human sentence rides in `ToolError.message` and never doubles
968
+ * as the code.
969
+ *
970
+ * - `evaluation_invalid` / `contract_invalid` / `policy_invalid` — a payload
971
+ * or configuration defect; the same roundId may be retried.
972
+ * - `round_id_required` / `round_id_mismatch` — the anchor is missing or no
973
+ * longer names the current round.
974
+ * - `session_not_found` / `state_unavailable` — the named session or read
975
+ * model is not there.
976
+ * - `invalid_argument` — the request itself is malformed at the tool boundary.
977
+ * - `gate_disabled` / `loop_already_running` — a state condition, not a defect.
978
+ *
979
+ * Note: a `loopforge_next` submission whose roundId no longer matches is NOT
980
+ * `round_id_mismatch` — it returns the held prompt with a warning and
981
+ * `ok: true` so the agent can recover the response it missed. That recovery
982
+ * contract (v3.0.1) is deliberate; `round_id_mismatch` is for the places with
983
+ * no held prompt to return (the gate preflight). */
984
+ export type ToolErrorCode = "evaluation_invalid" | "contract_invalid" | "policy_invalid" | "session_not_found" | "round_id_required" | "round_id_mismatch" | "state_unavailable" | "invalid_argument" | "gate_disabled" | "loop_already_running";
985
+ /** v3.8: The structured error inside the uniform `{ok: false}` envelope. */
986
+ export interface ToolError {
987
+ code: ToolErrorCode;
988
+ /** Human-readable cause. Never the code. */
989
+ message: string;
990
+ /** Whether the fix is a corrected payload the agent may resend. */
991
+ retryable: boolean;
992
+ sessionId?: string;
993
+ roundId?: string;
994
+ details?: Record<string, unknown>;
995
+ }
753
996
  export declare function makeTaskId(taskDescription: string): string;
754
997
  //# sourceMappingURL=protocol.d.ts.map