infinity-harness 2.1.0 → 2.2.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,72 @@ All notable changes to this project are documented here.
4
4
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.2.0] — 2026-08-23
8
+
9
+ Nine modules shipped in this package, typechecked, and passed their tests while no code path in the
10
+ running product could reach a single one — about 2,800 lines, advertised in the README. They are all
11
+ connected now, and connecting them found four reasons the most important of them had never worked.
12
+
13
+ ### Added
14
+
15
+ - **The escalation ladder actually escalates.** `unstuck.ts` could always *choose* what to do when a
16
+ run stalled — retry → reframe → consult → rework → replan → master, with budgets, fingerprint
17
+ dedup and a cooldown — and nothing ever executed one. It was a chooser with no actuator, so
18
+ `/infinity:run` did the only thing it could when the gate kept failing: count three strikes and
19
+ stop. `src/escalate.ts` is the actuator. On a stall it climbs a rung, does the part that is ours
20
+ (flipping tasks to `rework`, naming the model to escalate to) and hands the agent an instruction
21
+ for the part that is the agent's. Every rung says something different; a run that gives up now
22
+ names every rung it spent first.
23
+ - **The goal loop turns.** `goalSpec`, `goalLoop` and `goalState` are a complete outer loop that
24
+ nothing ever drove, which meant the harness could finish a pipeline and declare "complete" without
25
+ anyone asking whether the thing the human asked for was done. `src/goal.ts` drives it, and the
26
+ mapping is the design: **one goal iteration is one full pass of the pipeline.** `/infinity:goal
27
+ <what you want>` states it; when the pipeline finishes, the run asks whether the GOAL is met, not
28
+ whether the plan is. A verdict of anything but `complete` must name what is still missing, and the
29
+ pipeline rewinds to the first phase with that list carried into the brief — so the next pass plans
30
+ for the remainder instead of rebuilding what the last review already accepted.
31
+ - **Five tools and three commands** for what was previously unreachable: `infinity_unstuck`,
32
+ `infinity_rework`, `infinity_replan`, `infinity_spawn_worker`, `infinity_goal`, and
33
+ `/infinity:goal`, `/infinity:unstuck`, `/infinity:rework`.
34
+ - **A `skills-load` advisory gate check.** The skills audit was the ninth orphan. It now runs at
35
+ DEFINE and REVIEW over any skills a project ships, so a project finds out that pi will print a
36
+ `[Skill conflicts]` block before its users do. Advisory: a malformed skill does not make the code
37
+ wrong.
38
+ - **The widget shows which pass you are on and the last rung taken.** A second pass at a goal looks
39
+ identical to a first one in every other part of the display, which is exactly when someone glances
40
+ at a half-full progress bar and walks away thinking it is nearly done.
41
+ - **Two E2E scenarios** — `escalation` and `goal` — driving both through the real adapter over real
42
+ projects, and the reachability allowlist in the `package` scenario is now **empty**.
43
+
44
+ ### Fixed
45
+
46
+ Wiring the ladder in exposed why it had never worked, none of which its own passing tests could see:
47
+
48
+ - **`reframe` had no budget**, so it was eligible forever and shadowed every rung below it. The
49
+ ladder could not climb past rung two — `consult`, `rework`, `replan` and `master` were unreachable
50
+ through the function whose job was to reach them.
51
+ - **`rework` and `replan` were vetoed unless the working tree had moved.** A stall is *defined* by
52
+ the tree not moving, so the two rungs that exist for exactly this situation could never fire in
53
+ it. That guard is a review-bounce policy — do not bounce REVIEW backwards again if nothing changed
54
+ — and it stays that for review bounces; the stuck ladder opts out explicitly.
55
+ - **The budgets counted effects on disk**, which only appear if the agent acts on the advice. A
56
+ stuck agent does not, so the budget never moved and the ladder jammed, offering `replan` forever.
57
+ Each rung now gets one turn per stall; the on-disk budgets still bound the run across stalls.
58
+ - **MASTER defaulted to a specific third-party model** — in a package whose 2.0.0 release promised
59
+ every routing slot ships empty. The last rung of the ladder silently redirected the hardest work
60
+ in the run to one vendor. It is `null` now, meaning "whatever pi is configured with", unless the
61
+ user chose one.
62
+
63
+ ### Changed
64
+
65
+ - A stalled iteration consults the ladder before the no-progress strike is spent, and a new rung
66
+ resets the streak — a different attempt is not another repetition of the same one. This cannot run
67
+ forever: every rung is bounded, so the ladder runs out, returns nothing, and the run stops with a
68
+ full account of what was tried.
69
+ - `loop-state.json` carries the ladder's position. State written before it existed loads fine.
70
+
71
+ ---
72
+
7
73
  ## [2.1.0] — 2026-08-23
8
74
 
9
75
  You could not start, and if you had, you could not have got past the first gate. Both are fixed.
package/README.md CHANGED
@@ -99,6 +99,9 @@ the craft skills that match the work, and what to do next. Do the work, then:
99
99
  /infinity:config change any setting, including which model runs which tier
100
100
  /infinity:models what models pi has, and how they are being routed
101
101
  /infinity:dashboard open the live web view
102
+ /infinity:goal state a goal and pursue it across passes
103
+ /infinity:unstuck what the escalation ladder would try next
104
+ /infinity:rework send a task and its dependents backwards
102
105
  /infinity:halt take the wheel back
