@cassiomc1/forgeloop 1.3.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/.github/copilot-instructions.md +1 -0
  2. package/AGENTS.md +1 -0
  3. package/CLAUDE.md +1 -0
  4. package/DOCS_INDEX.md +20 -8
  5. package/EXECUTION_STATE.md +60 -0
  6. package/LOOP_ENGINEERING.md +135 -5
  7. package/LOOP_SYSTEM_DESIGN.md +54 -1
  8. package/PROTOCOL_INTEGRATION.md +87 -0
  9. package/QUALITY_SCORECARD.md +2 -0
  10. package/README.md +69 -9
  11. package/TERMINOLOGY.md +15 -0
  12. package/THIRD_PARTY_NOTICES.md +30 -0
  13. package/THREAT_MODEL.md +59 -1
  14. package/docs/ARTIFACT_REFERENCE.md +183 -0
  15. package/docs/CLI_REFERENCE.md +391 -6
  16. package/docs/CROSS_HARNESS_CONTINUITY.md +23 -0
  17. package/docs/DIAGNOSTIC_MODEL.md +181 -0
  18. package/docs/DOCUMENTATION_GUIDE.md +36 -13
  19. package/docs/EXECUTION_TRACE.md +76 -0
  20. package/docs/GETTING_STARTED.md +1 -0
  21. package/docs/MCP.md +159 -0
  22. package/docs/RECIPES.md +149 -0
  23. package/docs/RELEASE_CHECKLIST_1_4.md +38 -0
  24. package/docs/RELEASE_CHECKLIST_1_5_MCP.md +78 -0
  25. package/docs/TROUBLESHOOTING.md +217 -3
  26. package/docs/UNIVERSAL_INTEGRATION.md +48 -0
  27. package/docs/assets/diagrams/forgeloop-engineering-flow.html +13797 -0
  28. package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +37 -0
  29. package/docs/assets/diagrams/forgeloop-engineering-flow.svg +5002 -0
  30. package/docs/diagrams/README.md +55 -0
  31. package/docs/diagrams/forgeloop-engineering-flow.workflow.json +122 -0
  32. package/docs/diagrams/manifest.json +42 -0
  33. package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +20 -0
  34. package/package.json +21 -8
  35. package/schemas/action.schema.json +100 -0
  36. package/schemas/approval.schema.json +51 -0
  37. package/schemas/capability-policy.schema.json +41 -0
  38. package/schemas/diagnostic-case.schema.json +85 -0
  39. package/schemas/execution-receipt.schema.json +16 -0
  40. package/schemas/hypothesis-disposition.schema.json +16 -0
  41. package/schemas/intervention.schema.json +27 -0
  42. package/schemas/policy-lock.schema.json +1 -0
  43. package/schemas/policy-snapshot.schema.json +2 -0
  44. package/schemas/task-recovery.schema.json +61 -0
  45. package/schemas/trajectory-evaluation.schema.json +64 -0
  46. package/schemas/trajectory-scenario.schema.json +42 -0
  47. package/src/cli.js +267 -347
  48. package/src/commands/action-authorize.js +41 -0
  49. package/src/commands/action-propose.js +10 -0
  50. package/src/commands/action-reconcile.js +10 -0
  51. package/src/commands/action-record.js +47 -0
  52. package/src/commands/action-show.js +10 -0
  53. package/src/commands/action-verify.js +10 -0
  54. package/src/commands/advance.js +7 -2
  55. package/src/commands/approval-request.js +64 -0
  56. package/src/commands/approval-resolve.js +10 -0
  57. package/src/commands/audit.js +5 -0
  58. package/src/commands/baseline.js +3 -3
  59. package/src/commands/eval.js +6 -0
  60. package/src/commands/history.js +18 -0
  61. package/src/commands/init.js +2 -2
  62. package/src/commands/inspect.js +55 -0
  63. package/src/commands/metrics.js +7 -0
  64. package/src/commands/next.js +8 -2
  65. package/src/commands/policy-discover.js +2 -2
  66. package/src/commands/progress.js +6 -2
  67. package/src/commands/record-diagnosis.js +37 -1
  68. package/src/commands/record-hypothesis-disposition.js +45 -0
  69. package/src/commands/record-intervention.js +35 -0
  70. package/src/commands/reflect.js +38 -0
  71. package/src/commands/report.js +9 -1
  72. package/src/commands/run-action.js +18 -0
  73. package/src/commands/status.js +17 -0
  74. package/src/commands/task-create.js +39 -1
  75. package/src/commands/task-list.js +14 -1
  76. package/src/commands/task-lock-status.js +2 -2
  77. package/src/commands/task-recover.js +202 -0
  78. package/src/commands/task-repair-legacy-recovery.js +417 -0
  79. package/src/commands/task-resume.js +172 -0
  80. package/src/commands/task-scope.js +23 -4
  81. package/src/commands/task-show.js +18 -4
  82. package/src/commands/trace.js +34 -0
  83. package/src/commands/validate-protocol.js +40 -15
  84. package/src/core/action-authorization.js +106 -0
  85. package/src/core/action-constants.js +86 -0
  86. package/src/core/action-execution.js +105 -0
  87. package/src/core/action-ledger-projection.js +302 -0
  88. package/src/core/action-model.js +581 -0
  89. package/src/core/action-readiness.js +141 -0
  90. package/src/core/action-reconciliation-policy.js +49 -0
  91. package/src/core/action-reconciliation.js +66 -0
  92. package/src/core/action-verification.js +111 -0
  93. package/src/core/actions.js +462 -0
  94. package/src/core/approvals.js +405 -0
  95. package/src/core/artifact-registry.js +60 -0
  96. package/src/core/audit.js +45 -4
  97. package/src/core/bundles.js +30 -0
  98. package/src/core/capability-policy.js +226 -0
  99. package/src/core/cli-command-definitions.js +260 -5
  100. package/src/core/command-executors.js +543 -0
  101. package/src/core/command-input.js +107 -0
  102. package/src/core/command-runtime.js +117 -0
  103. package/src/core/completion-artifacts.js +39 -15
  104. package/src/core/completion-ownership.js +88 -0
  105. package/src/core/completion-recovery-rebind.js +194 -0
  106. package/src/core/completion.js +70 -0
  107. package/src/core/continuity-reconciliation.js +24 -5
  108. package/src/core/diagnostic-model.js +396 -0
  109. package/src/core/diagnostic-projection.js +51 -0
  110. package/src/core/diagnostic-record.js +360 -0
  111. package/src/core/error-codes.js +461 -1
  112. package/src/core/events.js +171 -2
  113. package/src/core/execution-prerequisites.js +4 -1
  114. package/src/core/execution.js +26 -188
  115. package/src/core/failure-signature.js +70 -0
  116. package/src/core/failure-surface.js +57 -0
  117. package/src/core/filesystem.js +55 -6
  118. package/src/core/history.js +110 -0
  119. package/src/core/hypothesis-projection.js +85 -0
  120. package/src/core/information-gain-projection.js +283 -0
  121. package/src/core/information-gain.js +138 -0
  122. package/src/core/inspect.js +132 -7
  123. package/src/core/integration-invocation-policy.js +217 -0
  124. package/src/core/integration-limits.js +20 -0
  125. package/src/core/integration-resources.js +178 -0
  126. package/src/core/next-action-model.js +94 -0
  127. package/src/core/next-action.js +490 -3
  128. package/src/core/phase.js +42 -22
  129. package/src/core/policy-engine.js +113 -6
  130. package/src/core/preflight-consistency.js +31 -5
  131. package/src/core/preflight.js +19 -2
  132. package/src/core/prepared-execution.js +227 -0
  133. package/src/core/progress.js +41 -4
  134. package/src/core/project-root.js +21 -0
  135. package/src/core/protocol-info.js +61 -0
  136. package/src/core/protocol.js +14 -0
  137. package/src/core/receipt.js +1 -0
  138. package/src/core/reconcile-closure.js +35 -10
  139. package/src/core/recovery-history.js +116 -0
  140. package/src/core/reflection.js +305 -0
  141. package/src/core/resumability.js +57 -3
  142. package/src/core/schema-validation.js +9 -0
  143. package/src/core/strategy-analysis.js +97 -0
  144. package/src/core/task-claim-state.js +272 -0
  145. package/src/core/task-command.js +5 -1
  146. package/src/core/task-conflict-inspection.js +321 -0
  147. package/src/core/task-context.js +32 -29
  148. package/src/core/task-discovery.js +14 -1
  149. package/src/core/task-lock.js +216 -22
  150. package/src/core/task-paths.js +31 -2
  151. package/src/core/task-recovery-migration.js +192 -0
  152. package/src/core/task-recovery.js +205 -0
  153. package/src/core/task-scope.js +33 -1
  154. package/src/core/task-snapshot.js +53 -0
  155. package/src/core/templates.js +9 -0
  156. package/src/core/trace.js +548 -0
  157. package/src/core/trajectory-evaluation.js +71 -0
  158. package/src/core/trajectory-metrics.js +80 -0
  159. package/src/core/transaction.js +36 -2
  160. package/src/core/work-state.js +10 -5
  161. package/src/integration.js +47 -0
  162. package/docs/assets/forgeloop-flow.svg +0 -1
  163. package/docs/forgeloop-flow.mmd +0 -51
