pi-gauntlet 7.33.0 → 7.35.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 +14 -0
- package/README.md +32 -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/skills/shape-ticket/SKILL.md +11 -10
- package/skills/shape-ticket/reference/repo-audit.md +57 -3
- package/skills/shape-ticket/reference/tracker-ladder.md +10 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v7.35.0 - 2026-10-26
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `shape-ticket` now makes a parent-owned, evidence-backed obsolete verdict in both modes: delivered, superseded, premise contradicted, not reproduced, or duplicate (repair only). Repair offers a close row; create offers "Drop the idea" alongside create anyway. Exactly one selectable option is recommended, with the obsolete exit recommended when present. Close remains explicitly gated on its displayed operations and evidence, not approval of a body edit; even an otherwise conforming obsolete ticket reaches the gate. The README documents close defaults and free-form tracker overrides. (#88)
|
|
8
|
+
|
|
9
|
+
## v7.34.0 - 2026-10-26
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **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.
|
|
14
|
+
- 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.
|
|
15
|
+
- pi-cohort peer floor raised to 7.5.0.
|
|
16
|
+
|
|
3
17
|
## v7.33.0 - 2026-10-26
|
|
4
18
|
|
|
5
19
|
### 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
|
|
|
@@ -408,6 +408,37 @@ tracker selection; free-form verb mappings keep working both without a `tracker:
|
|
|
408
408
|
key (ladder rung 1, as today) and as the mechanics source when `tracker:` names an
|
|
409
409
|
unknown value.
|
|
410
410
|
|
|
411
|
+
### Close verb defaults and overrides
|
|
412
|
+
|
|
413
|
+
`shape-ticket` resolves `close:` as a free-form command mapping under
|
|
414
|
+
`## Issue tracker`, not a sixth Linear configuration key. Its defaults are:
|
|
415
|
+
|
|
416
|
+
| Audit reason | GitHub reason | Linear status |
|
|
417
|
+
|---|---|---|
|
|
418
|
+
| Delivered | `completed` | `Done` |
|
|
419
|
+
| Superseded, premise contradicted, not reproduced | `not planned` | `Canceled` |
|
|
420
|
+
| Duplicate with a tracker-native target | `duplicate` | `Duplicate` |
|
|
421
|
+
|
|
422
|
+
GitHub uses one close-with-evidence command:
|
|
423
|
+
`gh issue close <n> --reason "<reason>" [--duplicate-of <ref>] --comment "<evidence>"`.
|
|
424
|
+
Linear posts evidence first with `linearis issues discuss <id> --body "<evidence>"`,
|
|
425
|
+
then closes with `linearis issues update <id> --status <Done|Canceled|Duplicate>
|
|
426
|
+
[--duplicate-of <ref>]`. A native duplicate target is a GitHub issue number or URL,
|
|
427
|
+
or a Linear identifier such as `ABC-123`, for the selected tracker. Only that
|
|
428
|
+
mapping includes `--duplicate-of`; a nonnative target uses `not planned` /
|
|
429
|
+
`Canceled` and keeps the reference in the evidence.
|
|
430
|
+
|
|
431
|
+
Add `- close: <command>` under `## Issue tracker` to replace the entire close
|
|
432
|
+
sequence, including evidence posting. Override renamed Linear workflows there.
|
|
433
|
+
Section prose also applies: if a mapped state is reserved for humans, the menu
|
|
434
|
+
shows `Close as <reason> - run by hand: <operations>`; selecting it writes nothing.
|
|
435
|
+
Selecting an executable close row authorizes only its displayed operations and
|
|
436
|
+
evidence, not a body edit or Reporter note. This explicit close gate still applies
|
|
437
|
+
when ordinary status changes are described as "announced, not gated". This mapping
|
|
438
|
+
is separate from the `## cleanup` `close ticket` convention in the example above.
|
|
439
|
+
See the [tracker resolution ladder](skills/shape-ticket/reference/tracker-ladder.md)
|
|
440
|
+
for resolution details.
|
|
441
|
+
|
|
411
442
|
### Worked example: wrapper-managed worktrees (acme-mono)
|
|
412
443
|
|
|
413
444
|
Complete `.pi/settings.json`:
|
|
@@ -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.35.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
|
|
|
@@ -12,13 +12,14 @@ description: Use when asked to file, create, or shape a ticket, open a tracker i
|
|
|
12
12
|
| Free text / vague ask, no ticket ref | Create mode: gather -> bounded overlap check -> draft -> gates -> roast -> confirm -> write (9-step pipeline below) |
|
|
13
13
|
| Issue refs (`#N`, `ABC-123`, URL), comma/whitespace list | Repair mode: fetch full ticket + 1-hop links -> diff old->new -> gates -> roast -> confirm -> re-fetch and re-diff before write (9-step pipeline below) |
|
|
14
14
|
| Ref + extra text | Repair mode, extra text folded into gather |
|
|
15
|
-
|
|
|
15
|
+
| Audit shows the ticket should not stand | Obsolete line above Title; close row (repair) or drop-the-idea row (create), tagged recommended |
|
|
16
|
+
| Ordinary repair already conforms + metadata clean + no comment proposed, unless the audit carries an obsolete line | No-op: report and stop, no gate, no write |
|
|
16
17
|
| AC is wishful/tautological | Ticket-local hard stop or affected overlap alternative; source-ticket split stays atomic - fix or split to discovery |
|
|
17
18
|
| AC is unspecified-but-binding or needs external input | Ticket filed, parked in not-ready state, blocker named |
|
|
18
19
|
| Independent shippable slices detected | Split proposed at the gate, one approval, per-issue subset selection |
|
|
19
20
|
| Headless / no interactive response available | Stops at the confirmation gate |
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
Apply the [hard constraint](#hard-constraint) at every ticket's **own single confirmation gate**. Ordinary repair no-op stops before the gate; overlap alternatives use the payload-local gates in the overlap reference.
|
|
22
23
|
|
|
23
24
|
Model-initiated invocation is allowed: another skill, a command, or an ask matching the description starts this pipeline without a human typing the command. That changes who starts the pipeline, never who approves the write - the human answers the gate.
|
|
24
25
|
|
|
@@ -34,7 +35,7 @@ It is a tool, not a phase: no `plan_tracker`, no `phase_tracker`, no worktree re
|
|
|
34
35
|
|
|
35
36
|
## Hard constraint
|
|
36
37
|
|
|
37
|
-
**Every tracker write sits behind exactly one confirmation gate, presented as an explicit old->new (or as-new) diff. No affirmative answer on that exact diff = no write.** Approve the exact presented diff plus only the `source:` footer substitutions resolved by that same approving reply under step 8; make no other post-approval edit and add no second gate. This includes create, repair, split writes, and discovery-conversion writes - one gate covers a source-ticket split's N bodies, with subset selection. A repair batch has one exact-diff gate per ticket; never approve an unseen ticket. A headless or unattended run (no interactive response available) stops at the gate. There is no timeout-approve, no "the user implied yes earlier," no partial write before the gate.
|
|
38
|
+
**Every tracker write sits behind exactly one confirmation gate, presented as an explicit old->new (or as-new) diff. No affirmative answer on that exact diff (or, for the close row, the displayed operation sequence and evidence) = no write.** Approve the exact presented diff plus only the `source:` footer substitutions resolved by that same approving reply under step 8; make no other post-approval edit and add no second gate. This includes create, repair, split writes, and discovery-conversion writes - one gate covers a source-ticket split's N bodies, with subset selection. A repair batch has one exact-diff gate per ticket; never approve an unseen ticket. A headless or unattended run (no interactive response available) stops at the gate. There is no timeout-approve, no "the user implied yes earlier," no partial write before the gate.
|
|
38
39
|
|
|
39
40
|
## Mode routing
|
|
40
41
|
|
|
@@ -44,7 +45,7 @@ Consume explicit invocation option `--skip-overlap` before routing and exclude i
|
|
|
44
45
|
- **Free text or no argument** -> **create mode**, from the argument plus surrounding conversation.
|
|
45
46
|
- **Refs + extra text** -> repair mode. Fold ref-named statements into only that ref's gather. Carry requester-supplied unscoped text as common context to each scout and gather summary; carry it into the Context of each ticket whose snapshot or audit supports it, and surface applicability only at the other tickets' gates.
|
|
46
47
|
- **Unreadable refs** -> report each ref and reason as unfetched and continue fetched tickets. When every ref is unfetched, abort repair and offer create mode from accompanying text. Never guess ticket content.
|
|
47
|
-
- **Out of scope**: read-only asks (search, status lookup) and administrative writes (status transitions, standalone comment posts) - use the tracker CLI directly; gated Reporter-note and overlap-evidence comments inside this pipeline are the comment exceptions.
|
|
48
|
+
- **Out of scope**: read-only asks (search, status lookup) and administrative writes (status transitions, standalone comment posts) - use the tracker CLI directly; gated Reporter-note and overlap-evidence comments inside this pipeline are the comment exceptions; except the close row the step 8 template renders, keep status transitions outside this pipeline.
|
|
48
49
|
|
|
49
50
|
## The pipeline
|
|
50
51
|
|
|
@@ -99,7 +100,7 @@ Exempt one deletion-safe rule-7 pointer per failure, rule-5 one-sentence/one-num
|
|
|
99
100
|
|
|
100
101
|
### 6 - No-op check
|
|
101
102
|
|
|
102
|
-
For ordinary repair only, if the body already conforms AND the metadata audit is clean AND no comment is proposed: report "conforms, no changes proposed" and stop. No write, no confirmation prompt, no roast. A conforming ticket never pays for a roast dispatch; the gather audit already ran and its Audit lines ride on the no-op report. Treat draft-changing audit findings under `reference/repo-audit.md` as non-conforming; quiet findings alone keep the no-op. A conforming body with pending overflow still reaches the gate.
|
|
103
|
+
For ordinary repair only, if the body already conforms AND the metadata audit is clean AND no comment is proposed AND the audit carries no obsolete line: report "conforms, no changes proposed" and stop. No write, no confirmation prompt, no roast. A conforming ticket without an obsolete line never pays for a roast dispatch; the gather audit already ran and its Audit lines ride on the no-op report. Treat the obsolete line and other draft-changing audit findings under `reference/repo-audit.md` as non-conforming; quiet findings alone keep the no-op. A conforming body with pending overflow still reaches the gate.
|
|
103
104
|
|
|
104
105
|
"Conforms" includes the ticket wording contract (`reference/ticket-wording.md`, resolved against this skill's own directory), applied inline as a short checklist over Context/Problem/Idea: strip test passes (rule 2)? plain-words lead per asserted failure (rule 4)? example or `none (<reason>)` per failure (rule 5)? repo-native terms defined or dropped and requester-used terms left undefined under rule 6's attribution test? Idea within one attributed sketch line? Context/Problem free of step-5 closed-list matches? references parenthetical and deletion-safe (rule 7)? links summarized, no spiderman hops (rule 8, with the named example serving as a source footer's summary)? every gathered URL, attachment, or pasted screenshot is carried in a source: footer under its example (Evidence gate carry rule)? every non-discovery Problem example has a source: footer (Evidence gate gap rule)? Any "no" makes the body non-conforming: repair proposes a rewrite through the normal draft -> gates -> roast -> gate path instead of reporting "conforms" - the contract-briefed roast backstops this inline judgment. Route each failure through draft -> step 5 -> roast -> old/new gate, with a new comment for newly displaced detail. For a conformance-only rewrite with no audit or uniqueness change to AC text, rows, or groups, touch Context/Problem/Idea prose only: copy the original bytes under the AC heading unchanged and compare bytes before presenting the gate; any mismatch stops that ticket. Any AC text, row, or group change from audit or uniqueness instead takes substantive full-replacement repair with `- [ ]` normalization; retain displaced text verbatim in the Reporter note. Check source carrying for every title; check source gaps only for non-discovery bodies. Preserve existing `source:` lines verbatim. For missing-footer-only repair, add only the footer under step 8 and leave existing prose and AC bytes unchanged; never report "conforms, no changes proposed".
|
|
105
106
|
|
|
@@ -109,7 +110,7 @@ See Roast below. Surface source-gap findings at step 8; never apply them by inve
|
|
|
109
110
|
|
|
110
111
|
### 8 - Confirmation gate
|
|
111
112
|
|
|
112
|
-
Finish initial preparation and roasts for all eligible tickets before the first gate. Present only the current ticket in ref order: decline skips it; revision rechecks and re-presents its exact diff; approval completes step 9 before the next ticket prints. Never treat a reply as approval of an unseen ticket. Present stopped tickets' draft/report at their turn with no approval option; preserve a split's N-body subset-selection gate. End with one line per ref: `<ref>: written | declined | stopped | no-op | unfetched
|
|
113
|
+
Finish initial preparation and roasts for all eligible tickets before the first gate. Present only the current ticket in ref order: decline skips it; revision rechecks and re-presents its exact diff; approval completes step 9 before the next ticket prints. Never treat a reply as approval of an unseen ticket. Present stopped tickets' draft/report at their turn with no approval option; preserve a split's N-body subset-selection gate. End with one line per ref: `<ref>: written | closed | close failed (<operation>: <reason>) | close by hand | dropped | declined | stopped | no-op | unfetched` (use the drafted title for create).
|
|
113
114
|
|
|
114
115
|
Present, per proposed issue:
|
|
115
116
|
|
|
@@ -137,11 +138,11 @@ Keep partially resolved create gates open with only unresolved rows; never fill
|
|
|
137
138
|
|
|
138
139
|
Read and apply [menu-layout](../brainstorming/reference/menu-layout.md) before presenting these options and before acting on a numeric reply.
|
|
139
140
|
|
|
140
|
-
Number the options. A split offers per-issue subset selection, e.g. "approve 1,3; decline 2". **No affirmative answer on the exact presented diff plus only the `source:` substitutions resolved by that same approving reply = no write; make no other post-approval edit and add no second gate.**
|
|
141
|
+
Render the options from the gate menu template in `reference/repo-audit.md`, including its mode's exit row and `[recommended]` tag. Number the options. A split offers per-issue subset selection, e.g. "approve 1,3; decline 2". **No affirmative answer on the exact presented diff (or the close row's displayed operations and evidence) plus only the `source:` substitutions resolved by that same approving reply = no write; make no other post-approval edit and add no second gate.**
|
|
141
142
|
|
|
142
143
|
### 9 - Write
|
|
143
144
|
|
|
144
|
-
Complete the current ticket's write before presenting the next ticket. Immediately before any mutation, including comments - after approval, not at gate-open - re-fetch the relevant body, discussion, and workflow of any existing ticket underlying the selected changeset (repair, enrichment, or override-create). Write the resolved source footers in the approved payload. Compare against the original gathered ticket snapshot the user approved, not the pending footer-bearing replacement; only a change loops back to step 8 with the delta. Use tracker version/ETag preconditions where supported. Treat unrelated hits listed as rejected coverage as non-sources; a plain create with no underlying existing ticket has nothing to revalidate. For overlap, follow the gathered reference's selected-operation rules. Then one batched write per approved issue, body first, then the approved Reporter-note comment if any; a split is N gated writes under the one approval, honoring subset selection. Mid-batch failure: report exactly what landed; the remaining changeset is preserved for retry.
|
|
145
|
+
Complete the current ticket's write before presenting the next ticket. Immediately before any mutation, including comments - after approval, not at gate-open - re-fetch the relevant body, discussion, and workflow, including state before a close, of any existing ticket underlying the selected changeset (repair, enrichment, or override-create). Write the resolved source footers in the approved payload. Compare against the original gathered ticket snapshot the user approved, not the pending footer-bearing replacement; only a change loops back to step 8 with the delta. Use tracker version/ETag preconditions where supported. Treat unrelated hits listed as rejected coverage as non-sources; a plain create with no underlying existing ticket has nothing to revalidate. For close/drop, apply the selected-exit recipe in `reference/repo-audit.md` before the body-first branch; never fall through to body writing. For overlap, follow the gathered reference's selected-operation rules. Then one batched write per approved issue, body first, then the approved Reporter-note comment if any; a split is N gated writes under the one approval, honoring subset selection. Mid-batch failure: report exactly what landed; the remaining changeset is preserved for retry.
|
|
145
146
|
|
|
146
147
|
## AC integrity gate
|
|
147
148
|
|
|
@@ -277,7 +278,7 @@ Read `reference/examples.md` now for the built-in bad->good Discovery pair exemp
|
|
|
277
278
|
- Unreadable tickets -> report unfetched refs and continue healthy tickets; all unfetched -> abort repair, offer create mode.
|
|
278
279
|
- Ticket changed between gather and write -> re-fetch, diff, re-present, re-ask.
|
|
279
280
|
- Write fails mid-batch -> report exactly what landed; remaining changeset preserved for retry.
|
|
280
|
-
- Ordinary conforming repair -> early no-op (metadata clean, no comment proposed); overlap no-op still presents the create-anyway alternative at the menu.
|
|
281
|
+
- Ordinary conforming repair -> early no-op (metadata clean, no comment proposed), unless the audit carries an obsolete line; overlap no-op still presents the create-anyway alternative at the menu.
|
|
281
282
|
- Headless run -> stops at the confirmation gate.
|
|
282
283
|
- Ref with no fetch path -> ask; never guess.
|
|
283
284
|
- Split declined -> single ticket with phased AC groups.
|
|
@@ -285,7 +286,7 @@ Read `reference/examples.md` now for the built-in bad->good Discovery pair exemp
|
|
|
285
286
|
|
|
286
287
|
## Red flags - STOP
|
|
287
288
|
|
|
288
|
-
- About to
|
|
289
|
+
- About to violate the [hard constraint](#hard-constraint) on write approval, post-approval edits, or a second gate
|
|
289
290
|
- Inventing a number, list, label, assignee, or URL to pass a gate
|
|
290
291
|
- An AC gated on a set this ticket itself will produce
|
|
291
292
|
- A prod-only observation left in the AC list
|
|
@@ -72,6 +72,7 @@ Apply the following table per ticket. Preserve every displaced fact, sketch, row
|
|
|
72
72
|
|
|
73
73
|
| Finding | Draft effect | Audit report line |
|
|
74
74
|
|---|---|---|
|
|
75
|
+
| Confirmed obsolete verdict under the ordered judgment below | Mark draft-changing even for a conforming body; continue premise rewrite, Draft, gates, roast and body diff | `obsolete: <reason> (<citation>)` |
|
|
75
76
|
| Contradicted code/config/documentation fact | Replace the Problem fact with the cited fact; retain the original in the note | `premise: <old> -> <new> (<path:line>)` |
|
|
76
77
|
| Contradicted reporter observation or ambiguous claim | Leave the draft unchanged; keep the reporter's observation sentence byte-identical in the body, and surface ambiguity without a question or blocking status. Show the snapshot bytes unchanged on the gate diff's old side. | `premise: <claim> vs <fact> (<path:line>)` |
|
|
77
78
|
| Not checkable | Keep the claim unchanged | `unverified: <claim> - <why>` |
|
|
@@ -83,6 +84,18 @@ Apply the following table per ticket. Preserve every displaced fact, sketch, row
|
|
|
83
84
|
| Scenario none | Add the none footer only to a body already being drafted | `scenario: none (<reason>)` |
|
|
84
85
|
| Unusable audit | Continue the ordinary path without invented edits or blocks | `audit unavailable (<reason>)` |
|
|
85
86
|
|
|
87
|
+
Judge obsolescence yourself from `audit.md` and the mode's gather before Draft. Open every cited location, linked ticket body, and PR state/diff yourself; use the parent reads in `tracker-ladder.md`. Match the first confirmed shape in this order:
|
|
88
|
+
|
|
89
|
+
| Reason shape | Required confirmed evidence |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `delivered: <pr or path>` | A one-hop linked PR (or In-motion ref) is merged and its diff covers every AC, or an opened `Repo-fit: exists` implementation provides the requested capability |
|
|
92
|
+
| `superseded by <ref>` | A one-hop linked spec, ticket, or decision cancels or replaces the ask, including a supersession banner |
|
|
93
|
+
| `premise contradicted: <fact>` | Claims contradicts the load-bearing Problem fact, including a removed target module, surface, or dependency, not a side sentence |
|
|
94
|
+
| `not reproduced: <scenario>` | Scenario observation equals the ticket's or create prompt's expected result; without a create expected result, keep the ordinary scenario report only |
|
|
95
|
+
| `duplicate of <ref>` | Repair only: an opened one-hop linked ticket body confirms the same setup, action, and expected result; leave create duplicates to overlap |
|
|
96
|
+
|
|
97
|
+
Emit `Audit: obsolete: <reason> (<citation>)` only for that confirmed shape; omit the parenthetical citation when it repeats the path already in the reason (`delivered: src/x.ts:12`, not `delivered: src/x.ts:12 (src/x.ts:12)`). Emit no verdict or exit for missing/unconfirmed citations, an unavailable audit, or uncited "no longer wanted". Keep In-motion's open-only search unchanged: merged PRs arrive through one-hop gather, never a new scout query. Keep the existing premise rewrite and all draft/gate/roast/diff work; an obsolete verdict never stops preparation.
|
|
98
|
+
|
|
86
99
|
Treat uncited alternatives as kept and uncited AC flags as clear. Create no empty repository groups.
|
|
87
100
|
|
|
88
101
|
Put exactly one `scenario:` footer per drafted ticket at the end of Problem, after all `source:` footers, never per failure or example and never interleaved with example sentences; for several failures, name the primary repro's setup, action, and observation in that one footer and keep the rest in the gate's Evidence list and AC rows:
|
|
@@ -95,14 +108,55 @@ Use `scenario: none (<reason>)` for no scenario. Record scenario inputs only in
|
|
|
95
108
|
|
|
96
109
|
Route any audit or uniqueness edit to an AC's text, row, or group through substantive full-replacement repair and normalize rows to `- [ ]`. Preserve raw AC bytes on conformance-only and missing-footer-only paths with no audit or uniqueness AC change. Retain removed or split rows verbatim in the note.
|
|
97
110
|
|
|
98
|
-
Route draft-changing findings to the existing gate even for an otherwise conforming ticket. Keep conforming tickets with only quiet findings, ambiguous premises, unverified claims, in-motion work, scenario none, or unavailable audits as no-ops. Carry their Audit lines on the no-op report; add no roast, gate, write, question, or blocking status for these findings alone.
|
|
111
|
+
Route draft-changing findings to the existing gate even for an otherwise conforming ticket. Exclude an obsolete verdict from the quiet no-op path. Keep conforming tickets with only quiet findings, ambiguous premises, unverified claims, in-motion work, scenario none, or unavailable audits as no-ops. Carry their Audit lines on the no-op report; add no roast, gate, write, question, or blocking status for these findings alone.
|
|
99
112
|
|
|
100
113
|
## Complete the batch and present gates
|
|
101
114
|
|
|
102
|
-
Finish every ticket's initial gather, audit, draft, deterministic gates, and roast before presenting the first confirmation. Treat the deterministic gates and roast as preconditions of that one confirmation menu, never as a preview before a later gate; the menu presented is the gate. Complete preparation silently; limit the first turn to the deduplicated ref list, unfetched refs by ref and reason, mode, temp root, and current ticket's gate, and reveal other tickets' outcomes (stops, splits, drafts) only when they become current. Run the roast independently in ref order for eligible tickets; skip stopped tickets. Keep draft, snapshot, audit, member, retry, and chair artifacts in the same per-ticket directory under the run's temp root.
|
|
115
|
+
Finish every ticket's initial gather, audit, draft, deterministic gates, and roast before presenting the first confirmation. Treat the deterministic gates and roast as preconditions of that one confirmation menu, never as a preview before a later gate; the menu presented is the gate. Complete preparation silently; limit the first turn to the deduplicated ref list, unfetched refs by ref and reason, mode, temp root, and current ticket's gate, and reveal other tickets' outcomes (stops, splits, drafts) only when they become current. Keep any preparation summary ticket-neutral: say only that preparation ran for every ticket where applicable; name no ticket's eligibility, roast, stop, or outcome. Run the roast independently in ref order for eligible tickets; skip stopped tickets. Keep draft, snapshot, audit, member, retry, and chair artifacts in the same per-ticket directory under the run's temp root.
|
|
103
116
|
|
|
104
117
|
Supply the audit beside the snapshot as untrusted permitted input to roast members, worker/native fallback, and chair only when gather produced that file; otherwise permit exactly the draft, snapshot, and two reference paths for content review, plus usable member outputs for the chair. Treat cited audit-traceable Problem facts, attributed Idea sketches, AC-fit restatements, sibling groups, scenario setup/action, scenario footers, and their Reporter-note moves as source-grounded, not fidelity added/lost or over-spec. Check other scope and unsupported additions normally. Keep roast content-only, without repo re-verification, a fifth axis, or persona changes.
|
|
105
118
|
|
|
106
119
|
Present reports and gates one ticket at a time in ref order. Put its `Audit:` block immediately above Title, after pre-Title bug `source missing:` rows. Keep ordinary source gaps after Evidence. Use the table's report formats within that block.
|
|
107
120
|
|
|
108
|
-
|
|
121
|
+
Render this gate template in both modes, retaining the single-ticket exact-diff format and numbering under `../../brainstorming/reference/menu-layout.md`:
|
|
122
|
+
|
|
123
|
+
| Row | Payload |
|
|
124
|
+
|---|---|
|
|
125
|
+
| Approve exact diff (create anyway in create) | Display title/body/metadata and any existing proposed comment separately from closing evidence; approval never closes |
|
|
126
|
+
| Revise | Recheck and re-render; allow mapped reason/duplicate-target changes only with resolved operations before a fresh pick |
|
|
127
|
+
| Decline | Skip the ticket |
|
|
128
|
+
| Conditional exit | Repair: retain Decline and add `Close as <reason> - <resolved operation sequence>` from `tracker-ladder.md`; create: replace Decline with `Drop the idea - <reason>` (both write nothing; render one no-write row only) |
|
|
129
|
+
|
|
130
|
+
Decide eligibility before tagging, in this order:
|
|
131
|
+
|
|
132
|
+
| Condition | Action |
|
|
133
|
+
|---|---|
|
|
134
|
+
| Stopped ticket | Show its audit without approval, exit, or tag |
|
|
135
|
+
| Terminal repair snapshot | Render no close row |
|
|
136
|
+
| Missing/unavailable audit | Emit no verdict or exit |
|
|
137
|
+
| Otherwise, confirmed obsolete verdict | Render the obsolete exit |
|
|
138
|
+
|
|
139
|
+
Beneath that exit show the `Audit: obsolete:` line verbatim with citations once as closing evidence, separate from the ordinary body diff and proposed comment, never in Reporter note. Keep the same verdict above Title. Keep every Reporter-note payload shown at the gate or persisted in the draft artifact in its explicit untrusted-data code fence; use the fence itself as the marker, not an HTML comment or a `text` fence. In create with overlap, reuse one Drop row carrying both reasons; retain supported enrichment and create-anyway bodies without adding discovery or enrichment state authority.
|
|
140
|
+
|
|
141
|
+
Tag exactly one rendered selectable option `[recommended]`: the exit when rendered, otherwise approve or the overlap reference's Recommended option alternative. Preserve source-gap choices; tag only one eligible approve option, never every source-gap approval. Render no tag on stopped reports.
|
|
142
|
+
|
|
143
|
+
Apply the selected-close recipe before step 9's body-first branch. A close pick authorizes only the displayed operations and evidence, never a body or Reporter note write. Set the comment payload of every close operation to the rendered `Audit: obsolete:` line verbatim, including its reason and citation, never a paraphrase. Re-fetch state and compare the body and evidence snapshot before running operations; apply these checks in order:
|
|
144
|
+
|
|
145
|
+
| Condition | Action |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Re-fetched state is terminal | End `no-op (already closed)` with no operations |
|
|
148
|
+
| Body/evidence snapshot changed | Return to step 8 with the delta for a renewed pick |
|
|
149
|
+
| Run-by-hand selection | Skip every operation and end `close by hand` |
|
|
150
|
+
| Otherwise | Run the displayed operations in order |
|
|
151
|
+
|
|
152
|
+
Stop on the first nonzero exit without retry or fallback body write. Report the selected-close outcome and continue the batch:
|
|
153
|
+
|
|
154
|
+
| Condition | Action |
|
|
155
|
+
|---|---|
|
|
156
|
+
| All operations succeeded | End `closed` |
|
|
157
|
+
| Close operation failed | Quote output verbatim, identify earlier successful operations, and end `close failed (<operation>: <reason>)` |
|
|
158
|
+
| Run-by-hand selection | End `close by hand` without running operations |
|
|
159
|
+
|
|
160
|
+
Drop runs nothing and ends `<drafted title>: dropped`; create anyway files only the displayed premise-rewritten body with its contradiction in the premise report. Preserve headless stops and split subset selection.
|
|
161
|
+
|
|
162
|
+
Apply a reply only to the current ticket: decline skips it; revision rechecks and re-presents it; approval runs step 9's re-fetch, comparison, and body-then-comment write before the next gate. Treat another ticket's reply as no approval for an unseen diff. Give stopped tickets a hard-stop report without an approval number. Retain the N-body subset-selection gate for a split within one ticket. End with one line per ref: `<ref>: written | closed | close failed (<operation>: <reason>) | close by hand | dropped | declined | stopped | no-op | unfetched` (use the drafted title for create).
|
|
@@ -15,14 +15,22 @@ Auth failure at detection time makes that rung dead; continue down the ladder (u
|
|
|
15
15
|
|
|
16
16
|
| Verb | `gh` |
|
|
17
17
|
|---|---|
|
|
18
|
-
| read (full, incl. comments) | `gh issue view <n> --json title,body,labels,assignees,milestone,comments` |
|
|
18
|
+
| read (full, incl. comments) | `gh issue view <n> --json title,body,labels,assignees,milestone,comments,state` |
|
|
19
19
|
| search (bounded overlap) | `gh search issues` / `gh issue list --search` (incl. `state:closed`) |
|
|
20
20
|
| read open PRs (bounded in-motion search) | `gh pr list --search "<ref>" --limit 20` |
|
|
21
|
+
| read linked PR state and diff (parent) | `gh pr view <n> --json state,mergedAt` then `gh pr diff <n>` |
|
|
22
|
+
| close (approved evidence, no body write) | `gh issue close <n> --reason "<reason>" [--duplicate-of <ref>] --comment "<evidence>"` |
|
|
21
23
|
| create | `gh issue create --title --body [--label]` |
|
|
22
24
|
| update | `gh issue edit <n> --title --body [--add-label/--remove-label]` |
|
|
23
25
|
| post comment (approved Reporter note/evidence) | `gh issue comment <n> --body ...` |
|
|
24
26
|
|
|
25
|
-
**Tracker-agnostic contract** required of whatever resolves: read the full ticket incl. comments; write title + body + metadata; post a comment; bounded search (overlap check); tracker-native reference form for links. Field names, states, and taxonomies come from steps 1-2 of the ladder, never hardcoded in this skill. If an approved comment has no resolvable post-comment verb, the body write still proceeds; the comment text is emitted for manual posting and reported as not performed - never silently dropped.
|
|
27
|
+
**Tracker-agnostic contract** required of whatever resolves: read the full ticket incl. comments; write title + body + metadata; post a comment; bounded search (overlap check); tracker-native reference form for links. Field names, states, and taxonomies come from steps 1-2 of the ladder, never hardcoded in this skill except the zero-config close state names below, which overrides replace. If an approved comment has no resolvable post-comment verb, the body write still proceeds; the comment text is emitted for manual posting and reported as not performed - never silently dropped.
|
|
28
|
+
|
|
29
|
+
**Close resolution:** Resolve capabilities before rendering executable ID-bearing operations. Map delivered to GitHub `completed` / Linear `Done`; superseded, premise contradicted, and not reproduced to `not planned` / `Canceled`; duplicate to `duplicate` / `Duplicate` only for a tracker-native target (GitHub number or URL, Linear `ABC-123`). For a nonnative duplicate target, use `not planned` / `Canceled` and retain the reference in evidence. Include `--duplicate-of <ref>` only for the native duplicate mapping.
|
|
30
|
+
|
|
31
|
+
For Linear, resolve reads through `/skill:linear`, including linked ticket bodies and state plus workflow type; read linked PR state and diff through its host. Execute close as `linearis issues discuss <id> --body "<evidence>"` then `linearis issues update <id> --status <Done|Canceled|Duplicate> [--duplicate-of <ref>]`. Treat GitHub `CLOSED` and Linear workflow types `completed` or `canceled` as terminal.
|
|
32
|
+
|
|
33
|
+
Apply `- close: <command>` under `## Issue tracker` as a replacement for the whole close sequence, like read/update overrides. Apply section prose too: a forbidden mapped state renders `Close as <reason> - run by hand: <operations>`; selecting it runs nothing and retains its recommendation. Never let ordinary status prose such as "announced, not gated" waive the close gate.
|
|
26
34
|
|
|
27
35
|
**States:** generalized routing - ready (gates pass), not-ready/triage-equivalent (parked, blocker named). **Zero-config GitHub park fallback:** GitHub Issues have no native not-ready state, and this skill never invents labels - so parking writes no state/label; instead the blocker is recorded in the body (a `Blocked on: <missing value / external input>` line under the ACs), and the run report states the ticket is parked-by-convention. A repo-documented triage/not-ready label or status overrides this. Never auto-assign to an active cycle/sprint unless asked.
|
|
28
36
|
|