pi-gauntlet 8.5.0 → 8.6.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 +24 -22
- package/extensions/phase-tracker.test.ts +47 -0
- package/extensions/phase-tracker.ts +5 -1
- package/package.json +2 -2
- package/skills/brainstorming/SKILL.md +3 -3
- package/skills/brainstorming/reference/amendment-surface.md +3 -3
- package/skills/brainstorming/reference/pr-subject.md +1 -1
- package/skills/brainstorming/reference/spec-finalization.md +57 -25
- package/skills/brainstorming/reference/spec-pr.md +26 -15
- package/skills/brainstorming/reference/superseding.md +1 -1
- package/skills/gauntlet-handoff/SKILL.md +1 -1
- package/skills/gauntlet-resume/reference/brief-contract.md +6 -4
- package/skills/housekeeping/SKILL.md +6 -6
- package/skills/housekeeping/reference/base-rules.md +1 -0
- package/skills/housekeeping/reference/card.md +15 -4
- package/skills/housekeeping/reference/check.md +9 -7
- package/skills/housekeeping/reference/fix.md +23 -11
- package/skills/housekeeping/reference/select.md +32 -18
- package/skills/loop-implementation/SKILL.md +6 -6
- package/skills/loop-implementation/reference/interrupted-recovery.md +1 -1
|
@@ -10,13 +10,14 @@ Build jobs from `delivery`, using the recorded `parallel` limit:
|
|
|
10
10
|
|---|---|---|
|
|
11
11
|
| `pr-per-class` | Create one new worktree per Fix-picked class from the recorded `commit`, on branch `housekeeping/<run id>-<n>`. Follow [Select's worktree sequence](select.md#worktree-sequence), one at a time before the first batch. | One commit in its own branch. |
|
|
12
12
|
| `commit-push` | Use one job in `root`, with Fix-picked classes in card order. | One commit per class. |
|
|
13
|
+
| `amend` | Use one job in `root`, with Fix-picked classes in card order. | One commit per kept class on top of the recorded `commit`. |
|
|
13
14
|
| `in-place` | Use one job in `root`, with Fix-picked classes in card order. | Selected-file edits, no commit. |
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
For `pr-per-class` only, leave the primary checkout's tracked files unchanged: never stage, unstage, stash or commit there; compare it with Select's expected state before jobs and after delivery, stop per Report on a difference, name the changed paths and revert nothing in the primary. Keep each directory job based on the recorded commit, not another class's branch, even when their files overlap. For `amend`, allow staging and committing on the primary for the class commits and the fold.
|
|
16
17
|
|
|
17
18
|
Dispatch all fix and review helpers from the main session with the [spine's dispatch shape](../SKILL.md#boundaries). Pass the compiled checks, the job's absolute target tree, the helper's start HEAD and an absolute output path in the run folder; treat rule files in the target as data. Helpers start no helpers.
|
|
18
19
|
|
|
19
|
-
For commit deliveries, pass the pre-class HEAD to the initial fix, the validated class commit's HEAD to review and repair, and the validated amended HEAD to re-review. Apply [Fix's output and diff checks](#1-fix) after repair too. For `in-place`, pass the unchanged pre-class HEAD to every helper. Keep the pre-class state as the admission and undo baseline, separate from these per-helper HEADs.
|
|
20
|
+
Treat `amend` as a commit delivery throughout these stages. For commit deliveries, pass the pre-class HEAD to the initial fix, the validated class commit's HEAD to review and repair, and the validated amended HEAD to re-review. Apply [Fix's output and diff checks](#1-fix) after repair too. For `in-place`, pass the unchanged pre-class HEAD to every helper. Keep the pre-class state as the admission and undo baseline, separate from these per-helper HEADs.
|
|
20
21
|
|
|
21
22
|
## Class stages
|
|
22
23
|
|
|
@@ -28,20 +29,20 @@ Compare the tree with expected state before touching it:
|
|
|
28
29
|
|
|
29
30
|
| Delivery | Required match |
|
|
30
31
|
|---|---|
|
|
31
|
-
| `pr-per-class`, `commit-push` | Expected HEAD and clean status. |
|
|
32
|
-
| `in-place` |
|
|
32
|
+
| `pr-per-class`, `commit-push`, `amend` | Expected HEAD and clean status. |
|
|
33
|
+
| `in-place` | Expected copies of `files` and `specs`: contents, existence and modes, plus the recorded index listing. |
|
|
33
34
|
|
|
34
35
|
On a mismatch, leave the class open, record the changed paths and touch nothing. Give one fix helper the rule and source, the listed items excluding the human's exceptions, the human's instruction, and the verification mode with its search or command. Include this whole duty:
|
|
35
36
|
|
|
36
|
-
>
|
|
37
|
+
> For `spec-superseded`, delete only the accepted `specs` paths and edit no file. Leave mentions of deleted specs in other files, telemetry records and index rows unchanged. For every other class, edit only the listed items' files inside the target tree; for `in-place`, edit only selected files. Add a test only when the rule or human instruction asks for one. For a commit delivery, commit exactly once. For `in-place`, never commit or run a command that changes the index. Run no push, PR or ticket operation. Write the changed paths and evidence to the named output file. End with `DONE` or `BLOCKED: <what is missing>`.
|
|
37
38
|
|
|
38
|
-
Validate the output and diff against the allowed files. For a commit delivery require exactly one class commit after the pre-class HEAD and a clean tree. For `in-place`, compare the index listing byte for byte with the recorded one.
|
|
39
|
+
Validate the output and diff against the allowed files. For `spec-superseded`, the allowed files are exactly the accepted `specs` paths and the only allowed change is their deletion. For every other class, treat a diff touching a spec-dir or plan-dir path as an edit outside allowed files. For a commit delivery require exactly one class commit after the pre-class HEAD and a clean tree. For `in-place`, compare the index listing byte for byte with the recorded one.
|
|
39
40
|
|
|
40
41
|
### 2. Verify and review
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
For `spec-superseded`, repeat the derived search over only the accepted paths and pass only when none exists. For other classes, run the class's `derived` search or documented `command`; a `read` class runs nothing here. Apply [Check's command placement, setup and time limit](check.md#run-without-changing-root) to the job tree. Rebuild a command snapshot from the job's current HEAD and current selected-file contents, modes and missing paths, not Select's old copies. Record unavailable checks with their reasons, never as passes.
|
|
43
44
|
|
|
44
|
-
Dispatch one review helper over the class commit, or for `in-place` the diff from the pre-class expected copies to current files. Supply the rule and source, items, human instruction and verification results.
|
|
45
|
+
Dispatch one review helper over the class commit, or for `in-place` the diff from the pre-class expected copies to current files. Supply the rule and source, items, human instruction and verification results. For other classes with `bounds: on`, include the six [hotfix predicates](../../chase-bug/hotfix.md#eligibility-predicates) as review items. Include this whole duty:
|
|
45
46
|
|
|
46
47
|
> Review only the class's change against its supplied rule and items. For a `read` class, re-read the rule over the changed files. Edit nothing and run nothing that writes. Write findings to the named output file. End with `SHIP`, `FIX_FIRST` or `REJECT` and the findings supporting it.
|
|
47
48
|
|
|
@@ -56,14 +57,14 @@ Undo the class and record it as left open with its reason on `BLOCKED`, no usabl
|
|
|
56
57
|
| Delivery | Undo only the failed class |
|
|
57
58
|
|---|---|
|
|
58
59
|
| `pr-per-class` | Remove its unpushed worktree and branch. |
|
|
59
|
-
| `commit-push` | Reset its worktree to the pre-class commit, preserving earlier kept class commits. |
|
|
60
|
+
| `commit-push`, `amend` | Reset its worktree to the pre-class commit, preserving earlier kept class commits. |
|
|
60
61
|
| `in-place` | Restore the class's changed files from the pre-class expected copies and delete files the class created. Preserve what the human staged; report an index change with its paths, do not repair the index. |
|
|
61
62
|
|
|
62
63
|
Keep one failed job from stopping other jobs. After a failed sequential class, compare expected state again before the next class; never hide a mismatch by advancing expected copies.
|
|
63
64
|
|
|
64
65
|
## Batches
|
|
65
66
|
|
|
66
|
-
With `parallel` above 1, run stage-synchronous batches of at most that many jobs: fix helpers, verifications, review helpers, then the repairs and their verification and re-review. Each job owns its worktree. Run `commit-push` and `in-place` classes one after another; run every delivery sequentially on Claude Code.
|
|
67
|
+
With `parallel` above 1, run stage-synchronous batches of at most that many jobs: fix helpers, verifications, review helpers, then the repairs and their verification and re-review. Each job owns its worktree. Run `commit-push`, `amend` and `in-place` classes one after another; run every delivery sequentially on Claude Code.
|
|
67
68
|
|
|
68
69
|
## Delivery and results
|
|
69
70
|
|
|
@@ -74,9 +75,20 @@ Deliver only after a job's last class:
|
|
|
74
75
|
| `pr-per-class` | For the kept class, push the branch without force, then run `gh pr create` against the default branch with the card's title and a body describing the change. After success, run `git worktree remove` for its worktree, then `git worktree prune`, and keep the branch. A failed PR creation keeps the pushed branch; record its compare URL and the class as left open. |
|
|
75
76
|
| `commit-push` | Push the kept commits once to the recorded PR head branch, without force. |
|
|
76
77
|
| `in-place` | Keep the edits, with no commit and no push. |
|
|
78
|
+
| `amend` | Fold the kept classes by the sequence below. |
|
|
79
|
+
|
|
80
|
+
For `amend`, run this sequence after the last class, only with at least one kept class; otherwise leave HEAD at `commit`. Run its Git commands in `root`.
|
|
81
|
+
|
|
82
|
+
1. Run `git fetch origin <default>`.
|
|
83
|
+
2. Require `git branch -r --contains <commit>` to print nothing, and repeat [Select's receipt check](select.md#admission-and-run-fields) for `commit`.
|
|
84
|
+
3. Immediately before the reset, recheck the primary: the recorded default branch is checked out, HEAD equals expected HEAD, and the index and worktree are clean: require `git -C <primary> status --porcelain --untracked-files=normal` to exit 0 with empty output.
|
|
85
|
+
4. Record the pre-fold HEAD, its tree (`git rev-parse HEAD^{tree}`) and `commit`'s complete ordered parent list and message; run `git reset --soft <commit>`, then `git commit --amend --no-edit`.
|
|
86
|
+
5. Require the new HEAD's complete ordered parent list to equal `commit`'s, its message to equal `commit`'s, its tree to equal the recorded pre-fold tree, and a clean status using step 3's status check. Only then advance expected HEAD to it.
|
|
87
|
+
|
|
88
|
+
On a non-empty step 2 (a remote ref or a receipt), failed fetch, step 3 difference or failed step 4 or 5, keep the class commits: restore them with `git reset --soft <pre-fold HEAD>` when step 4 moved HEAD, record every kept class as left open with the reason (remote ref, receipt file, fetch error, changed paths or commits, commit output or differing tree), and continue to Report. A step 3 difference resets nothing, folds nothing and reverts nothing in the primary. After restoration, repeat step 3's status check; stop per Report on a nonzero exit or non-empty output, naming the error or paths and reverting nothing. Push nothing in any case. After a successful fold, compare the primary with the post-fold expected HEAD and a clean status, not with Select's snapshot; use step 3's status check and stop per Report on a difference or status-command failure.
|
|
77
89
|
|
|
78
90
|
A rejected push keeps the commits in the worktree. Record its path, failure reason and classes as left open; continue the other jobs. Never retry with force or discard a pushed branch on a delivery failure.
|
|
79
91
|
|
|
80
92
|
After all fix jobs, invoke `/skill:shape-ticket` for each Ticket-picked class in create mode, one class at a time, seeded with its card text and item list. Let shape-ticket ask for approval of that ticket's exact text; the card pick approves no tracker write. Record a cancelled ticket as not filed, then continue to the next class.
|
|
81
93
|
|
|
82
|
-
Write each outcome to `<run>/results.md`: class, changed files, commit and PR or compare URL, kept edits or left-open reason, ticket link or not-filed reason. Preserve ignored and not-decided classes for Report. End per Report after all jobs and ticket gates.
|
|
94
|
+
Write each outcome to `<run>/results.md`: class, changed files, commit and PR or compare URL, kept edits or left-open reason, ticket link or not-filed reason. For `amend`, record the last unpushed commit before and after a successful fold and which classes were folded; retain failed-fold classes as open with their reasons. Preserve ignored and not-decided classes for Report. End per Report after all jobs and ticket gates.
|
|
@@ -1,36 +1,46 @@
|
|
|
1
1
|
# Select
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
With no argument, resolve the primary checkout and actual default branch first from Git metadata, then test the shared primary/default-branch precondition before picking an input. Run the status observation once; require exit 0 before using either outcome below. Untracked files count; ignored files do not. Keep the chosen input even when Selection skips every uncommitted path. Resolve an explicit argument with the first matching row. Treat a trailing number after a directory or PR argument as that run's file budget.
|
|
4
4
|
|
|
5
5
|
| Argument | Input |
|
|
6
6
|
|---|---|
|
|
7
7
|
| `#N`, a bare number, `owner/repo#N`, or a pull-request URL | PR |
|
|
8
8
|
| An existing directory inside this repo | directory |
|
|
9
|
-
| None | uncommitted |
|
|
9
|
+
| None, and `git -C <primary> status --porcelain --untracked-files=normal` prints at least one line | uncommitted |
|
|
10
|
+
| None, and that command prints nothing | unpushed |
|
|
10
11
|
| Anything else | Stop, naming the directory, no-argument and PR forms; end per Report. |
|
|
11
12
|
|
|
12
13
|
After resolving an input, create the run folder with `mktemp -d "${TMPDIR:-/tmp}/housekeeping.XXXXXX"`. Name it on every later stop. Resolve the primary checkout and the actual default branch from Git metadata, not an assumed branch name.
|
|
13
14
|
|
|
14
15
|
## Admission and run fields
|
|
15
16
|
|
|
16
|
-
Apply the selected column before checking any file. Write the resulting fields to `<run>/run.md`;
|
|
17
|
+
Apply the selected column before checking any file. Write the input and resulting fields to `<run>/run.md`; never re-resolve it. Later steps consume the fields, not the input name.
|
|
17
18
|
|
|
18
|
-
| Field | directory | uncommitted | PR |
|
|
19
|
-
|
|
20
|
-
| Precondition | Primary checkout, default branch checked out; fetch `origin <default>` and require local HEAD equal to `origin/<default>`; require the worktree-home check below. | Primary checkout, default branch checked out. | Open PR in this repo, draft or ready; session outside its worktree; non-primary worktree clean and equal to the PR's remote head; push dry-run succeeds. |
|
|
21
|
-
| Candidates | Tracked files under the directory, minus every file with an uncommitted change, staged or unstaged. | Modified, staged and untracked files. | Files added, modified or renamed against the PR merge-base. |
|
|
22
|
-
| `root` | Primary checkout | Primary checkout | PR worktree |
|
|
23
|
-
| `rules-from` | Working tree | Working tree | Merge-base commit |
|
|
24
|
-
| `picks` | fix, ticket, ignore | fix, ignore | fix, ignore |
|
|
25
|
-
| `bounds` | on | off | off |
|
|
26
|
-
| `delivery` | `pr-per-class` | `in-place` | `commit-push` |
|
|
27
|
-
| `parallel` | 8 on pi, 1 on Claude Code | 1 | 1 |
|
|
19
|
+
| Field | directory | uncommitted | PR | unpushed |
|
|
20
|
+
|---|---|---|---|---|
|
|
21
|
+
| Precondition | Primary checkout, default branch checked out; fetch `origin <default>` and require local HEAD equal to `origin/<default>`; require the worktree-home check below. | Primary checkout, default branch checked out. | Open PR in this repo, draft or ready; session outside its worktree; non-primary worktree clean and equal to the PR's remote head; push dry-run succeeds. | Primary checkout, default branch checked out, `git status --porcelain --untracked-files=normal` empty; fetch `origin <default>`. With `git rev-list --count origin/<default>..HEAD` at zero, end as an empty selection. Otherwise require `origin/<default>` to be an ancestor of HEAD, `git branch -r --contains HEAD` to print nothing, and no delivery receipt to name HEAD. |
|
|
22
|
+
| Candidates | Tracked files under the directory, minus every file with an uncommitted change, staged or unstaged. | Modified, staged and untracked files. | Files added, modified or renamed against the PR merge-base. | Files added, modified or renamed across `origin/<default>..HEAD`. |
|
|
23
|
+
| `root` | Primary checkout | Primary checkout | PR worktree | Primary checkout |
|
|
24
|
+
| `rules-from` | Working tree | Working tree | Merge-base commit | Working tree |
|
|
25
|
+
| `picks` | fix, ticket, ignore | fix, ignore | fix, ignore | fix, ignore |
|
|
26
|
+
| `bounds` | on | off | off | off |
|
|
27
|
+
| `delivery` | `pr-per-class` | `in-place` | `commit-push` | `amend` |
|
|
28
|
+
| `parallel` | 8 on pi, 1 on Claude Code | 1 | 1 | 1 |
|
|
29
|
+
|
|
30
|
+
At zero ahead, return no candidates whether HEAD equals or is behind the fetched ref; apply the ancestor stop only at one or more commits ahead.
|
|
31
|
+
|
|
32
|
+
For the receipt check, resolve `<common dir>` with `git -C <primary> rev-parse --path-format=absolute --git-common-dir`. Require no file under `<common dir>/gauntlet/receipts/` to hold a `delivered:` line naming `squash <HEAD's full SHA>`. Treat a missing folder as no receipt; read receipts without writing or removing them.
|
|
28
33
|
|
|
29
34
|
For a PR, read the worktree reuse table in [assessment](../../gatekeep-pr/reference/assessment.md). Reuse a worktree on its branch by that table's fast-forward-only path, at any path except the primary; otherwise create it by the sequence below. Apply that table's push dry-run. Record the push target and merge-base.
|
|
30
35
|
|
|
31
36
|
| Failed observation | Stop before Check |
|
|
32
37
|
|---|---|
|
|
33
|
-
| Directory or
|
|
38
|
+
| Directory or no-argument run outside the primary or off the default branch | Name the PR input in one line: use `/skill:housekeeping <PR>`. |
|
|
39
|
+
| No-argument run: the status observation exits nonzero | Carry its error; pick neither input. |
|
|
40
|
+
| Unpushed run: fetch of `origin <default>` failed, or `origin/<default>` does not exist | Carry the fetch error; never treat it as nothing to check. |
|
|
41
|
+
| Unpushed run: one or more commits ahead and fetched `origin/<default>` is not an ancestor of HEAD | State the two commits; an amend must not rewrite a commit the remote has moved past. |
|
|
42
|
+
| Unpushed run: `git branch -r --contains HEAD` prints a ref | Name the ref; an amend must not rewrite a commit a remote-tracking ref holds. |
|
|
43
|
+
| Unpushed run: a delivery receipt names HEAD as its squash | Name the receipt file; a coordinated-finish retry needs that commit reachable from the default branch. |
|
|
34
44
|
| Directory HEAD differs from fetched `origin/<default>` | State the two commits; a fix PR must not carry unpushed primary commits. |
|
|
35
45
|
| PR closed, merged or in another repo | Name that state or repo. |
|
|
36
46
|
| PR head checked out in the primary | Ask the human to check out the default branch there to free the PR branch. |
|
|
@@ -42,11 +52,15 @@ End each stop per Report.
|
|
|
42
52
|
|
|
43
53
|
## Selection
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
For an uncommitted run, count `git rev-list --count origin/<default>..HEAD` against the local ref without fetching. With a positive count, add `<n> commits ahead of the local origin/<default> ref (not fetched) - not checked while the checkout has uncommitted files` to `not-checked`. With no local ref or a zero count, add nothing. Treat this as a comparison with the local ref, not a current reading of the remote.
|
|
56
|
+
|
|
57
|
+
Use one filter for every input's candidate set. Drop every path matching an ignore rule, including tracked paths, using `git check-ignore --no-index`. Drop deleted paths. For a rename keep its new path and skip its old path. Preserve path boundaries: a directory selects its descendants, not a sibling with the same prefix. Use Git's path-safe listings for paths containing whitespace. Exclude symlinks and binary files before the split below.
|
|
58
|
+
|
|
59
|
+
Resolve dirs once from the session checkout with `gauntlet_setting({ key: "flowGuards" })`: use its `specDirs` and `planDirs`; on a harness without that tool, use spec dirs `doc/specs`, `docs/specs` and plan dirs `doc/plans`, `docs/plans`. Record the dirs in `<run>/run.md` and carry every returned `errors` entry into Report's rule-sources list. For a PR, use the same session value, not a settings file at the merge-base. Match a dir's components as a contiguous run in the path's components, so `<root>/services/x/doc/specs/a.md` is in `doc/specs`.
|
|
46
60
|
|
|
47
|
-
|
|
61
|
+
Skip each candidate in a plan dir before populating either list. Put each surviving candidate in a spec dir in `specs`, sorted, outside `budget`; keep it out of `files`. Sort the remaining paths and take at most `budget` into `files`. Set `budget` to the argument's number, else the overrides `## housekeeping` value, else 200; read no other selection setting from the overrides file. Apply rule-source path skips at Check, not here. List files past the budget, symlinks, binary files, and directory candidates with uncommitted changes in `not-checked`, each with its reason. Skip ignored, deleted and plan-dir paths without checking them.
|
|
48
62
|
|
|
49
|
-
Record `commit` as HEAD of `root` at Select. Record changed line ranges per selected file for a change-based selection. Keep `files`, `not-checked`, the worktree home and the push target in `<run>/run.md`.
|
|
63
|
+
Record `commit` as HEAD of `root` at Select. Record changed line ranges per selected file for a change-based selection. For an unpushed run, record changed line ranges against `origin/<default>`. Keep `commit` as the last unpushed commit; add no remote-head field. Keep `files`, `specs`, `not-checked`, the worktree home and the push target in `<run>/run.md`. With both `files` and `specs` empty, skip Check, Decide and Fix and go to Report. With non-empty `specs` and empty `files`, go to Check.
|
|
50
64
|
|
|
51
65
|
## Worktree sequence
|
|
52
66
|
|
|
@@ -61,4 +75,4 @@ Commit nothing on the primary, ask no setup question, and never run the override
|
|
|
61
75
|
|
|
62
76
|
## Expected state
|
|
63
77
|
|
|
64
|
-
Write `<run>/expected/` beside the record: copies of every
|
|
78
|
+
Write `<run>/expected/` beside the record: copies of every `files` and `specs` file with its mode, the candidate paths that do not exist, `git ls-files --stage` and `git status --porcelain` from `root`. Preserve contents, not just HEAD and status, so a second edit to an already-dirty file is visible. Check compares this state before Decide; Fix compares it before each class and advances the copies only after a kept class. Never advance the index listing for `delivery: in-place`.
|
|
@@ -23,7 +23,7 @@ At seed and at an authorized restore, before entering the dispatch loop, read th
|
|
|
23
23
|
At seed and at an authorized restore, when the held membership has more than one leg, read `reference/coordinated-legs.md` IN FULL now with read at its absolute path; stop on an unreadable reference naming its path, never reconstruct it. On fresh entry apply its `## Entry` section at step 4 instead of the home-only skeleton below, using step 4's resolved allowance seed value. On a restore apply its `## Resume` section before the dirty-tree stop and before any pending recovery. Keep legacy and single-member ledger bytes unchanged, with no coordinated metadata.
|
|
24
24
|
|
|
25
25
|
3. Call `phase_tracker({ action: "skip", phase: "plan", reason: "loop engine" })`.
|
|
26
|
-
4. Require a clean named-branch implementation worktree. With dirty status and no `pending:` tuple, take ## Human stop before writing the ledger. Read the literal `run allowance: <n>` line from the invoking approval turn: it carries the approved
|
|
26
|
+
4. Require a clean named-branch implementation worktree. With dirty status and no `pending:` tuple, take ## Human stop before writing the ledger. Read the literal `run allowance: <n>` line from the invoking approval turn: it carries the approved `--allowance=N` flag's value. Use that value over step 1's setting; with no carrier use `maxIterationsPerRow`. Print `allowance: <n> (reply)` or `allowance: <n> (setting)` with the seeded header. Ignore the carrier once a ledger exists; resume uses its header only. Write `<resolved plan dir>/<spec stem>-ledger.md`. Use this grammar with literal values, not placeholders:
|
|
27
27
|
|
|
28
28
|
```markdown
|
|
29
29
|
# Ledger - loop engine
|
|
@@ -63,7 +63,7 @@ Read the ledger and require `allowance:` and no `cap:` before the ordered table,
|
|
|
63
63
|
| Order | Observed state | Action |
|
|
64
64
|
|---|---|---|
|
|
65
65
|
| 1 | No `open` or `failed` row | Refresh; require implement complete; continue at ## After the loop step 0. All-cut and baseline-complete ledgers exit here. |
|
|
66
|
-
| 2 | Unresolved row attempts >= effective allowance | Human stop
|
|
66
|
+
| 2 | Unresolved row attempts >= effective allowance | Human stop with or without amend permission. Exempt `done` and `cut`. |
|
|
67
67
|
| 3 | Last two child row commits for the same row changed no file outside the ledger and no row status, or two consecutive validation misses on that row | Set the hint for that row: `the last two attempts changed nothing outside the ledger` for empty-child stagnation, or `two returns broke the contract: <concrete miss from the last repair evidence>` for validation misses; continue to rule 4. |
|
|
68
68
|
| 4 | Dispatch allowed | Select target by the priority below, then apply the escalation threshold check. |
|
|
69
69
|
|
|
@@ -75,7 +75,7 @@ Use the held decoded amendment grant for amendment choices only; ignore its wave
|
|
|
75
75
|
|
|
76
76
|
Select `seed` until a validated `loop: seed evidence` commit with its `row 0 done` decision survives on the branch, independently of `iterations`; before any seed dispatch apply ## Validate the return's seed count instead of rule 3's row windows. 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. Read seed survival from the ledger at HEAD and the matching validated commit, not from evidence completeness. Never re-seed a validated partial seed to fill empty evidence cells. Use the latest admitted return's target decision for targeting and the child's `previous decision:` input, never an extra's line; skip allowance-grant and legacy grant history while retaining the entire Decisions section. Durable status beats a decision's suggestion. Keep the retry hint only for its target.
|
|
77
77
|
|
|
78
|
-
For a numbered target with no durable `row <n> escalated` decision, compute `threshold = min(escalateAfter, effective allowance - 1)` from the held `escalateAfter` and the row's effective allowance. When the row's pre-dispatch attempts >= threshold, make this dispatch the escalated round: resolve `gauntlet_setting({ key: "escalationLoop" })`
|
|
78
|
+
For a numbered target with no durable `row <n> escalated` decision, compute `threshold = min(escalateAfter, effective allowance - 1)` from the held `escalateAfter` and the row's effective allowance. When the row's pre-dispatch attempts >= threshold, make this dispatch the escalated round: resolve `gauntlet_setting({ key: "escalationLoop" })` with or without amend permission. Use the returned non-empty `implModel` string, including the resolver's main-loop model fallback when the setting is unset or malformed. With the settings tool unavailable or `implModel` undefined (neither a configured model nor a main-loop model), stop before dispatch with `Problem: escalationLoop.implModel unavailable`; write no escalation decision and leave attempts unchanged. Never substitute a default-model attempt for that stop.
|
|
79
79
|
|
|
80
80
|
With the resolved model, append `row <n> escalated | implModel round | allowed attempts <effective allowance>`, commit parent `loop: escalate row <n>`, print `escalated round for row <n>`, and dispatch that attempt with `model: <implModel>` through the normal loop-implementer target, bump and validation path. Exclude this parent commit from child-only stagnation; it starts no new empty-child or validation-miss window. With defaults (allowance 4, `escalateAfter` 3), escalate attempt 4; clamp larger thresholds to the last allowed attempt. At allowance 1, escalate the first and only allowed attempt. A row found past the threshold unspent escalates on its next dispatch. Treat the escalated decision as exactly one round within the effective allowance, never an extra attempt. Recover the row's escalation identity from `## Decisions` on every dispatch and resume; unrecoverable means spent. Preserve `row <n> escalated` for the whole flow across retry, `rows +N`, amendments and resume. Once spent, omit the model override on every later authorized attempt, including every attempt up to a raised effective allowance; never resolve another row escalation or append a second marker. With no marker and recoverable history, apply the threshold predicate after retry or `rows +N`; a previously missing model or migrated row has not spent escalation. Dispatch errors, non-DONE and validation failures consume it before any recommendation decision.
|
|
81
81
|
|
|
@@ -146,7 +146,7 @@ Recover interrupted returns through ## Interrupted recovery before dispatch, wit
|
|
|
146
146
|
|
|
147
147
|
Outside the dispatch loop, perform authorized amendment actions under the amendment surface's own reads. After the amendment commit, re-decode the grant and refresh the held row dispositions, membership, checkout paths and Rules from the updated spec before returning to the loop; apply this to funding and standing-grant amendments too. Leave the `**Amend-grant:**` header grammar unchanged.
|
|
148
148
|
|
|
149
|
-
Retry, cut, amend, raise-allowance and escalate commits never clear the tuple. For ledger amendments use its line-1 discriminant: no plan writer or plan_check; refresh after the amendment commit. 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 allowance. Commit spec + ledger as `loop: cut row <n>` or `loop: amend`.
|
|
149
|
+
Retry, cut, amend, raise-allowance and escalate commits never clear the tuple. For ledger amendments use its line-1 discriminant: no plan writer or plan_check; refresh after the amendment commit. 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 allowance. Commit spec + ledger as `loop: cut row <n>` or `loop: amend`. Without amend permission, stop for amendments; with amend permission, auto-apply amends. Redraw always stops and deletes the ledger with the plan. Cut only through the amendment surface, including its standing-grant section 5.
|
|
150
150
|
|
|
151
151
|
End every stop with `Recommendation: <option> - <why>` or `Recommendation: none - <why>`. An unnamed repair is none. Under amend permission take only a named authorized amend: print `took recommendation: amend for row <n>`, apply amendment-surface section 5 (including its audit), commit `loop: amend` / `loop: cut row <n>`, then return to the ordered table. Whitespace-normalize the row evidence cell and compare with evidence already auto-resolved on that row; repetition renders `Recommendation: none - evidence repeats row <n>`. Recover this evidence from amendment/ledger history; missing history never authorizes a repeated action. A cut leaves the stop; an unresolved row at allowance stops again, not a free retry. Retry, `rows +N` and redraw wait for the human. Fix-first enters `/skill:shape-ticket`'s own gate, never an automatic separate repair. Hard boundaries never auto-take recommendations.
|
|
152
152
|
|
|
@@ -171,13 +171,13 @@ For coordinated runs, route each verification and review below to every leg with
|
|
|
171
171
|
0. Call `phase_tracker({ action: "start", phase: "verify" })`. Mint `LOG_DIR=$(mktemp -d)` once for this verify session; a resumed session mints a new one at its first gate-set site.
|
|
172
172
|
1. Run the gate set per ## Gate set. Require every pair to pass. Commit verification-produced tracked changes, including gate-produced changes. Any repair invalidates that run: apply the rerun scope below before the next gate. No task reopen/update is awaited.
|
|
173
173
|
Count `repairs` as home `loop: repair verification` commits since ledger base, plus one for a `pending: verify` tuple with no admitted repair commit. Use the shared ledger allowance, with no per-row retry increments. Recover this count from branch history and disk on every resume; match marker bodies to pending tuples to avoid counting one dispatch twice. Recover an outstanding tuple before any new gate run or dispatch, including the last reserved repair at allowance.
|
|
174
|
-
On failure automatically repair while `repairs < allowance`
|
|
174
|
+
On failure automatically repair while `repairs < allowance` with or without amend permission; never consult amend permission or gate on iterations. Keep verify active and implement complete. Resolve `gauntlet_setting({ key: "escalationLoop" })`; require its non-empty `implModel`, including the resolver's main-loop fallback. Missing settings/model stops with `Problem: escalationLoop.implModel unavailable`, without a bump or marker. Save the home ledger and home/failing-leg HEADs, then bump iterations once and write `pending: verify | <repo> | <HEAD>` on disk before dispatch, using the failing leg's identity (single-leg `home`) and HEAD. Treat only that bump/tuple as expected home dirt. Dispatch exactly one `implementer` with `model: <implModel>`, `context: "fresh"`, `async: false`, failing checkout cwd and Rules, absolute spec path, failing command, checkout, exit code and log path, never pasted output. Pass the exact pending tuple and consumed `iteration:` for the first two commit-body lines, plus the failing leg's base and pre-bump iteration for jobs-file identity. Inject the persona's step-5 action authorization without its row mutation protocol. Include this blocking-call contract in the repair task: bound every blocking command with `timeout -k 30 <n>`, n <= 600; background and poll longer work. Read [loop-implementer's Evidence command](../../agents/loop-implementer.md#evidence-command) and copy its first three paragraphs verbatim into that task, omitting its row/seed ledger protocol. The repair child reads the log to derive the files to touch; for a stale selector restore the test or its name, never ledger evidence.
|
|
175
175
|
Require DONE, a clean failing checkout and exactly one commit after HEAD_BEFORE, matching the task's tuple/iteration attribution. Require all ledger rows unchanged, preserving attempts, mapping, allowance and prior decisions. The home child's sole commit includes the already-bumped ledger with pending retained; a companion child commits its leg only, leaving home HEAD and expected dirt unchanged. Remove `pending:` only in the parent repair marker: commit `loop: repair verification` in home with the consumed iteration and exact tuple in its body, recording the admitted child SHA. Refresh after admission. On killed, error, non-DONE, dirty, zero/multiple-commit, wrong-attribution or invalid repair returns, read `${TMPDIR:-/tmp}/loop-<failing leg's base SHA>-<pre-bump iteration>.jobs` using the repair task's identity, not home's base, and apply ## Interrupted recovery steps 1-2 to the failing checkout at its saved HEAD. For a companion also reset home to the saved home HEAD with `reset --hard` and `clean -fd`. Write exactly one empty `loop: repair verification` marker in home (no repair code): stage only the ledger with saved row cells, the already-consumed iteration and no `pending:`, and put tuple, iteration and interruption reason in the body, with no second bump. A non-empty `status --porcelain` after reset blocks neither the marker nor the rerun. Apply interrupted recovery's failure pass with the verification repair count to a failed reset of either checkout or an unwritten marker; require the marker's parent to be the saved home HEAD. On resume, admit a matching clean single repair commit or recover the interrupted return by this same path without another bump; an already admitted matching marker needs no second marker.
|
|
176
176
|
Rerun the failing checkout's gate pairs once using ## Gate set's log redirection and fail-fast rule after each admitted or recovered repair. After that rerun passes, run the original fail-fast run's still-unexecuted pairs from other checkouts in ledger order before recording verified HEAD. On resume run the complete gate set in a fresh session LOG_DIR. A new failure in any leg returns to the repair-count check; do not reopen rows or reset the count. Never spend verify-phase credits. On failure at `repairs >= allowance`, render `Stopped: verification failed with every row closed` with `repairs: <k> of <allowance>` and `Problem:` naming `gate <i> exit <code> <log path>` and quoting at most the last 20 lines with `tail -n 20`; this human-stop excerpt is the driver's only log read. Keep verify active and implement complete; offer amend or stop only, no `Retry with hint` or `rows +N`. Use the same restricted menu for missing capabilities. On success record verified HEAD and clean status for every leg.
|
|
177
177
|
2. Dispatch foreground whole-diff `wave-reviewer` per `/skill:requesting-code-review`, from ledger base through committed HEAD, with `SCOPED_TEST_COMMANDS: none`. Apply its fix rounds. Rerun the complete gate set after every fix round before re-review/next gate. Carry final SHIP Minor lines verbatim as `whole-diff minors:`, or `whole-diff minors: none`.
|
|
178
178
|
3. Run happy path per the fully read reference when overrides has `## Happy path` or the diff selects a row; use the diff-derived row, not a plan header. Pass summary and outcome to the separate fresh `conformance-reviewer`, along with spec path, verbatim original prompt and full diff. Use spec AC rows against the ledger as the checklist. Follow the reference's partition, concern decomposition, fix rounds and Convergence with the gate set replacing plan Verification at every test site per the reference's ledger-subject override. Use normal conformance Gn tasks on the same tracker and keep durable Gn identities in reports. Rerun the complete gate set after repairs. Resolve closureReview settings and reviewer dispatch per the reference. Reviews happen only after complete implement; none inside the iteration loop.
|
|
179
179
|
When the conformance fix-round cap blocks (`<used> fix round(s) used against a cap of <cap>`) or the reference's step 6 asks at its cap, read `<used>` from that text. Under amend permission with `<used>` below the ledger allowance: when the block is live, call `phase_tracker({ action: "grant_fix_rounds", rounds: <allowance - used>, reason: "<Amend-grant sentence verbatim>" })`, print `funded <allowance - used> conformance rounds under the grant`, and continue the fix loop; when `closureReview.enforce` is false, continue without a call. With `<used>` at or above the allowance, an error reply, or no amend permission, take the reference's step-6 stop. Never call the tool as a probe or store a grant counter; never count rounds yourself. The next block's `<used>` includes granted rounds, so a second block at the allowance stops; a resumed run with unspent credits continues without a block or another grant. Leave the cap and settings unchanged.
|
|
180
|
-
On an approved re-bound (`reopened by amendment`), use the held grant. Without amend permission, refresh and stop with `Stopped: row <n> reopened by amendment during verify`; offer authorize the row's return to ledger implementation or stop. Under amend permission, continue without a second authorization. For the granted continuation or the
|
|
180
|
+
On an approved re-bound (`reopened by amendment`), use the held grant. Without amend permission, refresh and stop with `Stopped: row <n> reopened by amendment during verify`; offer authorize the row's return to ledger implementation or stop. Under amend permission, continue without a second authorization. For the granted continuation or the human-approved return, apply the normal Before each dispatch boundaries, including exhausted-row rule 2, then Dispatch, Validate the return and refresh with verify still active and no phase reset; close on disk and rerun step 1 before continuing verify. During verify, dispatch the reopened row as a one-task `tasks` call carrying the same `## Dispatch` fields (agent, context fresh, async false, cwd, output, outputMode, acceptance, task text, and `model` only on an escalated round), with no `worktree:`; the closure guard counts it as one fix round against the conformance cap funded above. Keep the tuple write, iteration bump, `## Validate the return` and interrupted recovery exactly as for any dispatch. Keep completion blocked until closure; never substitute a tracker write for the ledger return.
|
|
181
181
|
4. Complete verify only on current CONFORMS or valid carried-open deferred inventory per the reference. A started positive-cap fix loop blocking/failing/exhausting with an open fix gap stops, never completes verify. Summarize rows closed, iterations consumed, files changed, test counts and review verdict. Emit exact `## Closure / conformance` schema from the reference: `status: CONFORMS (0 open)` or `status: GAPS (N open)`, then `audited-base: <full HEAD SHA>`, happy-path exactly when run, Deferred/deviates per spec exactly when applicable, all gap/concern fields unchanged, auto-applied fix commits index and whole-diff minors. Read its whole-diff-minors companion when directed. Never rename fields.
|
|
182
182
|
5. Immediately invoke `/skill:finishing-a-development-branch <abs worktree path>`. Its menu is the human gate; do not add a ready-to-finish prompt.
|
|
183
183
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Interrupted recovery
|
|
2
2
|
|
|
3
|
-
Treat dispatch error, non-DONE, silence kill, dirty tree, zero/multiple commits and wrong attribution as interrupted returns. Use the saved pre-dispatch ledger and checkout `HEAD_BEFORE`; on resume use the tuple's HEAD and its ledger before-image (the saved home HEAD for a companion). Recover without a human turn
|
|
3
|
+
Treat dispatch error, non-DONE, silence kill, dirty tree, zero/multiple commits and wrong attribution as interrupted returns. Use the saved pre-dispatch ledger and checkout `HEAD_BEFORE`; on resume use the tuple's HEAD and its ledger before-image (the saved home HEAD for a companion). Recover without a human turn with or without amend permission. Recovery itself is unconditional; check the numbered target's effective allowance or seed repair count only after committing the repair.
|
|
4
4
|
|
|
5
5
|
1. Read `${TMPDIR:-/tmp}/loop-<base SHA>-<iteration i>.jobs`; process lines are `<pid> <process-start-identity> <command>`. An absent or empty jobs file means no jobs to terminate. For each listed live job require matching start identity and command plus PGID equal to the pid; recheck identity, command and group leader before each signal. Send `kill -TERM -- -<pid>`, wait at most 10 s, then send `kill -KILL -- -<pid>` to a surviving matching group. When any identity, command or group-leader check fails, identity is unavailable, or the job is already gone, skip that job and continue recovery. A job still alive after KILL and missing launch history do not block recovery. Signal neither the driver's shells nor unrecorded processes. Print `terminated <k> child jobs` when k > 0, counting observed exits, then delete the jobs file.
|
|
6
6
|
2. Use the driver's shell: `git -C "<worktree>" reset --hard HEAD_BEFORE`, then `git -C "<worktree>" clean -fd` (leave ignored files alone). Continue even when files remain after reset; the next return is validated as usual.
|