infinity-harness 2.2.0 → 2.2.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ 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.1] — 2026-08-23
8
+
9
+ ### Fixed
10
+
11
+ - **Reviewing a goal before the pipeline finished threw an internal error.** `GoalLoopStateError:
12
+ Cannot update goal iteration 2 from status pending` — a phase name from inside the state machine,
13
+ thrown at whoever called the tool. Reviewing early is legitimate: you can see a pass will not meet
14
+ the goal well before the pipeline agrees, and waiting for a doomed pipeline to finish first is
15
+ theatre. The review now records the pass itself and answers.
16
+
17
+ Found by running the shipped package against a real project, in the first minute. Every test
18
+ recorded a pipeline pass before reviewing, so not one of them ever asked what happens when a
19
+ review arrives without one.
20
+
21
+ ---
22
+
7
23
  ## [2.2.0] — 2026-08-23
8
24
 
9
25
  Nine modules shipped in this package, typechecked, and passed their tests while no code path in the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infinity-harness",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "A pi agent extension that runs a gated build pipeline unattended \u2014 enforces phases, validates with deterministic gates, and keeps working for hours or days without losing the plan.",
5
5
  "type": "module",
6
6
  "keywords": [
package/src/goal.ts CHANGED
@@ -262,6 +262,17 @@ export async function reviewGoal(
262
262
  return { state, terminal: true, message: `The goal loop already finished: ${state.status}.`, rewoundTo: null };
263
263
  }
264
264
 
265
+ // A review can legitimately arrive before the pipeline finishes: someone can
266
+ // already see that this pass will not meet the goal, and making them wait
267
+ // for a doomed pipeline to complete first is theatre. The state machine only
268
+ // accepts a verdict on an iteration that has recorded its work, so record it
269
+ // — otherwise the caller gets `Cannot update goal iteration 2 from status
270
+ // pending`, which names an internal phase and helps nobody.
271
+ if (state.phase === "goal_received" || state.phase === "todo_generated") {
272
+ const caught = await recordPipelinePass(targetDir, "reviewed before the pipeline finished", now);
273
+ if (caught) state = caught;
274
+ }
275
+
265
276
  const at = (now ?? new Date()).toISOString();
266
277
  const remainingWork = (input.remainingWork ?? []).map((s) => s.trim()).filter(Boolean);
267
278
  if (input.decision !== "complete" && remainingWork.length === 0) {