@@ -39,11 +39,12 @@ ForgeLoop uses a definition-driven command-line parser:
39
39
 
40
40
  | Category | Commands |
41
41
  | --- | --- |
42
- | **Inspection & Diagnostics** | [`protocol-info`](#protocol-info), [`doctor`](#doctor), [`progress`](#progress), [`profile-interview`](#profile-interview), [`inspect`](#inspect), [`status`](#status), [`validate-state`](#validate-state), [`validate-protocol`](#validate-protocol) |
43
- | **Setup & Maintenance** | [`init`](#init), [`update`](#update), [`task-migrate`](#task-migrate), [`migrate-protocol`](#migrate-protocol), [`task-unlock`](#task-unlock) |
44
- | **Lifecycle & State** | [`activate`](#activate), [`route`](#route), [`preflight`](#preflight), [`advance`](#advance), [`next`](#next), [`record-diagnosis`](#record-diagnosis), [`record-decision-criterion`](#record-decision-criterion), [`complete`](#complete), [`clear-state`](#clear-state), [`reconcile-closure`](#reconcile-closure), [`task-create`](#task-create), [`task-list`](#task-list), [`task-show`](#task-show), [`task-lock-status`](#task-lock-status), [`task-scope`](#task-scope) |
42
+ | **Inspection & Diagnostics** | [`protocol-info`](#protocol-info), [`doctor`](#doctor), [`metrics`](#metrics), [`eval`](#eval), [`history`](#history), [`trace`](#trace), [`reflect`](#reflect), [`progress`](#progress), [`profile-interview`](#profile-interview), [`inspect`](#inspect), [`status`](#status), [`validate-state`](#validate-state), [`validate-protocol`](#validate-protocol) |
43
+ | **Setup & Maintenance** | [`init`](#init), [`update`](#update), [`task-migrate`](#task-migrate), [`migrate-protocol`](#migrate-protocol), [`task-unlock`](#task-unlock), [`task-recover`](#task-recover), [`task-repair-legacy-recovery`](#task-repair-legacy-recovery), [`task-resume`](#task-resume) |
44
+ | **Lifecycle & State** | [`activate`](#activate), [`route`](#route), [`preflight`](#preflight), [`advance`](#advance), [`next`](#next), [`record-diagnosis`](#record-diagnosis), [`record-intervention`](#record-intervention), [`record-hypothesis-disposition`](#record-hypothesis-disposition), [`record-decision-criterion`](#record-decision-criterion), [`complete`](#complete), [`clear-state`](#clear-state), [`reconcile-closure`](#reconcile-closure), [`task-create`](#task-create), [`task-list`](#task-list), [`task-show`](#task-show), [`task-lock-status`](#task-lock-status), [`task-scope`](#task-scope) |
45
45
  | **Cross-Harness Continuity** | [`continuity`](#continuity), [`record-continuity`](#record-continuity), [`reconcile-continuity`](#reconcile-continuity), [`clear-continuity`](#clear-continuity) |
46
46
  | **Verification & Completion** | [`prepare-completion`](#prepare-completion), [`run-check`](#run-check), [`record-check`](#record-check), [`record-terminal-result`](#record-terminal-result), [`audit`](#audit), [`report`](#report), [`validate-receipt`](#validate-receipt) |
47
+ | **Durable Actions & Approvals** | [`run-action`](#run-action), [`action-propose`](#action-propose), [`action-record`](#action-record), [`action-show`](#action-show), [`action-reconcile`](#action-reconcile), [`action-verify`](#action-verify), [`action-authorize`](#action-authorize), [`approval-request`](#approval-request), [`approval-resolve`](#approval-resolve) |
47
48
  | **Policy & Auditing** | [`policy`](#policy), [`policy-discover`](#policy-discover), [`policy-status`](#policy-status), [`policy-diff`](#policy-diff), [`rule-verify`](#rule-verify), [`baseline`](#baseline), [`bundle`](#bundle) |
48
49
 
49
50
  <!-- END FORGELOOP GENERATED: cli-command-index -->
@@ -52,6 +53,163 @@ ForgeLoop uses a definition-driven command-line parser:
52
53
 
53
54
  ## 1. Setup & Maintenance
54
55
 
56
+ ## Durable Actions, Approvals, and Trajectory
57
+
58
+ ForgeLoop is still a protocol/evidence layer, not an agent runtime. Use
59
+ `COMMIT_UNKNOWN` as a hard stop: do not retry until an external observation is
60
+ recorded with `action-reconcile`. `run-action` has no shell mode and executes
61
+ only exact argv. Caller-reported and externally observed provenance are not host authority, and a project capability policy cannot mint host authority.
62
+
63
+ ### `run-action`
64
+
65
+ <!-- BEGIN FORGELOOP GENERATED: cli:run-action:options -->
66
+
67
+ - `--path <directory>`: target project directory (default: current directory)
68
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
69
+ - `--action <id>`: stable durable action ID
70
+ - `--capability <capability>`: canonical action capability
71
+ - `--effect-class <class>`: durable action effect class
72
+ - `--target <target>`: bounded external action target
73
+ - `--idempotency-key <key>`: immutable logical action idempotency key
74
+ - `--requirement <id>`: bound completion requirement
75
+ - `--required-for-completion`: mark the action as required for completion
76
+ - `--approval <id>`: current fingerprint-bound approval
77
+ - `--timeout-ms <number>`: maximum command duration before termination
78
+ - `-- <argv...>`: exact command argv; shell mode is never used
79
+ - `--json`: emit structured output as JSON
80
+
81
+ <!-- END FORGELOOP GENERATED: cli:run-action:options -->
82
+
83
+ ### `action-propose`
84
+
85
+ <!-- BEGIN FORGELOOP GENERATED: cli:action-propose:options -->
86
+
87
+ - `--path <directory>`: target project directory (default: current directory)
88
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
89
+ - `--id <id>`: stable action ID
90
+ - `--capability <capability>`: canonical capability
91
+ - `--effect-class <class>`: effect class
92
+ - `--target <target>`: bounded action target
93
+ - `--operation <text>`: bounded operation description
94
+ - `--idempotency-key <key>`: logical action idempotency key
95
+ - `--requirement <id>`: bound requirement
96
+ - `--required-for-completion`: mark required for completion
97
+ - `--json`: emit structured output as JSON
98
+
99
+ <!-- END FORGELOOP GENERATED: cli:action-propose:options -->
100
+
101
+ ### `action-record`
102
+
103
+ <!-- BEGIN FORGELOOP GENERATED: cli:action-record:options -->
104
+
105
+ - `--path <directory>`: target project directory (default: current directory)
106
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
107
+ - `--action <id>`: durable action ID
108
+ - `--state <state>`: next canonical action state
109
+ - `--provenance <value>`: CALLER_REPORTED or EXTERNAL_OBSERVED
110
+ - `--evidence-ref <ref>`: bounded external evidence reference
111
+ - `--json`: emit structured output as JSON
112
+
113
+ <!-- END FORGELOOP GENERATED: cli:action-record:options -->
114
+
115
+ ### `action-show`
116
+
117
+ <!-- BEGIN FORGELOOP GENERATED: cli:action-show:options -->
118
+
119
+ - `--path <directory>`: target project directory (default: current directory)
120
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
121
+ - `--action <id>`: durable action ID
122
+ - `--json`: emit structured output as JSON
123
+
124
+ <!-- END FORGELOOP GENERATED: cli:action-show:options -->
125
+
126
+ ### `action-verify`
127
+
128
+ <!-- BEGIN FORGELOOP GENERATED: cli:action-verify:options -->
129
+
130
+ - `--path <directory>`: target project directory (default: current directory)
131
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
132
+ - `--action <id>`: durable action ID
133
+ - `--evidence <ref>`: canonical execution or check reference proving the postcondition
134
+ - `--json`: emit structured output as JSON
135
+
136
+ <!-- END FORGELOOP GENERATED: cli:action-verify:options -->
137
+
138
+ ### `action-authorize`
139
+
140
+ <!-- BEGIN FORGELOOP GENERATED: cli:action-authorize:options -->
141
+
142
+ - `--path <directory>`: target project directory (default: current directory)
143
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
144
+ - `--action <id>`: durable action ID
145
+ - `--approval <id>`: current fingerprint-bound approval
146
+ - `--json`: emit structured output as JSON
147
+
148
+ <!-- END FORGELOOP GENERATED: cli:action-authorize:options -->
149
+
150
+ ### `action-reconcile`
151
+
152
+ <!-- BEGIN FORGELOOP GENERATED: cli:action-reconcile:options -->
153
+
154
+ - `--path <directory>`: target project directory (default: current directory)
155
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
156
+ - `--action <id>`: ambiguous durable action ID
157
+ - `--outcome <outcome>`: externally observed reconciliation outcome
158
+ - `--evidence-ref <ref>`: bounded external evidence reference (repeatable)
159
+ - `--observed-at <timestamp>`: external observation timestamp
160
+ - `--json`: emit structured output as JSON
161
+
162
+ <!-- END FORGELOOP GENERATED: cli:action-reconcile:options -->
163
+
164
+ ### `metrics`
165
+
166
+ <!-- BEGIN FORGELOOP GENERATED: cli:metrics:options -->
167
+
168
+ - `--path <directory>`: target project directory (default: current directory)
169
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
170
+ - `--json`: emit trajectory metrics as JSON
171
+
172
+ <!-- END FORGELOOP GENERATED: cli:metrics:options -->
173
+
174
+ ### `eval`
175
+
176
+ <!-- BEGIN FORGELOOP GENERATED: cli:eval:options -->
177
+
178
+ - `--path <directory>`: target project directory (default: current directory)
179
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
180
+ - `--scenario <path>`: project-local trajectory scenario JSON
181
+ - `--json`: emit evaluation as JSON
182
+
183
+ <!-- END FORGELOOP GENERATED: cli:eval:options -->
184
+
185
+ ### `approval-request`
186
+
187
+ <!-- BEGIN FORGELOOP GENERATED: cli:approval-request:options -->
188
+
189
+ - `--path <directory>`: target project directory (default: current directory)
190
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
191
+ - `--approval <id>`: approval artifact ID
192
+ - `--action <id>`: bound action ID
193
+ - `--reason <text>`: bounded approval reason
194
+ - `--json`: emit structured output as JSON
195
+
196
+ <!-- END FORGELOOP GENERATED: cli:approval-request:options -->
197
+
198
+ ### `approval-resolve`
199
+
200
+ <!-- BEGIN FORGELOOP GENERATED: cli:approval-resolve:options -->
201
+
202
+ - `--path <directory>`: target project directory (default: current directory)
203
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
204
+ - `--approval <id>`: approval artifact ID
205
+ - `--decision <decision>`: approval decision
206
+ - `--authority <kind>`: CALLER_ACKNOWLEDGED or HOST_ATTESTED
207
+ - `--host-grant-ref <ref>`: host boundary grant reference
208
+ - `--reason <text>`: bounded resolution reason
209
+ - `--json`: emit structured output as JSON
210
+
211
+ <!-- END FORGELOOP GENERATED: cli:approval-resolve:options -->
212
+
55
213
  ### `protocol-info`
56
214
 
57
215
  Reports the public compatibility handshake required by external ForgeLoop harnesses.
@@ -496,6 +654,7 @@ Records an append-only diagnosis event in the lifecycle event ledger for the act
496
654
 
497
655
  - `--path <directory>`: target project directory (default: current directory)
498
656
  - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
657
+ - `--file <path>`: structured diagnostic case JSON file (mutually exclusive with legacy diagnosis fields)
499
658
  - `--hypothesis <text>`: specific root-cause hypothesis explaining the verification failure
500
659
  - `--failure-class <class>`: canonical failure class taxonomy
501
660
  - `--evidence-ref <check-id>`: reference to failed/blocked check from current cycle (repeatable)
@@ -516,6 +675,63 @@ Records an append-only diagnosis event in the lifecycle event ledger for the act
516
675
  --next-safe-action="Adjust offset +1 in slice.js"
517
676
  ```
518
677
 
678
+ ### `record-intervention`
679
+
680
+ Records an append-only intervention bound to hypotheses; the described change is never executed by ForgeLoop.
681
+
682
+ - **Purpose**: Records corrective or experimental changes (code, config, tests, instrumentation) associated with one or more hypotheses.
683
+ - **When to use**: In `CORRECTING` phase after a structured diagnostic case has been recorded.
684
+ - **Mutation**: Appends `INTERVENTION_RECORDED` to event ledger.
685
+ - **Options**:
686
+
687
+ <!-- BEGIN FORGELOOP GENERATED: cli:record-intervention:options -->
688
+
689
+ - `--path <directory>`: target project directory (default: current directory)
690
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
691
+ - `--file <path>`: intervention JSON file describing the recorded change (never executed)
692
+ - `--json`: emit structured output as JSON
693
+
694
+ <!-- END FORGELOOP GENERATED: cli:record-intervention:options -->
695
+
696
+ - **Example**:
697
+
698
+ ```bash
699
+ forgeloop record-intervention --task checkout --file intervention.json --json
700
+ ```
701
+
702
+ ### `record-hypothesis-disposition`
703
+
704
+ Records an evidence-bound hypothesis disposition update in the lifecycle event ledger.
705
+
706
+ - **Purpose**: Updates hypothesis status (SUPPORTED, WEAKENED, FALSIFIED, SUPERSEDED, UNRESOLVED) based on recorded evidence.
707
+ - **When to use**: After new verification evidence resolves an open hypothesis.
708
+ - **Mutation**: Appends `HYPOTHESIS_DISPOSITION_RECORDED` to event ledger.
709
+ - **Options**:
710
+
711
+ <!-- BEGIN FORGELOOP GENERATED: cli:record-hypothesis-disposition:options -->
712
+
713
+ - `--path <directory>`: target project directory (default: current directory)
714
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
715
+ - `--hypothesis <id>`: existing hypothesis ID to disposition
716
+ - `--status <status>`: SUPPORTED, WEAKENED, FALSIFIED, SUPERSEDED, or UNRESOLVED
717
+ - `--evidence-ref <check-id>`: check ID supporting this disposition (repeatable)
718
+ - `--reason <text>`: evidence-bound reason for the disposition
719
+ - `--json`: emit structured output as JSON
720
+
721
+ <!-- END FORGELOOP GENERATED: cli:record-hypothesis-disposition:options -->
722
+
723
+ - **Example**:
724
+
725
+ ```bash
726
+ forgeloop record-hypothesis-disposition \
727
+ --task checkout \
728
+ --hypothesis h-timeout-latency \
729
+ --status SUPPORTED \
730
+ --evidence-ref checkout-tests \
731
+ --reason "Instrumented dependency time exceeded the timeout." \
732
+ --json
733
+ ```
734
+
519
735
  ### `validate-state`
520
736
 
521
737
  Validates `.forgeloop/task-state/<taskKey>/work-state.json` structure, hash chain, and repository binding.
@@ -821,7 +1037,7 @@ Displays human-readable or structured summary of current task state.
821
1037
 
822
1038
  ### `inspect`
823
1039
 
824
- Inspects checkout changes and compares them against contract deliverables.
1040
+ Inspects checkout changes and compares them against contract deliverables. With `--task <id>`, human output renders a task inspection report (phase, cycle, ledger/snapshot health, progress, verification attempts, diagnostics, failure surface, signals, next command); `--json` keeps the full additive `taskInspection` section.
825
1041
 
826
1042
  - **Purpose**: Shows modified files, untracked files, and deliverable coverage.
827
1043
  - **Mutation**: Read-only.
@@ -842,6 +1058,81 @@ Inspects checkout changes and compares them against contract deliverables.
842
1058
  forgeloop inspect --json
843
1059
  ```
844
1060
 
1061
+ ### `history`
1062
+
1063
+ Shows chronological protocol history reconstructed from canonical ForgeLoop state.
1064
+
1065
+ - **Purpose**: Answers "what happened during this task?" with deterministic, read-only reconstruction from the event ledger.
1066
+ - **Mutation**: Read-only.
1067
+ - **Options**:
1068
+
1069
+ <!-- BEGIN FORGELOOP GENERATED: cli:history:options -->
1070
+
1071
+ - `--path <directory>`: target project directory (default: current directory)
1072
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1073
+ - `--type <list>`: comma-separated event types or categories to include
1074
+ - `--phase <list>`: comma-separated lifecycle phases to include
1075
+ - `--failures`: show only failed/blocked verification events
1076
+ - `--checks`: show only verification events
1077
+ - `--since <timestamp>`: include events at or after this timestamp
1078
+ - `--until <timestamp>`: include events at or before this timestamp
1079
+ - `--limit <number>`: show only the last N events after filtering
1080
+ - `--compact`: one line per event
1081
+ - `--verbose`: show full event data
1082
+ - `--json`: emit structured history output as JSON
1083
+
1084
+ <!-- END FORGELOOP GENERATED: cli:history:options -->
1085
+
1086
+ - **Example**:
1087
+
1088
+ ```bash
1089
+ forgeloop history --task auth-feature --json
1090
+ ```
1091
+
1092
+ ### `trace`
1093
+
1094
+ Emits detailed structured task trace with provenance and artifact relationships.
1095
+
1096
+ - **Purpose**: Machine-readable protocol reconstruction consumed by history, reflect, task-level inspect, and external integrations.
1097
+ - **Mutation**: Read-only.
1098
+ - **Options**:
1099
+
1100
+ <!-- BEGIN FORGELOOP GENERATED: cli:trace:options -->
1101
+
1102
+ - `--path <directory>`: target project directory (default: current directory)
1103
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1104
+ - `--json`: emit structured trace output as JSON (default rendering is a summary)
1105
+
1106
+ <!-- END FORGELOOP GENERATED: cli:trace:options -->
1107
+
1108
+ - **Example**:
1109
+
1110
+ ```bash
1111
+ forgeloop trace --task auth-feature --json
1112
+ ```
1113
+
1114
+ ### `reflect`
1115
+
1116
+ Analyzes diagnostic and correction history deterministically for information gain, repeated failures, ineffective interventions, and oscillation.
1117
+
1118
+ - **Purpose**: Whole-task retrospective that reports whether the run actually learned anything, without calling an LLM.
1119
+ - **Mutation**: Read-only.
1120
+ - **Options**:
1121
+
1122
+ <!-- BEGIN FORGELOOP GENERATED: cli:reflect:options -->
1123
+
1124
+ - `--path <directory>`: target project directory (default: current directory)
1125
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1126
+ - `--json`: emit structured reflection output as JSON
1127
+
1128
+ <!-- END FORGELOOP GENERATED: cli:reflect:options -->
1129
+
1130
+ - **Example**:
1131
+
1132
+ ```bash
1133
+ forgeloop reflect --task auth-feature --json
1134
+ ```
1135
+
845
1136
  ### `policy`
846
1137
 
847
1138
  Evaluates compliance against a named policy pack.
@@ -1263,9 +1554,9 @@ protocol version.
1263
1554
 
1264
1555
  ### `task-unlock`
1265
1556
 
1266
- Forces the release of a stale task lock.
1557
+ Forces the release of a task lock or CAS-safely releases an unchanged stale lease.
1267
1558
 
1268
- - **Purpose**: Removes `.lock` file from the task directory when process crashed.
1559
+ - **Purpose**: Removes `.forgeloop/locks/<taskKey>.lock` when its owner is no longer valid. Prefer `--stale-only`; `--force` is an explicit unconditional maintenance action.
1269
1560
  - **Mutation**: Deletes task lock file.
1270
1561
  - **Options**:
1271
1562
 
@@ -1284,3 +1575,97 @@ Forces the release of a stale task lock.
1284
1575
  ```bash
1285
1576
  forgeloop task-unlock --task task-001 --force --json
1286
1577
  ```
1578
+
1579
+ ### `task-recover`
1580
+
1581
+ Suspends mutation and releases effective claims for a task deterministically classified `STALE` or `ABANDONED`.
1582
+
1583
+ - **Purpose**: For a task classified only `STALE` or `ABANDONED`, persists `recovery.json` plus a linked append-only event without changing work state or fabricating completion. The canonical claim-state resolver must validate both before claims become effective-empty. `RECOVERABLE` tasks must use `reconcile-closure`.
1584
+ - **Mutation**: Transactionally writes recovery state and appends the recovery event. Historical descriptor claims and all lifecycle evidence remain intact; ordinary mutations return `E_TASK_RECOVERED`.
1585
+ - **Options**:
1586
+
1587
+ <!-- BEGIN FORGELOOP GENERATED: cli:task-recover:options -->
1588
+
1589
+ - `--path <directory>`: target project directory (default: current directory)
1590
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1591
+ - `--acknowledge-recovery`: acknowledge release of claims for a STALE or ABANDONED task (required; not host attestation)
1592
+ - `--operator-authorized`: deprecated alias for --acknowledge-recovery; does not attest operator authority
1593
+ - `--json`: emit structured output as JSON
1594
+
1595
+ <!-- END FORGELOOP GENERATED: cli:task-recover:options -->
1596
+
1597
+ - **Example**:
1598
+
1599
+ ```bash
1600
+ forgeloop task-recover --task task-001 --acknowledge-recovery --json
1601
+ ```
1602
+
1603
+ `--acknowledge-recovery` is caller acknowledgement only. The deprecated
1604
+ `--operator-authorized` alias has the same semantics and is not host attestation.
1605
+ Fake, missing, corrupt, or mismatched recovery state is
1606
+ `E_TASK_CLAIM_OWNERSHIP_INCONSISTENT`/`E_TASK_RECOVERY_INCONSISTENT`; historical
1607
+ claims remain reserved.
1608
+
1609
+ ### `task-resume`
1610
+
1611
+ Reacquires a recovered task's write claims and restores ordinary mutation authority.
1612
+
1613
+ - **Purpose**: Validates active recovery ownership, CAS-settles only an unchanged stale task lease, reuses normal claim-overlap and clean-checkout enforcement under project/task serialization, then removes `recovery.json` transactionally.
1614
+ - **Mutation**: Optionally updates historical claims in `task.json`, appends `TASK_RECOVERY_RESUMED`, and removes `recovery.json` in one transaction.
1615
+ - **Options**:
1616
+
1617
+ <!-- BEGIN FORGELOOP GENERATED: cli:task-resume:options -->
1618
+
1619
+ - `--path <directory>`: target project directory (default: current directory)
1620
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1621
+ - `--claim <path>`: write claim to reacquire (defaults to all released claims) (repeatable)
1622
+ - `--json`: emit structured output as JSON
1623
+
1624
+ <!-- END FORGELOOP GENERATED: cli:task-resume:options -->
1625
+
1626
+ - **Example**:
1627
+
1628
+ ```bash
1629
+ forgeloop task-resume --task task-001 --claim src --claim tests --json
1630
+ ```
1631
+
1632
+ With no `--claim`, the command attempts to reacquire all claims recorded in the
1633
+ active recovery artifact. It returns `E_TASK_SCOPE_CONFLICT` without removing
1634
+ recovery state when another active task owns an overlapping path.
1635
+ The resume event counts as meaningful task activity. Never create, edit, or
1636
+ delete `recovery.json` manually to emulate this command.
1637
+
1638
+ ### `task-repair-legacy-recovery`
1639
+
1640
+ Migrates one recognized legacy recovery boundary event into the modern durable recovery representation.
1641
+
1642
+ - **Purpose**: Proves that a historical `OPERATOR_RECOVERY_RECORDED` without `recoveryId` marks the effective task boundary and materializes its modern representation as an append-only `LEGACY_RECOVERY_MIGRATION_RECORDED` event plus a transactional `recovery.json`. The original legacy event is never modified.
1643
+ - **Mutation**: Appends the migration event at the ledger tail and writes `recovery.json` in one transaction under project claims locking.
1644
+ - **Options**:
1645
+
1646
+ <!-- BEGIN FORGELOOP GENERATED: cli:task-repair-legacy-recovery:options -->
1647
+
1648
+ - `--path <directory>`: target project directory (default: current directory)
1649
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1650
+ - `--acknowledge-recovery`: fresh explicit acknowledgement of the legacy boundary migration (required)
1651
+ - `--json`: emit structured output as JSON
1652
+
1653
+ <!-- END FORGELOOP GENERATED: cli:task-repair-legacy-recovery:options -->
1654
+
1655
+ - **Example**:
1656
+
1657
+ ```bash
1658
+ forgeloop task-repair-legacy-recovery --task task-001 --acknowledge-recovery --json
1659
+ ```
1660
+
1661
+ Only the exact known legacy signature is eligible; ambiguous, tampered, or
1662
+ post-boundary-active ledgers fail closed with
1663
+ `E_LEGACY_RECOVERY_MIGRATION_INVALID` and ownership stays INCONSISTENT. A
1664
+ `STALE` task lease is settled only through CAS-safe stale release when the
1665
+ observed lock is unchanged; `LIVE` locks refuse with `E_TASK_LOCKED`, and
1666
+ `UNKNOWN`/`CORRUPT` locks fail closed with the lock preserved — never delete a
1667
+ lock file manually to unblock this command. The repair is idempotent: an
1668
+ already repaired task returns `{repaired: 0, alreadyRepaired: true}` only when
1669
+ the whole canonical recovery relationship validates; any mismatch fails closed.
1670
+ The repair itself never releases claims directly; ownership becomes validated
1671
+ recovery state and ordinary mutation remains blocked until `task-resume`.
@@ -54,6 +54,7 @@ Key continuity invariants:
54
54
  | --- | --- | --- | --- |
55
55
  | **Task Descriptor** | `.forgeloop/task-state/<taskKey>/task.json` | Task ID, write claims, and task registration | Descriptor authority |
56
56
  | **Lifecycle Checkpoint** | `.forgeloop/task-state/<taskKey>/work-state.json` | Current phase, cycle, active guides, preflight binding | Canonical lifecycle truth |
57
+ | **Recovery State** | `.forgeloop/task-state/<taskKey>/recovery.json` | Candidate current suspension bound to ledger history | One input to canonical validated claim ownership; never sufficient alone and never completion evidence |
57
58
  | **Operational Continuity** | `.forgeloop/task-state/<taskKey>/continuity.json` | Active focus, remaining items, known issues, inspect-first paths | Operational context only (non-evidence) |
58
59
  | **Implementation Truth** | Git checkout / filesystem | Actual source code and files | Ground truth for changes |
59
60
  | **Task Intent** | `.forgeloop/task-state/<taskKey>/contract.json` | Objectives, constraints, deliverables, verification requirements | Contract authority |
@@ -182,6 +183,26 @@ forgeloop next --task auth-feature --json
182
183
 
183
184
  Follow the deterministic action returned by ForgeLoop (e.g. `CONTINUE_IMPLEMENTATION`, `ENTER_VERIFYING`, or `RECORD_CHECK`).
184
185
 
186
+ If `next` returns `RESUME_RECOVERED_TASK`, the handoff is still the same task,
187
+ but ordinary mutation is suspended. Inspect the recovery metadata and current
188
+ claim owners, then reacquire claims explicitly:
189
+
190
+ ```bash
191
+ forgeloop task-show --task auth-feature --json
192
+ forgeloop task-resume --task auth-feature --json
193
+ ```
194
+
195
+ Do not create, edit, or delete `recovery.json` manually. Every harness must use
196
+ the canonical validated descriptor + work-state + recovery + ledger projection;
197
+ a tombstone alone never releases claims. If another task owns an
198
+ overlapping path, `task-resume` fails with `E_TASK_SCOPE_CONFLICT` and leaves
199
+ the recovery state intact.
200
+
201
+ A project containing active task recovery state requires ForgeLoop 1.4.0 or
202
+ newer and `features.taskClaimRecovery.validatedClaimProjection=true` in
203
+ `protocol-info`. An unaware reader must fail closed rather than continue from
204
+ descriptor-only ownership.
205
+
185
206
  ---
186
207
 
187
208
  ## 6. Stale, Inconsistent, or Missing Handoffs
@@ -197,6 +218,8 @@ ForgeLoop handles edge cases deterministically:
197
218
  | **Multiple Active Tasks** | No `--task` or `FORGELOOP_TASK` supplied | `E_TASK_AMBIGUOUS` | List tasks with `task-list` and supply `--task` |
198
219
  | **Different Task ID** | Contract / state ID mismatch | `TASK_MISMATCH` | Do not merge contexts; complete or clear previous state |
199
220
  | **Malformed State** | Corrupted JSON or invalid hash chain | `INVALID` | Fails closed; inspect errors via `forgeloop doctor --json` |
221
+ | **Recovered Task** | `recovery.json` and its complete ledger history validate as one active recovery cycle | `RESUME_RECOVERED_TASK` | Inspect ownership, then use `task-resume`; recovery is not completion |
222
+ | **Recovery Inconsistency** | Artifact/history, descriptor claims, lock, or ledger evidence is missing, corrupt, or mismatched | `RESOLVE_RECOVERY_INCONSISTENCY` | Historical claims remain reserved; run `validate-protocol` and repair the named artifact instead of forcing recovery |
200
223
 
201
224
  ---
202
225
 
@@ -0,0 +1,181 @@
1
+ # ForgeLoop Diagnostic Model
2
+
3
+ Canonical reference for structured diagnostic cases, interventions, and hypothesis dispositions (ForgeLoop 1.6.0+, Protocol v1 additive).
4
+
5
+ ## Principles
6
+
7
+ 1. **Observation is not hypothesis.** Observations are bounded statements grounded in recorded evidence. Hypotheses are falsifiable claims that may explain observations.
8
+ 2. **Hypothesis is not proof.** Statuses are `OPEN`, `SUPPORTED`, `WEAKENED`, `FALSIFIED`, `SUPERSEDED`, `UNRESOLVED`. ForgeLoop never emits `ROOT_CAUSE_CONFIRMED` or similar.
9
+ 3. **Append-only truth.** Diagnostic revisions are never rewritten; the ledger records evolving understanding.
10
+ 4. **Diagnostic prose is metadata.** Statements, settlement predicates, and next-safe-action text are never executed by ForgeLoop.
11
+
12
+ ## Structured diagnostic case
13
+
14
+ One diagnostic revision for one verification cycle, recorded with:
15
+
16
+ ```bash
17
+ forgeloop record-diagnosis --task <id> --file diagnostic-case.json --json
18
+ ```
19
+
20
+ Legacy flag-based `record-diagnosis` syntax remains valid; both forms cannot be combined.
21
+
22
+ Schema: `schemas/diagnostic-case.schema.json`. Bounded limits: 64 observations, 64 contributors, 32 hypotheses per case; statements up to 4096 characters; IDs match `^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$`.
23
+
24
+ ### Semantic fingerprint
25
+
26
+ `diagnosticFingerprint` hashes the canonicalized semantic content (cycle, failure class, observations/contributors/hypotheses semantics, next-safe action). Whitespace, key ordering, unordered reference arrays, and object IDs are excluded. Re-recording a semantically identical case is idempotent.
27
+
28
+ ### Revisions
29
+
30
+ `diagnosticRevision` starts at 1 and increases monotonically per cycle. Each revision binds `previousDiagnosticFingerprint` to the prior active revision.
31
+
32
+ ## Interventions
33
+
34
+ Recorded in `CORRECTING` phase:
35
+
36
+ ```bash
37
+ forgeloop record-intervention --task <id> --file intervention.json --json
38
+ ```
39
+
40
+ Interventions bind to at least one recorded hypothesis and carry a semantic fingerprint used to detect repetition without information gain.
41
+
42
+ ## Hypothesis dispositions
43
+
44
+ ```bash
45
+ forgeloop record-hypothesis-disposition --task <id> \
46
+ --hypothesis h-timeout-latency --status SUPPORTED \
47
+ --evidence-ref checkout-tests --reason "..." --json
48
+ ```
49
+
50
+ Allowed transitions: `OPEN → {SUPPORTED, WEAKENED, FALSIFIED, SUPERSEDED, UNRESOLVED}`, `SUPPORTED → {WEAKENED, FALSIFIED, SUPERSEDED}`, `WEAKENED → {SUPPORTED, FALSIFIED, SUPERSEDED}`.
51
+
52
+ ## Diagnostic precedence
53
+
54
+ One canonical resolver backs every lifecycle gate, `next`, `progress`, and reflection:
55
+
56
+ 1. latest valid structured diagnostic case (`DIAGNOSTIC_CASE_RECORDED`) for the active task/cycle;
57
+ 2. latest valid legacy diagnosis (`DIAGNOSIS_RECORDED`) for the active task/cycle;
58
+ 3. none.
59
+
60
+ Structured diagnosis is therefore a first-class protocol-native diagnostic source: a task using only `record-diagnosis --file` can traverse `DIAGNOSING -> CORRECTING -> VERIFYING` without any legacy event, and no duplicate legacy event is synthesized. Legacy diagnosis remains fully valid as a compatibility input.
61
+
62
+ ## Hypothesis state projection
63
+
64
+ Hypothesis status is projected forward from append-only chronology (case creation in `OPEN`, then each disposition validated against the last effective projected state) — never re-read from the source case. Terminal states (`FALSIFIED`, `SUPERSEDED`, `UNRESOLVED`) do not transition unless a future protocol revision explicitly allows reopening. Invalid transitions fail closed with `E_HYPOTHESIS_DISPOSITION_INVALID`. `trace`, `reflect`, and continuity `openHypotheses` all consume this same projection.
65
+
66
+ ## Evidence binding
67
+
68
+ Structured cases require at least one hypothesis; `CHECK_RESULT` observations must resolve to a real check from the active verification cycle; a `VERIFICATION_FAILURE` case must bind at least one hypothesis or observation to failed/blocked evidence from the active cycle. Revision chains are revalidated at read time (`revision N.previousDiagnosticFingerprint == revision N-1.diagnosticFingerprint`).
69
+
70
+ ## Effective gain definition
71
+
72
+ Effective Information Gain exists when a diagnostic cycle changes a meaningful
73
+ semantic dimension of the verified engineering state:
74
+
75
+ ```text
76
+ new observation new contributor new hypothesis
77
+ new evidence hypothesis disposition hypothesis elimination
78
+ failure signature failure surface intervention semantics
79
+ strategy
80
+ ```
81
+
82
+ All of these participate in `effectiveGain`. Semantic noise — new IDs,
83
+ timestamps, property order, whitespace-equivalent paraphrases — never does.
84
+
85
+ ## Classification vs effective gain
86
+
87
+ The compatibility classification (`FIRST_DIAGNOSIS`, `NEW_HYPOTHESIS`,
88
+ `NEW_EVIDENCE`, `NEW_HYPOTHESIS_AND_EVIDENCE`, `NONE`) intentionally does not
89
+ encode every v2 dimension. A cycle can therefore report:
90
+
91
+ ```text
92
+ classification = NONE
93
+ failureSurfaceChanged = true
94
+ effectiveGain = true
95
+ ```
96
+
97
+ `effectiveGain` is computed once from the final dimensions by the authoritative
98
+ cycle analysis projection; consumers (progress, reflect, next, inspect,
99
+ continuity) must not recompute or post-mutate it.
100
+
101
+ ## Stall policy (fail-fast)
102
+
103
+ A structured diagnostic state is **stalled** when its latest comparable
104
+ diagnostic state has no effective information gain. There is no two-cycle
105
+ threshold: one no-gain comparison blocks another blind correction retry with
106
+ `E_DIAGNOSIS_NO_NEW_INFORMATION`, and progress/reflect/next/inspect expose the
107
+ same condition. The first diagnosis is never stalled. High correction-cycle
108
+ count alone remains advisory (`WATCH`), never `STALLED`.
109
+
110
+ Stall is not terminal: recording a diagnostic with meaningful new information
111
+ (a new observation, contributor, evidence, hypothesis change, and so on)
112
+ clears it immediately. Strategy oscillation (`A -> B -> A`) keeps the more
113
+ specific `INTRODUCE_NEW_OBSERVATION` guidance over generic no-gain guidance.
114
+ Historical repetition metrics remain available as reflective explanation
115
+ (`stallAnalysis`) but do not change the stall decision. Semantic noise — new IDs,
116
+ timestamps, property order, whitespace-equivalent paraphrases — never counts as
117
+ gain or as hypothesis elimination.
118
+
119
+ ## Failure surface evolution
120
+
121
+ Every canonically verified cycle appears in failure surfaces, including
122
+ successful ones:
123
+
124
+ ```text
125
+ cycle 2 ["lint"]
126
+ cycle 3 [] <- explicit empty successful cycle, direction REDUCED
127
+ ```
128
+
129
+ A full reduction to `[]` classifies the preceding intervention as `IMPROVED`.
130
+
131
+ ## Intervention repetition
132
+
133
+ ```text
134
+ repeatedSemanticIntervention
135
+ = the same intervention semantic fingerprint was recorded before
136
+
137
+ NON_INFORMATIVE
138
+ = later verification produced no meaningful semantic change
139
+ ```
140
+
141
+ Recording an intervention returns `repeatedSemanticIntervention` plus
142
+ `effectiveness: "PENDING"`. Only a subsequent completed verification cycle can
143
+ classify `IMPROVED | REGRESSED | INFORMATIVE | NON_INFORMATIVE`.
144
+
145
+ ## Continuity diagnostic context
146
+
147
+ ```json
148
+ {
149
+ "activeFailureSignatures": ["<sha256-like canonical fingerprint>"],
150
+ "activeFailedRequirements": ["auth-tests"],
151
+ "openHypotheses": [],
152
+ "latestIntervention": null,
153
+ "nextExperiment": null,
154
+ "doNotRepeat": []
155
+ }
156
+ ```
157
+
158
+ `activeFailureSignatures` contains canonical `computeFailureSignature` hashes
159
+ scoped to the active verification cycle; requirement names are exposed
160
+ separately in `activeFailedRequirements`.
161
+
162
+ ## Structured case hypothesis invariant
163
+
164
+ At least one hypothesis is mandatory: `hypotheses.minItems = 1` is enforced
165
+ identically by the JSON schema, the runtime validator, ledger validation, and
166
+ the record-diagnosis command path.
167
+
168
+ ## Information gain
169
+
170
+ Compatibility values (`FIRST_DIAGNOSIS`, `NEW_HYPOTHESIS`, `NEW_EVIDENCE`, `NEW_HYPOTHESIS_AND_EVIDENCE`, `NONE`) remain valid. Structured dimensions add observation/contributor/hypothesis novelty, disposition changes, failure-signature change, failure-surface change, and intervention change. New IDs, timestamps, whitespace, paraphrases, and identical reruns never constitute gain.
171
+
172
+ ## Stall and oscillation
173
+
174
+ - High correction-cycle count alone is advisory (`WATCH`), never `STALLED`.
175
+ - Strong stall requires identical failure signature, strategy, contributors, hypotheses, surface, and no new evidence across consecutive cycles. Two consecutive correction cycles without effective gain under the same strategy reach `STALLED` (`REQUIRE_NEW_DIAGNOSTIC_INFORMATION`).
176
+ - Repetition of an intervention is not automatically non-informative: effectiveness (`PENDING | IMPROVED | REGRESSED | INFORMATIVE | NON_INFORMATIVE`) is classified only after subsequent verification. Continuity `doNotRepeat` requires semantic repetition AND at least two completed post-intervention verification cycles AND unchanged failure surface.
177
+ - Oscillation (`A→B→A`) surfaces as `OSCILLATING_STRATEGY`; `next` recommends `INTRODUCE_NEW_OBSERVATION`.
178
+
179
+ ## Capability discovery
180
+
181
+ `forgeloop protocol-info --json` advertises `features.diagnostics`, `executionHistory`, `structuredTrace`, `taskInspection`, and `reflection`.