mandrel 2.8.0 → 2.9.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/docs/configuration.md +26 -0
- package/.agents/schemas/agentrc.schema.json +21 -0
- package/.agents/scripts/audit-to-stories.js +51 -0
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +120 -55
- package/.agents/scripts/lib/config-settings-schema.js +32 -0
- package/.agents/scripts/lib/findings/semantic-issue-search.js +43 -5
- package/.agents/scripts/lib/observability/terse-result.js +114 -0
- package/.agents/scripts/lib/orchestration/complexity-gate.js +207 -0
- package/.agents/scripts/lib/orchestration/plan-context.js +3 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +221 -8
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +55 -14
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +9 -3
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +4 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +13 -40
- package/.agents/scripts/lib/story-body/body-format-lints.js +215 -0
- package/.agents/scripts/lib/story-body/story-body.js +18 -2
- package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -0
- package/.agents/scripts/providers/github/issues.js +54 -7
- package/.agents/scripts/providers/github/search-budget.js +124 -0
- package/.agents/scripts/providers/github/search-query.js +71 -0
- package/.agents/scripts/single-story-confirm-merge.js +14 -5
- package/.agents/scripts/single-story-init.js +19 -3
- package/.agents/scripts/sync-branch-from-base.js +9 -3
- package/.agents/workflows/helpers/deliver-story.md +10 -0
- package/.agents/workflows/plan.md +27 -2
- package/docs/CHANGELOG.md +20 -0
- package/package.json +1 -1
|
@@ -44,6 +44,7 @@ import { gh as defaultGh } from './lib/gh-exec.js';
|
|
|
44
44
|
import { getStoryBranch } from './lib/git-utils.js';
|
|
45
45
|
import { Logger } from './lib/Logger.js';
|
|
46
46
|
import { emitTerminalFriction } from './lib/observability/runtime-friction.js';
|
|
47
|
+
import { emitTerseResult } from './lib/observability/terse-result.js';
|
|
47
48
|
import { MERGED_FLIP_FAILED_BLOCK_CLASS } from './lib/orchestration/lifecycle/emit-merge-flip-failed.js';
|
|
48
49
|
import { parsePrNumber } from './lib/orchestration/single-story-close/phases/code-review.js';
|
|
49
50
|
import { runConfirmMergePhase as defaultRunConfirmMergePhase } from './lib/orchestration/single-story-close/phases/confirm-merge.js';
|
|
@@ -142,11 +143,19 @@ async function resolvePrNumber({ cwd, storyBranch, gh }) {
|
|
|
142
143
|
* exits via `process.exit` the moment `main` resolves.
|
|
143
144
|
*/
|
|
144
145
|
async function logConfirmResult(result, terminal, config) {
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
// Story #4685 — full detail to a temp log; the agent acts on the terminal
|
|
147
|
+
// envelope emitted below. The summary line keeps the at-a-glance fields.
|
|
148
|
+
emitTerseResult({
|
|
149
|
+
label: 'CONFIRM MERGE RESULT',
|
|
150
|
+
result,
|
|
151
|
+
scope: result?.storyId,
|
|
152
|
+
summary: {
|
|
153
|
+
storyId: result?.storyId,
|
|
154
|
+
action: result?.action,
|
|
155
|
+
reason: result?.reason,
|
|
156
|
+
status: terminal?.status,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
150
159
|
emitTerminalEnvelope(terminal);
|
|
151
160
|
await emitTerminalFriction({ envelope: terminal, config });
|
|
152
161
|
return { success: terminal.status !== 'failed', result, terminal };
|
|
@@ -55,6 +55,7 @@ import { getStoryBranch, gitSpawn, gitSync } from './lib/git-utils.js';
|
|
|
55
55
|
import { Logger } from './lib/Logger.js';
|
|
56
56
|
import { TYPE_LABELS } from './lib/label-constants.js';
|
|
57
57
|
import { setActiveStoryEnv } from './lib/observability/active-story-env.js';
|
|
58
|
+
import { emitTerseResult } from './lib/observability/terse-result.js';
|
|
58
59
|
import {
|
|
59
60
|
executeFastForward,
|
|
60
61
|
planFastForward,
|
|
@@ -769,9 +770,24 @@ export async function runSingleStoryInit({
|
|
|
769
770
|
}
|
|
770
771
|
}
|
|
771
772
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
773
|
+
// Story #4685 — route the full result to a temp log and emit a single-line
|
|
774
|
+
// summary carrying the fields the orchestrating agent acts on (workCwd,
|
|
775
|
+
// remoteVerified). The `## Spec` names this the hot-path stdout to quiet.
|
|
776
|
+
emitTerseResult({
|
|
777
|
+
label: 'STORY INIT RESULT',
|
|
778
|
+
result,
|
|
779
|
+
scope: storyId,
|
|
780
|
+
logDir: path.join(cwd, 'temp', 'orchestration'),
|
|
781
|
+
summary: {
|
|
782
|
+
storyId,
|
|
783
|
+
storyBranch,
|
|
784
|
+
workCwd,
|
|
785
|
+
worktreeCreated,
|
|
786
|
+
dependenciesInstalled,
|
|
787
|
+
remoteVerified: result.remoteVerified,
|
|
788
|
+
dryRun,
|
|
789
|
+
},
|
|
790
|
+
});
|
|
775
791
|
progress(
|
|
776
792
|
'DONE',
|
|
777
793
|
dryRun
|
|
@@ -34,6 +34,7 @@ import { runAsCli } from './lib/cli-utils.js';
|
|
|
34
34
|
import { syncBranchFromBase } from './lib/git/sync-from-base.js';
|
|
35
35
|
import { gitSpawn, gitSync } from './lib/git-utils.js';
|
|
36
36
|
import { Logger } from './lib/Logger.js';
|
|
37
|
+
import { emitTerseResult } from './lib/observability/terse-result.js';
|
|
37
38
|
import { PROJECT_ROOT } from './lib/project-root.js';
|
|
38
39
|
|
|
39
40
|
const progress = Logger.createProgress('sync-branch-from-base', {
|
|
@@ -93,9 +94,14 @@ export async function runSyncBranchFromBase(opts = {}) {
|
|
|
93
94
|
gitSpawn,
|
|
94
95
|
});
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
// Story #4685 — full detail to a temp log; emit a single summary line.
|
|
98
|
+
emitTerseResult({
|
|
99
|
+
label: 'SYNC RESULT',
|
|
100
|
+
result,
|
|
101
|
+
scope: branch,
|
|
102
|
+
logDir: path.join(cwd, 'temp', 'orchestration'),
|
|
103
|
+
summary: { branch, base, synced: result.synced, kind: result.kind },
|
|
104
|
+
});
|
|
99
105
|
|
|
100
106
|
if (!result.synced) {
|
|
101
107
|
const detail =
|
|
@@ -39,6 +39,16 @@ large — uses the same machinery:
|
|
|
39
39
|
If the Story still carries an `Epic: #N` reference, **stop** — that is a v1
|
|
40
40
|
Epic-attached ticket; re-plan as a v2 Story or finish it on a pre-v2 checkout.
|
|
41
41
|
|
|
42
|
+
> **Ceremony-lite Stories still land through this engine unchanged (Story
|
|
43
|
+
> #4683).** A Story that `/plan` routed onto the ceremony-lite path (its
|
|
44
|
+
> `complexityRoute.route === "lite"`) collapses only the *advisory* plan/deliver
|
|
45
|
+
> ceremony — the fresh-critic / Tech-Spec authoring a one-artifact scope does
|
|
46
|
+
> not earn. It does **not** get a cheaper landing: the close-validation gates
|
|
47
|
+
> (lint / test / format / coverage / CRAP / maintainability), the PR to `main`,
|
|
48
|
+
> and the `rules/security-baseline.md` MUSTs all run here exactly as for a
|
|
49
|
+
> full-ceremony Story. The lite route's `preserves` field is the machine-readable
|
|
50
|
+
> record of those non-negotiables; there is no lite-specific gate bypass.
|
|
51
|
+
|
|
42
52
|
## Prerequisites
|
|
43
53
|
|
|
44
54
|
1. A GitHub Issue with the `type::story` label and **no** `Epic: #N`
|
|
@@ -79,11 +79,36 @@ That is what makes superseding work without anyone re-typing ids
|
|
|
79
79
|
|
|
80
80
|
The envelope carries docs context, codebase snapshot, BDD probe, risk
|
|
81
81
|
heuristics, the story-author system prompt, `sourceTickets[]` (`--tickets`
|
|
82
|
-
mode),
|
|
83
|
-
seed — never Epics).
|
|
82
|
+
mode), `duplicates[]` (open **Stories** whose title/body overlap the
|
|
83
|
+
seed — never Epics), and the `complexityRoute` ceremony-lite signal (below).
|
|
84
84
|
Under `--yes`, do not ask free-form operator questions — unresolved
|
|
85
85
|
unknowns land in Key Assumptions.
|
|
86
86
|
|
|
87
|
+
#### Ceremony-lite complexity gate (`complexityRoute`)
|
|
88
|
+
|
|
89
|
+
The envelope's `complexityRoute` field is a **deterministic, conservative**
|
|
90
|
+
plan-time gate (Story #4683) that routes a genuinely trivial single-artifact
|
|
91
|
+
seed onto a collapsed path so it stops paying the full two-session
|
|
92
|
+
plan/deliver ceremony that measurably buys no quality at that size:
|
|
93
|
+
|
|
94
|
+
- **`route: "lite"`** — a trivial scope (seed ≤ `maxSeedWords` words **and** ≤
|
|
95
|
+
`maxArtifacts` enumerated items). Collapse the ceremony: author **one minimal
|
|
96
|
+
Story** and skip the fresh-critic / Tech-Spec ceremony a one-artifact scope
|
|
97
|
+
does not earn. The lite route is **not** licence to drop a non-negotiable —
|
|
98
|
+
its `preserves` field enumerates exactly what still holds: the Story ticket,
|
|
99
|
+
the PR-to-`main` landing, every repo quality gate, and the security baseline.
|
|
100
|
+
Those gates still run in `single-story-close.js` regardless of route.
|
|
101
|
+
- **`route: "full"`** — everything else. The gate fails toward `full` on any
|
|
102
|
+
doubt (empty seed, over the word ceiling, a multi-capability enumeration, or
|
|
103
|
+
the gate disabled via `planning.complexityGate.enabled=false`), so a real
|
|
104
|
+
capability slice never loses ceremony. Author normally under the split policy.
|
|
105
|
+
|
|
106
|
+
The threshold and its override knob (`planning.complexityGate.{enabled,
|
|
107
|
+
maxSeedWords, maxArtifacts}`) are documented in
|
|
108
|
+
[`.agents/docs/configuration.md`](../docs/configuration.md) under `### planning`;
|
|
109
|
+
the defaults live on `DEFAULT_COMPLEXITY_GATE` in
|
|
110
|
+
[`lib/orchestration/complexity-gate.js`](../scripts/lib/orchestration/complexity-gate.js).
|
|
111
|
+
|
|
87
112
|
**Gate #1** — STOP to confirm the sharpened plan intent and any
|
|
88
113
|
duplicate-candidate review. Under `--yes`, auto-proceed.
|
|
89
114
|
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.9.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.8.0...mandrel-v2.9.0) (2026-07-21)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
* ceremony-lite path: complexity-gate the full plan/deliver pipeline for trivial scopes ([#4683](https://github.com/dsj1984/mandrel/issues/4683)) ([#4688](https://github.com/dsj1984/mandrel/issues/4688)) ([1002776](https://github.com/dsj1984/mandrel/commit/10027761c7bf375aa32b4ffe8b526015433311ca))
|
|
11
|
+
* harden /audit-to-stories dedup search: budget the fan-out, bound the query, soft-fail instead of aborting ([#4678](https://github.com/dsj1984/mandrel/issues/4678)) ([#4679](https://github.com/dsj1984/mandrel/issues/4679)) ([c043b70](https://github.com/dsj1984/mandrel/commit/c043b708dca9daf10525fe0e810da9b13998454b))
|
|
12
|
+
* **plan:** pre-empt deterministic body-format lints in the story-author prompt and auto-fix mechanical ones (refs [#4684](https://github.com/dsj1984/mandrel/issues/4684)) ([#4689](https://github.com/dsj1984/mandrel/issues/4689)) ([8dea7ad](https://github.com/dsj1984/mandrel/commit/8dea7adc71e9adcb746022747f3d436ccb520758))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
* land tail: tolerate/pre-empt a worktree-held story branch so a merged PR is never stranded at agent::blocked ([#4681](https://github.com/dsj1984/mandrel/issues/4681)) ([#4686](https://github.com/dsj1984/mandrel/issues/4686)) ([0436af0](https://github.com/dsj1984/mandrel/commit/0436af0ab183c6e423cf2b56e749d63fa0c6b150))
|
|
18
|
+
* root-cause and fix: second-touch change-request deliveries complete but their PR never lands ([#4682](https://github.com/dsj1984/mandrel/issues/4682)) ([#4687](https://github.com/dsj1984/mandrel/issues/4687)) ([2010739](https://github.com/dsj1984/mandrel/commit/20107399a9a1645c0d8b259245b275a965ffdcbc))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Performance
|
|
22
|
+
|
|
23
|
+
* **orchestration:** quiet hot-path script stdout to terse summaries (refs [#4685](https://github.com/dsj1984/mandrel/issues/4685)) ([#4690](https://github.com/dsj1984/mandrel/issues/4690)) ([310ee4a](https://github.com/dsj1984/mandrel/commit/310ee4a70726dee0ace6da8bb866cb01e57f7c2b))
|
|
24
|
+
|
|
5
25
|
## [2.8.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.7.0...mandrel-v2.8.0) (2026-07-21)
|
|
6
26
|
|
|
7
27
|
|
package/package.json
CHANGED