mandrel 2.7.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 (95) hide show
  1. package/.agents/README.md +104 -330
  2. package/.agents/agents/auditor.md +135 -0
  3. package/.agents/agents/plan-critic.md +80 -0
  4. package/.agents/audit-checklists/dependencies.md +7 -0
  5. package/.agents/audit-checklists/documentation.md +1 -0
  6. package/.agents/docs/SDLC.md +69 -162
  7. package/.agents/docs/configuration.md +159 -499
  8. package/.agents/docs/quality-gates.md +59 -180
  9. package/.agents/instructions.md +170 -295
  10. package/.agents/rules/changelog-style.md +8 -66
  11. package/.agents/rules/ci-remediation.md +65 -124
  12. package/.agents/rules/gherkin-standards.md +10 -31
  13. package/.agents/rules/git-conventions-reference.md +28 -61
  14. package/.agents/rules/git-conventions.md +1 -1
  15. package/.agents/rules/orchestration-error-handling.md +5 -15
  16. package/.agents/rules/security-baseline.md +7 -13
  17. package/.agents/rules/shell-conventions.md +4 -13
  18. package/.agents/rules/test-seams.md +2 -2
  19. package/.agents/rules/testing-standards.md +7 -17
  20. package/.agents/schemas/agentrc.schema.json +21 -0
  21. package/.agents/scripts/audit-to-stories.js +51 -0
  22. package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +120 -55
  23. package/.agents/scripts/lib/config-settings-schema.js +32 -0
  24. package/.agents/scripts/lib/findings/semantic-issue-search.js +43 -5
  25. package/.agents/scripts/lib/observability/terse-result.js +114 -0
  26. package/.agents/scripts/lib/orchestration/complexity-gate.js +207 -0
  27. package/.agents/scripts/lib/orchestration/plan-context.js +3 -0
  28. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +221 -8
  29. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +55 -14
  30. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +9 -3
  31. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +4 -1
  32. package/.agents/scripts/lib/orchestration/task-body-validator.js +13 -40
  33. package/.agents/scripts/lib/story-body/body-format-lints.js +215 -0
  34. package/.agents/scripts/lib/story-body/story-body.js +18 -2
  35. package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -0
  36. package/.agents/scripts/providers/github/issues.js +54 -7
  37. package/.agents/scripts/providers/github/search-budget.js +124 -0
  38. package/.agents/scripts/providers/github/search-query.js +71 -0
  39. package/.agents/scripts/single-story-confirm-merge.js +14 -5
  40. package/.agents/scripts/single-story-init.js +19 -3
  41. package/.agents/scripts/sync-branch-from-base.js +9 -3
  42. package/.agents/skills/core/api-and-interface-design/SKILL.md +23 -297
  43. package/.agents/skills/core/api-and-interface-design/reference.md +76 -0
  44. package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +20 -327
  45. package/.agents/skills/core/browser-testing-with-devtools/reference.md +74 -0
  46. package/.agents/skills/core/code-review-and-quality/reference.md +16 -398
  47. package/.agents/skills/core/debugging-and-error-recovery/reference.md +14 -281
  48. package/.agents/skills/core/documentation-and-adrs/reference.md +42 -338
  49. package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +28 -326
  50. package/.agents/skills/core/idea-refinement/SKILL.md +67 -193
  51. package/.agents/skills/core/security-and-hardening/SKILL.md +15 -31
  52. package/.agents/skills/core/security-and-hardening/reference.md +15 -273
  53. package/.agents/skills/skills.index.json +5 -5
  54. package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +16 -222
  55. package/.agents/skills/stack/qa/gherkin-authoring/reference.md +157 -0
  56. package/.agents/skills/stack/qa/playwright/SKILL.md +0 -29
  57. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +19 -23
  58. package/.agents/skills/stack/qa/qa-harness/SKILL.md +35 -53
  59. package/.agents/skills/stack/qa/vitest/SKILL.md +0 -29
  60. package/.agents/workflows/audit-accessibility.md +34 -108
  61. package/.agents/workflows/audit-architecture.md +35 -123
  62. package/.agents/workflows/audit-clean-code.md +19 -78
  63. package/.agents/workflows/audit-data-model.md +32 -100
  64. package/.agents/workflows/audit-dependencies.md +47 -111
  65. package/.agents/workflows/audit-devops.md +16 -83
  66. package/.agents/workflows/audit-documentation.md +46 -93
  67. package/.agents/workflows/audit-navigability.md +26 -80
  68. package/.agents/workflows/audit-performance.md +40 -106
  69. package/.agents/workflows/audit-privacy.md +17 -80
  70. package/.agents/workflows/audit-quality.md +35 -99
  71. package/.agents/workflows/audit-security.md +20 -78
  72. package/.agents/workflows/audit-seo.md +20 -98
  73. package/.agents/workflows/audit-sre.md +20 -88
  74. package/.agents/workflows/audit-to-stories.md +1 -8
  75. package/.agents/workflows/audit-ux-ui.md +17 -80
  76. package/.agents/workflows/deliver.md +54 -9
  77. package/.agents/workflows/git-cleanup.md +50 -275
  78. package/.agents/workflows/helpers/audit-lens-core.md +230 -0
  79. package/.agents/workflows/helpers/code-review.md +11 -23
  80. package/.agents/workflows/helpers/deliver-story-reference.md +114 -17
  81. package/.agents/workflows/helpers/deliver-story.md +36 -186
  82. package/.agents/workflows/helpers/qa-core.md +174 -0
  83. package/.agents/workflows/helpers/qa-run-scenario-reference.md +35 -0
  84. package/.agents/workflows/helpers/qa-run-scenario.md +11 -25
  85. package/.agents/workflows/helpers/worktree-lifecycle.md +6 -67
  86. package/.agents/workflows/mandrel-update.md +7 -13
  87. package/.agents/workflows/plan.md +44 -17
  88. package/.agents/workflows/qa-assist.md +140 -269
  89. package/.agents/workflows/qa-explore.md +125 -316
  90. package/.agents/workflows/qa-run.md +180 -380
  91. package/docs/CHANGELOG.md +30 -0
  92. package/package.json +1 -1
  93. package/.agents/workflows/helpers/audit-dual-path.md +0 -59
  94. package/.agents/workflows/helpers/audit-self-check.md +0 -70
  95. package/.agents/workflows/helpers/audit-severity-scale.md +0 -19
