pi-gauntlet 7.33.0 → 7.34.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 +8 -0
- package/README.md +1 -1
- package/extensions/lib/gauntlet-settings.test.ts +29 -5
- package/extensions/lib/gauntlet-settings.ts +14 -6
- package/extensions/lib/plan-check.test.ts +3 -1
- package/extensions/phase-tracker.test.ts +16 -7
- package/package.json +2 -2
- package/skills/brainstorming/reference/ticket-acceptance.md +1 -0
- package/skills/gauntlet-resume/SKILL.md +2 -2
- package/skills/gauntlet-resume/reference/brief-contract.md +3 -3
- package/skills/gauntlet-resume/reference/reconstruction.md +1 -1
- package/skills/loop-implementation/SKILL.md +15 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v7.34.0 - 2026-10-26
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Breaking:** `piGauntlet.loopEngine.maxIterations` is removed, not aliased; use `piGauntlet.loopEngine.maxIterationsPerRow` (default 4, integer floor 1). The loop seeds a durable ledger `cap:` from non-cut rows times that multiplier plus one seed dispatch. Cuts and reopening preserve the cap; redraw recomputes it. Clean cap stops accept durable `cap +N` grants without resetting attempts or iterations, and resume restores the ledger cap without settings. Legacy ledgers missing `cap:` stop for a grant based on consumed iterations.
|
|
8
|
+
- Drafted tree-wide or set-wide negative acceptance rows split into one row per family explicitly enumerated in Design, preserving every outcome. An absent, partial or unrelated enumeration stops spec-writing for clarification; ticket rows stay verbatim.
|
|
9
|
+
- pi-cohort peer floor raised to 7.5.0.
|
|
10
|
+
|
|
3
11
|
## v7.33.0 - 2026-10-26
|
|
4
12
|
|
|
5
13
|
### Changed
|
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ Run by a human against pi-cohort >= 7.1.0, before a pi-gauntlet release claims t
|
|
|
126
126
|
## Requirements
|
|
127
127
|
|
|
128
128
|
- [pi-coding-agent](https://github.com/earendil-works/pi) ≥ 0.85.1 - tested minimum for sequential `phase_tracker` tool execution, which persists a tracker update before a later tool call in the same model message.
|
|
129
|
-
- [pi-cohort](https://github.com/jjuraszek/pi-cohort) >= 7.
|
|
129
|
+
- [pi-cohort](https://github.com/jjuraszek/pi-cohort) >= 7.5.0 - required peer package, including binary-safe worktree patches; it also lets a persona with `subagent` in `tools:` start with inherited extensions ([pi-cohort #26](https://github.com/jjuraszek/pi-cohort/issues/26)), which multi-PR `gatekeep-pr` needs. Skills that dispatch agents (`requesting-code-review`, `subagent-driven-development`, `dispatching-parallel-agents`, `writing-plans`, `forge-skill`, `shape-ticket`, `roasting-the-spec`) call `subagent({})`, which pi-cohort provides. pi-gauntlet does not vendor the dispatch tool; without pi-cohort those skills have nothing to call. Gauntlet execution dispatches explicitly use `async: false`; do not enable pi-cohort's incompatible `forceTopLevelAsync` setting. See pi-cohort's [dispatch configuration](https://github.com/jjuraszek/pi-cohort/blob/main/doc/configuration.md) for that setting's owner and semantics. A wave of N >= 1 tasks dispatches its implementers and first spec reviews as one chain call. `subagent-driven-development` stops before dispatch on unsupported installs; there is no older-runtime fallback.
|
|
130
130
|
|
|
131
131
|
Both packages must be listed in your `.pi/settings.json#packages` array (pi adds them automatically when you `pi install`). pi-gauntlet and pi-cohort are versioned independently but release together whenever dispatch semantics change - pin compatible versions of both. At each pi-gauntlet release, set the pi-cohort peer minimum and README floor together to the newest released pi-cohort version; `/skill:release` checks the registry before proceeding.
|
|
132
132
|
|
|
@@ -21,12 +21,36 @@ import {
|
|
|
21
21
|
} from "./gauntlet-settings.ts";
|
|
22
22
|
|
|
23
23
|
test("loopEngine resolves defaults, integers, clamps, and malformed values", () => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
const warning = "loopEngine.maxIterationsPerRow must be an integer; using default 4";
|
|
25
|
+
for (const [raw, expected, expectedWarning] of [
|
|
26
|
+
[undefined, 4, undefined], [7, 7, undefined], [0, 1, undefined], [-3, 1, undefined],
|
|
27
|
+
["4", 4, warning], [4.5, 4, warning], [true, 4, warning], [null, 4, warning],
|
|
28
|
+
] as const) {
|
|
29
|
+
assert.deepEqual(resolveLoopEngine({ loopEngine: { maxIterationsPerRow: raw } }), {
|
|
30
|
+
maxIterationsPerRow: expected, warning: expectedWarning,
|
|
31
|
+
});
|
|
28
32
|
}
|
|
29
|
-
assert.deepEqual(resolveLoopEngine({}), {
|
|
33
|
+
assert.deepEqual(resolveLoopEngine({}), { maxIterationsPerRow: 4, warning: undefined });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("loopEngine ignores the removed key by own-property presence and orders warnings", () => {
|
|
37
|
+
const removed = "loopEngine.maxIterations is removed; set loopEngine.maxIterationsPerRow";
|
|
38
|
+
for (const raw of [30, undefined, null, false]) {
|
|
39
|
+
assert.deepEqual(resolveLoopEngine({ loopEngine: { maxIterations: raw } }), {
|
|
40
|
+
maxIterationsPerRow: 4, warning: removed,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
for (const [raw, expected, warning] of [
|
|
44
|
+
[7, 7, removed],
|
|
45
|
+
["4", 4, removed + "; loopEngine.maxIterationsPerRow must be an integer; using default 4"],
|
|
46
|
+
] as const) {
|
|
47
|
+
assert.deepEqual(resolveLoopEngine({ loopEngine: { maxIterations: 99, maxIterationsPerRow: raw } }), {
|
|
48
|
+
maxIterationsPerRow: expected, warning,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
assert.deepEqual(resolveLoopEngine({ loopEngine: Object.create({ maxIterations: 99 }) }), {
|
|
52
|
+
maxIterationsPerRow: 4, warning: undefined,
|
|
53
|
+
});
|
|
30
54
|
});
|
|
31
55
|
|
|
32
56
|
const CUSTOM_TEST_COMMANDS = ["make ci", "pytest"];
|
|
@@ -11,7 +11,7 @@ export interface PiGauntlet {
|
|
|
11
11
|
flowGuards?: { enforce?: unknown; specDirs?: unknown };
|
|
12
12
|
verifyBeforeShip?: { testCommands?: unknown; warningReference?: unknown };
|
|
13
13
|
escalationLoop?: { implModel?: unknown };
|
|
14
|
-
loopEngine?: { maxIterations?: unknown };
|
|
14
|
+
loopEngine?: { maxIterationsPerRow?: unknown; maxIterations?: unknown };
|
|
15
15
|
phaseModels?: { plan?: unknown; implement?: unknown; verify?: unknown; ship?: unknown };
|
|
16
16
|
telemetry?: { enabled?: unknown; dir?: unknown; buckets?: unknown };
|
|
17
17
|
}
|
|
@@ -93,11 +93,19 @@ export function resolveClosureReview(g: PiGauntlet): ClosureReviewResolved {
|
|
|
93
93
|
return { model, enforce, maxFixRounds };
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
export function resolveLoopEngine(g: PiGauntlet): {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
export function resolveLoopEngine(g: PiGauntlet): { maxIterationsPerRow: number; warning: string | undefined } {
|
|
97
|
+
const loop = g.loopEngine;
|
|
98
|
+
const raw = loop?.maxIterationsPerRow;
|
|
99
|
+
const valid = typeof raw === "number" && Number.isInteger(raw);
|
|
100
|
+
const maxIterationsPerRow = valid ? Math.max(1, raw) : 4;
|
|
101
|
+
const warnings: string[] = [];
|
|
102
|
+
if (loop && Object.hasOwn(loop, "maxIterations")) {
|
|
103
|
+
warnings.push("loopEngine.maxIterations is removed; set loopEngine.maxIterationsPerRow");
|
|
104
|
+
}
|
|
105
|
+
if (raw !== undefined && !valid) {
|
|
106
|
+
warnings.push("loopEngine.maxIterationsPerRow must be an integer; using default 4");
|
|
107
|
+
}
|
|
108
|
+
return { maxIterationsPerRow, warning: joinWarn(warnings) };
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
export interface EscalationLoopResolved {
|
|
@@ -16,7 +16,9 @@ const ledger = (rows = ["1 | open | 0 |", "2 | cut | 0 | deferred: #70", "3 | do
|
|
|
16
16
|
"# Ledger - loop engine\n**Spec:** `doc/specs/test.md`\nbase: abc\nverification: check\niterations: 0\n\n| row | status | attempts | evidence |\n|---|---|---|---|\n" + rows.map(r => `| ${r} |`).join("\n") + "\n\n## Decisions\n";
|
|
17
17
|
|
|
18
18
|
test("ledger admission bypasses task checks and permits empty open evidence", () => {
|
|
19
|
-
|
|
19
|
+
for (const input of [ledger(), ledger().replace("iterations: 0\n", "iterations: 0\ncap: 97\n")]) {
|
|
20
|
+
assert.deepEqual(checkPlan(input, ledgerSpec, { exists: () => false, glob: () => [] }), []);
|
|
21
|
+
}
|
|
20
22
|
});
|
|
21
23
|
for (const [name, rows] of Object.entries({
|
|
22
24
|
missing: ["1 | open | 0 |"],
|
|
@@ -1404,11 +1404,18 @@ test("gauntlet_setting escalationLoop: setting absent -> ctx-derived main-loop m
|
|
|
1404
1404
|
});
|
|
1405
1405
|
|
|
1406
1406
|
test("gauntlet_setting loopEngine resolves the key", async () => {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1407
|
+
for (const [loopEngine, expected, warning] of [
|
|
1408
|
+
[undefined, 4, undefined],
|
|
1409
|
+
[{ maxIterationsPerRow: 8 }, 8, undefined],
|
|
1410
|
+
[{ maxIterations: 99, maxIterationsPerRow: "4" }, 4,
|
|
1411
|
+
"loopEngine.maxIterations is removed; set loopEngine.maxIterationsPerRow; loopEngine.maxIterationsPerRow must be an integer; using default 4"],
|
|
1412
|
+
] as const) {
|
|
1413
|
+
const h = harness({ cwd: tempCwd({ piGauntlet: { loopEngine } }) });
|
|
1414
|
+
const tool = h.tools.find(t => t.name === "gauntlet_setting")!;
|
|
1415
|
+
const result = await tool.execute("loop", { key: "loopEngine" }, undefined, undefined, h.ctx) as any;
|
|
1416
|
+
assert.deepEqual(result.details, { key: "loopEngine", maxIterationsPerRow: expected, warning, errors: [] });
|
|
1417
|
+
assert.equal(Object.hasOwn(result.details, "maxIterations"), false);
|
|
1418
|
+
}
|
|
1412
1419
|
});
|
|
1413
1420
|
|
|
1414
1421
|
test("gauntlet_setting loopEngine composes settings load warnings", async () => {
|
|
@@ -1416,9 +1423,11 @@ test("gauntlet_setting loopEngine composes settings load warnings", async () =>
|
|
|
1416
1423
|
writeFileSync(join(dir, ".pi/settings.json"), "{");
|
|
1417
1424
|
const h = harness({ cwd: dir });
|
|
1418
1425
|
const result = await h.tools.find(t => t.name === "gauntlet_setting")!.execute("loop", { key: "loopEngine" }, undefined, undefined, h.ctx) as any;
|
|
1419
|
-
assert.equal(result.details.
|
|
1426
|
+
assert.equal(result.details.key, "loopEngine");
|
|
1427
|
+
assert.equal(result.details.maxIterationsPerRow, 4);
|
|
1428
|
+
assert.equal(Object.hasOwn(result.details, "maxIterations"), false);
|
|
1420
1429
|
assert.ok(result.details.errors.length);
|
|
1421
|
-
assert.
|
|
1430
|
+
assert.equal(result.details.warning, `⚠️ gauntlet settings load error (using defaults): ${result.details.errors.join("; ")}`);
|
|
1422
1431
|
});
|
|
1423
1432
|
|
|
1424
1433
|
test("ledger handler stamps after brainstorm and skipped plan, then admits implement", async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-gauntlet",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.34.0",
|
|
4
4
|
"description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
|
|
5
5
|
"author": "Jacek Juraszek",
|
|
6
6
|
"type": "module",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"test": "node scripts/ci.mjs"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"pi-cohort": ">=7.
|
|
65
|
+
"pi-cohort": ">=7.5.0"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"yaml": "^2.9.0"
|
|
@@ -42,6 +42,7 @@ Apply these integrity classes inline without invoking ticket shaping. Preserve e
|
|
|
42
42
|
|---|---|
|
|
43
43
|
| Wishful | Rewrite to the design's observable with design-sourced baseline, target, and measurement |
|
|
44
44
|
| Tautological | Rewrite to a design-sourced, already-enumerated set or observable |
|
|
45
|
+
| Tree-wide | Split a drafted row requiring zero/no findings of one or several kinds anywhere in or across a tree or set into one row per family from the explicit complete enumeration in Design for that row, covering every kind it names; give each family's own observable and preserve every outcome across the resulting rows. For an absent, partial, or unrelated enumeration, stop before writing, quote the row, and request the complete enumeration in Design. Keep this recovery drafted-only: a ticket row of this shape stays one verbatim row; require human ticket repair through `/skill:shape-ticket` before approval to split it |
|
|
45
46
|
| Unspecified-but-binding | Resolve the value from Design and record the resolution there; ask the user for a missing value |
|
|
46
47
|
| External-input | Ask the user for the external yardstick before writing |
|
|
47
48
|
| Post-deployment | Rewrite to a pre-production observation when available, retaining `venue:`; move production-only observations to a tracked, non-blocking `Post-deployment housekeeping` Design clause, never an AC row |
|
|
@@ -144,9 +144,9 @@ owning skill **without** its reset-bearing entry:
|
|
|
144
144
|
| brainstorm | [brainstorming checklist](../brainstorming/SKILL.md#checklist) | on-disk state decides the step: draft marker on line 1 of the spec file -> step 4; spec title -> step 8. Never `/skill:brainstorming` entry (it resets both trackers) |
|
|
145
145
|
| approved spec with `**Engine:** loop`, no ledger | loop-implementation | after check 6, arm with `start brainstorm`, then `skip brainstorm resume: <spec path>` before driver admission; carry absolute worktree/spec paths and plan directory through Entry steps 1-5 per `reference/reconstruction.md` "Spec without plan": settings step 1, verification step 2, driver's plan skip step 3, ledger creation step 4, check/commit and implement start step 5; no writing-plans body or task tracker |
|
|
146
146
|
| plan with task engine | writing-plans body | skip its `start plan` call (already in_progress) |
|
|
147
|
-
| implement with line-1 ledger | loop-implementation | complete `reference/reconstruction.md` "Spec with ledger" ordered restore, cited by `reference/brief-contract.md`'s call table: entry checks 1-6, brainstorm start/skip, plan start/check/skip with reason `resume: <spec> (loop engine)`, implement start, no task tracker; state the entire ordered sequence explicitly even when entry checks are already reported as passed; then continue at step 5 (`Before each dispatch`), preserving ledger iterations/retry data; dirty tree stops before dispatch; reuse the existing ledger |
|
|
147
|
+
| implement with line-1 ledger | loop-implementation | complete `reference/reconstruction.md` "Spec with ledger" ordered restore, cited by `reference/brief-contract.md`'s call table: entry checks 1-6, brainstorm start/skip, plan start/check/skip with reason `resume: <spec> (loop engine)`, implement start, no task tracker; state the entire ordered sequence explicitly even when entry checks are already reported as passed; then continue at step 5 (`Before each dispatch`), applying the shared cap boundary in reconstruction step 4 before continuation and preserving ledger cap, iterations/retry data; dirty tree stops before dispatch; reuse the existing ledger |
|
|
148
148
|
| implement with task plan | subagent-driven-development | re-validate `<task>` first (re-run its `Tests:`), then the task loop from the first non-complete task |
|
|
149
|
-
| verify with `Ledger:` (including ship-stage ledger briefs restored at verify) | /skill:loop-implementation | read `After the loop` and its references; continue from step 1, full ledger verification, after the already-restored `start verify`; retain whole-diff code review, happy path when triggered, fresh conformance review and finishing; no task-tracker calls |
|
|
149
|
+
| verify with `Ledger:` (including ship-stage ledger briefs restored at verify) | /skill:loop-implementation | apply the shared cap boundary in `reference/reconstruction.md` "Spec with ledger" step 4 before verification; render cap and restored ledger state; read `After the loop` and its references; continue from step 1, full ledger verification, after the already-restored `start verify`; retain whole-diff code review, happy path when triggered, fresh conformance review and finishing; no task-tracker calls |
|
|
150
150
|
| verify without `Ledger:` | verification-before-completion | full conformance gate; nothing carried over |
|
|
151
151
|
|
|
152
152
|
## Red flags — STOP
|
|
@@ -149,12 +149,12 @@ announcement without re-resolving it.
|
|
|
149
149
|
|---|---|
|
|
150
150
|
| brainstorm | `start brainstorm`; `substep` if the brief shows one |
|
|
151
151
|
| plan | `start brainstorm`; `skip brainstorm S`; `start plan`; `substep` if shown |
|
|
152
|
-
| implement with ledger | Read ledger line 1; resolve its path-only `**Spec:**` header; run entry checks 1-6, naming check 6 (Grant field); `start brainstorm`; `skip brainstorm` reason `resume: <spec path>`; `start plan`; `plan_check` on the absolute ledger path; on PASS `skip plan` reason `resume: <spec> (loop engine)` using the resolved absolute spec path as `<spec>`; `start implement`; no `plan_tracker init`; render rows and
|
|
152
|
+
| implement with ledger | Read ledger line 1; resolve its path-only `**Spec:**` header; run entry checks 1-6, naming check 6 (Grant field); `start brainstorm`; `skip brainstorm` reason `resume: <spec path>`; `start plan`; `plan_check` on the absolute ledger path; on PASS `skip plan` reason `resume: <spec> (loop engine)` using the resolved absolute spec path as `<spec>`; `start implement`; no `plan_tracker init`; apply the shared cap boundary in `reconstruction.md` "Spec with ledger" step 4 before continuation; render cap, rows and decisions; continue at loop step 5. Follow `reconstruction.md` "Spec with ledger" for this self-contained ordered restore. On FAIL stop with findings, never `## Plan repair` or writing-plans. |
|
|
153
153
|
| implement with task plan | `start brainstorm`; `skip brainstorm S`; `start plan`; `plan_check({ planPath })`; on FAIL run `## Plan repair`; on PASS `skip plan R`; `start implement`; `substep` if shown; `plan_tracker init` |
|
|
154
|
-
| verify |
|
|
154
|
+
| verify | `start brainstorm`; `skip brainstorm S`; `start plan`; `plan_check({ planPath })`; on FAIL run `## Plan repair`; on PASS `skip plan R`, then `skip implement R`; `start verify`; `substep` if shown; `plan_tracker init`. Never call `start implement`. |
|
|
155
155
|
| ship | as verify. Restoration stops at verify in_progress: `complete verify` needs a fresh conformance dispatch and `skip verify` would bypass a real gate. Announce that the closure review re-runs before ship |
|
|
156
156
|
|
|
157
|
-
For a ledger brief, pair by the ledger's path-only `**Spec:**` header, not basename; require the resolved spec under `flowGuards.specDirs` and the ledger under its sibling plans directory. Keep same-repository binding and human confirmation. For verify/ship ledger briefs, use the ledger restore sequence through `skip plan`, then `skip implement R`; `start verify`, with no task tracker. Continue verify/ship ledger briefs in `/skill:loop-implementation` `After the loop` from step 1 (full ledger verification), after the already-restored `start verify`, retaining whole-diff code review, happy path when triggered, fresh conformance review and finishing without task-tracker calls. Ship still stops at verify for fresh conformance.
|
|
157
|
+
For a ledger brief, pair by the ledger's path-only `**Spec:**` header, not basename; require the resolved spec under `flowGuards.specDirs` and the ledger under its sibling plans directory. Keep same-repository binding and human confirmation. For every ledger brief apply the shared cap boundary in `reconstruction.md` "Spec with ledger" step 4 before dispatch or verification, retaining its legacy stop and original-phase grant continuation. For verify/ship ledger briefs, use the ledger restore sequence through `skip plan`, then `skip implement R`; `start verify`, with no task tracker. Continue verify/ship ledger briefs in `/skill:loop-implementation` `After the loop` from step 1 (full ledger verification), after the already-restored `start verify`, retaining whole-diff code review, happy path when triggered, fresh conformance review and finishing without task-tracker calls. Ship still stops at verify for fresh conformance.
|
|
158
158
|
|
|
159
159
|
`planPath` (task-plan implement onward): the brief carries none. Resolve as reconstruction does
|
|
160
160
|
(`reconstruction.md`, "Candidates", including its `flowGuards.specDirs` resolution): the
|
|
@@ -80,7 +80,7 @@ After confirmation:
|
|
|
80
80
|
1. Read ledger line 1: require `# Ledger - loop engine`. Resolve its path-only `**Spec:**` header to an absolute spec path under the worktree's configured spec directories, not by basename. Run SKILL.md entry checks 1-6 in order, including check 6, **Grant field**, on that spec, before any tracker mutation.
|
|
81
81
|
2. Call `phase_tracker({ action: "start", phase: "brainstorm" })`, then `phase_tracker({ action: "skip", phase: "brainstorm", reason: "resume: <spec path>" })`, then `phase_tracker({ action: "start", phase: "plan" })`.
|
|
82
82
|
3. Call `plan_check({ planPath: <absolute ledger path> })`. On FAIL, stop with findings, retaining plan in_progress; never enter `## Plan repair` or writing-plans. On PASS, call `phase_tracker({ action: "skip", phase: "plan", reason: "resume: <spec> (loop engine)" })`, then `phase_tracker({ action: "start", phase: "implement" })`. Use the resolved absolute spec path as `<spec>` in the reason. Never call `plan_tracker init`.
|
|
83
|
-
4. Read `/skill:loop-implementation
|
|
83
|
+
4. **Shared cap boundary (every ledger restore, before phase continuation).** Read `/skill:loop-implementation`. Skip Entry step 1 entirely; settings resolution and its unavailable-tool stop apply only to fresh seeding. Restore base, verification, iterations, `cap:`, row attempts, funding and retry allowances from the ledger/spec and branch without overwriting it. Render `cap: <n>`, rows, iterations, attempts, funding, retry allowances and all decisions; distinguish the latest operational `row <n> ...` decision from the last physical history line. A dirty tree takes the driver's discard-authorization stop without offering a cap grant. On a clean ledger missing `cap:`, stop with `ledger has no cap: line - seeded under the old loopEngine contract`, even when every row is closed. Use the driver's legacy `cap +N` grant (durable iterations + N), never settings. After the grant continue the original phase: implement at `Before each dispatch`; verify/ship at `After the loop` step 1, never reseed.
|
|
84
84
|
5. Continue at loop step 5, the delivered driver's `Before each dispatch`, with durable iterations and retry data. Never reset counters or reseed a validated seed.
|
|
85
85
|
|
|
86
86
|
## Spec with plan
|
|
@@ -9,7 +9,7 @@ Run this driver in the main session. Carry the absolute implementation worktree
|
|
|
9
9
|
|
|
10
10
|
## Entry
|
|
11
11
|
|
|
12
|
-
1. Read project overrides below. Resolve `gauntlet_setting({ key: "loopEngine" })` and retain `
|
|
12
|
+
1. Read project overrides below. Resolve `gauntlet_setting({ key: "loopEngine" })` and retain `maxIterationsPerRow` (default 4). Stop on an unavailable settings tool.
|
|
13
13
|
2. Resolve verification once using this ordered table. Print `verification command: <command> (<source>)`.
|
|
14
14
|
|
|
15
15
|
| Observed configuration | Action |
|
|
@@ -27,6 +27,7 @@ Run this driver in the main session. Carry the absolute implementation worktree
|
|
|
27
27
|
base: <HEAD SHA before skeleton>
|
|
28
28
|
verification: <resolved command>
|
|
29
29
|
iterations: 0
|
|
30
|
+
cap: <n>
|
|
30
31
|
|
|
31
32
|
| row | status | attempts | evidence |
|
|
32
33
|
|---|---|---|---|
|
|
@@ -35,26 +36,26 @@ iterations: 0
|
|
|
35
36
|
## Decisions
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
Use the actual repo-relative spec path alone in the Spec header. Read base with `git -C "<worktree>" rev-parse HEAD`. Index every spec AC in order, including nested disposition lines without treating them as extra ACs; keep row text only in the spec. Initialize explicit/absent `in-scope` and `venue:` rows `open`, attempts 0, evidence empty. Initialize only `deviates:`, `deferred:`, `elsewhere:` rows `cut`, attempts 0, disposition text as evidence. Serialize evidence in one physical table cell, result lines separated by semicolons, pipes escaped, plain text without angle markup.
|
|
39
|
+
Use the actual repo-relative spec path alone in the Spec header. Read base with `git -C "<worktree>" rev-parse HEAD`. Index every spec AC in order, including nested disposition lines without treating them as extra ACs; keep row text only in the spec. Initialize explicit/absent `in-scope` and `venue:` rows `open`, attempts 0, evidence empty. Initialize only `deviates:`, `deferred:`, `elsewhere:` rows `cut`, attempts 0, disposition text as evidence. Compute cap once as (rows not initialized cut) * maxIterationsPerRow + 1, including the seed dispatch. Write `cap:` immediately after `iterations: 0`: 24 non-cut rows at default 4 yield 97; all-cut yields 1 and exits through rule 1 without a seed dispatch. Later cuts, reopens and requirement-preserving amendments leave cap unchanged; redraw deletes the ledger and reseeds it. Serialize evidence in one physical table cell, result lines separated by semicolons, pipes escaped, plain text without angle markup.
|
|
39
40
|
5. Call `plan_check({ planPath: <ledger path> })`. Stop with findings as a configuration error. Commit the stamped skeleton as `loop: seed ledger`; call `phase_tracker({ action: "start", phase: "implement" })`.
|
|
40
41
|
|
|
41
|
-
For resume, use the admitted ledger, its base and verification command, and durable iterations instead of overwriting it. Render rows and
|
|
42
|
+
For resume, use the admitted ledger, its base and verification command, and durable iterations and cap instead of overwriting it. Skip Entry step 1 for an admitted ledger; settings apply only to fresh seeding. Render rows, cap and decision history; stop on a dirty tree before dispatch.
|
|
42
43
|
|
|
43
44
|
## Before each dispatch
|
|
44
45
|
|
|
45
|
-
Read the ledger. Count empty child commits and validation misses only after the latest `loop: retry row <n>` commit. Funding alone resets neither window. Preserve every row's attempts and the total iteration cap. Apply this ordered table, starting here after each return or human decision:
|
|
46
|
+
Read the ledger and require its `cap:` header before the ordered table, including before rule 1. On a missing header stop with `ledger has no cap: line - seeded under the old loopEngine contract`, even for a completed ledger; use the legacy grant below, never derive cap from settings. Count empty child commits and validation misses only after the latest `loop: retry row <n>` commit. Funding alone resets neither window. Preserve every row's attempts and the total iteration cap. Apply this ordered table, starting here after each return or human decision:
|
|
46
47
|
|
|
47
48
|
| Order | Observed state | Action |
|
|
48
49
|
|---|---|---|
|
|
49
50
|
| 1 | No `open` or `failed` row | Exit verification. All-cut and baseline-complete ledgers exit normally. |
|
|
50
51
|
| 2 | Unresolved row attempts at its allowance | Human stop. Exempt `done` and `cut`, including third-attempt success. |
|
|
51
52
|
| 3 | Last two child row commits both changed no file outside the ledger and no row status | Human stop, regardless of funding. Count child `loop: row ...` commits only, excluding seed and parent repair/retry/cut commits. A decision alone is not progress. |
|
|
52
|
-
| 4 | `iterations` >= `
|
|
53
|
+
| 4 | `iterations` >= `cap` | Human stop naming the header cap value and every open/failed row with its attempts, before dispatch and before verification. Seed and interrupted dispatches count. |
|
|
53
54
|
| 5 | Dispatch allowed | Select target by the priority below. |
|
|
54
55
|
|
|
55
56
|
Set row allowance to 3 + funded N, increased to the latest `row <n> retry` decision's `allowed attempts <m>` when larger. Recover spent funding per row as `max(0, attempts - 3)`; a mid-loop grant applies prospectively. Before dispatch on a funded row with attempts >= 3 and spent < N print `funded round <k> of <N> for row <n>`, with k = attempts - 3 + 1. Funding buys neither cap bypass nor empty-commit bypass nor an escalated model. Include `budget: <spent> of <N> spent` in funded stops.
|
|
56
57
|
|
|
57
|
-
Select `seed` until a validated `loop: seed evidence` commit with its `row 0 done` decision and evidence on every non-cut row survives on the branch, independently of `iterations`; otherwise select the still-unresolved human retry target, then the still-failed row named by the previous decision, then first failed row, then first open row. Durable status beats a decision's suggestion. Keep the retry hint only for its target.
|
|
58
|
+
Select `seed` until a validated `loop: seed evidence` commit with its `row 0 done` decision and evidence on every non-cut row survives on the branch, independently of `iterations`; otherwise select the still-unresolved human retry target, then the still-failed row named by the previous decision, then first failed row, then first open row. Use the latest operational `row <n> ...` decision for targeting and the child's `previous decision:` input, skipping cap grant history while retaining the entire Decisions section. Durable status beats a decision's suggestion. Keep the retry hint only for its target.
|
|
58
59
|
|
|
59
60
|
## Dispatch
|
|
60
61
|
|
|
@@ -75,7 +76,7 @@ Omit the model override; let the persona override or parent inheritance resolve
|
|
|
75
76
|
## Validate the return
|
|
76
77
|
|
|
77
78
|
1. Require empty `git -C "<worktree>" status --porcelain` and exactly 1 from `git -C "<worktree>" rev-list HEAD_BEFORE..HEAD --count`. On dirty/zero/multiple commits stop, preserving changes and commits. Use `Stopped: iteration <i> left the tree dirty` or `Stopped: iteration <i> added <k> commits`. Read the ledger from HEAD only after this boundary passes.
|
|
78
|
-
2. Validate by dispatched `target`, not iteration number, against the saved copy using this table. Preserve headers including the bumped iterations, row identifiers and prior decisions.
|
|
79
|
+
2. Validate by dispatched `target`, not iteration number, against the saved copy using this table. Preserve headers including cap and the bumped iterations, row identifiers and prior decisions.
|
|
79
80
|
|
|
80
81
|
| Target | Required changes | Miss |
|
|
81
82
|
|---|---|---|
|
|
@@ -84,7 +85,7 @@ Omit the model override; let the persona override or parent inheritance resolve
|
|
|
84
85
|
|
|
85
86
|
Require ordinary decision grammar `^row <target> (done|failed) \| .{1,200} \| .{1,200}$`; an old conforming line is not a new line. Require check name plus at most three result lines in evidence, serialized with semicolons and escaped pipes as in the persona. Reject wrong targets, foreign cells, missing/malformed/new-extra decisions and changed headers.
|
|
86
87
|
|
|
87
|
-
On an ordinary miss restore every non-target row, headers and prior decisions from the saved copy, retaining the incremented iterations. Set the target `failed`, attempts = saved attempts +1, evidence = `iteration <i>: <concrete miss>`. Remove malformed appended decisions and commit `loop: repair row <n>`. Set previous decision to `none`; otherwise use the new conforming line. Two consecutive validation misses stop because the child is not following the contract. A conforming return resets the consecutive-miss count; parent repair commits do not count toward child-only empty stagnation.
|
|
88
|
+
On an ordinary miss restore every non-target row, headers (including the saved cap) and prior decisions from the saved copy, retaining the incremented iterations. Set the target `failed`, attempts = saved attempts +1, evidence = `iteration <i>: <concrete miss>`. Remove malformed appended decisions and commit `loop: repair row <n>`. Set previous decision to `none`; otherwise use the new conforming line. Two consecutive validation misses stop because the child is not following the contract. A conforming return resets the consecutive-miss count; parent repair commits do not count toward child-only empty stagnation.
|
|
88
89
|
|
|
89
90
|
## Exit verification
|
|
90
91
|
|
|
@@ -92,19 +93,22 @@ Run the ledger's `verification:` command exactly once foreground in the worktree
|
|
|
92
93
|
|
|
93
94
|
## Human stop
|
|
94
95
|
|
|
95
|
-
Leave implement active. Use one screen of plain words: `Stopped on row <n> (<row text>)` for row failures, or the concrete boundary/cap/verification header above. `Problem:` quotes the evidence cell verbatim, identifying the actual spec/code contradiction, failing assertion/output or missing capability, and quotes the last decision line. Include funding budget only when funded. Omit round history, model escalation and reasoning traces.
|
|
96
|
+
Leave implement active. Use one screen of plain words: `Stopped on row <n> (<row text>)` for row failures, or the concrete boundary/cap/verification header above. `Problem:` quotes the evidence cell verbatim, identifying the actual spec/code contradiction, failing assertion/output or missing capability, and quotes the last decision line. Include funding budget only when funded. At every stop print `Preserve every row's attempts and the total iteration cap.` Omit round history, model escalation and reasoning traces.
|
|
96
97
|
|
|
97
|
-
Offer these concrete actions:
|
|
98
|
+
Offer these concrete actions. Offer `cap +N` only at a clean cap or legacy missing-cap stop; dirty-tree and commit-boundary stops keep discard authorization and never offer `cap +N`. When both the row allowance and total cap are exhausted, list independent funding and cap offers despite rule 2 priority. Take separate replies: funding follows the spec's `**Amend-grant:**` contract, cap follows the row below; define no combined syntax.
|
|
98
99
|
|
|
99
100
|
| Human choice | Durable action |
|
|
100
101
|
|---|---|
|
|
102
|
+
| Raise cap (`cap +N`) | Parse anchored `cap +<n>` with `<n>` matching `[1-9][0-9]*` and a token boundary (end, whitespace or `\|`); reject `cap +50x`. Trim the optional remainder and optional leading pipe into the words cell. Append `cap +<n> \| <words>` under `## Decisions`; bare `cap +50` writes `cap +50 \|`. Raise the old header cap by N, or set a missing cap to durable iterations + N. Write a missing `cap:` directly after `iterations:`. Commit both changes exactly once as parent `loop: raise cap`, leaving iterations and all attempts unchanged; return to the ordered table. Malformed `cap +0`, `cap +x`, `cap -5` asks once; a second invalid reply holds the same stop with no commit. |
|
|
101
103
|
| Retry with hint | Append `row <n> retry | <hint> | allowed attempts <attempts + 1>`, commit `loop: retry row <n>`, resume checks with that target/hint. Never reset attempts or iterations. |
|
|
102
104
|
| Amend | Follow `/skill:brainstorming` amendment surface; cut only through an approved disposition amendment. Reconcile ledger and spec in one commit. |
|
|
103
105
|
| Stop | Keep phase implement and preserve branch state. |
|
|
104
106
|
|
|
107
|
+
Serialize the bare decision as `cap +50 |` with an empty words cell. A cap grant resets neither window (empty-child or validation-miss); exclude `loop: raise cap` from child-commit counting. Only retry starts new windows.
|
|
108
|
+
|
|
105
109
|
For dirty/commit-boundary retry, ask the human to authorize discarding uncommitted changes/resetting to last valid commit. Preserve consumed dispatch count: set iterations to restored HEAD's value +1 before the next normal bump. An interrupted dispatch consumes the same count; recover it from disk/branch rather than silently repeating iteration 0.
|
|
106
110
|
|
|
107
|
-
For ledger amendments use its line-1 discriminant: no plan writer, plan_check or task-tracker lifecycle. Approved deviates/deferred/elsewhere becomes `cut` with disposition evidence; requirement-preserving amendments leave rows unchanged; a re-bounded done row becomes `open` with `reopened by amendment`. Preserve attempts and
|
|
111
|
+
For ledger amendments use its line-1 discriminant: no plan writer, plan_check or task-tracker lifecycle. Approved deviates/deferred/elsewhere becomes `cut` with disposition evidence; requirement-preserving amendments leave rows unchanged; a re-bounded done row becomes `open` with `reopened by amendment`. Preserve attempts, iterations and cap. Commit spec + ledger as `loop: cut row <n>` or `loop: amend`. Option 4 stops for amendments, option 5 auto-applies amends, redraw always stops and deletes the ledger with the plan. Never cut automatically.
|
|
108
112
|
|
|
109
113
|
## After the loop
|
|
110
114
|
|