mandrel 2.24.0 → 2.26.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/agents/acceptance-critic.md +19 -21
- package/.agents/agents/auditor.md +16 -19
- package/.agents/agents/story-worker.md +41 -54
- package/.agents/audit-checklists/architecture.md +5 -1
- package/.agents/audit-checklists/baselines.md +21 -0
- package/.agents/audit-checklists/quality.md +3 -0
- package/.agents/docs/agentrc-reference.json +2 -1
- package/.agents/docs/configuration.md +2 -1
- package/.agents/docs/quality-gates.md +80 -18
- package/.agents/docs/workflows.md +4 -2
- package/.agents/instructions.md +1 -1
- package/.agents/rules/ci-remediation.md +68 -3
- package/.agents/schemas/agentrc.schema.json +6 -1
- package/.agents/schemas/audit-rules.json +15 -0
- package/.agents/schemas/baselines/audit-baselines-envelope.schema.json +242 -0
- package/.agents/schemas/baselines/baseline-envelope.schema.json +8 -0
- package/.agents/schemas/baselines/crap.schema.json +13 -1
- package/.agents/schemas/crap-report.schema.json +37 -0
- package/.agents/schemas/model-attribution.schema.json +4 -0
- package/.agents/scripts/acceptance-eval.js +124 -15
- package/.agents/scripts/audit-baselines.js +136 -0
- package/.agents/scripts/audit-labels-bootstrap.js +16 -95
- package/.agents/scripts/audit-to-stories.js +33 -3
- package/.agents/scripts/check-arch-cycles.js +12 -93
- package/.agents/scripts/check-baseline-drift.js +16 -3
- package/.agents/scripts/check-baselines.js +19 -3
- package/.agents/scripts/check-context-budget.js +95 -14
- package/.agents/scripts/check-cyclomatic.js +214 -0
- package/.agents/scripts/check-schema-references.js +392 -0
- package/.agents/scripts/check-test-temp-hygiene.js +121 -1
- package/.agents/scripts/check-workflow-timeouts.js +291 -0
- package/.agents/scripts/cleanup-repo-test-temp.js +7 -5
- package/.agents/scripts/deliver-light.js +3 -4
- package/.agents/scripts/deliver-recover.js +13 -0
- package/.agents/scripts/diagnose-friction.js +85 -19
- package/.agents/scripts/lib/audit-baselines/engine.js +177 -0
- package/.agents/scripts/lib/audit-baselines/gate-surface.js +63 -0
- package/.agents/scripts/lib/audit-baselines/headroom.js +72 -0
- package/.agents/scripts/lib/audit-baselines/hotspots.js +69 -0
- package/.agents/scripts/lib/audit-baselines/kinds.js +313 -0
- package/.agents/scripts/lib/audit-baselines/outliers.js +100 -0
- package/.agents/scripts/lib/audit-baselines/read.js +87 -0
- package/.agents/scripts/lib/audit-baselines/staleness.js +123 -0
- package/.agents/scripts/lib/audit-baselines/surface-entry.js +106 -0
- package/.agents/scripts/lib/audit-baselines/trend.js +125 -0
- package/.agents/scripts/lib/audit-baselines/weights.js +193 -0
- package/.agents/scripts/lib/audit-suite/index.js +0 -5
- package/.agents/scripts/lib/audit-suite/selector.js +9 -62
- package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +177 -0
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +1 -0
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +35 -3
- package/.agents/scripts/lib/audit-to-stories/group-findings.js +20 -11
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +23 -9
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +9 -2
- package/.agents/scripts/lib/baseline-loader.js +0 -0
- package/.agents/scripts/lib/baseline-schema-registry.js +13 -1
- package/.agents/scripts/lib/baselines/diff-scope-cli.js +22 -160
- package/.agents/scripts/lib/baselines/duplication-scanner.js +27 -0
- package/.agents/scripts/lib/baselines/git-base.js +0 -0
- package/.agents/scripts/lib/baselines/kinds/crap.js +499 -57
- package/.agents/scripts/lib/baselines/preview-gates.js +58 -15
- package/.agents/scripts/lib/baselines/reader.js +10 -0
- package/.agents/scripts/lib/baselines/refresh-service.js +69 -11
- package/.agents/scripts/lib/baselines/scope.js +39 -90
- package/.agents/scripts/lib/baselines/writer.js +16 -7
- package/.agents/scripts/lib/changed-files.js +8 -1
- package/.agents/scripts/lib/cli-args.js +115 -1
- package/.agents/scripts/lib/close-validation/runner.js +70 -25
- package/.agents/scripts/lib/config-settings-schema-delivery.js +5 -0
- package/.agents/scripts/lib/crap-engine.js +124 -27
- package/.agents/scripts/lib/crap-method-identity.js +153 -0
- package/.agents/scripts/lib/crap-utils.js +86 -13
- package/.agents/scripts/lib/cyclomatic-ceiling.js +265 -0
- package/.agents/scripts/lib/env-loader.js +46 -16
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -2
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +0 -2
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +0 -2
- package/.agents/scripts/lib/findings/route-finding.js +123 -17
- package/.agents/scripts/lib/findings/severity.js +80 -2
- package/.agents/scripts/lib/git/cached-fetch.js +0 -0
- package/.agents/scripts/lib/git-utils.js +136 -80
- package/.agents/scripts/lib/import-graph.js +156 -0
- package/.agents/scripts/lib/label-constants.js +17 -0
- package/.agents/scripts/lib/observability/runtime-friction.js +17 -2
- package/.agents/scripts/lib/observability/source-classifier.js +175 -2
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +110 -17
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +17 -12
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +36 -6
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +5 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +12 -1
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +8 -1
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +548 -0
- package/.agents/scripts/lib/orchestration/deliver-recover.js +2 -2
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +10 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +39 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +71 -20
- package/.agents/scripts/lib/orchestration/light-backstop.js +20 -3
- package/.agents/scripts/lib/orchestration/light-escalation.js +82 -3
- package/.agents/scripts/lib/orchestration/light-suitability.js +103 -5
- package/.agents/scripts/lib/orchestration/plan-context.js +119 -66
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +31 -5
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +216 -109
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +61 -13
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +79 -22
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +51 -20
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +70 -74
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +231 -0
- package/.agents/scripts/lib/orchestration/resolve-stories.js +18 -17
- package/.agents/scripts/lib/orchestration/retro-proposals.js +0 -0
- package/.agents/scripts/lib/orchestration/run-epilogue.js +12 -0
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +276 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +41 -10
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +125 -37
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +6 -6
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +42 -38
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +129 -21
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -1
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +267 -125
- package/.agents/scripts/lib/orchestration/spec-budget.js +16 -5
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +182 -95
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +22 -0
- package/.agents/scripts/lib/orchestration/ticket-validator.js +5 -11
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +4 -4
- package/.agents/scripts/lib/reserved-test-ids.js +77 -0
- package/.agents/scripts/lib/story-adjacency.js +3 -3
- package/.agents/scripts/lib/story-plan.js +137 -42
- package/.agents/scripts/lib/templates/decomposer-prompts.js +4 -4
- package/.agents/scripts/lib/test-runner-contract.js +134 -0
- package/.agents/scripts/lib/test-tiers.js +11 -2
- package/.agents/scripts/lib/ticket-body-sections.js +1 -1
- package/.agents/scripts/lib/util/concurrent-map.js +17 -0
- package/.agents/scripts/lib/util/parse-id-list.js +103 -0
- package/.agents/scripts/lib/util/poll-loop.js +18 -2
- package/.agents/scripts/lib/wave-runner/live-probe.js +29 -13
- package/.agents/scripts/lib/wave-runner/ready-set.js +254 -43
- package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +10 -13
- package/.agents/scripts/lib/workers/crap-worker.js +8 -13
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +4 -10
- package/.agents/scripts/lib/workers/maintainability-worker.js +4 -10
- package/.agents/scripts/lib/workers/serve-worker-messages.js +35 -0
- package/.agents/scripts/lib/worktree/git-hooks.js +206 -0
- package/.agents/scripts/lib/worktree/lifecycle/creation.js +6 -0
- package/.agents/scripts/lib/worktree-manager.js +14 -0
- package/.agents/scripts/plan-run-epilogue.js +17 -5
- package/.agents/scripts/pr-watch-with-update.js +568 -213
- package/.agents/scripts/providers/github/tickets.js +33 -10
- package/.agents/scripts/provision-git-hooks.js +85 -0
- package/.agents/scripts/quality-preview.js +137 -28
- package/.agents/scripts/resolve-stories.js +4 -1
- package/.agents/scripts/run-coverage.js +86 -35
- package/.agents/scripts/run-lint.js +20 -0
- package/.agents/scripts/run-tests.js +36 -36
- package/.agents/scripts/single-story-close.js +34 -2
- package/.agents/scripts/single-story-confirm-merge.js +22 -6
- package/.agents/scripts/single-story-init.js +7 -0
- package/.agents/scripts/stories-wave-tick.js +308 -47
- package/.agents/scripts/story-plan.js +65 -9
- package/.agents/scripts/update-coverage-baseline.js +34 -4
- package/.agents/scripts/update-crap-baseline.js +42 -4
- package/.agents/scripts/update-duplication-baseline.js +209 -83
- package/.agents/scripts/update-maintainability-baseline.js +31 -4
- package/.agents/scripts/validate-docs-freshness.js +1 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +4 -1
- package/.agents/skills/core/gates-and-baselines/SKILL.md +17 -11
- package/.agents/skills/skills.index.json +2 -2
- package/.agents/templates/single-story-body.md +16 -8
- package/.agents/workflows/audit-architecture.md +69 -13
- package/.agents/workflows/audit-baselines.md +289 -0
- package/.agents/workflows/audit-navigability.md +5 -4
- package/.agents/workflows/audit-quality.md +26 -0
- package/.agents/workflows/audit-to-stories.md +30 -4
- package/.agents/workflows/deliver.md +92 -97
- package/.agents/workflows/helpers/acceptance-self-eval.md +47 -10
- package/.agents/workflows/helpers/audit-lens-core.md +25 -4
- package/.agents/workflows/helpers/code-quality-guardrails.md +9 -2
- package/.agents/workflows/helpers/deliver-digest.md +41 -21
- package/.agents/workflows/helpers/deliver-reference.md +95 -4
- package/.agents/workflows/helpers/deliver-story-reference.md +174 -52
- package/.agents/workflows/helpers/deliver-story.md +104 -119
- package/.agents/workflows/helpers/plan-reference.md +49 -5
- package/.agents/workflows/memory-consolidate.md +116 -0
- package/.agents/workflows/plan.md +62 -75
- package/README.md +13 -6
- package/docs/CHANGELOG.md +93 -0
- package/lib/cli/update.js +14 -11
- package/lib/cli/version-check.js +9 -1
- package/package.json +9 -4
- package/.agents/schemas/friction-event.schema.json +0 -56
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +0 -707
|
@@ -8,73 +8,67 @@ description:
|
|
|
8
8
|
# /deliver
|
|
9
9
|
|
|
10
10
|
> **Lean spine.** Happy path + gate list. Sequencing, dispatch mechanics,
|
|
11
|
-
> intent phrases, ceremony
|
|
12
|
-
> [`helpers/deliver-reference.md`](helpers/deliver-reference.md)
|
|
13
|
-
>
|
|
14
|
-
>
|
|
15
|
-
> [`helpers/deliver-digest.md`](helpers/deliver-digest.md).
|
|
11
|
+
> intent phrases, ceremony and the epilogue live in on-demand
|
|
12
|
+
> [`helpers/deliver-reference.md`](helpers/deliver-reference.md) ("reference"
|
|
13
|
+
> below); the unplanned path in
|
|
14
|
+
> [`helpers/deliver-light.md`](helpers/deliver-light.md). Every delivery reads
|
|
15
|
+
> [`helpers/deliver-digest.md`](helpers/deliver-digest.md) once.
|
|
16
16
|
|
|
17
17
|
## Role
|
|
18
18
|
|
|
19
|
-
One delivery door. `/deliver` owns input resolution
|
|
20
|
-
|
|
19
|
+
One delivery door. `/deliver` owns input resolution, sequencing and the
|
|
20
|
+
close-and-land tail; Stories are implemented via
|
|
21
|
+
[`helpers/deliver-story.md`](helpers/deliver-story.md).
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
`
|
|
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.
|
|
23
|
+
The dependency graph is **discovered, not declared** — `resolve-stories.js`
|
|
24
|
+
reads it from live state, so you can deliver Stories **across plan runs and
|
|
25
|
+
over time**. `plan-run::<id>` is filter metadata, never a resolution input;
|
|
26
|
+
`route::lite` a body-derived hint only.
|
|
32
27
|
|
|
33
28
|
## Inputs
|
|
34
29
|
|
|
35
|
-
Classify what the operator typed **before**
|
|
36
|
-
|
|
30
|
+
Classify what the operator typed **before** anything else, and say which shape
|
|
31
|
+
you read:
|
|
37
32
|
|
|
38
33
|
| Invocation | Shape | Behavior |
|
|
39
34
|
| --- | --- | --- |
|
|
40
35
|
| `/deliver` | bare | List the open `agent::ready` Stories and ask which to deliver. Deliver nothing until answered. |
|
|
41
36
|
| `/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,
|
|
37
|
+
| `/deliver 4712 4713 …` | ids | Resolve the set, sequence by the discovered graph via `stories-wave-tick.js`, dispatch sub-agents. |
|
|
38
|
+
| `/deliver 4712 - 4716` | ids | A **range** — every id in the inclusive span. |
|
|
43
39
|
| `/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). |
|
|
44
40
|
|
|
45
|
-
**The discriminator is lexical and total.**
|
|
46
|
-
`^#?\d+$`
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
**The discriminator is lexical and total.** An argument matching `^#?\d+$` is an
|
|
42
|
+
id, and `^#?\d+\s*[-–—]\s*#?\d+$` an inclusive **range** — pass one on as a
|
|
43
|
+
single unspaced token, never hand-expanded (reference § Ranges). Either shape
|
|
44
|
+
means ids; anything else means a prompt. A **mixed** invocation (ids *and*
|
|
45
|
+
prose) is a **hard error** — refuse it and ask which was meant. A ticket not
|
|
46
|
+
`type::story`, or carrying an `Epic: #N` footer, is a hard error too.
|
|
50
47
|
|
|
51
48
|
## Saying what you want
|
|
52
49
|
|
|
53
|
-
No flags to remember: state intent — *"…but I'll merge it myself"*, *"…
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
[`helpers/deliver-reference.md` § Intent phrases](helpers/deliver-reference.md).
|
|
50
|
+
No flags to remember: state intent — *"…but I'll merge it myself"*, *"…one at
|
|
51
|
+
a time"* — and announce what you read. Phrasings and the flags they fill in:
|
|
52
|
+
reference § Intent phrases.
|
|
57
53
|
|
|
58
|
-
`--yes` is **runner-set, never operator-typed**: cron, `/loop
|
|
59
|
-
dispatch set it to mean *nobody is at the keyboard*, which
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
`--yes` is **runner-set, never operator-typed**: cron, `/loop` and headless
|
|
55
|
+
dispatch set it to mean *nobody is at the keyboard*, which fails the unplanned
|
|
56
|
+
path's over-scope stop closed to an envelope instead of a question. Never offer
|
|
57
|
+
it to an operator or add it to an attended run.
|
|
62
58
|
|
|
63
59
|
## Procedure
|
|
64
60
|
|
|
65
61
|
0. **Classify and announce.** Read the invocation per § Inputs and state the
|
|
66
|
-
shape
|
|
67
|
-
[`helpers/deliver-light.md`](helpers/deliver-light.md); bare asks; ids
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
`
|
|
72
|
-
the
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
whose native edges cannot be read — a missing gate would co-dispatch against
|
|
77
|
-
an unlanded blocker.
|
|
62
|
+
shape. A prompt leaves for
|
|
63
|
+
[`helpers/deliver-light.md`](helpers/deliver-light.md); bare asks; ids go on.
|
|
64
|
+
|
|
65
|
+
1. **Resolve the set.** One command, one Story or many:
|
|
66
|
+
`node .agents/scripts/resolve-stories.js --ids <id,id,...>`. It validates the
|
|
67
|
+
set and shows what will run: read `stories[]`, `dag[]` and `done[]` to
|
|
68
|
+
present the order in step 2, but do **not** thread them into step 3 — the
|
|
69
|
+
tick re-resolves the graph every beat. It hard-errors (exit 1) on an id that
|
|
70
|
+
is not a Story, carries an `Epic: #N` footer, or whose edges cannot be
|
|
71
|
+
read — a missing gate would co-dispatch against an unlanded blocker.
|
|
78
72
|
|
|
79
73
|
2. **Confirm (N>1).** Present the order; wait unless `--yes`.
|
|
80
74
|
|
|
@@ -87,74 +81,75 @@ a question. Never offer it to an operator or add it to an attended run.
|
|
|
87
81
|
```
|
|
88
82
|
|
|
89
83
|
**Do not add `--concurrency` unless the operator explicitly asked for a
|
|
90
|
-
per-run cap** — an explicit value wins over config, so a
|
|
91
|
-
|
|
84
|
+
per-run cap** — an explicit value wins over config, so a literal defeats a
|
|
85
|
+
`.agentrc.local.json` override.
|
|
92
86
|
|
|
93
87
|
Each beat re-probes live state to derive done / in-flight itself; you never
|
|
94
88
|
compute them. `--dispatched` is the one thing you must supply — the
|
|
95
|
-
append-only list of every id you spawned this run
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
- **
|
|
102
|
-
`
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
(`gh issue view <id> --comments`) and resume only once the operator
|
|
114
|
-
unblocks it (`update-ticket-state.js --ticket <id> --state agent::ready`).
|
|
115
|
-
Blocked outranks a wedge but not a cycle (fix the graph first).
|
|
116
|
-
|
|
117
|
-
4. **Per-run epilogue (N>1).** Once step 3 reports `epilogueDue: true`, run
|
|
118
|
-
`node .agents/scripts/plan-run-epilogue.js --stories 101,102` — audit
|
|
119
|
-
roster, follow-up roll-up, sibling coherence. A single-Story run skips it
|
|
89
|
+
append-only list of every id you spawned this run. Cross-run de-confliction
|
|
90
|
+
via the assignee lease is automatic (reference §§ Sequencing edge cases,
|
|
91
|
+
Dispatch mechanics). Branch on the exit code:
|
|
92
|
+
- **0** — dispatch each `ready` id (already capped and overlap-free); an
|
|
93
|
+
empty `ready` with work in flight means "waiting", so keep looping;
|
|
94
|
+
`epilogueDue: true` means every Story is done — step 4.
|
|
95
|
+
- **2** — `cycleError`: the graph is self-referential; fix `depends_on`, do
|
|
96
|
+
not retry. **3** — `wedged`: nothing dispatchable, nothing in flight, the
|
|
97
|
+
undone Stories and their unmet blockers named; land a blocker or add it to
|
|
98
|
+
`--ids`. **4** — `blocked`: a Story carries `agent::blocked` with
|
|
99
|
+
`blockedReason`, the protocol's HITL pause
|
|
100
|
+
([`instructions.md` § 1.J](../instructions.md)) — **stop the loop and
|
|
101
|
+
surface it; do not poll**, resuming once the operator unblocks it. Blocked
|
|
102
|
+
outranks a wedge, not a cycle.
|
|
103
|
+
|
|
104
|
+
4. **Close each hand-off** (§ Closing what the workers hand back), then, with
|
|
105
|
+
every Story landed, run the **per-run epilogue (N>1)**:
|
|
106
|
+
`node .agents/scripts/plan-run-epilogue.js --stories 101,102`. N=1 skips it
|
|
120
107
|
([reference § Per-run epilogue](helpers/deliver-reference.md)).
|
|
121
108
|
|
|
122
|
-
|
|
109
|
+
5. **Correct what the change invalidated.** If a memory you recalled this
|
|
110
|
+
session is now wrong — a trap this landed, a budget it moved — fix that
|
|
111
|
+
entry now, while both the old belief and the new fact are in context, and
|
|
112
|
+
say so when you report. No memory substrate → skip silently. Sweeping the
|
|
113
|
+
whole pool is [`/memory-consolidate`](memory-consolidate.md), not this step.
|
|
114
|
+
|
|
115
|
+
## Closing what the workers hand back {#tail}
|
|
123
116
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
[`helpers/deliver-reference.md` § Ceremony](helpers/deliver-reference.md).
|
|
117
|
+
**The tail is the orchestrator's, not the worker's.** A dispatched
|
|
118
|
+
`story-worker` stops at a pushed branch and returns a hand-off; **you** run
|
|
119
|
+
[`helpers/deliver-story.md`](helpers/deliver-story.md) Step 3
|
|
120
|
+
(`single-story-close.js`) for it, foreground, and relay the envelope.
|
|
129
121
|
|
|
130
|
-
|
|
122
|
+
**Serialize the tail.** Implementation runs in parallel; closing does not. Close
|
|
123
|
+
one Story at a time — closes contend on the base branch, the merge queue and
|
|
124
|
+
the checkout. A worker handing back mid-close waits its turn.
|
|
131
125
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
126
|
+
**A worker returning no terminal envelope is the expected shape**, not a failure
|
|
127
|
+
to answer with a re-dispatch: only close mints one. Close the pushed branch, or
|
|
128
|
+
probe read-only with `node .agents/scripts/deliver-recover.js --story <storyId>`
|
|
129
|
+
and resume the worker or close it names.
|
|
135
130
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
131
|
+
**Reading the outcome.** Each close ends the Story in one schema-validated
|
|
132
|
+
envelope — `landed` | `pending` | `blocked` | `failed`; statuses, exits and
|
|
133
|
+
fields are digest § 5. `pending` is **not** a failure — `nextCommand` resumes
|
|
134
|
+
it; run that, do not re-dispatch.
|
|
139
135
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
`
|
|
136
|
+
**Branch model (authoritative).** `story-<id>` → PR → `main` (squash +
|
|
137
|
+
required checks), per digest § 2; dependent Stories land sequentially. Ceremony
|
|
138
|
+
depth (profiles + derived level via `ceremony-routing.js`, review depth reading
|
|
139
|
+
it): reference § Ceremony.
|
|
143
140
|
|
|
144
141
|
## Constraints
|
|
145
142
|
|
|
146
|
-
- **Land or block — never a silent local build** (digest § 2). Attended
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
- **Land or block — never a silent local build** (digest § 2). Attended delivers
|
|
144
|
+
default to close-and-land (`delivery.routing.closeAndLand: true`); rest at
|
|
145
|
+
`agent::closing` only when a human owns it.
|
|
149
146
|
- **`/deliver` never plans.** Planned tickets come from [`/plan`](plan.md), and
|
|
150
147
|
an over-scope prompt **escalates and ends** — never invoke `/plan` in this
|
|
151
148
|
session to rescue it ([`helpers/deliver-light.md`](helpers/deliver-light.md)
|
|
152
|
-
§ Escalation is terminal).
|
|
153
|
-
`deliver-story` owns every script.
|
|
149
|
+
§ Escalation is terminal).
|
|
154
150
|
|
|
155
151
|
## See also
|
|
156
152
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
prompt path, shared with `/plan` Gate #1.
|
|
153
|
+
[`/plan`](plan.md), [`helpers/deliver-story.md`](helpers/deliver-story.md) (the
|
|
154
|
+
engine), [`helpers/deliver-light.md`](helpers/deliver-light.md) (the unplanned
|
|
155
|
+
prompt path, shared with `/plan` Gate #1).
|
|
@@ -40,8 +40,8 @@ mid-delivery, and evaluates the actual work product.
|
|
|
40
40
|
`resolveCeremonyForRisk`). **Never run both**, and never run a
|
|
41
41
|
preliminary self-assessment pass before dispatching the fresh critic —
|
|
42
42
|
the redundant pre-pass buys no measurable quality and roughly triples
|
|
43
|
-
the acceptance-block cost. Step
|
|
44
|
-
of the one
|
|
43
|
+
the acceptance-block cost. Step 3's gate is the deterministic **scorer**
|
|
44
|
+
of the one merged verdict, not a second (or third) pass over the
|
|
45
45
|
criteria.
|
|
46
46
|
|
|
47
47
|
> **Sub-agent type + derived-level ceremony.** When
|
|
@@ -134,20 +134,56 @@ mid-delivery, and evaluates the actual work product.
|
|
|
134
134
|
fresh — a false-fresh coverage record without `coverage-final.json`
|
|
135
135
|
silently weakens the floor. Limit the evidence-share to `lint` and
|
|
136
136
|
`typecheck`.
|
|
137
|
-
- Emits a verdict file under `temp/` conforming to
|
|
137
|
+
- Emits a **cluster** verdict file under `temp/` conforming to
|
|
138
138
|
[`acceptance-eval-verdict.schema.json`](../../schemas/acceptance-eval-verdict.schema.json):
|
|
139
139
|
one `{ index, criterion, verdict: met|partial|unmet, evidence,
|
|
140
|
-
verifyEvidence[] }` record per acceptance item
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
verifyEvidence[] }` record per acceptance item **in that cluster**, each
|
|
141
|
+
`index` being the item's position in the Story's full `acceptance[]`
|
|
142
|
+
array. A fresh critic **returns that path to you** rather than calling the
|
|
143
|
+
gate itself.
|
|
144
|
+
2. **Dispatch the round's clusters in parallel, then merge into one verdict.**
|
|
145
|
+
The clusters of a round are independent, so dispatch **all** of the round's
|
|
146
|
+
fresh critics as N `Agent` calls **in a single assistant turn** —
|
|
147
|
+
[`parallel-tooling.md`](parallel-tooling.md) **Rule 3** — never serially,
|
|
148
|
+
and never one round per cluster. Clusters routed `inline` are authored in
|
|
149
|
+
the same round alongside them.
|
|
150
|
+
|
|
151
|
+
Then **merge** the cluster verdicts into **one** verdict file under `temp/`:
|
|
152
|
+
concatenate every cluster's `criteria[]` records and order the merged array
|
|
153
|
+
by `index`, so it holds exactly one record per `acceptance[]` item in
|
|
154
|
+
**acceptance-array order**, under a single top-level `storyId`,
|
|
155
|
+
`schemaVersion`, `round` and `commitSha`. The verdict schema deliberately
|
|
156
|
+
carries **no `clusterId`** — the round's artifact is the merged verdict, and
|
|
157
|
+
which critic scored which record is not part of the contract.
|
|
158
|
+
|
|
159
|
+
> **Why one gate call and not N.** The round counter is **Story-scoped** —
|
|
160
|
+
> derived by counting `acceptance-eval` signals in the Story's
|
|
161
|
+
> `signals.ndjson` — and each cluster verdict has a distinct fingerprint, so
|
|
162
|
+
> the replay guard never collapses them. A gate call per cluster would spend
|
|
163
|
+
> one of the (default 2) rounds *per cluster*, so a Story with more than 8
|
|
164
|
+
> acceptance criteria would exhaust its redraft budget on cluster arithmetic
|
|
165
|
+
> alone; N concurrent calls would also race that same ledger. Cluster-scoped
|
|
166
|
+
> round counting exists in
|
|
167
|
+
> [`acceptance-eval-decision.js`](../../scripts/lib/orchestration/acceptance-eval-decision.js)
|
|
168
|
+
> but requires an integer `epicId`, which v2 pins `null` — it is not a way
|
|
169
|
+
> around the merge.
|
|
170
|
+
3. **Decide — exactly one gate call per round.** Run the gate against the
|
|
171
|
+
**merged** verdict (the caller's Step 1a names the exact invocation — omit
|
|
172
|
+
`--epic`). The gate **scores the single verdict the round produced** —
|
|
173
|
+
schema validation, round cap, decision — and never re-scores the criteria
|
|
174
|
+
itself:
|
|
145
175
|
|
|
146
176
|
```bash
|
|
147
177
|
node <main-repo>/.agents/scripts/acceptance-eval.js \
|
|
148
|
-
--story <storyId> --verdict <verdict-path>
|
|
178
|
+
--story <storyId> --verdict <merged-verdict-path> \
|
|
179
|
+
--expected-criteria <number of acceptance[] items>
|
|
149
180
|
```
|
|
150
181
|
|
|
182
|
+
Pass `--expected-criteria` from the `acceptance[]` count you already read
|
|
183
|
+
off the Story body: a verdict whose `criteria[]` length differs — a single
|
|
184
|
+
cluster's verdict handed over unmerged — is rejected **before scoring**,
|
|
185
|
+
with an error naming the merge contract and consuming **no round**.
|
|
186
|
+
|
|
151
187
|
The gate validates the verdict against the schema, applies the round cap,
|
|
152
188
|
emits the per-criterion `acceptance-eval` signal into the retro / feedback
|
|
153
189
|
substrate, prints a JSON envelope, and exits with one of three decisions:
|
|
@@ -161,4 +197,5 @@ mid-delivery, and evaluates the actual work product.
|
|
|
161
197
|
(transition to `agent::blocked`) and post a `friction` comment naming the
|
|
162
198
|
unmet criteria and their evidence. Never silently proceed to close.
|
|
163
199
|
|
|
164
|
-
Write the verdict
|
|
200
|
+
Write both the per-cluster verdicts and the merged verdict under `temp/` only —
|
|
201
|
+
they are scratch artifacts.
|
|
@@ -76,7 +76,7 @@ the primary file the finding lives in:]
|
|
|
76
76
|
### `path/to/primary-file.ext` — [Short title of the issue]
|
|
77
77
|
|
|
78
78
|
- **Dimension:** [the lens-specific dimension — see the lens's own list]
|
|
79
|
-
- **Severity:** [Critical | High | Medium | Low]
|
|
79
|
+
- **Severity:** [Critical | High | Medium | Low | Info]
|
|
80
80
|
- **Location:** `path/to/primary-file.ext:line`
|
|
81
81
|
- **Current State:** [the specific file/line/module and why it is problematic]
|
|
82
82
|
- **Recommendation & Rationale:** [how to remediate and why it matters]
|
|
@@ -89,11 +89,18 @@ the primary file the finding lives in:]
|
|
|
89
89
|
|
|
90
90
|
## Severity scale {#severity-scale}
|
|
91
91
|
|
|
92
|
-
Every finding grades its severity (labelled `Severity` or `Impact`) on
|
|
93
|
-
ordered scale
|
|
94
|
-
|
|
92
|
+
Every finding grades its severity (labelled `Severity` or `Impact`) on the
|
|
93
|
+
ordered scale below. **The code owns this vocabulary**: it is defined in
|
|
94
|
+
[`lib/findings/severity.js`](../../scripts/lib/findings/severity.js)
|
|
95
|
+
(`SEVERITIES`), and every level here — including its accepted spellings — comes
|
|
96
|
+
from that module. A surviving **Critical** finding halts the delivery gate
|
|
95
97
|
(`lib/audit-suite/findings.js#hasSurvivingCritical`).
|
|
96
98
|
|
|
99
|
+
Grade on **exactly** these five levels. A level of your own invention does not
|
|
100
|
+
parse: it resolves to no severity, tallies as `unknown`, and the finding is
|
|
101
|
+
dropped by every severity-filtered run — including the most permissive one. A
|
|
102
|
+
dropped finding is indistinguishable from a finding you never wrote.
|
|
103
|
+
|
|
97
104
|
- **Critical** — an active, exploitable, or data-losing defect that must be
|
|
98
105
|
fixed before the change can ship (e.g. a leaked secret, an auth bypass, a
|
|
99
106
|
guaranteed production outage or data-loss path).
|
|
@@ -102,6 +109,11 @@ ordered scale. `parse-audit-md.js` recognizes every level, and a surviving
|
|
|
102
109
|
- **Medium** — a real problem worth scheduling; contained blast radius, or a
|
|
103
110
|
reasonable workaround exists.
|
|
104
111
|
- **Low** — minor or cosmetic; fix opportunistically.
|
|
112
|
+
- **Info** — the canonical floor: a real, grounded observation worth recording
|
|
113
|
+
that asks for no scheduled work (a documented deviation worth noting, a
|
|
114
|
+
measurement that is fine today and worth watching). Accepts `Informational`.
|
|
115
|
+
Use it instead of inventing a below-`Low` word of your own; a finding that
|
|
116
|
+
cannot clear the evidence bar below is **dropped**, not filed as `Info`.
|
|
105
117
|
|
|
106
118
|
## Self-cross-check (mandatory — filter false positives before you finalize) {#self-cross-check}
|
|
107
119
|
|
|
@@ -149,6 +161,15 @@ that rests on one of them:
|
|
|
149
161
|
- **Style-only nits already enforced by a formatter/linter** — do not
|
|
150
162
|
re-litigate what the committed tooling already governs.
|
|
151
163
|
|
|
164
|
+
> **Boundary with the dead-wiring mandate.** The architecture and quality lenses
|
|
165
|
+
> are required to report shipped seams with no live production caller (their own
|
|
166
|
+
> bodies carry the mandate). The exclusions above **bound** that mandate rather
|
|
167
|
+
> than cancelling it: a test seam, a CLI entry point, a declared `exports`
|
|
168
|
+
> surface, or a dynamically-reached symbol is still never a finding. What the
|
|
169
|
+
> mandate targets is the case none of those cover — an **internal** seam that a
|
|
170
|
+
> delivery shipped and nothing in production ever calls. When a candidate is
|
|
171
|
+
> genuinely one of the exclusions, cite the exclusion and drop it.
|
|
172
|
+
|
|
152
173
|
### Final re-open-and-drop pass (mandatory)
|
|
153
174
|
|
|
154
175
|
1. Walk your Detailed Findings once more, applying the bar and the exclusion
|
|
@@ -35,8 +35,15 @@ thresholds, sourced from
|
|
|
35
35
|
| CC range | Action |
|
|
36
36
|
| --- | --- |
|
|
37
37
|
| ≤ 8 | Pass — no annotation required. |
|
|
38
|
-
| > 8 (default `cyclomaticFlag`) | **Flag**
|
|
39
|
-
| > 12 (default `cyclomaticMustFix`) | **Must-fix**:
|
|
38
|
+
| > 8 (default `cyclomaticFlag`) | **Flag** — `quality:preview` counts the function in its `new-method count over c=<flag>` column. The function is allowed to land but the report names it. |
|
|
39
|
+
| > 12 (default `cyclomaticMustFix`) | **Must-fix**: `check-cyclomatic.js` fails when a file gains a function above the ceiling, or when its worst function gets worse than the recorded baseline. |
|
|
40
|
+
|
|
41
|
+
`check-cyclomatic.js` is a **ratchet**, not a cliff: `baselines/cyclomatic.json`
|
|
42
|
+
records the over-ceiling functions a repository already carries, so adopting
|
|
43
|
+
the gate never demands a mass refactor. Burning a recorded breach down is
|
|
44
|
+
always allowed and re-records itself on the next `--update`; adding one is
|
|
45
|
+
what fails. It runs in the same required-check slot as `check-arch-cycles.js`
|
|
46
|
+
and `check-dead-exports.js`.
|
|
40
47
|
|
|
41
48
|
A common refactor that pulls a 13-CC function under 8 is extracting the early-
|
|
42
49
|
return guard chain into a named predicate, then collapsing the remaining
|
|
@@ -10,10 +10,9 @@ description: >-
|
|
|
10
10
|
# Deliver digest (read once per session)
|
|
11
11
|
|
|
12
12
|
> **Bundle, not a procedure.** [`deliver-story.md`](deliver-story.md) is still
|
|
13
|
-
> the steps
|
|
14
|
-
>
|
|
15
|
-
>
|
|
16
|
-
> budgets, CI remediation) stays on demand in
|
|
13
|
+
> the steps; this file is the material they reference, bundled so one read
|
|
14
|
+
> covers the happy path. Situational material (lease preflight, recovery
|
|
15
|
+
> routers, merge-wait budgets, CI remediation) stays on demand in
|
|
17
16
|
> [`deliver-story-reference.md`](deliver-story-reference.md) and
|
|
18
17
|
> [`deliver-reference.md`](deliver-reference.md); read those **only** when an
|
|
19
18
|
> envelope or a failure routes you there.
|
|
@@ -28,10 +27,10 @@ rule produces it:
|
|
|
28
27
|
whatever its shape — sub-agent isolation is load-bearing only against a
|
|
29
28
|
*concurrent* sibling racing the same checkout, and a one-Story run has none.
|
|
30
29
|
2. **Every other run is `subagent`.** A multi-Story run dispatches every Story
|
|
31
|
-
as a sub-agent however trivial its shape
|
|
32
|
-
second session for a sibling
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
as a sub-agent however trivial its shape — a lite body does not conjure a
|
|
31
|
+
second session for a sibling, and the wave tick may hand you the whole set
|
|
32
|
+
on one beat. Shape still sets ceremony; the `route::lite` label is a
|
|
33
|
+
human-visible hint, never the control signal.
|
|
35
34
|
|
|
36
35
|
`inline` removes model-side fan-out only — no `story-worker` boot, no fresh
|
|
37
36
|
acceptance-critic spawn. **`subagent` and `inline` run the same engine**: same
|
|
@@ -54,21 +53,32 @@ the only sanctioned landing. A silent local build is not a delivery.
|
|
|
54
53
|
## 3. Change set — computed once, handed to everyone
|
|
55
54
|
|
|
56
55
|
One enumeration per Story. A critic that re-runs its own `git diff`
|
|
57
|
-
can score a different set than the one that routed it
|
|
56
|
+
can score a different set than the one that routed it. Both routing calls take
|
|
57
|
+
a single options object and are **total — they never throw**, so a wrong-shaped
|
|
58
|
+
argument is silently absorbed into the `null` fail-safe:
|
|
58
59
|
|
|
59
60
|
```bash
|
|
60
61
|
node --input-type=module -e '
|
|
61
|
-
|
|
62
|
+
const lib = "<main-repo>/.agents/scripts/lib/orchestration";
|
|
63
|
+
const { computeChangeSet } = await import(`${lib}/change-set.js`);
|
|
64
|
+
const { deriveChangeLevel } = await import(`${lib}/review-depth.js`);
|
|
65
|
+
const { resolveCeremonyForRisk } = await import(`${lib}/ceremony-routing.js`);
|
|
62
66
|
const { files } = computeChangeSet({ baseRef: "main", headRef: "story-<storyId>" });
|
|
63
|
-
|
|
67
|
+
// deriveChangeLevel({ changedFiles, injectedRules?, selectSensitivePathClassesFn? })
|
|
68
|
+
// -> { level, classes } — an OBJECT, never a bare level.
|
|
69
|
+
const { level, classes } = deriveChangeLevel({ changedFiles: files });
|
|
70
|
+
// resolveCeremonyForRisk({ derivedLevel, clusterIndex?, freshCriticSampleRate?,
|
|
71
|
+
// ceremonyProfile? }) -> { mode, reason, sampled, profile, verdictOwner }.
|
|
72
|
+
// derivedLevel is that level STRING. Handing it the object above matches no
|
|
73
|
+
// tier, so it routes to the null fail-safe: a fresh critic, silently.
|
|
74
|
+
const ceremony = resolveCeremonyForRisk({ derivedLevel: level, clusterIndex: 0 });
|
|
75
|
+
console.log(JSON.stringify({ files, level, classes, ...ceremony }));
|
|
64
76
|
'
|
|
65
77
|
```
|
|
66
78
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
→ `low`, an unenumerable diff (`files === null`) → `null`. Resolve
|
|
71
|
-
fresh-vs-inline critics with `resolveCeremonyForRisk`
|
|
79
|
+
Level rules ([`review-depth.js`](../../scripts/lib/orchestration/review-depth.js)):
|
|
80
|
+
a sensitive path registered in `audit-rules.json` → `high`, none → `low`, an
|
|
81
|
+
unenumerable diff (`files === null`) → `null`. Ceremony rules
|
|
72
82
|
([`ceremony-routing.js`](../../scripts/lib/orchestration/ceremony-routing.js)):
|
|
73
83
|
`minimal` → always inline, `strict` → always fresh, `standard` → `high`/`null`
|
|
74
84
|
→ fresh and `low` → inline unless the `freshCriticSampleRate` floor forces
|
|
@@ -78,16 +88,26 @@ fresh. An `inline` dispatch mode overrides all of it to inline critics. Close's
|
|
|
78
88
|
## 4. Acceptance self-eval (Step 1a, required)
|
|
79
89
|
|
|
80
90
|
**One verdict-owner per cluster** — the fresh critic *or* the inline
|
|
81
|
-
self-eval, named by `verdictOwner`, never both and never a warm-up pass.
|
|
82
|
-
scores
|
|
83
|
-
output as evidence. Bounded by `delivery.acceptanceEval.maxRounds`
|
|
84
|
-
|
|
91
|
+
self-eval, named by `verdictOwner`, never both and never a warm-up pass. Each
|
|
92
|
+
scores its cluster's `acceptance[]` items against the change set above, with
|
|
93
|
+
`verify[]` output as evidence. Bounded by `delivery.acceptanceEval.maxRounds`
|
|
94
|
+
(default 2).
|
|
95
|
+
|
|
96
|
+
**One round = N cluster critics → ONE merged verdict → ONE gate call.** Merge
|
|
97
|
+
every cluster's records into a single `criteria[]` in `acceptance[]` order, one
|
|
98
|
+
per acceptance item, and score that once. A gate call per cluster spends a
|
|
99
|
+
round *per cluster* and races the round ledger:
|
|
85
100
|
|
|
86
101
|
```bash
|
|
87
102
|
node <main-repo>/.agents/scripts/acceptance-eval.js \
|
|
88
|
-
--story <storyId> --verdict <verdict-path>
|
|
103
|
+
--story <storyId> --verdict <merged-verdict-path> \
|
|
104
|
+
--expected-criteria <acceptance[] count>
|
|
89
105
|
```
|
|
90
106
|
|
|
107
|
+
Pass `--expected-criteria` — **without it the coverage assertion is inert**, so
|
|
108
|
+
an unmerged cluster verdict scores a fraction of the criteria and still reports
|
|
109
|
+
`proceed`. A mismatch is rejected before scoring and costs no round.
|
|
110
|
+
|
|
91
111
|
`proceed` → close. `redraft` → one more round inside the cap. `block` → **do
|
|
92
112
|
not close**: post a `friction` comment and flip `agent::blocked`.
|
|
93
113
|
Per-round mechanics: [`acceptance-self-eval.md`](acceptance-self-eval.md).
|