@@ -151,31 +151,17 @@ finding, it **MUST** pass
151
151
  Redaction is not optional — findings are posted to GitHub at the orchestrator's
152
152
  approval time, so unredacted secrets must never reach the `findings` output.
153
153
 
154
- ## Deferred: batched sub-agent dispatch mode (spec-only)
155
-
156
- > **Not yet enabled.** This section specifies a future execution mode; the
157
- > current `/qa-run` sweep calls this helper **inline**, one scenario at a time,
158
- > in the orchestrator's own turn. The batched mode below is documented so the
159
- > contract is stable when it is turned on do not implement it as live
160
- > behavior from this spec alone.
161
-
162
- In the deferred mode, the orchestrator MAY dispatch scenarios to fresh-context
163
- sub-agents to keep its own context window focused, under these hard rules:
164
-
165
- - **Sequential, never parallel.** Sub-agents run **one at a time**, never
166
- concurrently. A live browser surface is a single shared resource; parallel
167
- drivers would race on navigation and cross-contaminate evidence.
168
- - **One sub-agent per persona group.** Scenarios are grouped by persona and a
169
- single sub-agent drives all of one persona's scenarios, so the persona is
170
- signed in once per group rather than per scenario.
171
- - **Re-verify auth on entry.** Each sub-agent MUST re-verify the
172
- authenticated-session precondition (a `take_snapshot` confirming the persona
173
- badge) when it starts, because it does not share the orchestrator's live
174
- session state.
175
- - **Same input/output contract.** Each sub-agent consumes the input contract
176
- above and returns the per-scenario result shape above for every scenario it
177
- drove — the orchestrator aggregates identically whether the helper ran inline
178
- or via a batched sub-agent.
154
+ ## Sequential-only driving (a live browser is a shared resource)
155
+
156
+ Scenarios are driven **one at a time, never concurrently**. A live browser
157
+ surface is a single shared resource; parallel drivers would race on navigation
158
+ and cross-contaminate evidence, so parallel driving is ruled out. Today the
159
+ `/qa-run` sweep calls this helper **inline**, one scenario per turn. A future,
160
+ **not-yet-enabled** batched sub-agent dispatch mode — which would still run
161
+ sub-agents sequentially, one per persona group, re-verifying auth on entry and
162
+ honoring the same input/output contract is specified in
163
+ [`qa-run-scenario-reference.md`](qa-run-scenario-reference.md). Do not implement
164
+ that mode as live behavior from the spec alone.
179
165
 
180
166
  ## Constraints
181
167
 
@@ -242,73 +242,12 @@ Symlink strategy:
242
242
  specific failure up to 3 times with 250/500/1000 ms backoff. Unrelated fetch
243
243
  failures surface immediately — no retry.
244
244
 
