loopforge 3.9.0 → 3.9.2

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 (133) hide show
  1. package/README.md +18 -0
  2. package/dist/audit.d.ts +13 -1
  3. package/dist/audit.d.ts.map +1 -1
  4. package/dist/audit.js +18 -3
  5. package/dist/audit.js.map +1 -1
  6. package/dist/committed-round.d.ts +29 -32
  7. package/dist/committed-round.d.ts.map +1 -1
  8. package/dist/committed-round.js +164 -157
  9. package/dist/committed-round.js.map +1 -1
  10. package/dist/contract-items.d.ts +3 -2
  11. package/dist/contract-items.d.ts.map +1 -1
  12. package/dist/contract-items.js +18 -7
  13. package/dist/contract-items.js.map +1 -1
  14. package/dist/enforcement-gate.d.ts.map +1 -1
  15. package/dist/enforcement-gate.js +13 -61
  16. package/dist/enforcement-gate.js.map +1 -1
  17. package/dist/engine.d.ts.map +1 -1
  18. package/dist/engine.js +16 -9
  19. package/dist/engine.js.map +1 -1
  20. package/dist/evidence-claims.d.ts +6 -5
  21. package/dist/evidence-claims.d.ts.map +1 -1
  22. package/dist/evidence-claims.js +21 -20
  23. package/dist/evidence-claims.js.map +1 -1
  24. package/dist/evidence-provider.d.ts +73 -42
  25. package/dist/evidence-provider.d.ts.map +1 -1
  26. package/dist/evidence-provider.js +437 -138
  27. package/dist/evidence-provider.js.map +1 -1
  28. package/dist/explain.d.ts +18 -3
  29. package/dist/explain.d.ts.map +1 -1
  30. package/dist/explain.js +26 -5
  31. package/dist/explain.js.map +1 -1
  32. package/dist/field-accounting.d.ts +29 -0
  33. package/dist/field-accounting.d.ts.map +1 -0
  34. package/dist/field-accounting.js +132 -0
  35. package/dist/field-accounting.js.map +1 -0
  36. package/dist/files-reconciliation.d.ts +18 -0
  37. package/dist/files-reconciliation.d.ts.map +1 -0
  38. package/dist/files-reconciliation.js +59 -0
  39. package/dist/files-reconciliation.js.map +1 -0
  40. package/dist/index.d.ts +7 -3
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +4 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/loop-compiler.d.ts +5 -11
  45. package/dist/loop-compiler.d.ts.map +1 -1
  46. package/dist/loop-compiler.js +33 -102
  47. package/dist/loop-compiler.js.map +1 -1
  48. package/dist/loop-store.d.ts +3 -0
  49. package/dist/loop-store.d.ts.map +1 -1
  50. package/dist/loop-store.js +21 -11
  51. package/dist/loop-store.js.map +1 -1
  52. package/dist/mcp/round-lifecycle.d.ts +26 -2
  53. package/dist/mcp/round-lifecycle.d.ts.map +1 -1
  54. package/dist/mcp/round-lifecycle.js +193 -25
  55. package/dist/mcp/round-lifecycle.js.map +1 -1
  56. package/dist/mcp/server.d.ts.map +1 -1
  57. package/dist/mcp/server.js +17 -14
  58. package/dist/mcp/server.js.map +1 -1
  59. package/dist/mcp/session.d.ts +15 -1
  60. package/dist/mcp/session.d.ts.map +1 -1
  61. package/dist/mcp/session.js +34 -1
  62. package/dist/mcp/session.js.map +1 -1
  63. package/dist/mcp/submission-boundary.d.ts +6 -3
  64. package/dist/mcp/submission-boundary.d.ts.map +1 -1
  65. package/dist/mcp/submission-boundary.js +54 -9
  66. package/dist/mcp/submission-boundary.js.map +1 -1
  67. package/dist/mcp/tools.d.ts.map +1 -1
  68. package/dist/mcp/tools.js +73 -39
  69. package/dist/mcp/tools.js.map +1 -1
  70. package/dist/policy-metrics.d.ts +18 -0
  71. package/dist/policy-metrics.d.ts.map +1 -1
  72. package/dist/policy-metrics.js +67 -1
  73. package/dist/policy-metrics.js.map +1 -1
  74. package/dist/prompt-assembler.d.ts.map +1 -1
  75. package/dist/prompt-assembler.js +63 -11
  76. package/dist/prompt-assembler.js.map +1 -1
  77. package/dist/protocol.d.ts +207 -11
  78. package/dist/protocol.d.ts.map +1 -1
  79. package/dist/protocol.js +7 -1
  80. package/dist/protocol.js.map +1 -1
  81. package/dist/replay.d.ts +3 -0
  82. package/dist/replay.d.ts.map +1 -1
  83. package/dist/replay.js +46 -7
  84. package/dist/replay.js.map +1 -1
  85. package/dist/round-contract.d.ts +5 -4
  86. package/dist/round-contract.d.ts.map +1 -1
  87. package/dist/round-contract.js +4 -4
  88. package/dist/round-contract.js.map +1 -1
  89. package/dist/round-coordinator.d.ts +2 -1
  90. package/dist/round-coordinator.d.ts.map +1 -1
  91. package/dist/round-coordinator.js +17 -9
  92. package/dist/round-coordinator.js.map +1 -1
  93. package/dist/round-driver.d.ts +4 -1
  94. package/dist/round-driver.d.ts.map +1 -1
  95. package/dist/round-driver.js +2 -0
  96. package/dist/round-driver.js.map +1 -1
  97. package/dist/round-facts.d.ts +3 -2
  98. package/dist/round-facts.d.ts.map +1 -1
  99. package/dist/round-facts.js +4 -4
  100. package/dist/round-facts.js.map +1 -1
  101. package/dist/round-transaction.d.ts +21 -10
  102. package/dist/round-transaction.d.ts.map +1 -1
  103. package/dist/round-transaction.js +81 -19
  104. package/dist/round-transaction.js.map +1 -1
  105. package/dist/self-eval.d.ts +40 -10
  106. package/dist/self-eval.d.ts.map +1 -1
  107. package/dist/self-eval.js +543 -123
  108. package/dist/self-eval.js.map +1 -1
  109. package/dist/submission-diagnostics.d.ts +12 -0
  110. package/dist/submission-diagnostics.d.ts.map +1 -0
  111. package/dist/submission-diagnostics.js +12 -0
  112. package/dist/submission-diagnostics.js.map +1 -0
  113. package/dist/submission-guidance.d.ts +137 -0
  114. package/dist/submission-guidance.d.ts.map +1 -0
  115. package/dist/submission-guidance.js +855 -0
  116. package/dist/submission-guidance.js.map +1 -0
  117. package/dist/submission-receipt.d.ts +48 -0
  118. package/dist/submission-receipt.d.ts.map +1 -0
  119. package/dist/submission-receipt.js +341 -0
  120. package/dist/submission-receipt.js.map +1 -0
  121. package/dist/token-utils.d.ts +7 -0
  122. package/dist/token-utils.d.ts.map +1 -1
  123. package/dist/token-utils.js +15 -0
  124. package/dist/token-utils.js.map +1 -1
  125. package/dist/verification-gate.d.ts +7 -6
  126. package/dist/verification-gate.d.ts.map +1 -1
  127. package/dist/verification-gate.js +100 -117
  128. package/dist/verification-gate.js.map +1 -1
  129. package/dist/version.d.ts +1 -1
  130. package/dist/version.js +1 -1
  131. package/loop_policy.json +58 -58
  132. package/package.json +2 -1
  133. package/skills/perception/SKILL.md +71 -27
