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.
Files changed (27) hide show
  1. package/.agents/docs/configuration.md +26 -0
  2. package/.agents/schemas/agentrc.schema.json +21 -0
  3. package/.agents/scripts/audit-to-stories.js +51 -0
  4. package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +120 -55
  5. package/.agents/scripts/lib/config-settings-schema.js +32 -0
  6. package/.agents/scripts/lib/findings/semantic-issue-search.js +43 -5
  7. package/.agents/scripts/lib/observability/terse-result.js +114 -0
  8. package/.agents/scripts/lib/orchestration/complexity-gate.js +207 -0
  9. package/.agents/scripts/lib/orchestration/plan-context.js +3 -0
  10. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +221 -8
  11. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +55 -14
  12. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +9 -3
  13. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +4 -1
  14. package/.agents/scripts/lib/orchestration/task-body-validator.js +13 -40
  15. package/.agents/scripts/lib/story-body/body-format-lints.js +215 -0
  16. package/.agents/scripts/lib/story-body/story-body.js +18 -2
  17. package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -0
  18. package/.agents/scripts/providers/github/issues.js +54 -7
  19. package/.agents/scripts/providers/github/search-budget.js +124 -0
  20. package/.agents/scripts/providers/github/search-query.js +71 -0
  21. package/.agents/scripts/single-story-confirm-merge.js +14 -5
  22. package/.agents/scripts/single-story-init.js +19 -3
  23. package/.agents/scripts/sync-branch-from-base.js +9 -3
  24. package/.agents/workflows/helpers/deliver-story.md +10 -0
  25. package/.agents/workflows/plan.md +27 -2
  26. package/docs/CHANGELOG.md +20 -0
  27. 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
- // Human-facing dump stays level-gated; the envelope is the machine
146
- // contract and must survive AGENT_LOG_LEVEL=silent.
147
- Logger.info(
148
- `\n--- CONFIRM MERGE RESULT ---\n${JSON.stringify(result, null, 2)}\n--- END RESULT ---\n`,
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
- Logger.info('\n--- STORY INIT RESULT ---');
773
- Logger.info(JSON.stringify(result, null, 2));
774
- Logger.info('--- END RESULT ---\n');
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
- Logger.info(
97
- `\n--- SYNC RESULT ---\n${JSON.stringify(result, null, 2)}\n--- END RESULT ---\n`,
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), and `duplicates[]` (open **Stories** whose title/body overlap the
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mandrel",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "Claude Code-first opinionated workflow framework: instructions, skills, rules, and SDLC workflows that govern AI coding assistants.",
5
5
  "files": [
6
6
  ".agents/",