mandrel 2.58.0 → 2.60.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/README.md +17 -12
- package/.agents/agents/acceptance-critic.md +24 -43
- package/.agents/agents/story-worker.md +18 -19
- package/.agents/docs/SDLC.md +12 -13
- package/.agents/docs/agentrc-reference.json +1 -2
- package/.agents/docs/configuration.md +29 -46
- package/.agents/docs/quality-gates.md +9 -5
- package/.agents/docs/workflows.md +1 -1
- package/.agents/instructions.md +5 -7
- package/.agents/rules/ci-remediation.md +41 -8
- package/.agents/rules/known-tooling-behavior.md +65 -15
- package/.agents/runtime-deps.json +7 -2
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +6 -11
- package/.agents/schemas/crap-baseline.schema.json +1 -1
- package/.agents/schemas/crap-report.schema.json +1 -1
- package/.agents/schemas/story-deliver-terminal.schema.json +3 -3
- package/.agents/scripts/README.md +11 -1
- package/.agents/scripts/acceptance-eval.js +25 -27
- package/.agents/scripts/ceremony-derive.js +15 -10
- package/.agents/scripts/check-context-budget.js +148 -228
- package/.agents/scripts/check-schema-references.js +5 -3
- package/.agents/scripts/check-workflow-citations.js +33 -147
- package/.agents/scripts/coverage-capture.js +7 -4
- package/.agents/scripts/deliver-light.js +41 -100
- package/.agents/scripts/deliver-run.js +631 -0
- package/.agents/scripts/file-ci-gap.js +59 -11
- package/.agents/scripts/install-matrix-assert.js +48 -3
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +51 -33
- package/.agents/scripts/lib/baselines/crap-preview-incremental.js +6 -2
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +0 -8
- package/.agents/scripts/lib/baselines/kinds/crap.js +35 -18
- package/.agents/scripts/lib/changed-files.js +30 -0
- package/.agents/scripts/lib/config/delivery-routing.js +5 -4
- package/.agents/scripts/lib/config/explain.js +1 -3
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +1 -1
- package/.agents/scripts/lib/config-resolver.js +1 -0
- package/.agents/scripts/lib/config-settings-schema-delivery.js +28 -21
- package/.agents/scripts/lib/coverage-capture-fullscope.js +10 -2
- package/.agents/scripts/lib/coverage-capture-incremental.js +3 -2
- package/.agents/scripts/lib/coverage-capture-usage.js +4 -1
- package/.agents/scripts/lib/crap-engine.js +2 -2
- package/.agents/scripts/lib/crap-utils.js +21 -5
- package/.agents/scripts/lib/doc-tiers.js +4 -2
- package/.agents/scripts/lib/escomplex-ast-compat.js +39 -17
- package/.agents/scripts/lib/escomplex-kernel.js +298 -0
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +7 -6
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +7 -5
- package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
- package/.agents/scripts/lib/gh-exec.js +160 -0
- package/.agents/scripts/lib/maintainability-engine.js +3 -3
- package/.agents/scripts/lib/observability/source-classifier.js +1 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +74 -132
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +123 -12
- package/.agents/scripts/lib/orchestration/complexity-gate.js +180 -352
- package/.agents/scripts/lib/orchestration/light-suitability.js +71 -136
- package/.agents/scripts/lib/orchestration/plan-context.js +44 -50
- package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +8 -6
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +104 -119
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +41 -25
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +11 -11
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +63 -29
- package/.agents/scripts/lib/orchestration/plan-persist/wave-collision-gate.js +107 -0
- package/.agents/scripts/lib/orchestration/review-depth.js +14 -11
- package/.agents/scripts/lib/orchestration/run-epilogue.js +260 -182
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +63 -99
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +3 -3
- package/.agents/scripts/lib/orchestration/single-story-close/phases/graphql-preflight.js +137 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +105 -18
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +4 -3
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +156 -39
- package/.agents/scripts/lib/orchestration/story-init-envelope.js +71 -0
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -17
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +25 -209
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +8 -5
- package/.agents/scripts/lib/orchestration/ticket-validator.js +44 -183
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +14 -25
- package/.agents/scripts/lib/runtime-deps/dep-resolution.js +155 -0
- package/.agents/scripts/lib/runtime-deps/ensure-installed.js +44 -9
- package/.agents/scripts/lib/runtime-deps/parser-major.js +110 -0
- package/.agents/scripts/lib/runtime-deps/preflight.js +6 -25
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +46 -1
- package/.agents/scripts/lib/skills/walk-skill-files.js +1 -1
- package/.agents/scripts/lib/story-body/body-format-lints.js +58 -12
- package/.agents/scripts/lib/story-body/story-body.js +83 -29
- package/.agents/scripts/lib/templates/decomposer-prompts.js +28 -33
- package/.agents/scripts/lib/wave-runner/live-probe.js +31 -5
- package/.agents/scripts/merge-baseline.js +4 -5
- package/.agents/scripts/plan-context.js +117 -28
- package/.agents/scripts/plan-persist.js +79 -39
- package/.agents/scripts/plan-run-epilogue.js +11 -8
- package/.agents/scripts/pr-watch-with-update.js +9 -2
- package/.agents/scripts/run-verify.js +13 -6
- package/.agents/scripts/single-story-init.js +7 -57
- package/.agents/scripts/stories-wave-tick.js +160 -26
- package/.agents/skills/core/gates-and-baselines/reference.md +0 -1
- package/.agents/skills/skills.index.json +2 -12
- package/.agents/skills/stack/qa/playwright/SKILL.md +26 -0
- package/.agents/workflows/audit-to-stories.md +14 -11
- package/.agents/workflows/helpers/acceptance-self-eval.md +84 -157
- package/.agents/workflows/helpers/code-review.md +4 -2
- package/.agents/workflows/helpers/deliver-digest.md +31 -24
- package/.agents/workflows/helpers/deliver-light.md +92 -101
- package/.agents/workflows/helpers/deliver-reference.md +116 -100
- package/.agents/workflows/helpers/deliver-story-reference.md +58 -124
- package/.agents/workflows/helpers/deliver-story.md +17 -18
- package/.agents/workflows/helpers/plan-reference.md +82 -60
- package/.agents/workflows/mandrel-deliver.md +47 -31
- package/.agents/workflows/mandrel-plan.md +32 -30
- package/.agents/workflows/mandrel-update.md +36 -21
- package/README.md +3 -3
- package/docs/CHANGELOG.md +43 -0
- package/lib/cli/registry.js +45 -25
- package/lib/cli/update.js +376 -17
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.60.0-retire-audit-results-autofile.js +40 -0
- package/package.json +8 -2
- package/.agents/schemas/model-attribution.schema.json +0 -53
- package/.agents/scripts/lib/orchestration/model-attribution.js +0 -418
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +0 -188
- package/.agents/scripts/lib/orchestration/story-plan-state.js +0 -33
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +0 -67
- package/.agents/scripts/lib/templates/spec-author-prompts.js +0 -76
- package/.agents/skills/core/scope-triage/SKILL.md +0 -48
|
@@ -66,16 +66,30 @@ commands** the script knows nothing about, so a locally green
|
|
|
66
66
|
| `check-dead-exports.js` | no | no | **yes** |
|
|
67
67
|
| `check-dead-exports.js --production` | no | no | **yes** |
|
|
68
68
|
| `check-context-budget.js` | no | no | **yes** |
|
|
69
|
-
| `check-workflow-citations.js` | no | no | **
|
|
69
|
+
| `check-workflow-citations.js` | no | no | **yes** |
|
|
70
70
|
| `check-cyclomatic.js` | no | no | **yes** |
|
|
71
71
|
| `check-schema-references.js` | no | no | **yes** |
|
|
72
72
|
| `check-knip-entries.js` | no | no | **yes** |
|
|
73
73
|
| `check-baseline-scope.js` | no | no | **no** |
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
One is still in **no** local aggregate command — `check-baseline-scope.js`,
|
|
76
|
+
reachable only as its own npm script (`baselines:scope`) or a direct
|
|
77
|
+
invocation. `check-workflow-citations.js` joined `verify` when Story #5340
|
|
78
|
+
demoted it to a report; before that it was exempted because
|
|
79
|
+
`tests/check-workflow-citations.test.js` re-ran its ratchet through the `test`
|
|
80
|
+
step.
|
|
81
|
+
|
|
82
|
+
**Two of the nine cannot fail this job any more** (Story #5340, ADR
|
|
83
|
+
20260917-5340). `check-workflow-citations.js` prints a per-file provenance
|
|
84
|
+
count and always exits 0 — it reads no baseline at all, and the one it used
|
|
85
|
+
to ratchet against is deleted.
|
|
86
|
+
`check-context-budget.js` fails on the `alwaysLoaded` tier alone: its
|
|
87
|
+
`workflow` and `mandatoryRead` tiers are printed, and the per-file 8 KB
|
|
88
|
+
agent-boot ceiling and the row-vs-tree drift gate are gone. A green run of
|
|
89
|
+
either is therefore **not** evidence the numbers held — read the report. Both
|
|
90
|
+
ratchets used to fail a *rise*, so a prose fix had to be paid for with an
|
|
91
|
+
unrelated trim in the same commit; the always-loaded gate is the one that
|
|
92
|
+
stays because every session and every subagent spawn re-pays that closure.
|
|
79
93
|
|
|
80
94
|
`prune-baseline-orphans.js --check` left this table in v2.32.0: it no longer
|
|
81
95
|
runs in CI in any mode. It reports the same absent / out-of-scope rows as
|
|
@@ -84,25 +98,24 @@ the required job made the scope gate's inherited-divergence warning
|
|
|
84
98
|
unreachable — a stale row on `main` red every open PR regardless of who landed
|
|
85
99
|
it. It stays the operator's remedy, via `npm run baselines:prune`.
|
|
86
100
|
|
|
87
|
-
`check-context-budget.js` additionally
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
`check-context-budget.js` and `check-workflow-citations.js` additionally run in
|
|
102
|
+
`.husky/pre-push`, as reports. A shrink in the always-loaded closure no longer
|
|
103
|
+
reds anything either (Story #5313): it is reported, and the close's write-back
|
|
104
|
+
seam commits the lower total on the Story branch.
|
|
91
105
|
|
|
92
106
|
**Reproduce.**
|
|
93
107
|
|
|
94
108
|
```bash
|
|
95
109
|
node .agents/scripts/check-baselines.js --format text # names the 3 gates it ran
|
|
96
110
|
sed -n '/name: baselines/,/windows-smoke/p' .github/workflows/ci.yml | grep 'js'
|
|
97
|
-
|
|
111
|
+
sed -n '/^const STEPS/,/^];/p' .agents/scripts/run-verify.js # the steps verify covers
|
|
98
112
|
```
|
|
99
113
|
|
|
100
114
|
**Safe move.** `npm run verify` is the closest local mirror. Run
|
|
101
|
-
`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
`.agentrc.json` command before a push is a false green.
|
|
115
|
+
`npm run baselines:scope && npm run baselines:prune -- --check` alongside it
|
|
116
|
+
when the change adds, deletes or moves files inside a scored `targetDirs`
|
|
117
|
+
root. Reproducing only the `.agentrc.json` command before a push is a false
|
|
118
|
+
green.
|
|
106
119
|
|
|
107
120
|
## 3. The two dead-export passes disagree, and the production pass is silent without `!`
|
|
108
121
|
|
|
@@ -148,3 +161,40 @@ hand-edit `baselines/dead-exports*.json`: a hand-written row set is the one
|
|
|
148
161
|
input no gate re-derives. `.agents/rules/test-seams.md` governs which seams
|
|
149
162
|
are sanctioned. Never remove the `!` suffixes from `knip.json` to quieten the
|
|
150
163
|
production pass.
|
|
164
|
+
|
|
165
|
+
## 4. A green pre-push is only evidence the two scopes agreed because `--ref` outranks config
|
|
166
|
+
|
|
167
|
+
**Behavior.** `.husky/pre-push` captures coverage and then scores it, both
|
|
168
|
+
against a literal `origin/main`. The CRAP half of `quality-preview.js` is a
|
|
169
|
+
function of complexity **and** coverage, so the preview is only reading its
|
|
170
|
+
own tree if the artifact under it was captured over the same change set.
|
|
171
|
+
Both steps resolve that set through **one** rule, stated once in
|
|
172
|
+
`resolveChangedFilesRef` (`.agents/scripts/lib/changed-files.js`): the ref the
|
|
173
|
+
caller named wins, and
|
|
174
|
+
`delivery.quality.gates.crap.incrementalCoverage.baseRef` is the default for a
|
|
175
|
+
caller that names none — the close-validation gate, which passes no `--ref`.
|
|
176
|
+
Both `coverage-capture` paths and the preview's CRAP baseline join call it, so
|
|
177
|
+
one hook invocation cannot resolve two refs.
|
|
178
|
+
|
|
179
|
+
Before Story #5365 the configured value outranked the flag. The preview has
|
|
180
|
+
no config ref to consult, so a consumer that set `baseRef` captured against
|
|
181
|
+
one ref while the preview scored another, and the preview could read an
|
|
182
|
+
artifact whose scope was not its own — the stale-artifact read the
|
|
183
|
+
capture-before-preview ordering (Story #5356) exists to prevent, reopened by
|
|
184
|
+
configuration rather than by editing the hook. **This repository sets no
|
|
185
|
+
`baseRef`**, so the divergence was invisible here: a green local run proved
|
|
186
|
+
nothing about a consumer's.
|
|
187
|
+
|
|
188
|
+
**Reproduce.**
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
node -e "import('./.agents/scripts/lib/changed-files.js').then(({ resolveChangedFilesRef }) => { const crap = { incrementalCoverage: { baseRef: 'develop' } }; console.log(resolveChangedFilesRef({ crap, ref: 'origin/main' })); console.log(resolveChangedFilesRef({ crap, ref: null })); })"
|
|
192
|
+
# → origin/main (the hook's flag wins over a configured baseRef)
|
|
193
|
+
# → develop (config still answers a caller that named no ref)
|
|
194
|
+
grep -n 'origin/main' .husky/pre-push # the same literal on both steps
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Safe move.** Read a green pre-push as evidence about CRAP only when both
|
|
198
|
+
hook steps still carry the same literal ref. Moving one means moving the
|
|
199
|
+
other; adding another consumer of the change set means routing it through
|
|
200
|
+
`resolveChangedFilesRef` rather than reading `baseRef` directly.
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Single source of truth for the third-party npm packages the .agents/ framework scripts import at runtime. This manifest ships *inside* .agents/ so it travels with the mandrel package into consumer projects. Consumers must provide these packages in the node_modules resolvable from their repository root (the framework scripts free-ride on the consumer's install). The `dependencies` block is fail-fast enforced by the preflight guard (.agents/scripts/lib/runtime-deps/ensure-installed.js); the `optionalDependencies` block lists packages that are imported behind graceful-degradation paths (try/catch or dev-only watch tooling) and are therefore declared but never preflight-blocked. A drift test (tests/scripts/runtime-deps-drift.test.js) asserts every third-party import under .agents/scripts/** is declared here. Version ranges mirror the framework's own root package.json.",
|
|
2
|
+
"description": "Single source of truth for the third-party npm packages the .agents/ framework scripts import at runtime. This manifest ships *inside* .agents/ so it travels with the mandrel package into consumer projects. Consumers must provide these packages in the node_modules resolvable from their repository root (the framework scripts free-ride on the consumer's install). The `dependencies` block is fail-fast enforced by the preflight guard (.agents/scripts/lib/runtime-deps/ensure-installed.js); the `optionalDependencies` block lists packages that are imported behind graceful-degradation paths (try/catch or dev-only watch tooling) and are therefore declared but never preflight-blocked. A drift test (tests/scripts/runtime-deps-drift.test.js) asserts every third-party import under .agents/scripts/** is declared here. Version ranges mirror the framework's own root package.json. Two entries need their reason recorded. `@babel/parser` is pinned to ^7 because the kernel's fixed plugin list does not parse under 8.x, and the range is documentation rather than enforcement \u2014 `.agents/` resolves from the consumer's own node_modules \u2014 so the kernel asserts the resolved major at load. `babel-runtime` is declared even though no framework script imports it: four of the metric-core packages require it and none of them declares it, so it resolved only by being hoisted from the parse/dispatch plumbing this framework used to depend on. Declaring it makes the closure explicit and preflight-enforced. The import-vs-manifest drift guard only flags imported-but-undeclared, so a declared-but-unimported peer repair like this is legal by design.",
|
|
3
3
|
"dependencies": {
|
|
4
|
+
"@babel/parser": "^7.29.3",
|
|
4
5
|
"ajv": "^8.20.0",
|
|
5
6
|
"ajv-formats": "^3.0.1",
|
|
7
|
+
"babel-runtime": "^6.26.0",
|
|
8
|
+
"escomplex-plugin-metrics-module": "^0.1.0",
|
|
9
|
+
"escomplex-plugin-syntax-babylon": "^0.1.0",
|
|
6
10
|
"js-yaml": "^4.3.1",
|
|
7
11
|
"minimatch": "^10.0.0",
|
|
8
12
|
"picomatch": "^4.0.4",
|
|
9
|
-
"typhonjs-
|
|
13
|
+
"typhonjs-ast-walker": "^0.2.1",
|
|
14
|
+
"typhonjs-escomplex-commons": "^0.1.1"
|
|
10
15
|
},
|
|
11
16
|
"optionalDependencies": {
|
|
12
17
|
"@commitlint/load": "^21.0.0",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "acceptance-eval-verdict",
|
|
4
4
|
"title": "Acceptance Self-Eval Verdict",
|
|
5
|
-
"description": "Structured output of one
|
|
5
|
+
"description": "Structured output of one acceptance self-eval round (Story #3819). One file per Story covering every inline acceptance[] item exactly once, authored by the round's single verdict owner — the inline self-eval under ceremonyProfile minimal/standard, a fresh-context maker-blind critic under strict (Story #5343) — in the Story-implementation phase (helpers/deliver-story.md Step 1a). Written under the gitignored temp tree and consumed by acceptance-eval.js, which enforces the bounded round cap and decides whether the Story proceeds to `closing`, redrafts, or escalates to `agent::blocked`. Whoever owns it scores the caller-injected change set afresh against each criterion, treating the implementation reasoning as untrusted; the gate is the scorer of that verdict, never a second pass over the criteria.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": ["storyId", "schemaVersion", "round", "criteria"],
|
|
8
8
|
"properties": {
|
|
@@ -904,7 +904,7 @@
|
|
|
904
904
|
"baseRef": {
|
|
905
905
|
"type": "string",
|
|
906
906
|
"minLength": 1,
|
|
907
|
-
"description": "
|
|
907
|
+
"description": "Default git ref the changed-file set is computed against, for a caller that passes no `--ref`. A `--ref` the caller named wins over this value, so a caller that anchors another gate on the same ref — `.husky/pre-push`, which passes `--ref origin/main` and then previews `--changed-since origin/main` — resolves ONE scope for both steps (Story #5365). Omitted and unpassed, the gate’s own default `main` applies."
|
|
908
908
|
}
|
|
909
909
|
},
|
|
910
910
|
"additionalProperties": false
|
|
@@ -1742,17 +1742,12 @@
|
|
|
1742
1742
|
},
|
|
1743
1743
|
"feedbackLoop": {
|
|
1744
1744
|
"type": "object",
|
|
1745
|
-
"description": "Opt-
|
|
1745
|
+
"description": "Opt-in toggle for the close-time retro auto-file graduator, plus the friction recurrence window. Auto-filing defaults to OFF (Story #5341).",
|
|
1746
1746
|
"properties": {
|
|
1747
|
-
"auditResultsAutoFile": {
|
|
1748
|
-
"type": "boolean",
|
|
1749
|
-
"description": "When true (default), the close-time audit-results graduator auto-files non-blocking audit-results findings as follow-up issues routed by source classification. Set to false to suppress auto-filing; findings remain accessible in the structured comments on the Story.",
|
|
1750
|
-
"default": true
|
|
1751
|
-
},
|
|
1752
1747
|
"retroProposals": {
|
|
1753
1748
|
"type": "boolean",
|
|
1754
|
-
"description": "When true
|
|
1755
|
-
"default":
|
|
1749
|
+
"description": "When true, the retro auto-files its actionable routed proposals as meta::<framework-gap|consumer-improvement> + friction::<category> issues via the graduator pre-parsed-findings seam, and the rendered retro sections list the filed issue numbers instead of paste-ready gh command stanzas. Defaults to false (Story #5341), which renders the command stanzas instead.",
|
|
1750
|
+
"default": false
|
|
1756
1751
|
},
|
|
1757
1752
|
"frictionWindowDays": {
|
|
1758
1753
|
"type": "integer",
|
|
@@ -1843,7 +1838,7 @@
|
|
|
1843
1838
|
},
|
|
1844
1839
|
"routing": {
|
|
1845
1840
|
"type": "object",
|
|
1846
|
-
"description": "v2 delivery-spawn routing: role-scoped boot contexts and the ceremony profile. The v1 singleDelivery epic-route kill-switch was removed in Stage 6; the freshCriticSampleRate sampling floor was retired in Story #5313.",
|
|
1841
|
+
"description": "v2 delivery-spawn routing: role-scoped boot contexts and the ceremony profile. The v1 singleDelivery epic-route kill-switch was removed in Stage 6; the freshCriticSampleRate sampling floor was retired in Story #5313 and the derived-level ceremony routing in Story #5343.",
|
|
1847
1842
|
"properties": {
|
|
1848
1843
|
"roleScopedAgents": {
|
|
1849
1844
|
"type": "boolean",
|
|
@@ -1853,7 +1848,7 @@
|
|
|
1853
1848
|
"ceremonyProfile": {
|
|
1854
1849
|
"type": "string",
|
|
1855
1850
|
"enum": ["minimal", "standard", "strict"],
|
|
1856
|
-
"description": "Acceptance-ceremony depth. minimal =
|
|
1851
|
+
"description": "Acceptance-ceremony depth — who authors the Story acceptance verdict. minimal and standard (default) = the inline self-eval, whatever the diff touches; strict = a fresh-context maker-blind critic. Review depth is a separate decision and still derives `deep` for any sensitive path (review-depth.js).",
|
|
1857
1852
|
"default": "standard"
|
|
1858
1853
|
},
|
|
1859
1854
|
"closeAndLand": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"escomplexVersion": {
|
|
20
20
|
"type": "string",
|
|
21
|
-
"description": "Version of the
|
|
21
|
+
"description": "Version of the package that computes the metrics (escomplex-plugin-metrics-module) used to produce this baseline. Informational: the axis that compared it was removed in Story #5336 — the v2 envelope does not carry the field, so it could not fire. scoringSemantics is the axis that rejects an incompatible scorer."
|
|
22
22
|
},
|
|
23
23
|
"tsTranspilerVersion": {
|
|
24
24
|
"type": "string",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"escomplexVersion": {
|
|
16
16
|
"type": "string",
|
|
17
|
-
"description": "
|
|
17
|
+
"description": "Version of the package that computes the metrics (escomplex-plugin-metrics-module) used for the scan."
|
|
18
18
|
},
|
|
19
19
|
"summary": {
|
|
20
20
|
"type": "object",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/story-deliver-terminal.schema.json",
|
|
4
4
|
"title": "story-deliver-terminal",
|
|
5
|
-
"description": "The single terminal envelope a Story delivery invocation emits (Story #4543). Before this schema, the delivery tail had two divergent prose return contracts — one in .agents/workflows/helpers/deliver-story.md, a different one in .agents/agents/story-worker.md — and neither was validated by anything, so a caller could not tell a landed Story from a parked one without re-probing GitHub. This is the SSOT both now reference rather than restate. status is exactly one of landed | pending | blocked | failed | escalated; phase names where the run ended; tail carries per-step booleans so a partial-tail degradation is visible without failing an otherwise-landed merge; nextCommand names the single command that resumes or remediates the run, drawn from the same vocabulary deliver-recover.js prints. escalated (Story #4746) is the one status emitted BEFORE a Story exists — /deliver-light's suitability gate refusing
|
|
5
|
+
"description": "The single terminal envelope a Story delivery invocation emits (Story #4543). Before this schema, the delivery tail had two divergent prose return contracts — one in .agents/workflows/helpers/deliver-story.md, a different one in .agents/agents/story-worker.md — and neither was validated by anything, so a caller could not tell a landed Story from a parked one without re-probing GitHub. This is the SSOT both now reference rather than restate. status is exactly one of landed | pending | blocked | failed | escalated; phase names where the run ended; tail carries per-step booleans so a partial-tail degradation is visible without failing an otherwise-landed merge; nextCommand names the single command that resumes or remediates the run, drawn from the same vocabulary deliver-recover.js prints. escalated (Story #4746) is the one status emitted BEFORE a Story exists — /deliver-light's suitability gate refusing a prompt — which is why storyId is null exactly there and non-null everywhere else.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": [
|
|
8
8
|
"kind",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"status": {
|
|
23
23
|
"type": "string",
|
|
24
|
-
"description": "landed — the PR merged, the Story is agent::done, and the post-land tail was attempted. pending — a bounded wait expired with the PR still in flight; NO label was mutated and no merge.unlanded event was emitted, so the run is resumable via nextCommand. blocked — a classified hard block; the Story carries agent::blocked and blocked.blockClass names the class. failed — a phase crashed; phase names which one. escalated —
|
|
24
|
+
"description": "landed — the PR merged, the Story is agent::done, and the post-land tail was attempted. pending — a bounded wait expired with the PR still in flight; NO label was mutated and no merge.unlanded event was emitted, so the run is resumable via nextCommand. blocked — a classified hard block; the Story carries agent::blocked and blocked.blockClass names the class. failed — a phase crashed; phase names which one. escalated — /deliver-light's suitability gate refused a prompt on an un-waivable risk rule or an un-ledgered verdict; nothing was created and the LIGHT PATH ends here, nextCommand naming the /mandrel-plan invocation that owns the work instead. Story #5344 narrowed what refuses (the predicted-shape ceilings are gone) and loosened what follows (that command may be run in the same session, seeded with escalation.reasons) without touching this shape.",
|
|
25
25
|
"enum": ["landed", "pending", "blocked", "failed", "escalated"]
|
|
26
26
|
},
|
|
27
27
|
"phase": {
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
},
|
|
180
180
|
"nextCommand": {
|
|
181
181
|
"type": ["string", "null"],
|
|
182
|
-
"description": "The single command that advances this work from where it stopped, or null when status === \"landed\" and nothing remains. Shares its vocabulary with deliver-recover.js so recovery and normal resumption speak one language. For status escalated it is the /mandrel-plan invocation
|
|
182
|
+
"description": "The single command that advances this work from where it stopped, or null when status === \"landed\" and nothing remains. Shares its vocabulary with deliver-recover.js so recovery and normal resumption speak one language. For status escalated it is the /mandrel-plan invocation that owns the work — the one case where the command is a slash command rather than a script, because the work needs planning, not resumption. Story #4746 required it to run in a FRESH session; Story #5344 permits the same session when it is seeded with escalation.reasons, and helpers/deliver-light.md carries the seeding contract.",
|
|
183
183
|
"minLength": 1
|
|
184
184
|
},
|
|
185
185
|
"elapsedSeconds": { "type": "number", "minimum": 0 },
|
|
@@ -13,7 +13,17 @@ GitHub Actions surfaces first. `check-knip-entries.js` derives that
|
|
|
13
13
|
caller set mechanically, so a CLI no invoker names is dead, not
|
|
14
14
|
operator-only.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
The one script an operator-facing workflow drives **by name, repeatedly**, is
|
|
17
|
+
[`deliver-run.js`](deliver-run.js): one beat of a multi-Story
|
|
18
|
+
`/mandrel-deliver` run — it ticks the ready set from live state, writes each
|
|
19
|
+
ready Story's dispatch prompt under `<tempRoot>/run-<id>/`, keeps the run
|
|
20
|
+
ledger that replaces hand-maintained dispatch bookkeeping, and renders the
|
|
21
|
+
`single-story-close.js` command for every hand-off. Everything else in the
|
|
22
|
+
delivery chain (`resolve-stories.js`, `single-story-init.js`,
|
|
23
|
+
`single-story-close.js`, `stories-wave-tick.js`) is reached through it or
|
|
24
|
+
through a workflow step.
|
|
25
|
+
|
|
26
|
+
`check-knip-entries.js` reads the entry list from whatever configuration knip itself would
|
|
17
27
|
load — `knip.json`, `knip.jsonc`, `.knip.json(c)`, `knip.ts`, `knip.js`,
|
|
18
28
|
`knip.config.ts`, `knip.config.js`, or `package.json#knip` — evaluating
|
|
19
29
|
TS/JS modules rather than parsing them, and counting entries declared
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* acceptance-eval.js — bounded per-Story acceptance self-eval gate (Story #3819).
|
|
5
5
|
*
|
|
6
|
-
* The Story-implementation phase runs ONE verdict-owner per
|
|
7
|
-
*
|
|
8
|
-
* `
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* emits one verdict file per round
|
|
6
|
+
* The Story-implementation phase runs ONE verdict-owner per Story
|
|
7
|
+
* (Story #4723, narrowed by #5343) — the contract-identical inline self-eval
|
|
8
|
+
* under `ceremonyProfile` `minimal` / `standard`, a fresh-context maker-blind
|
|
9
|
+
* critic under `strict` — which scores the caller-injected change set against
|
|
10
|
+
* each inline `acceptance[]` item and emits one verdict file per round
|
|
12
11
|
* (`.agents/schemas/acceptance-eval-verdict.schema.json`). This CLI is the
|
|
13
12
|
* deterministic SCORER of that single authored verdict — it validates and
|
|
14
13
|
* decides, it never re-scores the criteria as an independent additional
|
|
@@ -41,18 +40,17 @@
|
|
|
41
40
|
* tier along with the per-AC-cluster `--epic <id> --cluster <id>` mode that
|
|
42
41
|
* scored an Epic `## Acceptance Table` against a `main..epic/<id>` diff.)
|
|
43
42
|
*
|
|
44
|
-
* One gate call per round (Story #4951
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* scored here exactly once.
|
|
48
|
-
* one Story-level round
|
|
49
|
-
* guard) and race the `signals.ndjson` round
|
|
50
|
-
* Story's own `acceptance[]` count off its body
|
|
51
|
-
* verdict whose `criteria[]` length differs
|
|
52
|
-
* mistake costs no round. `--expected-criteria` is
|
|
53
|
-
* redundant with the derived count: when both are known
|
|
54
|
-
*
|
|
55
|
-
* merge applies only to fresh critics.
|
|
43
|
+
* One gate call per round (Story #4951; Story #5343 retired the cluster
|
|
44
|
+
* protocol that used to fan a round out). The round's owner authors ONE
|
|
45
|
+
* verdict covering every `acceptance[]` item — `criteria[]` in
|
|
46
|
+
* acceptance-array order — and it is scored here exactly once. A second call
|
|
47
|
+
* inside one round would burn a Story-level round for nothing (distinct
|
|
48
|
+
* fingerprints defeat the replay guard) and race the `signals.ndjson` round
|
|
49
|
+
* ledger. The gate reads the Story's own `acceptance[]` count off its body
|
|
50
|
+
* (Story #5313) and rejects a verdict whose `criteria[]` length differs
|
|
51
|
+
* **before** scoring, so the mistake costs no round. `--expected-criteria` is
|
|
52
|
+
* still accepted but is redundant with the derived count: when both are known
|
|
53
|
+
* they must agree.
|
|
56
54
|
*
|
|
57
55
|
* CLI:
|
|
58
56
|
* --story <id> Story ID (required).
|
|
@@ -180,13 +178,13 @@ function parseCliArgs(argv) {
|
|
|
180
178
|
}
|
|
181
179
|
|
|
182
180
|
/**
|
|
183
|
-
* The
|
|
181
|
+
* The coverage contract, stated once so both the flag error and the coverage
|
|
184
182
|
* error name the same shape the caller has to produce.
|
|
185
183
|
*/
|
|
186
184
|
const MERGE_CONTRACT =
|
|
187
|
-
'One round =
|
|
188
|
-
|
|
189
|
-
'
|
|
185
|
+
'One round = ONE verdict -> ONE gate call: the verdict must carry one ' +
|
|
186
|
+
'criteria[] record per acceptance[] item, in acceptance-array order, ' +
|
|
187
|
+
'before scoring.';
|
|
190
188
|
|
|
191
189
|
/**
|
|
192
190
|
* Read the Story's `acceptance[]` count off its body (Story #5313), so the
|
|
@@ -292,8 +290,8 @@ export function resolveExpectedCriteria(raw) {
|
|
|
292
290
|
* Reject a verdict that does not cover exactly `expectedCriteria` criteria.
|
|
293
291
|
*
|
|
294
292
|
* Called **before** `runAcceptanceEval`, which is where the round ledger is
|
|
295
|
-
* read and appended — so a partial
|
|
296
|
-
*
|
|
293
|
+
* read and appended — so a partial verdict handed to the gate by mistake
|
|
294
|
+
* costs no round and can never escalate a `redraft` into a `block`.
|
|
297
295
|
*
|
|
298
296
|
* Exported for tests.
|
|
299
297
|
*
|
|
@@ -544,9 +542,9 @@ export async function runAcceptanceEvalCli(
|
|
|
544
542
|
|
|
545
543
|
const verdict = validateVerdictImpl(parsed);
|
|
546
544
|
|
|
547
|
-
// Story #4951 / #5313:
|
|
548
|
-
//
|
|
549
|
-
//
|
|
545
|
+
// Story #4951 / #5313: the verdict must cover every acceptance[] item, and
|
|
546
|
+
// the count comes from the Story body itself. This runs before the round
|
|
547
|
+
// ledger is touched, so a partial verdict is a free mistake.
|
|
550
548
|
const config = resolveConfigImpl();
|
|
551
549
|
const expected = await resolveExpectedCriteriaCount({
|
|
552
550
|
storyId,
|
|
@@ -23,9 +23,16 @@
|
|
|
23
23
|
* { storyId, baseRef, headRef, files, enumerated, level, classes, profile,
|
|
24
24
|
* mode, reason, verdictOwner }
|
|
25
25
|
*
|
|
26
|
-
* `files` is the one change set
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* `files` is the one change set the verdict owner must be handed; the caller
|
|
27
|
+
* never lets it re-enumerate the diff. `files: null` means the diff could not
|
|
28
|
+
* be enumerated.
|
|
29
|
+
*
|
|
30
|
+
* `level` / `classes` are what **review depth** reads (`resolveDepth`), and a
|
|
31
|
+
* sensitive class still resolves `deep`. They do not route the verdict owner:
|
|
32
|
+
* `verdictOwner` follows the ceremony profile alone (Story #5343) —
|
|
33
|
+
* `inline-self-eval` under `minimal` / `standard`, `fresh-critic` under
|
|
34
|
+
* `strict` — and since Story #5366 the resolver does not even accept the
|
|
35
|
+
* level, so the two signals cannot be confused for one decision.
|
|
29
36
|
*
|
|
30
37
|
* Exit codes: 0 on a derived decision (including the `null` fail-safe — an
|
|
31
38
|
* unenumerable diff is a decision, not an error), 1 on a usage error.
|
|
@@ -114,13 +121,11 @@ export function deriveCeremony(
|
|
|
114
121
|
const { level, classes } = deriveChangeLevelImpl({
|
|
115
122
|
changedFiles: changeSet.files,
|
|
116
123
|
});
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
ceremonyProfile,
|
|
123
|
-
});
|
|
124
|
+
// The level is still derived and still printed — review depth reads it —
|
|
125
|
+
// but the ceremony profile alone resolves the verdict owner, and the
|
|
126
|
+
// resolver accepts nothing else, so nothing here can be talked into a
|
|
127
|
+
// different owner by the diff.
|
|
128
|
+
const ceremony = resolveCeremonyImpl({ ceremonyProfile });
|
|
124
129
|
return {
|
|
125
130
|
storyId,
|
|
126
131
|
baseRef,
|