package/loop_policy.json CHANGED
@@ -1,58 +1,58 @@
1
- {
2
- "version": "5",
3
- "constraints": {
4
- "retire_window": 3
5
- },
6
- "summary": {
7
- "window": 5,
8
- "milestone_interval": 20
9
- },
10
- "engine": {
11
- "stall_lookback_rounds": 3,
12
- "max_rounds": 200,
13
- "enforcement_escalation_enabled": true,
14
- "backtrack_enabled": true,
15
- "backtrack_max_depth": 3,
16
- "backtrack_preserve_discoveries": true,
17
- "unverified_claim_streak_limit": 3
18
- },
19
- "prompt": {
20
- "l0_max_chars": 5000,
21
- "l1_max_chars": 10000,
22
- "l2_max_chars": 18000,
23
- "l2_pointer_enabled": true,
24
- "max_emphasize_l2": 5,
25
- "max_emphasize_l1": 3,
26
- "max_confusion_points": 3
27
- },
28
- "backend": {
29
- "root_dir": ".loopforge"
30
- },
31
- "evolution": {
32
- "max_discovered_constraints_per_round": 5,
33
- "max_active_constraints": 15,
34
- "max_objective_versions": 10,
35
- "max_active_subgoals": 12
36
- },
37
- "checkpoint": {
38
- "outcome_max_chars": 200
39
- },
40
- "state_file": {
41
- "enabled": true,
42
- "directory": ".loopforge/state"
43
- },
44
- "evidence": {
45
- "providers": [
46
- "git"
47
- ],
48
- "timeout_ms": 120000,
49
- "commands": []
50
- },
51
- "mcp": {
52
- "session_lease_ms": 30000,
53
- "session_lease_renew_interval_ms": 10000
54
- },
55
- "gate": {
56
- "enabled": false
57
- }
58
- }
1
+ {
2
+ "version": "5",
3
+ "constraints": {
4
+ "retire_window": 3
5
+ },
6
+ "summary": {
7
+ "window": 5,
8
+ "milestone_interval": 20
9
+ },
10
+ "engine": {
11
+ "stall_lookback_rounds": 3,
12
+ "max_rounds": 200,
13
+ "enforcement_escalation_enabled": true,
14
+ "backtrack_enabled": true,
15
+ "backtrack_max_depth": 3,
16
+ "backtrack_preserve_discoveries": true,
17
+ "unverified_claim_streak_limit": 3
18
+ },
19
+ "prompt": {
20
+ "l0_max_chars": 5000,
21
+ "l1_max_chars": 10000,
22
+ "l2_max_chars": 18000,
23
+ "l2_pointer_enabled": true,
24
+ "max_emphasize_l2": 5,
25
+ "max_emphasize_l1": 3,
26
+ "max_confusion_points": 3
27
+ },
28
+ "backend": {
29
+ "root_dir": ".loopforge"
30
+ },
31
+ "evolution": {
32
+ "max_discovered_constraints_per_round": 5,
33
+ "max_active_constraints": 15,
34
+ "max_objective_versions": 10,
35
+ "max_active_subgoals": 12
36
+ },
37
+ "checkpoint": {
38
+ "outcome_max_chars": 200
39
+ },
40
+ "state_file": {
41
+ "enabled": true,
42
+ "directory": ".loopforge/state"
43
+ },
44
+ "evidence": {
45
+ "providers": [
46
+ "git"
47
+ ],
48
+ "timeout_ms": 120000,
49
+ "commands": []
50
+ },
51
+ "mcp": {
52
+ "session_lease_ms": 30000,
53
+ "session_lease_renew_interval_ms": 10000
54
+ },
55
+ "gate": {
56
+ "enabled": false
57
+ }
58
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopforge",
3
- "version": "3.9.0",
3
+ "version": "3.9.2",
4
4
  "description": "External cognitive infrastructure for AI coding agents — breaks the summary cascade, provides independent verification, and enables model-directed prompt prioritization for 100+ round agent loops.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -40,6 +40,7 @@
40
40
  "test:watch": "node scripts/sync-version.mjs && tsc && node scripts/trim-dist.mjs && node --test --watch dist/tests/*.test.js",
41
41
  "check": "node scripts/sync-version.mjs && tsc --noEmit",
42
42
  "verify:artifacts": "node scripts/verify-artifacts.mjs",
43
+ "measure:boundary": "node scripts/measure-boundary.mjs",
43
44
  "prepack": "npm run verify:artifacts && npm run build"
44
45
  },
