pi-gauntlet 7.28.0 → 7.29.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 +12 -0
- package/README.md +13 -5
- package/agents/loop-implementer.md +51 -0
- package/bin/gauntlet-performance.mjs +5 -1
- package/bin/gauntlet-performance.test.mjs +19 -3
- package/bin/gauntlet-telemetry-seal.mjs +2 -2
- package/extensions/lib/gauntlet-settings.test.ts +10 -0
- package/extensions/lib/gauntlet-settings.ts +8 -0
- package/extensions/lib/plan-check.test.ts +63 -0
- package/extensions/lib/plan-check.ts +42 -0
- package/extensions/lib/telemetry-record.test.ts +19 -0
- package/extensions/lib/telemetry-record.ts +5 -3
- package/extensions/phase-tracker.test.ts +40 -0
- package/extensions/phase-tracker.ts +6 -2
- package/extensions/telemetry.test.ts +58 -4
- package/extensions/telemetry.ts +21 -12
- package/package.json +2 -2
- package/skills/brainstorming/SKILL.md +3 -3
- package/skills/brainstorming/reference/amendment-surface.md +5 -5
- package/skills/brainstorming/reference/spec-finalization.md +12 -3
- package/skills/brainstorming/reference/ticket-acceptance.md +1 -1
- package/skills/finishing-a-development-branch/SKILL.md +6 -5
- package/skills/gauntlet-handoff/SKILL.md +1 -2
- package/skills/gauntlet-resume/SKILL.md +7 -4
- package/skills/gauntlet-resume/reference/brief-contract.md +19 -6
- package/skills/gauntlet-resume/reference/reconstruction.md +18 -5
- package/skills/loop-implementation/SKILL.md +124 -0
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
await h.phaseResult("substep", P({ brainstorm: "in_progress" }));
|
|
174
174
|
await h.phaseResult("complete", P({ brainstorm: "complete" }));
|
|
175
175
|
const rec2 = h.readRecord();
|
|
176
|
-
assert.equal(rec2.approved_at, rec2.events.
|
|
176
|
+
assert.equal(rec2.approved_at, rec2.events.findLast((e) => e.kind === "phase")!.ts);
|
|
177
177
|
assert.equal(h.gitWrites().length, 0, "the recorder never runs git add or git commit");
|
|
178
178
|
assert.equal(readFileSync(h.excludeFile(), "utf8"), ".pi/gauntlet/telemetry/\n");
|
|
179
179
|
await h.phaseResult("reset", P());
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
assert.equal(h.readRecord("docs/specs/x.md").spec, "docs/specs/x.md");
|
|
192
192
|
await h.phaseResult("complete", P({ brainstorm: "complete" }));
|
|
193
193
|
const rec = h.readRecord("docs/specs/x.md");
|
|
194
|
-
assert.equal(rec.approved_at, rec.events.
|
|
194
|
+
assert.equal(rec.approved_at, rec.events.findLast((e) => e.kind === "phase")!.ts);
|
|
195
195
|
assert.equal(h.gitWrites().length, 0);
|
|
196
196
|
});
|
|
197
197
|
|
|
@@ -310,7 +310,8 @@
|
|
|
310
310
|
const rec = parseRecord(readFileSync(first.recordPath(), "utf8"))!;
|
|
311
311
|
assert.equal(rec.run_id, runId);
|
|
312
312
|
assert.deepEqual(rec.sessions, ["s1", "s2"]);
|
|
313
|
-
assert.equal(rec.events.length, 1, "replay emits no duplicate events");
|
|
313
|
+
assert.equal(rec.events.filter((e) => e.kind !== "engine").length, 1, "replay emits no duplicate phase events");
|
|
314
|
+
assert.equal(rec.events.filter((e) => e.kind === "engine").length, 1);
|
|
314
315
|
});
|
|
315
316
|
|
|
316
317
|
test("rename at spec-writing: write to a new spec while the bound one is a draft rebinds and moves the record", async () => {
|
|
@@ -1111,7 +1112,7 @@
|
|
|
1111
1112
|
const rec = parseRecord(readFileSync(first.recordPath(), "utf8"))!;
|
|
1112
1113
|
assert.equal(rec.run_id, runId);
|
|
1113
1114
|
assert.deepEqual(rec.sessions, ["s1", "s2"]);
|
|
1114
|
-
assert.equal(rec.approved_at, rec.events.
|
|
1115
|
+
assert.equal(rec.approved_at, rec.events.findLast((e) => e.kind === "phase")!.ts);
|
|
1115
1116
|
});
|
|
1116
1117
|
|
|
1117
1118
|
test("reset then a new spec binds a fresh run with an empty buffer; the old record is untouched", async () => {
|
|
@@ -1280,3 +1281,56 @@
|
|
|
1280
1281
|
const [planPass] = await h3.emit("tool_call", { toolName: "write", toolCallId: "w3", input: { path: "doc/specs/a.md", content: "# again" } });
|
|
1281
1282
|
assert.equal(planPass, undefined);
|
|
1282
1283
|
});
|
|
1284
|
+
|
|
1285
|
+
for (const { engine, example } of [
|
|
1286
|
+
{ engine: "loop", example: false },
|
|
1287
|
+
{ engine: "waves", example: false },
|
|
1288
|
+
{ engine: undefined, example: false },
|
|
1289
|
+
{ engine: "waves", example: true },
|
|
1290
|
+
{ engine: undefined, example: true },
|
|
1291
|
+
]) {
|
|
1292
|
+
test(`brainstorm complete records bound spec engine ${engine ?? "legacy"}${example ? " with fenced loop example" : ""}, unrelated phases do not`, async () => {
|
|
1293
|
+
const h = harness();
|
|
1294
|
+
await h.phaseResult("start", P({ brainstorm: "in_progress" }));
|
|
1295
|
+
await h.writeSpec("doc/specs/a.md", `# Spec\n${engine ? `**Engine:** ${engine}\n` : ""}${example ? "\n## Design\n```markdown\n**Engine:** loop\n```\n" : ""}`);
|
|
1296
|
+
await h.writeSpec("doc/specs/other.md", "**Engine:** waves\n");
|
|
1297
|
+
await h.phaseResult("complete", P({ brainstorm: "complete" }));
|
|
1298
|
+
await h.phaseResult("start", P({ brainstorm: "complete", plan: "in_progress" }));
|
|
1299
|
+
const rec = h.readRecord();
|
|
1300
|
+
assert.deepEqual(rec.events.filter((e) => e.kind === "engine").map((e) => e.engine), [engine ?? "waves"]);
|
|
1301
|
+
assert.equal(rec.derived.engine, engine ?? "waves");
|
|
1302
|
+
h.setBranch([
|
|
1303
|
+
{ type: "message", message: { role: "toolResult", toolName: "phase_tracker", details: { action: "start", phases: P({ brainstorm: "in_progress" }) } } },
|
|
1304
|
+
{ type: "message", message: { role: "toolResult", toolName: "phase_tracker", details: { action: "complete", phases: P({ brainstorm: "complete" }) } } },
|
|
1305
|
+
{ type: "message", message: { role: "toolResult", toolName: "plan_check", details: { status: "pass", specPath: "doc/specs/a.md" } } },
|
|
1306
|
+
]);
|
|
1307
|
+
for (const event of ["session_start", "session_switch", "session_fork", "session_tree"]) {
|
|
1308
|
+
await h.emit(event, {});
|
|
1309
|
+
assert.deepEqual(h.readRecord().events.filter((e) => e.kind === "engine"), rec.events.filter((e) => e.kind === "engine"));
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
test("resume skip reads engine from bound spec live and on branch replay", async () => {
|
|
1315
|
+
for (const replay of [false, true]) {
|
|
1316
|
+
const h = harness();
|
|
1317
|
+
writeFileSync(join(h.root, "doc/specs/a.md"), "# Spec\n**Engine:** loop\n");
|
|
1318
|
+
const started = P({ brainstorm: "in_progress" });
|
|
1319
|
+
const skipped = { ...P({ brainstorm: "skipped" }), brainstorm: { status: "skipped", reason: "resume: doc/specs/a.md" } };
|
|
1320
|
+
if (replay) {
|
|
1321
|
+
h.setBranch([started, skipped].map((phases, i) => ({ type: "message", message: { role: "toolResult", toolName: "phase_tracker", details: { action: i ? "skip" : "start", phases } } })));
|
|
1322
|
+
await h.emit("session_start", {});
|
|
1323
|
+
} else {
|
|
1324
|
+
await h.phaseResult("start", started);
|
|
1325
|
+
await h.phaseResult("skip", skipped);
|
|
1326
|
+
}
|
|
1327
|
+
assert.equal(h.readRecord().derived.engine, "loop");
|
|
1328
|
+
assert.equal(h.readRecord().events.filter((e) => e.kind === "engine").length, 1);
|
|
1329
|
+
h.setBranch([started, skipped].map((phases, i) => ({ type: "message", message: { role: "toolResult", toolName: "phase_tracker", details: { action: i ? "skip" : "start", phases } } })));
|
|
1330
|
+
const events = h.readRecord().events.filter((e) => e.kind === "engine");
|
|
1331
|
+
for (const event of ["session_start", "session_switch", "session_fork", "session_tree"]) {
|
|
1332
|
+
await h.emit(event, {});
|
|
1333
|
+
assert.deepEqual(h.readRecord().events.filter((e) => e.kind === "engine"), events);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
});
|
package/extensions/telemetry.ts
CHANGED
|
@@ -420,11 +420,16 @@
|
|
|
420
420
|
};
|
|
421
421
|
|
|
422
422
|
// ---- phase mirror ----
|
|
423
|
-
const applyPhaseDetails = async (details: { action?: string; phases?: PhaseMap; error?: string; rounds?: number } | undefined, snap: SettingsSnapshot) => {
|
|
423
|
+
const applyPhaseDetails = async (details: { action?: string; phases?: PhaseMap; error?: string; rounds?: number } | undefined, snap: SettingsSnapshot, replay = false) => {
|
|
424
424
|
if (!details?.phases || details.error) return;
|
|
425
425
|
const action = details.action ?? "";
|
|
426
426
|
gauntletEntered = nextGauntletEntered(gauntletEntered, action, details.phases.brainstorm.status);
|
|
427
|
-
const transitions = diffPhases(phases, details.phases, action);
|
|
427
|
+
const transitions = diffPhases(replay ? emptyPhases() : phases, details.phases, action).filter((t) => !replay || t.name === "brainstorm");
|
|
428
|
+
if (action === "skip" && !boundSpec && canBind() && lastCtx) {
|
|
429
|
+
const resumed = resumeSpecOf(details.phases, snap.specDirs);
|
|
430
|
+
const loc = resumed ? await locate(lastCtx, resumed) : undefined;
|
|
431
|
+
if (loc && isSpecPath(loc.rel, snap.specDirs)) await bind(loc.rel, snap, loc.toplevel, loc.via);
|
|
432
|
+
}
|
|
428
433
|
if (action === "grant_fix_rounds") {
|
|
429
434
|
live().gates.fix_round_grants += 1;
|
|
430
435
|
pushEvent({ kind: "gate", gate: "fix_round_grant", rounds: typeof details.rounds === "number" ? details.rounds : undefined });
|
|
@@ -432,7 +437,7 @@
|
|
|
432
437
|
}
|
|
433
438
|
for (const t of transitions) {
|
|
434
439
|
const model = ctxModel();
|
|
435
|
-
const e = pushEvent(
|
|
440
|
+
const e = replay ? undefined : pushEvent(
|
|
436
441
|
t.action === "start"
|
|
437
442
|
? { kind: "phase", action: "start", name: t.name, model, thinking: ctxThinking() }
|
|
438
443
|
: t.action === "reset"
|
|
@@ -441,7 +446,15 @@
|
|
|
441
446
|
);
|
|
442
447
|
if (t.action === "start" && t.name === "brainstorm") councilPending = undefined;
|
|
443
448
|
phases = details.phases;
|
|
444
|
-
if (record && t.name === "brainstorm" && (t.action === "complete" || t.action === "skip"))
|
|
449
|
+
if (record && boundSpec && t.name === "brainstorm" && (t.action === "complete" || t.action === "skip")) {
|
|
450
|
+
if (e) record.approved_at ??= e.ts;
|
|
451
|
+
if (!replay || !record.events.some((event) => event.kind === "engine")) {
|
|
452
|
+
const body = deps.fs.readFile(abs(boundSpec)) ?? "";
|
|
453
|
+
const header = body.split(/^## /m, 1)[0];
|
|
454
|
+
const engine = /^\*\*Engine:\*\*[ \t]+loop[ \t]*$/m.test(header) ? "loop" : "waves";
|
|
455
|
+
pushEvent({ kind: "engine", engine });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
445
458
|
if (record && t.name === "ship" && t.action === "complete" && checkoutVia === "jj") await onShipKeep(snap);
|
|
446
459
|
flush();
|
|
447
460
|
if (t.action === "reset") {
|
|
@@ -452,14 +465,6 @@
|
|
|
452
465
|
}
|
|
453
466
|
}
|
|
454
467
|
phases = details.phases;
|
|
455
|
-
if (action === "skip" && !boundSpec && canBind() && lastCtx) {
|
|
456
|
-
const resumed = resumeSpecOf(details.phases, snap.specDirs);
|
|
457
|
-
const loc = resumed ? await locate(lastCtx, resumed) : undefined;
|
|
458
|
-
if (loc && isSpecPath(loc.rel, snap.specDirs)) {
|
|
459
|
-
await bind(loc.rel, snap, loc.toplevel, loc.via);
|
|
460
|
-
flush();
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
468
|
};
|
|
464
469
|
|
|
465
470
|
let lastCtx: ExtensionContext | undefined;
|
|
@@ -493,6 +498,10 @@
|
|
|
493
498
|
const loc = candidate ? await locate(ctx, candidate) : undefined;
|
|
494
499
|
if (loc && isSpecPath(loc.rel, snap.specDirs)) {
|
|
495
500
|
await bind(loc.rel, snap, loc.toplevel, loc.via);
|
|
501
|
+
const status = replay.phases.brainstorm.status;
|
|
502
|
+
if (status === "complete" || status === "skipped") {
|
|
503
|
+
await applyPhaseDetails({ action: status === "complete" ? "complete" : "skip", phases: replay.phases }, snap, true);
|
|
504
|
+
}
|
|
496
505
|
flush();
|
|
497
506
|
}
|
|
498
507
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-gauntlet",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.29.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.4.
|
|
65
|
+
"pi-cohort": ">=7.4.5"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"yaml": "^2.9.0"
|
|
@@ -32,7 +32,7 @@ Treat the flag as discovery control, not harness authorization. The command reli
|
|
|
32
32
|
|
|
33
33
|
## Checklist
|
|
34
34
|
|
|
35
|
-
Work through the items below **in order**. After a user answer or completed side task, resume the current checklist step and perform the next authorized action in the same turn, advancing once that step's required decisions and approvals are satisfied. Continue until a required question is unanswered, an existing approval is pending, the user explicitly pauses, or a failed required tool or unavailable required resource blocks progress. This is your own checklist to follow, not a `plan_tracker` plan — brainstorming is open-ended exploration, and `plan_tracker` is execution-only (the implement phase). The terminal state is the user review gate; after approval
|
|
35
|
+
Work through the items below **in order**. After a user answer or completed side task, resume the current checklist step and perform the next authorized action in the same turn, advancing once that step's required decisions and approvals are satisfied. Continue until a required question is unanswered, an existing approval is pending, the user explicitly pauses, or a failed required tool or unavailable required resource blocks progress. This is your own checklist to follow, not a `plan_tracker` plan — brainstorming is open-ended exploration, and `plan_tracker` is execution-only (the implement phase). The terminal state is the user review gate; after approval route 1/2 to `/skill:writing-plans` and 4/5 to `/skill:loop-implementation` per the gate. Do not jump ahead of approval, and do not silently drop the critique pass.
|
|
36
36
|
|
|
37
37
|
1. **Start brainstorm tracking (fresh epoch)** - as the first action on authorized fresh entry, before reading code, the worktree, or answering the user, reset both trackers and start the phase. A new brainstorm owns a clean slate, so stale phases and tasks from earlier work are cleared; re-entering mid-brainstorm is safe (nothing to lose, same clean slate):
|
|
38
38
|
|
|
@@ -53,7 +53,7 @@ Work through the items below **in order**. After a user answer or completed side
|
|
|
53
53
|
10. **Re-run placeholder scan** - follow [Spec Self-Review](#spec-self-review-before-user-review-gate).
|
|
54
54
|
11. **Generate spec summary** - follow [User Review Gate](#user-review-gate).
|
|
55
55
|
12. **User review gate** - follow [User Review Gate](#user-review-gate).
|
|
56
|
-
13. **Transition** - after approval, invoke `/skill:writing-plans` per [User Review Gate](#user-review-gate).
|
|
56
|
+
13. **Transition** - after approval, invoke `/skill:writing-plans` on 1/2 or `/skill:loop-implementation` on 4/5 per [User Review Gate](#user-review-gate).
|
|
57
57
|
|
|
58
58
|
## Project Routing
|
|
59
59
|
|
|
@@ -186,7 +186,7 @@ Classify first. Redraw test: the change alters the problem statement, adds or re
|
|
|
186
186
|
|
|
187
187
|
Amend -> `read` `reference/amendment-surface.md` and follow it (unreadable -> stop with a blocking error; never improvise the grammar). Apply its [Standing grants](reference/amendment-surface.md#standing-grants) boundaries.
|
|
188
188
|
|
|
189
|
-
Redraw: keep the worktree and the approved spec file. `plan_tracker({ action: "clear" })`, `phase_tracker({ action: "reset" })`, `phase_tracker({ action: "start", phase: "brainstorm" })`, delete the plan file, resume at checklist step 4 with the approved spec as the draft (steps 2-3 skipped); step 4's first-use check covers the read. Spec-writing overwrites it; the full gate follows.
|
|
189
|
+
Redraw: keep the worktree and the approved spec file. `plan_tracker({ action: "clear" })`, `phase_tracker({ action: "reset" })`, `phase_tracker({ action: "start", phase: "brainstorm" })`, delete the plan file and the loop ledger (identified by line 1 `# Ledger - loop engine` in the resolved plan dir), resume at checklist step 4 with the approved spec as the draft (steps 2-3 skipped); step 4's first-use check covers the read. Spec-writing overwrites it; the full gate follows.
|
|
190
190
|
|
|
191
191
|
## Red Flags — STOP
|
|
192
192
|
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
## Standing grants
|
|
6
6
|
|
|
7
|
-
Honor a user sentence in this flow that waives per-diff review for later amends (`auto-apply amends`, `approve, auto-apply amends` or a bare `2` at the spec gate, `auto-apply amends, stop only for redraws`, `apply spec fixes without asking`, or the same intent in other words). The digit grants only at the spec gate, and a prose grant after a `1` approval still counts. Apply every later amend-class change without review, scope changes included; redraws always stop and the grant never satisfies the spec gate.
|
|
7
|
+
Honor a user sentence in this flow that waives per-diff review for later amends (`auto-apply amends`, `approve, auto-apply amends` or a bare `2` at the spec gate (a bare `5` grants the same way), `auto-apply amends, stop only for redraws`, `apply spec fixes without asking`, or the same intent in other words). The digit grants only at the spec gate, and a prose grant after a `1` approval still counts. Apply every later amend-class change without review, scope changes included; redraws always stop and the grant never satisfies the spec gate.
|
|
8
8
|
|
|
9
9
|
A grant is the spec's `**Amend-grant:**` line read through the shared predicate; `none` or a missing line means no grant. A new brainstorm writes `none`; a resume honors the line as written. Never take a grant from commit history, a handoff brief, or the transcript; the one read of a prior commit is the post-revert restore, which reads the pre-revert HEAD's spec line.
|
|
10
10
|
|
|
11
|
-
**The line.** `**Amend-grant:** none` or `**Amend-grant:** <granting sentence verbatim, one physical line>`, in the header block (the span between the H1 and the first `##`). Writers place it directly below `**Goal:**` when that line exists, otherwise on the first line after the H1, its blank line, and any `> **Superseded by:**` banner lines; readers never depend on the position. When the reply was the digit `2`, the sentence is the grant description from the gate menu (the text after `2 - approve, auto-apply amends:` in `spec-finalization.md`), never the digit. Collapse a prose grant to one physical line before the write: newlines and runs of whitespace become single spaces, wording preserved. The same substitution applies wherever this file quotes the granting sentence in a commit body.
|
|
11
|
+
**The line.** `**Amend-grant:** none` or `**Amend-grant:** <granting sentence verbatim, one physical line>`, in the header block (the span between the H1 and the first `##`). Writers place it directly below `**Goal:**` when that line exists, otherwise on the first line after the H1, its blank line, and any `> **Superseded by:**` banner lines; readers never depend on the position. When the reply was the digit `2` or `5`, the sentence is the grant description from the gate menu (the text after `2 - approve, auto-apply amends:` in `spec-finalization.md`), never the digit. Collapse a prose grant to one physical line before the write: newlines and runs of whitespace become single spaces, wording preserved. The same substitution applies wherever this file quotes the granting sentence in a commit body.
|
|
12
12
|
|
|
13
13
|
**The predicate.** Every reader (gauntlet-resume at entry, this file at each batch boundary) applies it verbatim over the header block; occurrences below the first `##` never count.
|
|
14
14
|
|
|
@@ -26,7 +26,7 @@ A grant is the spec's `**Amend-grant:**` line read through the shared predicate;
|
|
|
26
26
|
| Event | Edit |
|
|
27
27
|
|---|---|
|
|
28
28
|
| Grant given at a tier-2 footer | `edit` the value to the sentence |
|
|
29
|
-
| Line absent (legacy spec) | insert the line at the writer placement above; when a plan exists, the insertion shifts every heading by one line, so run the section 5 aftermath's anchor repair (the `plan-writer` amend dispatch, then the parent `plan_check`) and commit spec and plan together |
|
|
29
|
+
| Line absent (legacy spec) | insert the line at the writer placement above; when a loop ledger exists, use section 5's ledger aftermath; otherwise when a plan exists, the insertion shifts every heading by one line, so run the section 5 aftermath's anchor repair (the `plan-writer` amend dispatch, then the parent `plan_check`) and commit spec and plan together |
|
|
30
30
|
| Revocation (`revoke auto-apply amends`, `stop auto-applying amends`, or the same intent in other words) | `edit` the value to `none` |
|
|
31
31
|
| Hand-edited line | not an event; the next batch boundary re-reads it and the value found is the current consent |
|
|
32
32
|
|
|
@@ -142,7 +142,7 @@ Before the aftermath, `read` this section again; never run it from memory.
|
|
|
142
142
|
|
|
143
143
|
Apply accepted items only: reviewer clears, `accept`, `alt-n`, and state-changing `custom`. Print one line per applied item: `amended the spec: <title> - <what>`.
|
|
144
144
|
|
|
145
|
-
Aftermath, once per batch, only when at least one item applied (nothing applied -> skip to the commit below). No plan yet -> commit the spec; continue. Plan exists -> read `git -C "<abs worktree path>" status --porcelain` (plain jj: `jj -R "<abs worktree path>" diff --summary`); collect the parent's in-flight workflow edits as worktree-relative paths, including the amended spec and staged in-place wave-repair deliverables. Dispatch `plan-writer` per `writing-plans` `## Author the plan` step 3 with an `Amend:` block naming the amended spec sections, an `In-flight:` list of those paths (the parent supplies the set; the child never infers it), and the rule "preserve every task title and wave position the amendment does not touch; edit only affected anchors and tasks", then run that section's steps 5-6 (the parent `plan_check` and its branches), then read the amended plan once (step 7's read, without its phase completion or `plan_tracker` init) - the main loop never edits the plan text; then update the tracker: `plan_tracker` `add` for new tasks; anchor-changed completed tasks are reopened as `in_progress` and re-run the task loop (`update` never sets `pending`). A removed task is deleted from the plan; then re-`init` the tracker with `{ name, status }` elements: preserved tasks keep their order and statuses, reopened tasks are `in_progress` in place, every still-`pending` task (including newly added ones, whatever wave label they carry) trails the non-pending ones, removed tasks are the only deletions (the only permitted `init` after handoff; never `clear`). Commit spec + plan together; continue. A task reopened while `verify` or `ship` is in progress stays in that phase - no `phase_tracker` call. Repair it through the current phase's fix loop and `plan_tracker({ action: "update", index: N, status: "complete" })` it once that repair's review or re-audit accepts; open tasks block `complete verify`, and in `ship` nothing checks them, so close them explicitly.
|
|
145
|
+
Aftermath, once per batch, only when at least one item applied (nothing applied -> skip to the commit below). Ledger exists (line 1 `# Ledger - loop engine` in the resolved plan dir) -> skip `plan-writer`, `plan_check`, and `plan_tracker`. Reconcile the ledger against the approved spec dispositions: `deviates:`, `deferred:`, or `elsewhere:` -> `cut`, evidence = the disposition; factual or requirement-preserving amendment -> preserve rows; re-bounded `done` row -> `open`, evidence = `reopened by amendment`. Preserve every row's attempts and the ledger's iterations. Never auto-edit ticket AC row texts. Commit spec + ledger together with subject `loop: cut row <n>` for a single cut, otherwise `loop: amend`, carrying the amendment audit body below (including each `granted` record and granting sentence); continue without task-plan aftermath. No plan yet -> commit the spec; continue. Plan exists -> read `git -C "<abs worktree path>" status --porcelain` (plain jj: `jj -R "<abs worktree path>" diff --summary`); collect the parent's in-flight workflow edits as worktree-relative paths, including the amended spec and staged in-place wave-repair deliverables. Dispatch `plan-writer` per `writing-plans` `## Author the plan` step 3 with an `Amend:` block naming the amended spec sections, an `In-flight:` list of those paths (the parent supplies the set; the child never infers it), and the rule "preserve every task title and wave position the amendment does not touch; edit only affected anchors and tasks", then run that section's steps 5-6 (the parent `plan_check` and its branches), then read the amended plan once (step 7's read, without its phase completion or `plan_tracker` init) - the main loop never edits the plan text; then update the tracker: `plan_tracker` `add` for new tasks; anchor-changed completed tasks are reopened as `in_progress` and re-run the task loop (`update` never sets `pending`). A removed task is deleted from the plan; then re-`init` the tracker with `{ name, status }` elements: preserved tasks keep their order and statuses, reopened tasks are `in_progress` in place, every still-`pending` task (including newly added ones, whatever wave label they carry) trails the non-pending ones, removed tasks are the only deletions (the only permitted `init` after handoff; never `clear`). Commit spec + plan together; continue. A task reopened while `verify` or `ship` is in progress stays in that phase - no `phase_tracker` call. Repair it through the current phase's fix loop and `plan_tracker({ action: "update", index: N, status: "complete" })` it once that repair's review or re-audit accepts; open tasks block `complete verify`, and in `ship` nothing checks them, so close them explicitly.
|
|
146
146
|
|
|
147
147
|
One commit per batch:
|
|
148
148
|
|
|
@@ -153,7 +153,7 @@ amend: <N> item(s) - <first title>[, <second title>]
|
|
|
153
153
|
<the granting sentence, quoted, when a grant applied>
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
`amend:` is the subject marker `finishing-a-development-branch` Step 4 greps for its digest; `<what>` is the item's one-sentence what-changes field, so the digest renders `<title> - <what changed>` from the body alone. When no item applied (every item dropped or redirected), nothing changed on disk; the commit still lands, with `git commit --allow-empty`, so the per-item `custom(<effect>)` records stay in the batch body - the digest ignores them because it reads only `auto-apply` and `granted` records. Wrong apply -> `git revert` the batch commit; then read the `**Amend-grant:**` line from the pre-revert HEAD (`git -C <abs worktree path> show HEAD^:<spec path>` through the predicate) and, if the working tree's line differs, restore that value and persist it per [Standing grants](#standing-grants) before re-entering this surface for the items to keep - the pre-revert HEAD holds every consent change committed so far, revocations included.
|
|
156
|
+
For a ledger batch, use the loop subject above and retain this same audit body. `amend:` is the subject marker `finishing-a-development-branch` Step 4 greps for its digest; `<what>` is the item's one-sentence what-changes field, so the digest renders `<title> - <what changed>` from the body alone. When no item applied (every item dropped or redirected), nothing changed on disk; the commit still lands, with `git commit --allow-empty`, so the per-item `custom(<effect>)` records stay in the batch body - the digest ignores them because it reads only `auto-apply` and `granted` records. Wrong apply -> `git revert` the batch commit; then read the `**Amend-grant:**` line from the pre-revert HEAD (`git -C <abs worktree path> show HEAD^:<spec path>` through the predicate) and, if the working tree's line differs, restore that value and persist it per [Standing grants](#standing-grants) before re-entering this surface for the items to keep - the pre-revert HEAD holds every consent change committed so far, revocations included.
|
|
157
157
|
|
|
158
158
|
## Conformance entry
|
|
159
159
|
|
|
@@ -126,11 +126,15 @@ New predecessor candidates at spec-writing: <path> (<title>), ... - index rows a
|
|
|
126
126
|
1 - approve: proceed to planning under the existing amendment review; a fresh reviewer applies evidence-backed factual corrections on its own, and every other spec amendment (scope, acceptance-criteria, or contract edits, and redraws) stops for your review.
|
|
127
127
|
2 - approve, auto-apply amends: every later spec amendment in this flow (corrected facts, paths, verification lines, and scope, acceptance-criteria, or public-contract edits alike) applies without asking; only a redraw (changed problem statement, component added, removed, or re-bounded) still stops for you, and the grant never stands in for a spec approval.
|
|
128
128
|
3 - show council dispositions: prints the council audit verbatim, then re-presents this gate. Not an approval.
|
|
129
|
-
|
|
129
|
+
4 - approve, loop engine (experimental): skip the plan; iterate a fresh loop-implementer over the acceptance-criteria ledger; amendments stop for your review as under 1.
|
|
130
|
+
5 - approve, loop engine, auto-apply amends: as 4 with option 2's amendment grant.
|
|
131
|
+
Add "; fund N fix rounds" (or "N more fix rounds") to 1, 2, 4, or 5 to fund N extra attempts per stagnant loop row or N implement fix rounds past the escalated waves round.
|
|
130
132
|
|
|
131
133
|
Or tell me what to change in the spec, or say "revert applied council edit <X>" to undo a specific applied edit.
|
|
132
134
|
```
|
|
133
135
|
|
|
136
|
+
For `none - <reason>` in `## Acceptance criteria`, render only options 1-3 and explain: "Loop engine unavailable: this spec has no acceptance-criteria rows." Keep the worker-path omission of option 3; do not invent a council audit.
|
|
137
|
+
|
|
134
138
|
If you believe the summary needs correcting, do **not** silently rewrite it - re-dispatch the summarizer or note the discrepancy as an adjacent line beneath the verbatim block.
|
|
135
139
|
|
|
136
140
|
**Revert valve.** "Revert applied council edit X" is a normal change request: revise the spec to undo edit X, re-dispatch the summarizer with a **fresh** temp path (per the re-dispatch rule below), and re-present the gate. This is cheap here - the spec is not yet plan- or code-bearing.
|
|
@@ -142,13 +146,16 @@ Wait for the user. Interpret funded replies with this table before routing chang
|
|
|
142
146
|
| bare `2` | approve; persist the option-2 description above |
|
|
143
147
|
| `2; fund 3 fix rounds` or `2, fund 3 fix rounds` | approve; persist that description plus `; fund 3 fix rounds`, not a change request |
|
|
144
148
|
| `1` with a budget token | approve; persist `fund 3 fix rounds` alone for that token (budget-only) |
|
|
149
|
+
| bare `5` | approve; persist the option-2 description above; engine loop |
|
|
150
|
+
| `5; fund 3 fix rounds` or `5, fund 3 fix rounds` | approve; persist the option-2 description plus `; fund 3 fix rounds`; engine loop |
|
|
151
|
+
| `4` with a budget token | approve; persist the token alone (budget-only); engine loop |
|
|
145
152
|
| approval prose with a token | approve; preserve the prose collapsed to one physical line |
|
|
146
|
-
| budget token alone (`fund 3 fix rounds`) | re-present the gate asking for `1` or `
|
|
153
|
+
| budget token alone (`fund 3 fix rounds`) | re-present the gate asking for `1`, `2`, `4`, or `5`; write nothing |
|
|
147
154
|
| token with malformed N | re-present the gate quoting the token; write nothing, never imply a change request |
|
|
148
155
|
|
|
149
156
|
For every value to persist, read [Standing grants](amendment-surface.md#standing-grants) and run Value decoding. Decode before `edit` or `--amend`; never persist a malformed token. Use the decoded table value in the approval persistence below, including budget-only approvals.
|
|
150
157
|
|
|
151
|
-
On a change request (including a revert), revise the spec and re-present - mint a **fresh** temp path for the re-dispatched summarizer (never reuse a prior round's path, so stale content can never be mistaken for the new summary). On `3` or its label alone: print the audit verbatim from `git -C <abs worktree path> show -s --format=%b HEAD` (never from a held tool result; the body survives the grant's `--amend --no-edit`), then re-present the same gate - the briefing text of the gate message just rendered, reused verbatim (no summarizer re-dispatch, no read of the removed `$SUMMARY_PATH`; if that text is no longer in context, the one-line degrade note takes its place), the `Council:` line, the adjacent lines, the
|
|
158
|
+
On a change request (including a revert), revise the spec and re-present - mint a **fresh** temp path for the re-dispatched summarizer (never reuse a prior round's path, so stale content can never be mistaken for the new summary). On `3` or its label alone: print the audit verbatim from `git -C <abs worktree path> show -s --format=%b HEAD` (never from a held tool result; the body survives the grant's `--amend --no-edit`), then re-present the same gate - the briefing text of the gate message just rendered, reused verbatim (no summarizer re-dispatch, no read of the removed `$SUMMARY_PATH`; if that text is no longer in context, the one-line degrade note takes its place), the `Council:` line, the adjacent lines, the rendered option rows; nothing in the spec or the commit changes. `3` plus a change request is a change request. `3` plus `1`/`2`/`4`/`5` prints and re-presents, and the approval is read only from a clean `1`/`2`/`4`/`5` on the re-presented gate - a reply carrying `3` never grants. A gate-round recommit (change request or revert) re-runs the same heredoc commit with the audit as its body, so HEAD always carries it; on a revert of edit X, move X's `Applied:` line to `Rejected:` with `-> reverted at gate` and recompute the `Council:` counts from the revised audit. On approval - `1`, `approve`, or equivalent prose approves without a grant; `2`, `approve, auto-apply amends`, or equivalent prose approves and grants; `4` approves without a grant; `5` approves and grants using option 2's description - first read [Standing grants](amendment-surface.md#standing-grants) (stop if unreadable). On every approval, `edit` the spec's `**Amend-grant:**` value to the decoded table value for funded replies, otherwise the granting sentence for 2/5 or `none` for 1/4. Write exactly one `**Engine:** loop` for 4/5 or `**Engine:** waves` for 1/2 directly below `**Amend-grant:**` in the header block (readers: absent -> `waves`). Then `git -C <abs worktree path> add -- <spec path>` and `git -C <abs worktree path> commit --amend --no-edit -q`, keeping the council-audit body; confirm `git -C <abs worktree path> show HEAD:<spec path>` contains both fields with the selected values and satisfies the grant predicate and Value decoding. A reply that mixes approval with a change request ("2 but rename the section") is a change request: revise, re-present, and read the grant only from the reply to the re-presented gate. If the amend or the HEAD check fails, stop and report; never proceed as granted. The plan and execution mode are mechanical derivatives, so the only human gate here is spec approval itself. Don't land the spec on `main`; it stays in the worktree and ships in the same squash commit as the implementation.
|
|
152
159
|
|
|
153
160
|
Post-approval changes follow [Amending an approved spec](../SKILL.md#amending-an-approved-spec).
|
|
154
161
|
|
|
@@ -157,3 +164,5 @@ After approval, mark the brainstorm phase complete:
|
|
|
157
164
|
```
|
|
158
165
|
phase_tracker({ action: "complete", phase: "brainstorm" })
|
|
159
166
|
```
|
|
167
|
+
|
|
168
|
+
Then invoke `/skill:writing-plans` on 1/2 or `/skill:loop-implementation` on 4/5 immediately, with no further prompt.
|
|
@@ -17,6 +17,6 @@ Ticket <ref>, <heading or "checkbox list">, rows verbatim:
|
|
|
17
17
|
<disposition>
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The heading `## Acceptance criteria` names the ticket contract only; the spec's own requirements stay in Design, and the section stays flat - a row's repo lives in its disposition token, never in a heading. Disposition is exactly one of `in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`, `elsewhere: <repo>`; default `in-scope`. Never edit the row text: an ambiguous row stays `in-scope` with the chosen reading written as a Design clause, and a moved path or a workflow artifact (spec, plan, changelog, telemetry file) is a Design clause too, never a disposition and never asked. A row under a repo group that is not this repo is `elsewhere: <repo>`, stated, never asked; a group matching no repo asks `A) this repo B) elsewhere: <name> C) repair the ticket - /skill:shape-ticket <ref>`. Name a `venue:` row's enabling change in Design; `venue:` states where the observation can happen and is never `prd`, `prod`, or `production` - a row observable only in production is a wrong row. An `in-scope` row is a requirement as written; disposition reasons are never normative for the plan or the reviewer, so a `deviates:` reason that adopts part of a row restates that part as a Design clause. A `deferred:` destination is a tracker ref (`#N`, `owner/repo#N`, `ABC-123`), a spec path, or a URL; a prose destination with none of these is a gap at the PR gate.
|
|
20
|
+
The heading `## Acceptance criteria` names the ticket contract only; the spec's own requirements stay in Design, and the section stays flat - a row's repo lives in its disposition token, never in a heading. Disposition is exactly one of `in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`, `elsewhere: <repo>`; default `in-scope`. Never edit the row text: an ambiguous row stays `in-scope` with the chosen reading written as a Design clause, and a moved path or a workflow artifact (spec, plan, changelog, telemetry file) is a Design clause too, never a disposition and never asked. A row under a repo group that is not this repo is `elsewhere: <repo>`, stated, never asked; a group matching no repo asks `A) this repo B) elsewhere: <name> C) repair the ticket - /skill:shape-ticket <ref>`. Replace `<name>` with the supplied unmatched group heading verbatim. Name a `venue:` row's enabling change in Design; `venue:` states where the observation can happen and is never `prd`, `prod`, or `production` - a row observable only in production is a wrong row. An `in-scope` row is a requirement as written; disposition reasons are never normative for the plan or the reviewer, so a `deviates:` reason that adopts part of a row restates that part as a Design clause. A `deferred:` destination is a tracker ref (`#N`, `owner/repo#N`, `ABC-123`), a spec path, or a URL; a prose destination with none of these is a gap at the PR gate.
|
|
21
21
|
|
|
22
22
|
**Cut question.** `deviates:` and `deferred:` come only from the user's answer to this question; never propose one. Ask it, in the questionary format, when the user's prompt or an answer raises dropping or changing a row, or when code, a cited contract, or the user shows a row is wrong or impossible: `A) in-scope - <reading> B) deviates: <why> C) deferred: <where> D) repair the ticket - /skill:shape-ticket <ref> <row and evidence>`, `Recommendation:` A or D with the reason the row ships in this gauntlet; B and C are never recommended. On D, run `/skill:shape-ticket <ref> <row and evidence>` (repair mode per `shape-ticket/SKILL.md:43`, its own confirm gate), then re-fetch the ticket, replace the gather draft's `## Ticket acceptance criteria (verbatim)` block, and re-extract; a cancel at that gate returns to this question with the row unchanged. Carry the full question and the user's answer of every question that offered a disposition into the council's `Human input` block. The gate lists every `deferred:`, `deviates:`, and `venue:` row on its `Scope cuts:` line (`spec-finalization.md`). A disposition changes in any later phase - a reviewer finding `recommended: rescope` at the finish gate, a wrong row noticed mid-implementation, or a ticket edited after approval when the user asks - through [Amending an approved spec](../SKILL.md#amending-an-approved-spec) (`amendment-surface.md`); the row text still never changes. With no ticket, or a ticket without ACs, the section body is the single line `none - no ticket`, `none - ticket has no acceptance criteria`, or `none - ticket not fetched (<reason>)`. Never author acceptance criteria on the ticket's behalf; that is `/skill:shape-ticket`'s job.
|
|
@@ -34,7 +34,7 @@ Then call `phase_tracker({ action: "start", phase: "ship" })`.
|
|
|
34
34
|
|
|
35
35
|
**Hard verification gate.** Tests/format/lint must pass before presenting any options — including Discard. The user's stated intent to throw the branch away does not change whether the diff is in a verifiable state; verifying first surfaces accidental damage to unrelated code before the branch is gone forever. The skip rule below is the only exception.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Recognize a ledger by line 1 exactly `# Ledger - loop engine`. For a ledger, use its `verification:` command in place of the task plan header's `**Verification:**` set throughout finish, including the minors round. Run that set in the worktree: `(cd "$WORKTREE" && <command>)`. With no plan in this session, run the verification command(s) of the affected services from the gauntlet overrides file or `AGENTS.md` (look for "verification", "CI", or "test" sections).
|
|
38
38
|
|
|
39
39
|
**Skip rule.** Skip the run only when this set passed on a known clean commit in the verify phase of this session and no edit or write landed outside `<telemetry.dir>` since. Check the current tree: `git -C "$WORKTREE" diff --quiet <commit the run passed on> -- . ':!<telemetry.dir>'` must exit 0, and `git -C "$WORKTREE" status --porcelain --untracked-files=all -- . ':!<telemetry.dir>'` must exit 0 with empty output (`<telemetry.dir>` defaults to `.pi/gauntlet/telemetry`). These checks cover committed, staged, unstaged, and untracked changes outside telemetry. Otherwise run it once; a missing verified commit, a failed check, or uncertainty means run.
|
|
40
40
|
|
|
@@ -169,7 +169,7 @@ A **heavy** revert is not a menu toggle — say so explicitly to the user before
|
|
|
169
169
|
|
|
170
170
|
### Step 4: Present Options
|
|
171
171
|
|
|
172
|
-
**Amendment digest (both variants).** Before the options, read `git -C "$WORKTREE" log <base-branch>..HEAD --grep '^amend:'` and take the `auto-apply` and `granted` records from those commit bodies. Render, then the options:
|
|
172
|
+
**Amendment digest (both variants).** Before the options, read `git -C "$WORKTREE" log <base-branch>..HEAD --extended-regexp --grep '^(amend:|loop: cut row [0-9]+|loop: amend)'` and take the `auto-apply` and `granted` records from those commit bodies. Render, then the options:
|
|
173
173
|
|
|
174
174
|
```
|
|
175
175
|
Amendments auto-applied (N):
|
|
@@ -221,11 +221,11 @@ Rows 1-2 run the Option 1/2 blocks; row 3 runs the Keep block and row 4 the Disc
|
|
|
221
221
|
|
|
222
222
|
Run this on the feature branch before any landing path. The spec and its telemetry record (`<telemetry.dir>/<spec path with .md -> .yaml>`, default `.pi/gauntlet/telemetry/doc/specs/<spec>.yaml`) are deliverables and ship in the squash; only the plan is stripped. The record is an untracked, git-excluded file until this step commits it (in a plain jj workspace there is no commit; jj snapshots the stamped record into the working-copy change). `<bin>` is `<directory of this skill's SKILL.md>/../../bin`, resolved from the skill's `<location>` in the system prompt.
|
|
223
223
|
|
|
224
|
-
Read the
|
|
224
|
+
Read the existing artifact's path-only `**Spec:**` header (repo-relative, backticks stripped) before removal; pass that value as `--spec`, including for a line-1 ledger. Resolve the spec dirs with `gauntlet_setting({ key: "flowGuards" })` and use their sibling `plans` dirs for plan paths. Enumerate both PLAN_PATH candidates: the task plan paired by basename and `<sibling plans dir>/<spec stem>-ledger.md`. Preserve the spec and telemetry.
|
|
225
225
|
|
|
226
226
|
```bash
|
|
227
227
|
# Plans are ephemeral - if one was committed on this branch, remove it before landing.
|
|
228
|
-
PLAN_PATH
|
|
228
|
+
for PLAN_PATH in <basename-task-plan-path> <sibling-plans-dir>/<spec-stem>-ledger.md; do
|
|
229
229
|
if git -C "$WORKTREE" ls-files --error-unmatch "$PLAN_PATH" >/dev/null 2>&1; then
|
|
230
230
|
git -C "$WORKTREE" rm "$PLAN_PATH" && git -C "$WORKTREE" commit -m "Remove ephemeral plan doc"
|
|
231
231
|
elif [ -f "$WORKTREE/$PLAN_PATH" ] && jj -R "$WORKTREE" root >/dev/null 2>&1; then
|
|
@@ -233,10 +233,11 @@ elif [ -f "$WORKTREE/$PLAN_PATH" ] && jj -R "$WORKTREE" root >/dev/null 2>&1; th
|
|
|
233
233
|
# root: anchors the path at the workspace root - jj resolves bare paths against cwd, not -R.
|
|
234
234
|
jj -R "$WORKTREE" restore --from <base-branch> -- "root:\"$PLAN_PATH\""
|
|
235
235
|
fi
|
|
236
|
+
done
|
|
236
237
|
|
|
237
238
|
# Seal the telemetry record: stamp shipped, compute the diff, commit it once.
|
|
238
239
|
# The bin detects a plain jj workspace (no .git) itself: jj diff, no commit step.
|
|
239
|
-
# --option is pr for Options 1-2 and squash for Option 3; --spec is the
|
|
240
|
+
# --option is pr for Options 1-2 and squash for Option 3; --spec is the artifact header's **Spec:** value (omit when no artifact is known).
|
|
240
241
|
node <bin>/gauntlet-telemetry-seal.mjs --worktree "$WORKTREE" --option <pr|squash> --base <base-branch> --spec <spec path>
|
|
241
242
|
```
|
|
242
243
|
|
|
@@ -83,8 +83,7 @@ loop: tracker state is extension state no subagent can read.
|
|
|
83
83
|
- A phase `in_progress` (verify or ship included - resume stops at verify on its own)
|
|
84
84
|
-> append the process-state section exactly as `## Producers` in
|
|
85
85
|
`reference/brief-contract.md` lays it out: both status outputs verbatim
|
|
86
|
-
(`No plan active.` verbatim when there is no plan), the
|
|
87
|
-
the first `→` task else `none`, the gate-history line. Append with a single
|
|
86
|
+
(`No plan active.` verbatim when there is no plan), the contract's artifact-specific fields, and the gate-history line. Recognize the loop alternative by ledger line 1; read the ledger from the run worktree for its durable last decision. Use only the contract's grammar; write no second state file. Append with a single
|
|
88
87
|
`cat >> "<brief path>" <<'EOF' ... EOF` whose body is that block.
|
|
89
88
|
- Re-read the file tail and confirm it ends with the gate-history line from the
|
|
90
89
|
contract and nothing after.
|
|
@@ -100,7 +100,7 @@ checks 2, 4, 5 do not apply; check 6 runs on the seed's pinned spec path.
|
|
|
100
100
|
6. **Grant field.** Runs once the route has resolved `<spec path>` - the `S` path that
|
|
101
101
|
`reference/brief-contract.md` "Process-state restore" resolves for `skip brainstorm`
|
|
102
102
|
(process-state briefs), the spec reconstruction resolves and the human approves
|
|
103
|
-
(Spec without plan) or confirms (Spec with plan) (`reference/reconstruction.md`), or
|
|
103
|
+
(Spec without plan) or confirms (Spec with ledger or Spec with plan) (`reference/reconstruction.md`), or
|
|
104
104
|
the pinned `<full-path>/<rel>` of a spec tracked on `main` (`reference/seed.md`) -
|
|
105
105
|
and before that route's first tracker call; the path is carried, never re-resolved.
|
|
106
106
|
Read the spec's header block (between the H1 and the first `##`) through the
|
|
@@ -142,9 +142,12 @@ owning skill **without** its reset-bearing entry:
|
|
|
142
142
|
| Active after restore | Continue in | Entry point |
|
|
143
143
|
|---|---|---|
|
|
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
|
-
|
|
|
146
|
-
|
|
|
147
|
-
|
|
|
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
|
+
| 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 |
|
|
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 |
|
|
150
|
+
| verify without `Ledger:` | verification-before-completion | full conformance gate; nothing carried over |
|
|
148
151
|
|
|
149
152
|
## Red flags — STOP
|
|
150
153
|
|
|
@@ -29,9 +29,17 @@ Headings, fixed order. A consumer keys on headings, never prose.
|
|
|
29
29
|
| `## Skills loaded` | frontmatter `name`s; `## Skills loaded: none` when none | always |
|
|
30
30
|
| `## Process state` | `phase_tracker status` then `plan_tracker status` verbatim; `Active task: <name|none>`; the line `Gate history not restored - re-validate before advancing.` | only when a phase is `in_progress` and no hotfix flow is in context |
|
|
31
31
|
|
|
32
|
+
For a loop ledger (line 1 exactly `# Ledger - loop engine`), replace `Active task` with these two fields, retaining both tracker status outputs and the gate-history line:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
Ledger: <path>
|
|
36
|
+
Last decision: <line>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Use the ledger path relative to the worktree and the last physical decision line, or `none` for an empty Decisions section. Read the ledger on disk; the brief is a pointer, not a second state carrier. Reject a block mixing these fields with `Active task`, missing either loop field, or carrying task rows with a ledger. Never initialize a task tracker for a ledger.
|
|
40
|
+
|
|
32
41
|
Consumer rules: process state absent -> plain handoff (the consumer starts its
|
|
33
|
-
own process from `## Intent`)
|
|
34
|
-
plan; loading named skills is the consumer's job.
|
|
42
|
+
own process from `## Intent`). Give valid ledger fields precedence over `No plan active.` and run ledger admission. Restore phase-only state for `No plan active.` only with no `Ledger` field. Load named skills as the consumer.
|
|
35
43
|
|
|
36
44
|
A brief is any text whose first line starts `# Handoff:` - a file on disk or pasted
|
|
37
45
|
inline. `## Repo state` is matched by prefix: `## Repo state` or
|
|
@@ -44,7 +52,7 @@ cohort's `handoff` skill wrote, which ends at `## Skills loaded`. Layout, byte-e
|
|
|
44
52
|
one blank line, the heading on its own line, a blank line, the `phase_tracker status`
|
|
45
53
|
output verbatim, a blank line, the `plan_tracker status` output verbatim, a blank line,
|
|
46
54
|
`Active task: <name|none>`, then the gate-history line - unfenced, nothing after.
|
|
47
|
-
`Active task`
|
|
55
|
+
For a task plan, set `Active task` to the first `→` task name, else `none` (also for `No plan active.`). For a line-1 ledger, read its path and last decision and use the loop alternative above.
|
|
48
56
|
|
|
49
57
|
Example appended block (the fence is documentation; the brief carries no fence):
|
|
50
58
|
|
|
@@ -130,11 +138,14 @@ announcement without re-resolving it.
|
|
|
130
138
|
|---|---|
|
|
131
139
|
| brainstorm | `start brainstorm`; `substep` if the brief shows one |
|
|
132
140
|
| plan | `start brainstorm`; `skip brainstorm S`; `start plan`; `substep` if shown |
|
|
133
|
-
| implement | `start brainstorm`; `skip brainstorm
|
|
141
|
+
| 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 last decision; 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. |
|
|
142
|
+
| 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` |
|
|
134
143
|
| verify | as implement through `skip plan R`, then `skip implement R`; `start verify`; `substep` if shown; `plan_tracker init` |
|
|
135
144
|
| 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 |
|
|
136
145
|
|
|
137
|
-
`
|
|
146
|
+
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.
|
|
147
|
+
|
|
148
|
+
`planPath` (task-plan implement onward): the brief carries none. Resolve as reconstruction does
|
|
138
149
|
(`reconstruction.md`, "Candidates", including its `flowGuards.specDirs` resolution): the
|
|
139
150
|
single plan added after base, paired with `<specDir>/<same basename>` whether that
|
|
140
151
|
spec was added after base or tracked from base (`reconstruction.md` "Candidates");
|
|
@@ -214,7 +225,9 @@ Every restore ends with:
|
|
|
214
225
|
Gate history not restored; re-validating `<task>` before any stage advance
|
|
215
226
|
```
|
|
216
227
|
|
|
217
|
-
|
|
228
|
+
For a ledger, use `ledger rows` as `<task>` and render the current rows and last decision from disk.
|
|
229
|
+
|
|
230
|
+
For a task plan, `<task>` is the brief's `Active task`, else the first in-progress task, else `none`
|
|
218
231
|
(whole-deliverable re-validation). Gate history, closure-review evidence, and fix rounds
|
|
219
232
|
are never inferred or restored; a ship-stage brief resumes at verify.
|
|
220
233
|
|
|
@@ -35,7 +35,7 @@ git -C <worktree> ls-files --others --exclude-standard -- <dirs>
|
|
|
35
35
|
Candidates are files under those directories added after base, plus untracked files
|
|
36
36
|
there. Paths returned by these commands are relative to `<worktree>`; resolve them to
|
|
37
37
|
absolute paths under `<worktree>` before reading artifacts, showing paths in prompts,
|
|
38
|
-
or calling `plan_check`.
|
|
38
|
+
or calling `plan_check`. Read every plan-directory candidate's first line. A line exactly `# Ledger - loop engine` pairs by its path-only `**Spec:**` header, not basename; resolve that spec under the worktree's configured spec dirs, including a spec tracked from base. Stop on a missing or foreign spec. A task-plan candidate pairs with
|
|
39
39
|
`<worktree>/<specDir>/<same basename>` whether that spec is a candidate or tracked
|
|
40
40
|
from base; count a base-tracked spec so paired as a spec in the route table below.
|
|
41
41
|
The plan commit is the first
|
|
@@ -48,7 +48,8 @@ plan commit; treat every task as `pending`.
|
|
|
48
48
|
| no spec | stop; offer `/skill:brainstorming` or pass the spec: `/skill:gauntlet-resume <specDir>/<name>.md`; no tracker call |
|
|
49
49
|
| more than one spec | the human picks one, then continue below with that spec |
|
|
50
50
|
| one spec, no plan | "Spec without plan" |
|
|
51
|
-
| one spec with
|
|
51
|
+
| one spec with ledger | "Spec with ledger" (takes precedence over a task plan) |
|
|
52
|
+
| one spec with task plan only | "Spec with plan" |
|
|
52
53
|
|
|
53
54
|
## Spec without plan
|
|
54
55
|
|
|
@@ -56,14 +57,26 @@ Ask exactly one question: is this spec approved, or do you select `/skill:brains
|
|
|
56
57
|
with this unapproved spec as the draft? Show the spec path (and the brief's
|
|
57
58
|
`## Intent`/`## Decisions` when present).
|
|
58
59
|
|
|
59
|
-
- Approved: run SKILL.md entry check 6 on `<spec path>` first (a malformed `**Amend-grant:**` line stops here, no tracker call)
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
- Approved: run SKILL.md entry check 6 on `<spec path>` first (a malformed `**Amend-grant:**` line stops here, no tracker call). Read the spec's `**Engine:**` line and take the matching route:
|
|
61
|
+
- `loop`: call `start brainstorm`, then `skip brainstorm` with reason `resume: <spec path>` to arm the flow before `plan_check`. Carry absolute worktree/spec paths and the resolved plan directory into `/skill:loop-implementation` Entry steps 1-5: resolve settings at step 1 and verification at step 2, retain the driver's `skip plan` at step 3, create the ledger at step 4, then check/commit it and start implement at step 5. Never enter the writing-plans body or initialize a task tracker.
|
|
62
|
+
- `waves` or absent: `start brainstorm`; `skip brainstorm resume: <spec path>`; `start plan`; continue in writing-plans, skipping its `start plan` call.
|
|
62
63
|
- Selected unapproved-draft brainstorming handoff: invoke [`/skill:brainstorming`](../../brainstorming/SKILL.md) with
|
|
63
64
|
the spec as the draft; arm nothing. using-git-worktrees Step 0 detects the existing
|
|
64
65
|
worktree and creates none. A bare "not approved" answer is not consent; wait for
|
|
65
66
|
explicit handoff selection.
|
|
66
67
|
|
|
68
|
+
## Spec with ledger
|
|
69
|
+
|
|
70
|
+
Show the spec and ledger paths, current rows, iterations, last decision, and `git -C <worktree> status --porcelain`. Ask the human to confirm the approved spec and continuation; carry brief Intent/Decisions when present. Keep entry and same-repository checks.
|
|
71
|
+
|
|
72
|
+
After confirmation:
|
|
73
|
+
|
|
74
|
+
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.
|
|
75
|
+
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" })`.
|
|
76
|
+
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`.
|
|
77
|
+
4. Read `/skill:loop-implementation`; resolve its Entry settings/maxIterations without creating or overwriting the ledger. Restore base, verification, iterations, row attempts, funding and retry allowances from the ledger/spec and branch. Render rows and last decision. A dirty tree stops before any dispatch using the driver's dirty-tree stop note; preserve changes for the human.
|
|
78
|
+
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.
|
|
79
|
+
|
|
67
80
|
## Spec with plan
|
|
68
81
|
|
|
69
82
|
Show, and ask the human to confirm or edit both in one reply:
|