103
106
  ```
104
107
 
@@ -164,6 +167,49 @@ define → plan → build → verify → [simplify] → review → ship
164
167
 
165
168
  Enable or disable phases in `harness/config.json` under `phases.enabled`. SIMPLIFY is off by default.
166
169
 
170
+ ## When it gets stuck
171
+
172
+ Stopping safely is the easy half. The hard half is trying something *else* first, and that is the
173
+ escalation ladder: when a run stalls — the gate fails and the working tree has not moved, meaning
174
+ the agent produced nothing — `/infinity:run` climbs it before spending a strike.
175
+
176
+ | Rung | What it does |
177
+ |---|---|
178
+ | **retry** | One more attempt. Sometimes a run is just slow. |
179
+ | **reframe** | State the assumption you have been working under, say why the evidence contradicts it, then try a different approach. |
180
+ | **consult** | Escalate to a stronger model, one step up the difficulty ladder. |
181
+ | **rework** | Flip the task and everything that depends on it back to `rework`. Work built on a broken thing is suspect until re-proved. |
182
+ | **replan** | The plan is wrong: something this needed was never planned. Amend it. |
183
+ | **master** | Last resort. State the problem from scratch, including what has been ruled out. |
184
+
185
+ Each rung gets one turn per stall, and each is bounded — reworks and replans have budgets, `consult`
186
+ has a per-task limit, `master` fires once per run. When the ladder runs out, the run stops and names
187
+ every rung it spent. Real progress resets it: a moving tree means a new problem, and a new problem
188
+ gets a fresh ladder.
189
+
190
+ `/infinity:unstuck` shows what it would try next without doing it.
191
+
192
+ ## Goals, and knowing when you are actually done
193
+
194
+ A finished pipeline is not a met goal. The gate decides whether the **work** is done; it has no
195
+ opinion on whether the work was the *right* work, because it only ever sees the plan — and the plan
196
+ is just what you thought the goal needed when you wrote it.
197
+
198
+ ```
199
+ /infinity:goal Ship the payments rewrite behind a flag
200
+ ```
201
+
202
+ That states the goal and starts pass 1. One pass at the goal is one full trip through the pipeline.
203
+ When the pipeline completes, the run does not end: it asks whether the goal is met.
204
+
205
+ - **complete** ends the run.
206
+ - Anything else must name what is still missing — and the pipeline rewinds to the first phase with
207
+ that list carried into the brief, so the next pass plans for the remainder rather than rebuilding
208
+ what the last review already accepted.
209
+
210
+ Bounded by an iteration ceiling and a wall clock, both configurable. The widget shows which pass you
211
+ are on, because a second pass looks exactly like a first one otherwise.
212
+
167
213
  ## Knowing when to stop
168
214
 
169
215
  This is the part that makes an unattended run safe. `/infinity:run` halts on any of:
@@ -284,6 +330,11 @@ that looks like a broken endpoint but is only a small cap.
284
330
  | `infinity_validate` | Run the gate for this phase |
285
331
  | `infinity_advance` | Move to the next phase (refuses on a failing gate) |
286
332
  | `infinity_dashboard` | Start/stop/query the web view |
333
+ | `infinity_unstuck` | What should I try next? (recommends; does not act) |
334
+ | `infinity_rework` | Send a task and its dependents back to rework |
335
+ | `infinity_replan` | Add what the plan was missing, mid-run |
336
+ | `infinity_spawn_worker` | Attempt one task in a clean-room worker |
337
+ | `infinity_goal` | State a goal, review it, or check which pass it is on |
287
338
 
288
339
  ## Layout
289
340
 
@@ -296,19 +347,21 @@ infinity-harness/
296
347
  │ │ · skills (match) · skillsAudit (guard)
297
348
  │ ├── ui/ theme · widget (terminal) · dashboard (web)
298
349
  │ ├── loop.ts the continuous-run driver and its stop conditions
350
+ │ ├── escalate.ts the ladder's actuator: chooses a rung and takes it
351
+ │ ├── goal.ts the outer loop: is the thing asked for actually done?
299
352
  │ ├── taskList.ts atomic plan editor
300
353
  │ ├── worker.ts isolated per-task workers
301
354
  │ ├── modelRouter.ts difficulty ladder + consultation
302
355
  │ ├── rework.ts · replan.ts backward rework with BFS impact · mid-build amendment
303
356
  │ ├── unstuck.ts · review.ts escalation strategy matrix · review bounce guard
304
- │ └── goalLoop.ts · goalState.ts · goalSpec.ts
357
+ │ └── goalLoop.ts · goalState.ts · goalSpec.ts goal state machine and its store
305
358
  ├── harness/
306
359
  │ ├── features/feature-list.json the plan
307
360
  │ ├── config.json pipeline state and settings
308
361
  │ ├── model-router.json optional routing
309
362
  │ ├── docs/ architecture · decisions · phase and role docs
310
363
  │ └── skills/ 28 craft skills the brief points at
311
- ├── tests/ 25 files, plain node:assert
364
+ ├── tests/ 28 files, plain node:assert
312
365
  └── scripts/run-tests.mjs
313
366
  ```
314
367
 
@@ -320,7 +373,7 @@ there is one implementation, and the adapter calls it.
320
373
  ```bash
321
374
  npm install
322
375
  npm run check # tsc --noEmit
323
- npm test # 25 test files
376
+ npm test # 28 test files
324
377
  npm run e2e # end-to-end against a live model
325
378
  ```
326
379