45
46
  "repository": {
@@ -66,10 +66,12 @@ objective, one evidence story, and one recovery path belong in the same round.
66
66
  Bind each item to a configured evidence command with `verify_with`, and limit
67
67
  `scope` to files or directories that slice may touch. The proposal becomes
68
68
  active only after its declaring round commits.
69
- While it is open, restating the same proposal continues it; a different
70
- proposal is ignored as `contract_premature`. If the slice is blocked, report
71
- `outcome: "blocked"` with a concrete `blocker` instead of silently replacing
72
- the active contract.
69
+ While it is open, you do **not** need to restate it: omitting `round_contract`
70
+ continues the active contract. A different proposal is ignored as
71
+ `contract_premature`. If this round closes the contract and another slice
72
+ follows, declare the successor in this same submission. If the slice is
73
+ blocked, report `outcome: "blocked"` with a concrete `blocker` instead of
74
+ silently replacing the active contract.
73
75
 
74
76
  This is a planning aid, not a second gate. LoopForge learns the plan only from
75
77
  committed evaluation fields, contract proposals, observations, and changes.
@@ -97,15 +99,39 @@ The four core evaluation fields are strict:
97
99
  | `constraint_violations` | Array of real violations, preferably using `c-XXXXXXXX` IDs. |
98
100
  | `should_continue` | Boolean. `false` only when the whole task is complete. |
99
101
 
100
- Useful optional fields include `execution_report` (`files_changed`,
101
- `tests_reported`, `criterion_claims`, and `contract_item_claims`),
102
- `discovered_constraints`, `emerged_subtasks`,
103
- `subgoal_updates`, `prompt_requests`, `round_contract`, `retroactiveClaims`,
104
- `gate_ids`, `worker_results`, and objective or constraint revisions.
102
+ Before submitting, check whether any of these events actually happened. Fill the
103
+ matching field only when it did; omit it otherwise.
104
+
105
+ | Event | Field | What LoopForge does with it |
106
+ | --- | --- | --- |
107
+ | The round changed files or ran tests | `execution_report.files_changed`, `execution_report.tests_reported` | Compares the report with machine observations; test counts stay self-reported |
108
+ | You found a constraint later rounds must respect | `discovered_constraints` | The compiler merges it into the active set |
109
+ | Evidence falsified an earlier assumption | `wrong_assumptions` | Feeds corrected-assumption state and recovery facts |
110
+ | A sub-problem surfaced | `emerged_subtasks` | The only sub-goal creation channel |
111
+ | An active sub-goal moved status | `subgoal_updates` | Applies an explicit transition |
112
+ | You delegated work | `worker_results` | Saves the report and delegation journal entry; does **not** promote worker discoveries |
113
+ | You are planning the next slice | `round_contract` | Becomes active only after this round commits |
114
+ | A contract item progressed | `execution_report.contract_item_claims` | Starts machine evaluation; the item is verified only when its bound commands pass |
115
+ | A success criterion moved | `execution_report.criterion_claims` | Advisory; cite the real `cr-` id/text from the prompt. Unknown references are dropped with a diagnostic; machine evidence still decides |
116
+ | You need context emphasized | `prompt_requests` | Exact-match reorder or confusion alerts in the next prompt; never long-term knowledge |
117
+ | You reached a meaningful boundary | `compression_checkpoint`, `checkpoint_label` | Creates a recoverable milestone |
118
+ | You are blocked or stopping | `outcome`, `blocker`, `stop_reason`, `no_change_reason` | Runs the corresponding stop/lifecycle rule |
119
+ | You understand the objective better | `objective_refinement` | Appends to the objective; never replaces it |
120
+ | A constraint or criterion is wrong | `retracted_constraints`, `revised_success_criteria` | Updates derived state within existing boundaries |
121
+ | You need a prior approval checked | `gate_ids`; `retroactiveClaims` | Checks existing gate references or prior-round evidence |
122
+
123
+ `execution_report.files_changed` is the **boundary net change**: paths whose
124
+ content or file type differs between round preparation and this submission,
125
+ including deletions. A commit alone adds no entry when content is unchanged.
126
+ Do not list gitignored paths merely to look complete. The receipt's
127
+ `files_reconciliation` block compares your report with the machine change set
128
+ and reports match/mismatch/unknown/not_applicable; an unobservable Git boundary
129
+ is `unknown`, never an empty diff.
105
130
 
106
131
  `emerged_subtasks` is the only sub-goal creation channel. It contains plain
107
132
  descriptions, never `sg-` IDs. `subgoal_updates` changes existing active IDs;
108
- done and canceled are terminal and cannot be reopened.
133
+ done and canceled are terminal and cannot be reopened. The prompt or
134
+ `submission_guidance` renders the real active IDs; never invent one.
109
135
 
110
136
  `outcome` may be `success`, `partial`, `failed`, or `blocked`. A blocked
111
137
  outcome needs a concrete `blocker`; `stop_reason` of `blocked` or
@@ -118,14 +144,24 @@ and workspace-containment errors return `evaluation_invalid` or
118
144
  `contract_invalid` before advance. Correct the payload and resubmit the same
119
145
  `roundId`; nothing is committed and no rejection counter moves.
120
146
 
121
- Every successful round still needs an `execution_report` with
122
- `files_changed` and `tests_reported`. `no_change_reason` is an escape only when
123
- no enabled verification command exists. It never creates evidence and never
124
- excuses an open contract.
147
+ A successful round should include an `execution_report`. An empty or missing
148
+ report is a reporting gap (a `warn`), not by itself a rejection: acceptance is
149
+ decided by machine evidence and contract rules, never by how many optional
150
+ fields were filled. `no_change_reason` is an escape only when no enabled
151
+ verification command exists. It never creates evidence and never excuses an
152
+ open contract.
125
153
 
126
154
  Agent reports are claims quoted for audit. They never become verified facts.
127
- Do not infer a missing field from natural language or put a guessed evaluation
128
- in free text.
155
+ Do not infer a missing field from natural language, do not fill a field to
156
+ satisfy a coverage check, and do not put a guessed evaluation in free text.
157
+ When no event occurred, omit the field.
158
+
159
+ Each prepared response carries `submission_guidance` with the real contract
160
+ item ids/statuses, active sub-goal ids, real criterion ids/text, usable
161
+ commands and the fields that apply now. Each submission returns
162
+ `submission_receipt`, which separates: reports that were saved, derived state
163
+ that actually changed, and machine verification results, plus the structured
164
+ `files_reconciliation` block. A report marked `saved` is not a verified fact.
129
165
 
130
166
  ## IDs and contracts
131
167
 
@@ -197,11 +233,12 @@ workspace. `loopforge doctor` statically checks every configured command —
197
233
  its name, executable, arguments, timeouts, and workspace containment — and
198
234
  never executes one.
199
235
 
200
- Every prepared round returns `capability`: which providers are available, which
201
- commands are enabled and after-capable, and `contractVerificationAvailable`.
202
- When that is `false`, no configured command can back a contract item: run
203
- rounds without a contract instead of declaring items that cannot close. The
204
- `warnings` list states the same thing in words.
236
+ Every prepared response carries `submission_guidance.contract_commands` and
237
+ `submission_guidance.contract_verification_available`; `loopforge_status`
238
+ `view=session` also returns the full `capability` object. When verification is
239
+ unavailable, no configured command can back a contract item: run rounds without
240
+ a contract instead of declaring items that cannot close. The `warnings` list
241
+ states the same thing in words.
205
242
 
206
243
  A command's ENTRYPOINT is the file it names plus `package.json` when a package
207
244
  manager runs it. It must already be part of the workspace when the round
@@ -260,11 +297,15 @@ same submission. Restating the stalled contract commits more of the same.
260
297
  prompt and round ID.
261
298
  - Null `prompt`: inspect `stopReason`.
262
299
 
263
- Read `verificationStatus`, `roundSuccess`, `level`, `warnings`, and
264
- `enforcementReason` before planning the next slice. `trusted` means claimed
265
- work is machine-backed, `insufficient` means evidence is missing, and
266
- `contradicted` means a machine fact denies a claim. These are evidence
267
- postures, not subjective quality scores.
300
+ Read `submission_guidance` before composing the next evaluation, and read
301
+ `verificationStatus`, `roundSuccess`, `level`, `warnings`, and
302
+ `enforcementReason` before planning the next slice. In
303
+ `submission_receipt.verification`, `contract_status` is the contract-item
304
+ posture and `evidence_status` is the round-level machine evidence posture; do
305
+ not read "no active contract" as "verified". `submission_receipt.reports`
306
+ distinguishes a saved report from derived state that changed and from a machine
307
+ verification result; `not_applied` means the submission did not become history.
308
+ These are evidence postures, not subjective quality scores.
268
309
 
269
310
  Errors use `{ok: false, error: {code, message, retryable, ...}}`. Branch on the
270
311
  stable `code`, not the prose in `message`. Payload errors such as
@@ -312,7 +353,10 @@ call. Safe investigation and dry-runs need no gate.
312
353
 
313
354
  Delegation does not create another LoopForge mode. Give each worker a
314
355
  self-contained subtask and hard constraints, then place the result in
315
- `worker_results` so it can enter the next Canonical State.
356
+ `worker_results`. A worker result is a report with its source: its
357
+ `discoveredConstraints` does **not** enter the global constraint set by itself.
358
+ If you accept a worker's finding, state it in top-level
359
+ `discovered_constraints` — that is the only promotion channel.
316
360
 
317
361
  ## Rules
318
362