245
- ## Harness-worktree ⇄ consumer-lint-ignore interaction (Story #152)
246
-
247
- Mandrel's own worktree isolation (above) always roots story worktrees at
248
- `delivery.worktreeIsolation.root` (default `.worktrees/` at the repo root).
249
- That path is separate from **the host IDE/CLI harness's own worktree
250
- mechanism** for example Claude Code, when it manages an agent session as a
251
- git worktree, nests it at `.claude/worktrees/<name>/`. A mandrel delivery
252
- agent can be invoked from *either* location depending on how the operator's
253
- harness composes with `/deliver`: mandrel's own `.worktrees/story-<id>/` when
254
- `worktreeIsolation.enabled` drives the checkout, or a harness-level
255
- `.claude/worktrees/<name>/` when the harness itself provides the isolated
256
- working directory mandrel runs inside.
257
-
258
- This matters because a consumer's `pre-push` (or `pre-commit`) lint step is
259
- commonly configured with an ignore glob that excludes noisy agent-tooling
260
- directories, e.g. a Biome `files.includes` entry like `"!**/.claude"`. When
261
- the *agent's CWD itself* resolves under `.claude/worktrees/<name>/`, a
262
- lint invocation scoped to `.` (`biome check .`, or equivalent) resolves
263
- every candidate path as living under the ignored `.claude` prefix — the glob
264
- matches zero files, and tools that treat zero-match as failure (Biome's
265
- default `check` behavior without `--no-errors-on-unmatched`) exit non-zero
266
- with something like `No files were processed in the specified paths`. This
267
- is a **false negative**: the changed files were never actually linted
268
- against, and the hook is not reporting a real defect. It is functionally
269
- distinct from a `pre-push` rejection caused by a genuine lint violation, and
270
- must not be treated the same way.
271
-
272
- **Do not resolve this by bypassing the push hook.**
273
- [`rules/git-conventions.md`](../../rules/git-conventions.md) § "Push
274
- Validation & Reliability" prohibits skipping hooks without explicit operator
275
- authorization, and that prohibition is not weakened by this interaction —
276
- the zero-match failure is a **consumer-tooling gap**, not a framework
277
- authorization the agent gets to grant itself.
278
-
279
- **Sanctioned resolution path:**
280
-
281
- 1. **Recognize the signature.** A `pre-push`/`pre-commit` failure whose
282
- message is a zero-match error (`No files were processed`, `0 files
283
- matched`, or equivalent for the consumer's linter) — not a reported
284
- violation in a specific file — combined with an agent CWD under
285
- `.claude/worktrees/` (or any other harness-managed path a consumer's lint
286
- config ignores) is this known interaction, not a real lint failure.
287
- 2. **Fix it in the consumer, not the agent invocation.** The remedy lives in
288
- the consumer's own lint command, mirroring what its `lint-staged` config
289
- (if present) likely already does for the same reason: make the zero-match
290
- case a no-op instead of a failure. For Biome:
291
- `biome check --no-errors-on-unmatched .`. Other linters have an
292
- equivalent flag (e.g. ESLint's `--no-error-on-unmatched-pattern`). This is
293
- a one-line consumer-side change, typically to `.husky/pre-push` or the
294
- `package.json` script it invokes.
295
- 3. **Escalate through the normal HITL path**, per
296
- [`.agents/instructions.md` § 1.J](../../instructions.md), if the agent
297
- cannot edit the consumer's hook/lint config directly (e.g. it sits outside
298
- the Story's scope). Transition to `agent::blocked`, name the zero-match
299
- signature and the one-line remedy in the blocker summary, and let the
300
- operator apply the consumer-side fix or explicitly authorize a one-time
301
- hook-skip per [`rules/git-conventions.md`](../../rules/git-conventions.md)
302
- § "Push Validation & Reliability". Explicit operator authorization is the
303
- *only* circumstance under which a hook may be skipped — never as an
304
- agent's unilateral default when this signature is recognized.
305
- 4. **Do not relocate mandrel's own worktrees to work around a harness-level
306
- path.** `delivery.worktreeIsolation.root` controls where *mandrel*
307
- materializes `story-<id>` worktrees (default `.worktrees/`, already
308
- outside `.claude/`) and is unrelated to where the host harness places its
309
- own session worktree. Changing `worktreeIsolation.root` does not fix this
310
- interaction when the false negative originates from the harness's path,
311
- not mandrel's.
245
+ ## Harness-worktree ⇄ consumer-lint-ignore interaction
246
+
247
+ When an agent's CWD resolves under a harness-managed worktree path the consumer's
248
+ lint config ignores (e.g. `.claude/worktrees/`), a `.`-scoped lint can zero-match
249
+ and fail falsely. Its signature and the sanctioned consumer-side fix (never a
250
+ hook bypass) live in [`rules/git-conventions-reference.md` § Push Validation](../../rules/git-conventions-reference.md).
312
251
 
313
252
  ## Fallback: single-tree mode
314
253
 
@@ -113,19 +113,13 @@ single source of truth, kept in lockstep with this table by
113
113
  | **migrate** | `npx mandrel migrate --from <cur> --to <target>` |
114
114
  | **doctor** | `npx mandrel doctor` (then apply the per-check remedies) |
115
115
 
116
- The exact stderr the CLI prints per failed phase:
117
-
118
- - **sync** the .agents/ materialization may be incomplete. Run `mandrel
119
- sync` manually to restore.
120
- - **sync-commands** the .claude/commands/ tree may be out of sync. Run `npm
121
- run sync:commands` manually to restore.
122
- - **migrate** some migrations for v\<cur\> → v\<target\> may not have
123
- applied. Run `mandrel migrate --from <cur> --to <target>` manually to retry.
124
- - **doctor** — upgraded to v\<target\> but doctor reported failures. → Run
125
- `mandrel doctor` for remedies.
126
-
127
- (`<cur>` / `<target>` are the installed and resolved-newest version strings
128
- the failing run reported.)
116
+ The CLI prints the matching remedy command to stderr per failed phase; the
117
+ workflow quotes those commands verbatim so an operator sees the same thing the
118
+ CLI told them, and the drift gate above keys on them: Run `mandrel sync`
119
+ manually to restore. · Run `npm run sync:commands` manually to restore. · Run
120
+ `mandrel migrate --from <cur> --to <target>` manually to retry. · Run
121
+ `mandrel doctor` for remedies. (`<cur>` / `<target>` are the installed and
122
+ resolved-newest version strings the failing run reported.)
129
123
 
130
124
  Recovery sequence: run the matching remedy, then **re-run
131
125
  `npx mandrel update`** — it is idempotent (the install already landed, so a
@@ -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
 
@@ -180,17 +205,21 @@ assumption, thin the Slicing checkpoint) and re-run this step. Empty
180
205
  provably have nothing for a critic to find, and each skip is recorded on the
181
206
  plan-metrics ledger so under-firing stays auditable.
182
207
  - **Either `dispatch: true`** — dispatch **one fresh-context sub-agent per
183
- firing critic** (a generic sub-agent), then fold its findings into the
184
- Gate #2 view or a re-author round before persist. Each critic is
208
+ firing critic**, then fold its findings into the Gate #2 view or a re-author
209
+ round before persist. When `delivery.routing.roleScopedAgents` is enabled
210
+ (the **default**), dispatch each firing critic with `subagent_type:
211
+ plan-critic` — it boots on the role-scoped
212
+ [`plan-critic`](../agents/plan-critic.md) context (its own system prompt, no
213
+ `CLAUDE.md` @-closure) that carries the maker-blind invariant, the
214
+ `consolidation` and `pre-mortem` charters, and the output shape standalone.
215
+ When the kill-switch is off (`roleScopedAgents: false`) or the host cannot
216
+ spawn at this depth, fall back to a generic sub-agent and hand it the same
217
+ charter (the `consolidation` / `pre-mortem` definitions in
218
+ [`plan-critic.md`](../agents/plan-critic.md)). Either way the critic is
185
219
  **maker-blind**: hand it the draft artifacts (`stories.json`, and
186
- `techspec.md` when present) plus its charter below never the authoring
187
- transcript or the reasons the planner believed its own draft is sound. A
188
- critic that reads the maker's case grades the case, not the draft.
189
- - `consolidation` — the draft's shape: Stories that should be one cohesive
190
- slice, a slice split per-module rather than per-capability, and
191
- `depends_on` edges that disagree with the Delivery Slicing table.
192
- - `pre-mortem` — assume the plan shipped and failed: name the most likely
193
- failure modes and what the draft would have to say to prevent them.
220
+ `techspec.md` when present) never the authoring transcript or the reasons
221
+ the planner believed its own draft is sound. A critic that reads the maker's
222
+ case grades the case, not the draft.
194
223
 
195
224
  Fold what survives back into `stories.json` and re-run this step. Findings are
196
225
  advisory input to the operator's Gate #2 decision, not an automatic re-author
@@ -201,11 +230,9 @@ mandate.
201
230
  **Gate #2** — when the operator passed `--force-review`, STOP for approval of
202
231
  the assembled plan before persist. Under `--yes`, auto-proceed.
203
232
 
204
- `--force-review` is the **only** thing that raises this gate. Story #4542
205
- retired the risk-derived alternative: the planner authored its own risk verdict,
206
- persist computed a `requiresStop` from it *after* `createStoryIssues` had already
207
- run, and nothing read the result — the STOP was prose executed by the same
208
- session that wrote the verdict. A gate a plan can lower for itself is not a gate.
233
+ `--force-review` is the **only** thing that raises this gate there is no
234
+ risk-derived routing (Story #4542): a gate a plan can lower for itself is not a
235
+ gate.
209
236
 
210
237
  #### Dry-run pre-pass (always)
211
238