mandrel 2.14.0 → 2.16.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/.agents/audit-checklists/navigability.md +1 -1
- package/.agents/docs/workflows.md +4 -4
- package/.agents/scripts/acceptance-eval.js +18 -1
- package/.agents/scripts/agents-bootstrap-github.js +22 -1
- package/.agents/scripts/apply-quality-bootstrap.js +6 -0
- package/.agents/scripts/audit-labels-bootstrap.js +15 -1
- package/.agents/scripts/audit-to-stories.js +26 -1
- package/.agents/scripts/boot-sweep.js +4 -1
- package/.agents/scripts/bootstrap.js +1 -0
- package/.agents/scripts/check-arch-cycles.js +20 -0
- package/.agents/scripts/check-baselines.js +8 -2
- package/.agents/scripts/check-context-budget.js +40 -5
- package/.agents/scripts/check-dead-exports.js +21 -0
- package/.agents/scripts/check-doc-links.js +12 -1
- package/.agents/scripts/check-lifecycle-doc-drift.js +9 -0
- package/.agents/scripts/check-workflow-citations.js +332 -0
- package/.agents/scripts/deliver-light.js +32 -3
- package/.agents/scripts/deliver-recover.js +4 -1
- package/.agents/scripts/diagnose-friction.js +17 -1
- package/.agents/scripts/diagnose.js +20 -14
- package/.agents/scripts/drain-pending-cleanup.js +20 -1
- package/.agents/scripts/evidence-gate.js +20 -1
- package/.agents/scripts/generate-config-docs.js +14 -1
- package/.agents/scripts/generate-lifecycle-docs.js +14 -1
- package/.agents/scripts/generate-workflows-doc.js +14 -1
- package/.agents/scripts/git-cleanup.js +32 -1
- package/.agents/scripts/lib/cli-usage.js +174 -0
- package/.agents/scripts/lib/cli-utils.js +12 -0
- package/.agents/scripts/lib/close-validation/process.js +61 -15
- package/.agents/scripts/lib/doc-tiers.js +53 -10
- package/.agents/scripts/lib/orchestration/complexity-gate.js +307 -89
- package/.agents/scripts/lib/orchestration/light-suitability.js +31 -9
- package/.agents/scripts/lib/orchestration/plan-context.js +205 -20
- package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +87 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +24 -15
- package/.agents/scripts/lib/workflow-closure.js +431 -0
- package/.agents/scripts/mandrel-update-preflight.js +9 -0
- package/.agents/scripts/nav-registry-diff.js +13 -0
- package/.agents/scripts/plan-context.js +21 -2
- package/.agents/scripts/plan-critics.js +10 -0
- package/.agents/scripts/plan-persist.js +33 -1
- package/.agents/scripts/plan-run-epilogue.js +12 -1
- package/.agents/scripts/quality-preview.js +17 -1
- package/.agents/scripts/resolve-doc-tiers.js +13 -0
- package/.agents/scripts/resolve-stories.js +1 -0
- package/.agents/scripts/resync-status-column.js +4 -1
- package/.agents/scripts/signals-view.js +11 -0
- package/.agents/scripts/single-story-close.js +24 -0
- package/.agents/scripts/single-story-confirm-merge.js +16 -0
- package/.agents/scripts/single-story-init.js +21 -1
- package/.agents/scripts/stories-wave-tick.js +1 -0
- package/.agents/scripts/sync-agentrc.js +16 -4
- package/.agents/scripts/update-ticket-state.js +23 -2
- package/.agents/workflows/audit-navigability.md +2 -2
- package/.agents/workflows/audit-to-stories.md +1 -1
- package/.agents/workflows/deliver.md +80 -81
- package/.agents/workflows/git-cleanup.md +9 -14
- package/.agents/workflows/helpers/acceptance-self-eval.md +14 -13
- package/.agents/workflows/helpers/audit-lens-core.md +2 -2
- package/.agents/workflows/helpers/code-review.md +11 -11
- package/.agents/workflows/helpers/deliver-digest.md +7 -8
- package/.agents/workflows/helpers/deliver-light.md +222 -0
- package/.agents/workflows/helpers/deliver-reference.md +46 -14
- package/.agents/workflows/helpers/deliver-story-reference.md +55 -63
- package/.agents/workflows/helpers/deliver-story.md +22 -22
- package/.agents/workflows/helpers/mandrel-sync-config.md +2 -2
- package/.agents/workflows/helpers/parallel-tooling.md +1 -2
- package/.agents/workflows/helpers/plan-reference.md +96 -17
- package/.agents/workflows/helpers/worktree-lifecycle.md +1 -4
- package/.agents/workflows/mandrel-update.md +6 -6
- package/.agents/workflows/plan.md +90 -85
- package/.agents/workflows/prototype.md +104 -0
- package/docs/CHANGELOG.md +32 -0
- package/package.json +2 -1
- package/.agents/workflows/deliver-light.md +0 -148
|
@@ -251,4 +251,28 @@ async function main() {
|
|
|
251
251
|
runAsCli(import.meta.url, main, {
|
|
252
252
|
source: 'single-story-close',
|
|
253
253
|
propagateExitCode: true,
|
|
254
|
+
usage: {
|
|
255
|
+
invocation:
|
|
256
|
+
'node .agents/scripts/single-story-close.js --story <id> [--cwd <main-repo>] [options]',
|
|
257
|
+
summary:
|
|
258
|
+
'Run the whole delivery tail for one Story — close gates, base sync, push, PR to the base branch, merge wait, agent::done flip — and emit the terminal envelope.',
|
|
259
|
+
flags: [
|
|
260
|
+
['--story <id>', 'GitHub issue number of the Story (required).'],
|
|
261
|
+
[
|
|
262
|
+
'--cwd <main-repo>',
|
|
263
|
+
'Main-repo checkout to run from (default: project root).',
|
|
264
|
+
],
|
|
265
|
+
['--skip-validation', 'Skip the close-validation gate chain.'],
|
|
266
|
+
['--skip-sync', 'Skip the base-branch sync phase.'],
|
|
267
|
+
['--no-auto-merge', 'Open the PR without arming native auto-merge.'],
|
|
268
|
+
['--wait-merge', 'Force the in-close merge wait.'],
|
|
269
|
+
['--no-wait-merge', 'Return as soon as the PR is open; do not wait.'],
|
|
270
|
+
['--max-wait-seconds <n>', 'Per-invocation merge-wait bound.'],
|
|
271
|
+
['--no-evidence', 'Do not reuse or write gate evidence stamps.'],
|
|
272
|
+
['--dry-run', 'Report the plan; mutate nothing.'],
|
|
273
|
+
],
|
|
274
|
+
notes: [
|
|
275
|
+
'Exit codes:\n 0 landed\n 1 blocked or failed\n 3 pending (resumable — run the envelope’s nextCommand)',
|
|
276
|
+
],
|
|
277
|
+
},
|
|
254
278
|
});
|
|
@@ -538,4 +538,20 @@ async function main() {
|
|
|
538
538
|
runAsCli(import.meta.url, main, {
|
|
539
539
|
source: 'single-story-confirm-merge',
|
|
540
540
|
propagateExitCode: true,
|
|
541
|
+
usage: {
|
|
542
|
+
invocation:
|
|
543
|
+
'node .agents/scripts/single-story-confirm-merge.js --story <id> [--pr <n>] [--wait] [--max-wait-seconds <n>] [--cwd <main-repo>]',
|
|
544
|
+
summary:
|
|
545
|
+
'Confirm a Story PR merged and flip the Story to agent::done. With --wait, resumes the bounded merge wait a close handed off.',
|
|
546
|
+
flags: [
|
|
547
|
+
['--story <id>', 'GitHub issue number of the Story (required).'],
|
|
548
|
+
['--pr <n>', 'PR number (default: resolved from the Story branch).'],
|
|
549
|
+
['--wait', 'Resume the bounded merge wait instead of probing once.'],
|
|
550
|
+
['--max-wait-seconds <n>', 'Per-invocation bound for the --wait path.'],
|
|
551
|
+
[
|
|
552
|
+
'--cwd <main-repo>',
|
|
553
|
+
'Main-repo checkout to run from (default: project root).',
|
|
554
|
+
],
|
|
555
|
+
],
|
|
556
|
+
},
|
|
541
557
|
});
|
|
@@ -831,4 +831,24 @@ export function renderSingleStoryInitComment(result) {
|
|
|
831
831
|
].join('\n');
|
|
832
832
|
}
|
|
833
833
|
|
|
834
|
-
runAsCli(import.meta.url, runSingleStoryInit, {
|
|
834
|
+
runAsCli(import.meta.url, runSingleStoryInit, {
|
|
835
|
+
source: 'single-story-init',
|
|
836
|
+
usage: {
|
|
837
|
+
invocation:
|
|
838
|
+
'node .agents/scripts/single-story-init.js --story <id> [--dry-run] [--steal] [--cwd <main-repo>]',
|
|
839
|
+
summary:
|
|
840
|
+
'Initialize a Story for delivery: acquire the lease, seed story-<id> from the base branch, materialize the worktree, and flip the Story to agent::executing.',
|
|
841
|
+
flags: [
|
|
842
|
+
['--story <id>', 'GitHub issue number of the Story (required).'],
|
|
843
|
+
[
|
|
844
|
+
'--dry-run',
|
|
845
|
+
'Report what would happen; no mutations, no lease, no sweep.',
|
|
846
|
+
],
|
|
847
|
+
['--steal', 'Forcibly transfer a lease held by another assignee.'],
|
|
848
|
+
[
|
|
849
|
+
'--cwd <main-repo>',
|
|
850
|
+
'Main-repo checkout to run from (default: project root).',
|
|
851
|
+
],
|
|
852
|
+
],
|
|
853
|
+
},
|
|
854
|
+
});
|
|
@@ -21,15 +21,27 @@
|
|
|
21
21
|
* 0 — Config is valid (advisories may still appear).
|
|
22
22
|
* 1 — Config is missing, malformed, or fails schema validation.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
* --cwd <path> Project root (defaults to process.cwd()).
|
|
26
|
-
* --quiet Suppress advisory rows (only print the status line).
|
|
24
|
+
* The flag contract lives in `USAGE` below — `--help` is the one home for it.
|
|
27
25
|
*/
|
|
28
26
|
|
|
29
27
|
import { fileURLToPath } from 'node:url';
|
|
28
|
+
import { respondToHelp } from './lib/cli-usage.js';
|
|
30
29
|
import { formatSyncReport, syncAgentrc } from './lib/config/sync-agentrc.js';
|
|
31
30
|
import { Logger } from './lib/Logger.js';
|
|
32
31
|
|
|
32
|
+
const USAGE = {
|
|
33
|
+
invocation: 'node .agents/scripts/sync-agentrc.js [--cwd <path>] [--quiet]',
|
|
34
|
+
summary:
|
|
35
|
+
'Validate `.agentrc.json` against the framework schema and report every project leaf that merely restates a framework default. Never writes the config.',
|
|
36
|
+
flags: [
|
|
37
|
+
['--cwd <path>', 'Project root (default: process cwd).'],
|
|
38
|
+
['--quiet', 'Suppress advisory rows; print only the status line.'],
|
|
39
|
+
],
|
|
40
|
+
notes: [
|
|
41
|
+
'Exit codes:\n 0 config is valid (advisories may still appear)\n 1 config is missing, malformed, or fails schema validation',
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
|
|
33
45
|
function parseArgs(argv) {
|
|
34
46
|
const out = { cwd: null, quiet: false };
|
|
35
47
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -67,5 +79,5 @@ function trimAdvisories(report) {
|
|
|
67
79
|
// cli-opt-out: synchronous CLI with explicit exit-code return.
|
|
68
80
|
const isMain = process.argv[1] === fileURLToPath(import.meta.url);
|
|
69
81
|
if (isMain) {
|
|
70
|
-
process.exit(main());
|
|
82
|
+
process.exit(respondToHelp(process.argv.slice(2), USAGE) ? 0 : main());
|
|
71
83
|
}
|
|
@@ -6,16 +6,37 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { parseArgs } from 'node:util';
|
|
9
|
+
import { respondToHelp } from './lib/cli-usage.js';
|
|
9
10
|
import { resolveConfig } from './lib/config-resolver.js';
|
|
10
11
|
import { Logger } from './lib/Logger.js';
|
|
11
12
|
import { transitionTicketState } from './lib/orchestration/ticketing.js';
|
|
12
13
|
import { createProvider } from './lib/provider-factory.js';
|
|
13
14
|
|
|
15
|
+
const USAGE = {
|
|
16
|
+
invocation:
|
|
17
|
+
'node .agents/scripts/update-ticket-state.js --ticket <id> [--state <state> | --remove-label <label>]',
|
|
18
|
+
summary:
|
|
19
|
+
'The one sanctioned surface for an agent::* label transition on a ticket.',
|
|
20
|
+
flags: [
|
|
21
|
+
['--ticket <id>', 'GitHub issue number to transition (required).'],
|
|
22
|
+
[
|
|
23
|
+
'--state <state>',
|
|
24
|
+
'Target agent state (e.g. agent::ready, agent::executing, agent::done).',
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
'--remove-label <label>',
|
|
28
|
+
'Drop a single label without flipping the agent state.',
|
|
29
|
+
],
|
|
30
|
+
],
|
|
31
|
+
notes: ['Exactly one of --state or --remove-label is required.'],
|
|
32
|
+
};
|
|
33
|
+
|
|
14
34
|
// ── CLI Main Block ────────────────────────────────────────────────────────
|
|
15
35
|
// cli-opt-out: re-export shim with a DEBUG_MAIN escape hatch for tests; runAsCli's strict path-equality guard would block the env-flag entry path.
|
|
16
36
|
if (
|
|
17
|
-
process.argv[1]?.endsWith('update-ticket-state.js') ||
|
|
18
|
-
|
|
37
|
+
(process.argv[1]?.endsWith('update-ticket-state.js') ||
|
|
38
|
+
process.env.DEBUG_MAIN) &&
|
|
39
|
+
!respondToHelp(process.argv.slice(2), USAGE)
|
|
19
40
|
) {
|
|
20
41
|
const { values } = parseArgs({
|
|
21
42
|
args: process.argv.slice(2),
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
description: >-
|
|
3
3
|
Audit the whole route tree against the consumer's nav-registry SSOT —
|
|
4
4
|
every route has a persona nav door and no nav href is dead. A
|
|
5
|
-
deliberately-global lens
|
|
6
|
-
|
|
5
|
+
deliberately-global lens exempt from the cross-epic-leak guard and
|
|
6
|
+
routed onto route-adding change sets.
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Navigability Audit
|
|
@@ -204,7 +204,7 @@ workflow owns **no** parallel dedup or footer-parsing code: the
|
|
|
204
204
|
fingerprint, footer round-trip, and routing all live in that one shared
|
|
205
205
|
module.
|
|
206
206
|
|
|
207
|
-
Dedup runs in **two stages** when a provider resolves
|
|
207
|
+
Dedup runs in **two stages** when a provider resolves: a
|
|
208
208
|
meaning-first **semantic candidate** pass (`searchCandidates`, wired to
|
|
209
209
|
[`lib/findings/semantic-issue-search.js`](../scripts/lib/findings/semantic-issue-search.js))
|
|
210
210
|
runs FIRST and widens the net across open + closed issues; the exact
|
|
@@ -1,65 +1,72 @@
|
|
|
1
1
|
---
|
|
2
2
|
description:
|
|
3
|
-
Unified delivery entry point. Takes
|
|
4
|
-
|
|
3
|
+
Unified delivery entry point. Takes Story ids or a plain-language prompt,
|
|
4
|
+
derives which path the work belongs on, and lands it via the single
|
|
5
5
|
deliver-story engine — story-<id> → PR → main.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# /deliver
|
|
8
|
+
# /deliver
|
|
9
9
|
|
|
10
|
-
> **Lean spine.** Happy path + gate list. Sequencing
|
|
11
|
-
>
|
|
12
|
-
>
|
|
13
|
-
> [`helpers/deliver-
|
|
14
|
-
> delivery always needs is
|
|
15
|
-
> [`helpers/deliver-digest.md`](helpers/deliver-digest.md)
|
|
10
|
+
> **Lean spine.** Happy path + gate list. Sequencing, dispatch mechanics,
|
|
11
|
+
> intent phrases, ceremony, and the epilogue live in the on-demand
|
|
12
|
+
> [`helpers/deliver-reference.md`](helpers/deliver-reference.md); the unplanned
|
|
13
|
+
> path in [`helpers/deliver-light.md`](helpers/deliver-light.md). What every
|
|
14
|
+
> delivery always needs is one read:
|
|
15
|
+
> [`helpers/deliver-digest.md`](helpers/deliver-digest.md).
|
|
16
16
|
|
|
17
17
|
## Role
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
shape (#4736) — sub-agent isolation only earns its cost against a concurrent
|
|
33
|
-
sibling.
|
|
19
|
+
One delivery door. `/deliver` owns input resolution and sequencing only — every
|
|
20
|
+
Story lands through [`helpers/deliver-story.md`](helpers/deliver-story.md).
|
|
21
|
+
|
|
22
|
+
Nothing about the route is declared at the invocation; it is **derived, then
|
|
23
|
+
announced, then acted on**. The dependency graph is **discovered, not
|
|
24
|
+
declared** — `resolve-stories.js` reads it from live state (body edges ∪ native
|
|
25
|
+
`blocked_by` edges, each blocker resolved against its real issue state), so
|
|
26
|
+
there is no graph to hand it and no batch label, which is what lets you deliver
|
|
27
|
+
Stories **across plan runs and over time**.
|
|
28
|
+
`plan-run::<id>` is filter metadata, never a resolution input; `route::lite` is
|
|
29
|
+
a body-derived hint only. Ahead of all of it, a **single-Story run runs the
|
|
30
|
+
engine inline** whatever the shape — sub-agent isolation only earns its cost
|
|
31
|
+
against a concurrent sibling.
|
|
34
32
|
|
|
35
33
|
## Inputs
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
|
35
|
+
Classify what the operator typed **before** doing anything else, and say which
|
|
36
|
+
shape you read it as:
|
|
37
|
+
|
|
38
|
+
| Invocation | Shape | Behavior |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `/deliver` | bare | List the open `agent::ready` Stories and ask which to deliver. Deliver nothing until answered. |
|
|
41
|
+
| `/deliver 4712` | ids | One Story via `helpers/deliver-story.md`, **inline in this session** — no `story-worker` spawn. |
|
|
42
|
+
| `/deliver 4712 4713 …` | ids | Resolve the set, then sequence by the discovered graph via `stories-wave-tick.js`, dispatching role-scoped sub-agents. |
|
|
43
|
+
| `/deliver add a --json flag to doctor` | prompt | Unplanned work: gate, author a receipt Story, land it — [`helpers/deliver-light.md`](helpers/deliver-light.md). |
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
**The discriminator is lexical and total.** Every positional argument matching
|
|
46
|
+
`^#?\d+$` means ids; anything else means a prompt. A **mixed** invocation (ids
|
|
47
|
+
*and* prose) is a **hard error** — refuse it and ask which was meant, the way
|
|
48
|
+
resolution refuses a whole set rather than under-delivering. A named ticket
|
|
49
|
+
that is not `type::story`, or carries an `Epic: #N` footer, is a hard error too.
|
|
45
50
|
|
|
46
|
-
##
|
|
51
|
+
## Saying what you want
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
| `--steal` | Forwarded to `single-story-init.js` / lease steal. |
|
|
53
|
-
| `--wait-merge` | Force close-and-land (the default; `delivery.routing.closeAndLand`). |
|
|
54
|
-
| `--no-wait-merge` | Opt out; stop at `agent::closing` for a human land. |
|
|
53
|
+
No flags to remember: state intent — *"…but I'll merge it myself"*, *"…take the
|
|
54
|
+
lease"*, *"…one at a time"* — and announce what you read before acting.
|
|
55
|
+
Phrasings and the flag each fills in:
|
|
56
|
+
[`helpers/deliver-reference.md` § Intent phrases](helpers/deliver-reference.md).
|
|
55
57
|
|
|
56
|
-
**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
`--yes` is **runner-set, never operator-typed**: cron, `/loop`, and headless
|
|
59
|
+
dispatch set it to mean *nobody is at the keyboard*, which is what makes the
|
|
60
|
+
unplanned path's over-scope stop fail closed to a terminal envelope instead of
|
|
61
|
+
a question. Never offer it to an operator or add it to an attended run.
|
|
60
62
|
|
|
61
63
|
## Procedure
|
|
62
64
|
|
|
65
|
+
0. **Classify and announce.** Read the invocation per § Inputs and state the
|
|
66
|
+
shape you derived. A prompt leaves for
|
|
67
|
+
[`helpers/deliver-light.md`](helpers/deliver-light.md); bare asks; ids
|
|
68
|
+
continue below.
|
|
69
|
+
|
|
63
70
|
1. **Resolve the set.** One command, for one Story or many:
|
|
64
71
|
`node .agents/scripts/resolve-stories.js --ids <id,id,...>`. It validates
|
|
65
72
|
the set and shows what will run: read `stories[]`, `dag[]`, and `done[]` to
|
|
@@ -81,15 +88,14 @@ Story). Resolution refuses the whole set rather than silently under-delivering.
|
|
|
81
88
|
|
|
82
89
|
**Do not add `--concurrency` unless the operator explicitly asked for a
|
|
83
90
|
per-run cap** — an explicit value wins over config, so a filled-in literal
|
|
84
|
-
silently defeats a `.agentrc.local.json` override
|
|
91
|
+
silently defeats a `.agentrc.local.json` override.
|
|
85
92
|
|
|
86
93
|
Each beat re-probes live state to derive done / in-flight itself; you never
|
|
87
|
-
compute them
|
|
88
|
-
|
|
94
|
+
compute them. `--dispatched` is the one thing you must supply — the
|
|
95
|
+
append-only list of every id you spawned this run — and cross-run
|
|
89
96
|
de-confliction via the assignee lease is automatic
|
|
90
|
-
([`helpers/deliver-reference.md`
|
|
91
|
-
|
|
92
|
-
spawn, lite-route execution, and `checklistPath`).
|
|
97
|
+
([`helpers/deliver-reference.md`](helpers/deliver-reference.md) §§ Sequencing
|
|
98
|
+
edge cases, Dispatch mechanics).
|
|
93
99
|
|
|
94
100
|
Branch on the exit code:
|
|
95
101
|
- **0** — dispatch each `ready` id (already capped and overlap-free). Empty
|
|
@@ -98,64 +104,57 @@ Story). Resolution refuses the whole set rather than silently under-delivering.
|
|
|
98
104
|
- **2** — `cycleError`: the graph is self-referential. Fix the `depends_on`
|
|
99
105
|
declarations; do not retry.
|
|
100
106
|
- **3** — `wedged`: nothing dispatchable, nothing in flight, undone Stories
|
|
101
|
-
waiting on blockers
|
|
102
|
-
|
|
103
|
-
unchanged.
|
|
107
|
+
waiting on unmet blockers — both named in the envelope. Land the blocker
|
|
108
|
+
or include it in `--ids`; do not retry unchanged.
|
|
104
109
|
- **4** — `blocked`: a Story carries `agent::blocked`, named in `blocked[]`
|
|
105
110
|
with `blockedReason` — the protocol's HITL pause
|
|
106
111
|
([`instructions.md` § 1.J](../instructions.md)). **Stop the loop and
|
|
107
112
|
surface it; do not poll.** Read the friction comment
|
|
108
113
|
(`gh issue view <id> --comments`) and resume only once the operator
|
|
109
114
|
unblocks it (`update-ticket-state.js --ticket <id> --state agent::ready`).
|
|
110
|
-
|
|
115
|
+
Blocked outranks a wedge but not a cycle (fix the graph first).
|
|
111
116
|
|
|
112
117
|
4. **Per-run epilogue (N>1).** Once step 3 reports `epilogueDue: true`, run
|
|
113
118
|
`node .agents/scripts/plan-run-epilogue.js --stories 101,102` — audit
|
|
114
|
-
roster, follow-up roll-up, sibling coherence. A single-Story run skips it
|
|
115
|
-
|
|
116
|
-
[`helpers/deliver-reference.md` § Per-run epilogue](helpers/deliver-reference.md).
|
|
119
|
+
roster, follow-up roll-up, sibling coherence. A single-Story run skips it
|
|
120
|
+
([reference § Per-run epilogue](helpers/deliver-reference.md)).
|
|
117
121
|
|
|
118
122
|
## Branch model (authoritative)
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
No `epic/<id>` integration branch and no `--no-ff` wave merge. Dependent
|
|
125
|
-
Stories land sequentially so each builds on the previous merge to `main`.
|
|
126
|
-
Ceremony depth (profiles + derived level via `ceremony-routing.js`,
|
|
127
|
-
review depth reading the same level) and the mechanism table:
|
|
124
|
+
`story-<id>` → PR → `main` (squash + required checks), per digest § 2.
|
|
125
|
+
Dependent Stories land sequentially so each builds on the previous merge.
|
|
126
|
+
Ceremony depth (profiles + derived level via `ceremony-routing.js`, review
|
|
127
|
+
depth reading the same level):
|
|
128
128
|
[`helpers/deliver-reference.md` § Ceremony](helpers/deliver-reference.md).
|
|
129
129
|
|
|
130
130
|
## Reading a Story's outcome
|
|
131
131
|
|
|
132
|
-
Each Story
|
|
133
|
-
`
|
|
134
|
-
[`helpers/deliver-digest.md`](helpers/deliver-digest.md) § 5
|
|
135
|
-
[schema](../schemas/story-deliver-terminal.schema.json) (Story #4543).
|
|
132
|
+
Each Story ends in exactly one schema-validated terminal envelope — `landed` |
|
|
133
|
+
`pending` | `blocked` | `failed`. Statuses, exits, and fields:
|
|
134
|
+
[`helpers/deliver-digest.md`](helpers/deliver-digest.md) § 5.
|
|
136
135
|
|
|
137
|
-
`pending` is **not** a failure: the bounded
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
`async` mode (Story #4698) returns `pending` by design — launch its
|
|
141
|
-
`nextCommand` as a background invocation (reference appendix).
|
|
136
|
+
`pending` is **not** a failure: the bounded wait expired with the PR healthy
|
|
137
|
+
(or a human owns the merge), nothing was mutated, and `nextCommand` resumes it
|
|
138
|
+
— run that rather than re-dispatching.
|
|
142
139
|
|
|
143
140
|
For a Story in an unclear state — including the merged-but-label-stale one a
|
|
144
|
-
|
|
141
|
+
re-run refuses outright — probe it read-only with
|
|
145
142
|
`node .agents/scripts/deliver-recover.js --story <storyId>`.
|
|
146
143
|
|
|
147
144
|
## Constraints
|
|
148
145
|
|
|
149
146
|
- **Land or block — never a silent local build** (digest § 2). Attended
|
|
150
147
|
delivers default to close-and-land (`delivery.routing.closeAndLand: true`);
|
|
151
|
-
|
|
152
|
-
-
|
|
153
|
-
|
|
148
|
+
rest at `agent::closing` only when a human owns the merge.
|
|
149
|
+
- **`/deliver` never plans.** Planned tickets come from [`/plan`](plan.md), and
|
|
150
|
+
an over-scope prompt **escalates and ends** — never invoke `/plan` in this
|
|
151
|
+
session to rescue it ([`helpers/deliver-light.md`](helpers/deliver-light.md)
|
|
152
|
+
§ Escalation is terminal). The router performs no git/label mutations;
|
|
153
|
+
`deliver-story` owns every script.
|
|
154
154
|
|
|
155
155
|
## See also
|
|
156
156
|
|
|
157
157
|
- [`/plan`](plan.md) — unified planning entry point.
|
|
158
|
-
- [`helpers/deliver-story.md`](helpers/deliver-story.md) — the one
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
dispatch, ceremony, and epilogue detail.
|
|
158
|
+
- [`helpers/deliver-story.md`](helpers/deliver-story.md) — the one engine.
|
|
159
|
+
- [`helpers/deliver-light.md`](helpers/deliver-light.md) — the unplanned
|
|
160
|
+
prompt path, shared with `/plan` Gate #1.
|
|
@@ -22,12 +22,12 @@ Reach for it when the automated hygiene left an unusual state behind.
|
|
|
22
22
|
|
|
23
23
|
The enumeration + reap logic lives in
|
|
24
24
|
[`git-cleanup.js`](../scripts/git-cleanup.js) — it computes the candidate list,
|
|
25
|
-
the skip taxonomy, the detection signals, and the JSON envelope
|
|
26
|
-
|
|
27
|
-
mutated. When no phase flag is passed, **all four phases run** sequentially;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
the skip taxonomy, the detection signals, and the JSON envelope, and prints them
|
|
26
|
+
itself. Without `--execute` the script is a **dry-run preview**; nothing is
|
|
27
|
+
mutated. When no phase flag is passed, **all four phases run** sequentially; a
|
|
28
|
+
phase flag narrows the run. A failure in one phase does not short-circuit the
|
|
29
|
+
others — each runs and reports independently. The script documents its own
|
|
30
|
+
flags: `node .agents/scripts/git-cleanup.js --help`.
|
|
31
31
|
|
|
32
32
|
## Phases
|
|
33
33
|
|
|
@@ -44,14 +44,9 @@ runs and reports independently.
|
|
|
44
44
|
> branches, delete remote refs (with `--remote`), and drop stashes. Without
|
|
45
45
|
> `--execute` the script only previews.
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
undone without re-pushing.
|
|
51
|
-
- **`--yes`** — bypass every per-step prompt (CI / non-interactive). Under it,
|
|
52
|
-
stash drops still require `--drop-stashes <ref>`.
|
|
53
|
-
- **`--exclude '<pattern>'`** — carve a branch out of the reap. This is the only
|
|
54
|
-
way to protect an in-scope merged-PR branch you want to keep.
|
|
47
|
+
Two consequences the flag list alone does not carry: `--remote` deletions cannot
|
|
48
|
+
be undone without re-pushing, and `--exclude '<pattern>'` is the **only** way to
|
|
49
|
+
protect an in-scope merged-PR branch you want to keep.
|
|
55
50
|
|
|
56
51
|
Do **not** run with `--execute` if there is unmerged work that needs saving. The
|
|
57
52
|
fast-forward phase skips on a dirty tree (safe), but the branches phase reaps any
|
|
@@ -15,7 +15,7 @@ description: >-
|
|
|
15
15
|
After the implementation commits land and **before** the Story proceeds to
|
|
16
16
|
close, run an explicit, **independent** eval pass that scores the change set
|
|
17
17
|
computed once for this Story and injected into the critic — never one the
|
|
18
|
-
critic re-derives
|
|
18
|
+
critic re-derives — against **each** `acceptance[]` item
|
|
19
19
|
individually. This is the acceptance gate
|
|
20
20
|
the close-validation chain does not provide: that chain (lint / test / format /
|
|
21
21
|
maintainability / coverage / crap) proves the code is *healthy*, not that it
|
|
@@ -30,7 +30,7 @@ mid-delivery, and evaluates the actual work product.
|
|
|
30
30
|
|
|
31
31
|
## Per round
|
|
32
32
|
|
|
33
|
-
1. **Eval pass — one verdict-owner per cluster
|
|
33
|
+
1. **Eval pass — one verdict-owner per cluster.** Exactly
|
|
34
34
|
**one** pass authors each cluster's verdict: the **fresh-context critic**
|
|
35
35
|
when the ceremony routing below resolves `fresh` (a sub-agent via the
|
|
36
36
|
`Agent` tool, *not* a continuation of your implementing turn — the
|
|
@@ -44,7 +44,7 @@ mid-delivery, and evaluates the actual work product.
|
|
|
44
44
|
of the one authored verdict, not a second (or third) pass over the
|
|
45
45
|
criteria.
|
|
46
46
|
|
|
47
|
-
> **Sub-agent type + derived-level ceremony
|
|
47
|
+
> **Sub-agent type + derived-level ceremony.** When
|
|
48
48
|
> `delivery.routing.roleScopedAgents` is enabled (the **default**), dispatch
|
|
49
49
|
> the critic with `subagent_type: acceptance-critic` — it boots on the
|
|
50
50
|
> role-scoped [`acceptance-critic`](../../agents/acceptance-critic.md) context
|
|
@@ -57,8 +57,8 @@ mid-delivery, and evaluates the actual work product.
|
|
|
57
57
|
> — the same signal `review-depth.js` resolves depth from, so the two
|
|
58
58
|
> decisions cannot disagree. Derive it with `deriveChangeLevel` from
|
|
59
59
|
> [`review-depth.js`](../../scripts/lib/orchestration/review-depth.js) over
|
|
60
|
-
> the **change set your caller computed once** for this Story
|
|
61
|
-
> `computeChangeSet` from
|
|
60
|
+
> the **change set your caller computed once** for this Story
|
|
61
|
+
> (`computeChangeSet` from
|
|
62
62
|
> [`change-set.js`](../../scripts/lib/orchestration/change-set.js); see
|
|
63
63
|
> [`deliver-story.md`](deliver-story.md) Step 2), then
|
|
64
64
|
> resolve the ceremony per cluster with `resolveCeremonyForRisk` from
|
|
@@ -73,9 +73,10 @@ mid-delivery, and evaluates the actual work product.
|
|
|
73
73
|
> full ceremony** (fail-safe). This chooses fresh-vs-inline **per cluster
|
|
74
74
|
> only — it never changes the cluster count**.
|
|
75
75
|
>
|
|
76
|
-
>
|
|
77
|
-
> the plan asserted about itself was exactly the signal
|
|
78
|
-
> independent checking, and nothing verified it
|
|
76
|
+
> The routing signal is deliberately **not** a planner-authored risk
|
|
77
|
+
> verdict: a level the plan asserted about itself was exactly the signal
|
|
78
|
+
> that could *reduce* independent checking, and nothing verified it
|
|
79
|
+
> against the diff.
|
|
79
80
|
>
|
|
80
81
|
> **Inline-critic path (low-level-routed OR nesting-absent harness).** The
|
|
81
82
|
> verdict is authored **inline** whenever the risk router above resolves to
|
|
@@ -83,8 +84,8 @@ mid-delivery, and evaluates the actual work product.
|
|
|
83
84
|
> a **fallback** on any harness that cannot spawn the fresh critic.
|
|
84
85
|
> Dispatching the critic as a nested `Agent` is the fresh-context shape and
|
|
85
86
|
> works on any harness that carries `Agent` into sub-agents (Claude Code ≥
|
|
86
|
-
> 2.1.202
|
|
87
|
-
>
|
|
87
|
+
> 2.1.202). This eval loop itself runs inside a Story delivery
|
|
88
|
+
> sub-agent, so the nested
|
|
88
89
|
> critic sits at nesting depth 2. If the host does **not** support nested
|
|
89
90
|
> `Agent` dispatch at that depth — the tool is absent, or a spawn attempt
|
|
90
91
|
> returns an unsupported-capability error — do **not** stall the Story
|
|
@@ -104,7 +105,7 @@ mid-delivery, and evaluates the actual work product.
|
|
|
104
105
|
- Inspects the **change set handed to it in its spawn context** — the one
|
|
105
106
|
list computed above — and the Story's inline `acceptance[]` / `verify[]`
|
|
106
107
|
arrays. Pass the file list explicitly when you dispatch the critic; it
|
|
107
|
-
does not re-enumerate the diff for itself
|
|
108
|
+
does not re-enumerate the diff for itself, so a commit
|
|
108
109
|
landing mid-ceremony cannot leave the critic scoring a different change
|
|
109
110
|
than the one that routed it.
|
|
110
111
|
- **Runs the `verify[]` commands** and consumes their output as **required
|
|
@@ -112,7 +113,7 @@ mid-delivery, and evaluates the actual work product.
|
|
|
112
113
|
optional advisory pre-flight — a criterion cannot be scored `met` without
|
|
113
114
|
the supporting `verify[]` evidence where a `verify[]` command is relevant
|
|
114
115
|
to it.
|
|
115
|
-
- **Shares `lint` / `typecheck` evidence with close
|
|
116
|
+
- **Shares `lint` / `typecheck` evidence with close.** When a
|
|
116
117
|
`verify[]` command is **byte-identical** to a close-validation gate — in
|
|
117
118
|
practice only the cheap, command-identical `lint` and `typecheck` gates
|
|
118
119
|
(`npm run lint` and the resolved `project.commands.typecheck`) — the
|
|
@@ -140,7 +141,7 @@ mid-delivery, and evaluates the actual work product.
|
|
|
140
141
|
2. **Decide.** Run the gate against the verdict (the caller's Step 1a names the
|
|
141
142
|
exact invocation — omit `--epic`). The gate **scores the single verdict
|
|
142
143
|
the round's owner authored** — schema validation, round cap, decision —
|
|
143
|
-
and never re-scores the criteria itself
|
|
144
|
+
and never re-scores the criteria itself:
|
|
144
145
|
|
|
145
146
|
```bash
|
|
146
147
|
node <main-repo>/.agents/scripts/acceptance-eval.js \
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Audit lens core (shared contract)
|
|
2
2
|
|
|
3
|
-
> **Single source of truth for every audit lens's shared machinery
|
|
4
|
-
>
|
|
3
|
+
> **Single source of truth for every audit lens's shared machinery.**
|
|
4
|
+
> Each `audit-<lens>.md` workflow references this file instead
|
|
5
5
|
> of re-stating the blocks below. A lens carries only its own frontmatter, a
|
|
6
6
|
> short preamble, its `{{changedFiles}}` fence, and its genuinely lens-specific
|
|
7
7
|
> dimensions / detection batteries / applicability gates / boundary
|
|
@@ -53,9 +53,9 @@ envelope.
|
|
|
53
53
|
### Review depth (`depth`)
|
|
54
54
|
|
|
55
55
|
`depth` is the thoroughness lever: `runCodeReview` derives it from the diff via
|
|
56
|
-
[`review-depth.js`](../../scripts/lib/orchestration/review-depth.js)
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
[`review-depth.js`](../../scripts/lib/orchestration/review-depth.js) — an
|
|
57
|
+
observable signal that takes no planner-authored input — and forwards it to
|
|
58
|
+
every provider's `runReview` input.
|
|
59
59
|
|
|
60
60
|
It is an **input-only** signal: it changes *how thorough* the review is, never
|
|
61
61
|
the findings envelope (`{ status, severity, posted, report, halted,
|
|
@@ -98,7 +98,7 @@ The caller invokes the in-process code-review pipeline
|
|
|
98
98
|
(`runCodeReview` in `.agents/scripts/lib/orchestration/code-review.js`)
|
|
99
99
|
with the resolved `{ scope, ticketId, baseRef, headRef, depth }` envelope
|
|
100
100
|
(`depth` defaults to `standard` when the caller omits it). The
|
|
101
|
-
pluggable `ReviewProvider` adapter chain
|
|
101
|
+
pluggable `ReviewProvider` adapter chain runs against the
|
|
102
102
|
diff `baseRef..headRef`, with the LLM-backed providers honoring `depth`
|
|
103
103
|
(see **Review depth** above), and posts a structured summary to `[TICKET_ID]`.
|
|
104
104
|
The pipeline will:
|
|
@@ -108,7 +108,7 @@ The pipeline will:
|
|
|
108
108
|
- Run a focused lint check on the change set.
|
|
109
109
|
- Post a structured summary report to the `[TICKET_ID]` issue.
|
|
110
110
|
|
|
111
|
-
### Step 1a — Story-scope local-lens pass (`scope: story` only
|
|
111
|
+
### Step 1a — Story-scope local-lens pass (`scope: story` only)
|
|
112
112
|
|
|
113
113
|
When `scope === 'story'`, the shared review spine
|
|
114
114
|
[`runStoryReviewCore`](../../scripts/lib/orchestration/story-close/phases/review-core.js)
|
|
@@ -173,7 +173,7 @@ The diff under review is `baseRef..headRef`
|
|
|
173
173
|
(`main..story-<storyId>`, or the configured base branch to the Story
|
|
174
174
|
branch). The Story-scope local-lens pass (Step 1a) has already covered the
|
|
175
175
|
local-tier concerns. Lens findings and pillar findings share the single
|
|
176
|
-
`verification-results` comment this pass posts
|
|
176
|
+
`verification-results` comment this pass posts. The
|
|
177
177
|
integration view here focuses on cross-cutting ripple within the Story and
|
|
178
178
|
contract drift against the base branch. Look for:
|
|
179
179
|
|
|
@@ -257,9 +257,9 @@ prior baseline before merging.
|
|
|
257
257
|
## Step 4 — Produce Findings Report
|
|
258
258
|
|
|
259
259
|
Findings are **persisted as a `verification-results` structured comment on
|
|
260
|
-
the `[TICKET_ID]` issue** by `runCodeReview` (the unified findings contract
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
the `[TICKET_ID]` issue** by `runCodeReview` (the unified findings contract —
|
|
261
|
+
this single comment carries the Story-scope lens findings). The target
|
|
262
|
+
ticket is the Story. The comment
|
|
263
263
|
is idempotent — re-runs replace the prior one — and its body includes
|
|
264
264
|
severity-tier counts plus the full findings list so downstream workflows
|
|
265
265
|
(notably the retro helper) can summarise blockers/high findings without
|
|
@@ -289,7 +289,7 @@ For every finding, provide:
|
|
|
289
289
|
fix worked. Keep it tight (≤ 5 sentences); the sub-agent will read the
|
|
290
290
|
surrounding code itself.
|
|
291
291
|
|
|
292
|
-
### The `## Fixed on-branch` section
|
|
292
|
+
### The `## Fixed on-branch` section
|
|
293
293
|
|
|
294
294
|
Findings that Step 4.5 remediated on `[HEAD_REF]` MUST be rendered under a
|
|
295
295
|
dedicated **`## Fixed on-branch`** heading, **not** in the severity groups
|
|
@@ -322,7 +322,7 @@ the executor: it decides, per finding, between a focused fix on
|
|
|
322
322
|
`[HEAD_REF]` and leaving the finding on the `verification-results`
|
|
323
323
|
structured comment for the operator.
|
|
324
324
|
|
|
325
|
-
### Resolve the remediation threshold
|
|
325
|
+
### Resolve the remediation threshold
|
|
326
326
|
|
|
327
327
|
Read `delivery.codeReview.autoFixSeverity` from the resolved `.agentrc.json`
|
|
328
328
|
(default **`medium`**; the resolver in
|