mandrel 2.39.0 → 2.41.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 (76) hide show
  1. package/.agents/README.md +8 -5
  2. package/.agents/agents/auditor.md +5 -0
  3. package/.agents/docs/SDLC.md +21 -12
  4. package/.agents/instructions.md +22 -22
  5. package/.agents/rules/api-conventions.md +43 -7
  6. package/.agents/rules/ci-remediation.md +3 -14
  7. package/.agents/rules/gherkin-standards.md +21 -6
  8. package/.agents/rules/git-conventions.md +6 -5
  9. package/.agents/rules/security-baseline.md +6 -7
  10. package/.agents/rules/testing-standards.md +75 -198
  11. package/.agents/scripts/audit-to-stories.js +510 -66
  12. package/.agents/scripts/install-matrix-assert.js +2 -2
  13. package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +45 -0
  14. package/.agents/scripts/lib/audit-to-stories/ledger-commit.js +290 -0
  15. package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +94 -3
  16. package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +10 -0
  17. package/.agents/scripts/lib/label-constants.js +18 -0
  18. package/.agents/scripts/lib/label-taxonomy.js +18 -5
  19. package/.agents/scripts/lib/orchestration/dependency-candidates.js +139 -0
  20. package/.agents/scripts/lib/orchestration/epic-candidates.js +159 -0
  21. package/.agents/scripts/lib/orchestration/epic-checklist.js +103 -0
  22. package/.agents/scripts/lib/orchestration/epic-container.js +202 -0
  23. package/.agents/scripts/lib/orchestration/epic-expansion.js +148 -0
  24. package/.agents/scripts/lib/orchestration/plan-context.js +97 -36
  25. package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +80 -0
  26. package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +192 -0
  27. package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +324 -0
  28. package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +164 -0
  29. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +30 -0
  30. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +26 -5
  31. package/.agents/scripts/lib/orchestration/run-epilogue.js +130 -1
  32. package/.agents/scripts/lib/orchestration/ticket-validator.js +11 -1
  33. package/.agents/scripts/plan-persist.js +98 -1
  34. package/.agents/scripts/providers/github/sub-issue-add.js +218 -0
  35. package/.agents/scripts/resolve-stories.js +42 -2
  36. package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +5 -10
  37. package/.agents/skills/core/browser-testing-with-devtools/reference.md +7 -46
  38. package/.agents/skills/core/code-review-and-quality/SKILL.md +0 -5
  39. package/.agents/skills/core/documentation-and-adrs/SKILL.md +0 -3
  40. package/.agents/skills/core/gates-and-baselines/SKILL.md +10 -137
  41. package/.agents/skills/core/gates-and-baselines/reference.md +103 -0
  42. package/.agents/skills/core/idea-refinement/SKILL.md +2 -18
  43. package/.agents/skills/core/security-and-hardening/SKILL.md +2 -4
  44. package/.agents/skills/core/security-and-hardening/reference.md +0 -70
  45. package/.agents/skills/skills.index.json +10 -70
  46. package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +4 -10
  47. package/.agents/skills/stack/qa/gherkin-authoring/reference.md +9 -113
  48. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +29 -154
  49. package/.agents/skills/stack/qa/qa-harness/SKILL.md +157 -98
  50. package/.agents/templates/docs/audit-sweep-runbook.md +169 -0
  51. package/.agents/workflows/audit-to-stories.md +85 -7
  52. package/.agents/workflows/git-cleanup.md +3 -2
  53. package/.agents/workflows/git-deliver.md +3 -2
  54. package/.agents/workflows/helpers/audit-lens-core.md +24 -4
  55. package/.agents/workflows/helpers/deliver-reference.md +8 -0
  56. package/.agents/workflows/helpers/plan-reference.md +109 -1
  57. package/.agents/workflows/mandrel-deliver.md +47 -43
  58. package/.agents/workflows/mandrel-plan.md +61 -55
  59. package/.agents/workflows/qa-assist.md +20 -17
  60. package/.agents/workflows/qa-explore.md +30 -29
  61. package/.agents/workflows/qa-run.md +2 -1
  62. package/docs/CHANGELOG.md +30 -0
  63. package/package.json +1 -1
  64. package/.agents/rules/changelog-style.md +0 -180
  65. package/.agents/rules/shell-conventions.md +0 -61
  66. package/.agents/scripts/lib/qa/coverage-verdict.js +0 -214
  67. package/.agents/skills/core/api-and-interface-design/SKILL.md +0 -55
  68. package/.agents/skills/core/api-and-interface-design/reference.md +0 -76
  69. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +0 -45
  70. package/.agents/skills/core/debugging-and-error-recovery/reference.md +0 -56
  71. package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +0 -54
  72. package/.agents/skills/core/idea-refinement/refinement-criteria.md +0 -155
  73. package/.agents/skills/core/idea-refinement/scripts/idea-refine.sh +0 -15
  74. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +0 -105
  75. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +0 -152
  76. package/.agents/skills/stack/qa/vitest/SKILL.md +0 -22
@@ -1,49 +1,47 @@
1
1
  ---
2
2
  description:
3
3
  Unified planning entry point. Interrogate → author → persist. Emits one
4
- Story by default; splits into N>1 only under the default-single split
5
- policy.
4
+ Story by default; splits into N>1 only under the default-single split policy.
6
5
  ---
7
6
 
8
7
  # /mandrel-plan
9
8
 
10
- > **Lean spine.** Happy path + gate list; edge-case detail lives on demand in
9
+ > **Lean spine.** Happy path + gate list; edge-case detail is on demand in
11
10
  > [`helpers/plan-reference.md`](helpers/plan-reference.md).
12
11
 
13
12
  ## Inputs
14
13
 
15
14
  Single planning path — there is no Epic/Story router, no scope-triage
16
- `epic|story` verdict. **Derive the mode from what the operator typed, announce
17
- it, act**:
15
+ `epic|story` verdict (Gate #3's container groups, never routes). **Derive the
16
+ mode from what the operator typed, announce it, act**:
18
17
 
19
18
  | Invocation | Mode | Behavior |
20
19
  | --- | --- | --- |
21
20
  | `/mandrel-plan` | ask | Ask what to plan; nothing runs first. |
22
- | `/mandrel-plan add a --json flag to doctor` | seed | Ideation from prose: interrogate author **one Story by default** → persist. |
21
+ | `/mandrel-plan add a --json flag to doctor` | seed | Ideation from prose → **one Story by default** → persist. |
23
22
  | `/mandrel-plan temp/notes/idea.md` | seed-file | Same, from notes. An existing file is a path, not prose. |
24
23
  | `/mandrel-plan 4712[,4713…]` | tickets | Fetch issue(s), analyze into proper Stories (prefer N=1 rewrite). |
25
- | `/mandrel-plan 4712`, already delivered | amends | Amend a shipped Story from a **delta envelope**, not a re-interrogation. |
24
+ | `/mandrel-plan 4712`, already delivered | amends | Amend a shipped Story from a **delta envelope**. |
26
25
 
27
26
  **Resolving a bare id.** Read live state rather than asking: `agent::done` can
28
- only be amended, an open unplanned issue can only be planned. **Announce the
27
+ only be amended, an open unplanned issue only planned. **Announce the
29
28
  derivation** — "4712 is `agent::done` → amending". Ask **only** for an open
30
29
  Story already at `agent::ready`.
31
30
 
32
31
  ## Saying what you want
33
32
 
34
33
  No flags to remember — state intent; the workflow fills in the CLI
35
- ([reference](helpers/plan-reference.md)). Run scripts with `--help`.
34
+ ([ref](helpers/plan-reference.md)). Run scripts with `--help`.
36
35
 
37
36
  `--yes` is **runner-set, never operator-typed** — cron, `/loop`, and headless
38
37
  dispatch set it to mean *nobody is at the keyboard*, which auto-proceeds the
39
- gates below (#1 and #2). Never offer it to an operator or an attended run.
38
+ gates below (#1 and #2) and skips #3. Never offer it to an operator.
40
39
 
41
40
  ## Default-single split policy
42
41
 
43
42
  Author **one Story** unless the pieces have **near-zero overlap** or sit across
44
43
  an **architectural seam**. Coupled work stays one Story — `## Slicing`
45
- checkpoints, not sibling tickets
46
- ([detail](helpers/plan-reference.md)). **N=1 is lean.**
44
+ checkpoints, not sibling tickets ([ref](helpers/plan-reference.md)).
47
45
 
48
46
  ## Procedure
49
47
 
@@ -52,56 +50,56 @@ checkpoints, not sibling tickets
52
50
  ```bash
53
51
  node .agents/scripts/plan-context.js --seed "<seed>" \
54
52
  --out temp/plan-<slug>/plan-context.json
55
- # or: --seed-file <path> | --tickets 123,456 | --amends #<id>
53
+ # or: --seed-file <path> | --tickets 123,456 | --amends #<id>
56
54
  ```
57
55
 
58
56
  **Always pass `--out`.** Persist auto-discovers the envelope from `--plan-dir`
59
- and derives source ids from its `sourceTickets[]`; the CLI also writes
57
+ and derives source ids from its `sourceTickets[]`; it also writes
60
58
  **`stories.template.json`**, step 2's skeleton.
61
59
 
62
60
  The envelope carries docs context, the story-author prompt, `sourceTickets[]`,
63
- `duplicates[]` (open **Stories**, never Epics) and advisory `complexitySignals`
64
- (**no routing authority**). A trivial scope can claim the lite route at
65
- persist shape-validated, failing closed to `full`
66
- ([detail](helpers/plan-reference.md)).
61
+ `duplicates[]` (open **Stories**, never Epics), `epicCandidates[]` +
62
+ `dependencyCandidates[]` (Gate #3; path collisions) and advisory
63
+ `complexitySignals` (**no routing authority**). A trivial scope can claim the
64
+ lite route at persist — shape-validated, failing closed to `full`
65
+ ([ref](helpers/plan-reference.md)).
67
66
 
68
- **Triage each unknown by resolver** ([detail](helpers/plan-reference.md)): an
67
+ **Triage each unknown by resolver** ([ref](helpers/plan-reference.md)): an
69
68
  **AFK** unknown (research settles it) is resolved before authoring, never
70
- assumed; a **HITL** unknown (an operator call) goes to Gate #1 as "needs your
71
- decision". Under `--yes` do not ask free-form operator questions AFK unknowns
72
- are still researched; only HITL unknowns land in Key Assumptions, each marked a
73
- decision-made-by-default.
69
+ assumed; a **HITL** unknown goes to Gate #1. Under `--yes` do not ask free-form
70
+ operator questions AFK unknowns are still researched; only HITL unknowns land
71
+ in Key Assumptions, each a decision-made-by-default.
74
72
 
75
73
  **Gate #1** — STOP to confirm the sharpened plan intent and any
76
74
  duplicate-candidate review. Under `--yes`, auto-proceed.
77
75
 
78
- On a truthy `memoryPoolAdvisory.recommend`, name [`/memory-consolidate`](memory-consolidate.md)
79
- as an operator option, quoting its `reasons[]` — advisory, never invoked here.
76
+ On a truthy `memoryPoolAdvisory.recommend`, name
77
+ [`/memory-consolidate`](memory-consolidate.md) quoting its `reasons[]`;
78
+ advisory.
80
79
 
81
80
  On a truthy `deliverLightSuggestion.suggested`, offer — advisory, never an
82
- automatic reroute — to deliver the seed instead; on confirm, route **in this
81
+ automatic reroute — to deliver the seed instead; on confirm route **in this
83
82
  session** into [`helpers/deliver-light.md`](helpers/deliver-light.md), its gate
84
- filled from this envelope. A truthy `complexitySignals.uiSurface` marks a
85
- UI-touching plan: name [`/prototype`](prototype.md) as an operator option,
86
- never invoke it here. [Both offers](helpers/plan-reference.md).
83
+ filled from this envelope. A truthy `complexitySignals.uiSurface` names
84
+ [`/prototype`](prototype.md); never invoke it here.
85
+ [Both](helpers/plan-reference.md).
87
86
 
88
87
  ### 2. Author
89
88
 
90
- **One-shot authoring.** Start from `stories.template.json`; author
91
- `stories.json` in one pass. `body` is markdown **or** a structured object;
89
+ **One-shot authoring.** From `stories.template.json`, author `stories.json`
90
+ in one pass. `body` is markdown **or** a structured object;
92
91
  persist parses either, serializes canonical markdown and syncs top-level
93
- `acceptance[]` / `verify[]` into it — never dual-author those lists.
92
+ `acceptance[]` / `verify[]` in — never dual-author them.
94
93
 
95
94
  **Grounding = your reads + Phase 8.** Nothing inventories the repo: read each
96
- file you cite; persist's file-assumption gate hard-errors on any
97
- `{path, assumption}` absent from the tree. Entry fields:
98
- [reference](helpers/plan-reference.md).
95
+ file you cite; persist hard-errors on any `{path, assumption}` absent from the
96
+ tree. Fields: [ref](helpers/plan-reference.md).
99
97
 
100
98
  Artifacts under `temp/plan-<slug>/`: `stories.json` (**length 1 by default**;
101
99
  over-budget Specs fail closed — split or tighten, never under `docs/`); optional
102
- `techspec.md` (**N===1 only** folded into `## Spec`); optional
103
- `acceptance-manifest.json` (N>1 partition — `--plan-acceptance`). For N=1 use
104
- the envelope `systemPrompts.story`; split only under the policy above.
100
+ `techspec.md` (**N===1 only**, folded into `## Spec`) and
101
+ `acceptance-manifest.json` (N>1 — `--plan-acceptance`). Use the envelope
102
+ `systemPrompts.story`; split only under the policy above.
105
103
 
106
104
  **Tickets mode:** every Story authors a top-level `supersedes[]`; persist
107
105
  refuses a partial map ([shape](helpers/plan-reference.md)).
@@ -114,10 +112,10 @@ node .agents/scripts/plan-critics.js \
114
112
  [--tech-spec temp/plan-<slug>/techspec.md]
115
113
  ```
116
114
 
117
- Run **before** persist — the last point a finding folds into a re-author.
118
- It exits 0 on **any** verdict (verdicts route work, they do not gate) and exits
119
- **1** only on a usage/IO error — no critic ran, no skip ledgered: **do not
120
- proceed to Persist**, fix and re-run.
115
+ Run **before** persist — the last point a finding folds into a re-author. It
116
+ exits 0 on **any** verdict (verdicts route work, they do not gate) and exits
117
+ **1** only on a usage/IO error — no critic ran: **do not proceed to Persist**,
118
+ fix and re-run.
121
119
 
122
120
  - **Both `dispatch: false`** — proceed to Persist (each skip is ledgered).
123
121
  - **Either `dispatch: true`** — dispatch **one fresh-context, maker-blind
@@ -125,16 +123,19 @@ proceed to Persist**, fix and re-run.
125
123
  authoring transcript), fold findings into Gate #2 or a re-author round, re-run
126
124
  this step. Pre-mortem triggers (incl. the external-dependency probe), the
127
125
  advisory-only `textHygiene.findings[]` lints and dispatch shape:
128
- [reference § Critic dispatch detail](helpers/plan-reference.md).
126
+ [reference](helpers/plan-reference.md).
129
127
 
130
128
  ### 3. Persist
131
129
 
132
130
  **Gate #2** — STOP for approval before persist **only** when the operator asked
133
131
  to review (`--force-review`). Under `--yes`, auto-proceed.
134
132
 
135
- Run persist with `--dry-run` **first** same command, writes suppressed;
136
- every gate runs before the first `createIssue`
137
- ([the list](helpers/plan-reference.md)):
133
+ **Gate #3 adopt, else create.** Offer the top `epicCandidates[]` Epic at
134
+ **any N** (`--epic <id>`); else, at **N>2**, a new container (`--epic-title` /
135
+ `--epic-goal`). Never unasked ([ref](helpers/plan-reference.md)).
136
+
137
+ Run persist `--dry-run` **first** — same command, writes suppressed; every gate
138
+ runs before the first `createIssue` ([list](helpers/plan-reference.md)):
138
139
 
139
140
  ```bash
140
141
  node .agents/scripts/plan-persist.js \
@@ -142,24 +143,29 @@ node .agents/scripts/plan-persist.js \
142
143
  --plan-dir temp/plan-<slug> \
143
144
  [--plan-acceptance temp/plan-<slug>/acceptance-manifest.json] \
144
145
  [--tech-spec temp/plan-<slug>/techspec.md] \
145
- [--source-tickets 123,456]
146
+ [--source-tickets 123,456] \
147
+ [--epic <id> | --epic-title "<name>" --epic-goal "<one paragraph>"]
146
148
  ```
147
149
 
148
- At lite shape, `--chain-on-clean` folds a clean dry-run into the real persist;
149
- a full plan keeps its review trip.
150
+ At lite shape `--chain-on-clean` folds a clean dry-run into the persist; a full
151
+ plan keeps its review trip.
150
152
 
151
153
  Persist creates `type::story` issue(s), a **metadata-only** `plan-run::<id>`
152
- label, and `blocked by #<id>` footers for N>1 `depends_on` edges.
153
- `agent::ready` is the **terminal** flip after receipts land; stdout is pure
154
- JSON. Tickets mode also comments on and closes each source id
155
- ([detail](helpers/plan-reference.md)).
154
+ label, `blocked by #<id>` footers for every `depends_on` edge, and on a Gate #3
155
+ yes links them under a `type::epic` container (adopted or new). `agent::ready`
156
+ is the **terminal** flip after receipts land; stdout is pure JSON. Tickets mode
157
+ also comments on and closes each source id ([ref](helpers/plan-reference.md)).
156
158
 
157
159
  ## Constraints
158
160
 
159
- - `/mandrel-plan` starts delivery **only** through a confirmed Gate #1 light route —
160
- never off its own authored Stories, which land via [`/mandrel-deliver`](mandrel-deliver.md).
161
+ - `/mandrel-plan` starts delivery **only** through a confirmed Gate #1 light
162
+ route — never off its Stories, which land via
163
+ [`/mandrel-deliver`](mandrel-deliver.md).
161
164
  - Duplicate search targets open Stories (`type::story`), not Epics; and
162
165
  deterministic gates still fail closed under `--yes`.
166
+ - A container Epic is never a work item and only an **open** one is adoptable;
167
+ no Story body gains an `Epic: #N` footer (linkage is parent→child only).
168
+ - `depends_on` takes a sibling slug or `#<id>` (open Story).
163
169
 
164
170
  ## See also
165
171
 
@@ -42,7 +42,8 @@ Constraints delta.
42
42
  > triage-ready finding without breaking stride — then, when the testing pass is
43
43
  > done, turned into a plan in one batch.
44
44
  >
45
- > **Skills**: `core/qa-coverage-mapping`
45
+ > **Rules**: [`testing-standards.md`](../rules/testing-standards.md)
46
+ > (§ The Three Tiers — the tier-classification rules enrichment applies)
46
47
 
47
48
  ## Role framing
48
49
 
@@ -106,7 +107,8 @@ ledger is hard-gated.**
106
107
 
107
108
  Goal: become the operator's QA assistant before any observation arrives.
108
109
 
109
- 1. Re-read the QA role framing and `core/qa-coverage-mapping` skill.
110
+ 1. Re-read the QA role framing and the tier-classification rules in
111
+ [`testing-standards.md`](../rules/testing-standards.md) (§ The Three Tiers).
110
112
  2. **Load codebase context.** Read the files in `project.docsContextFiles`
111
113
  (architecture, decisions, patterns) and, when the testing touches UI/routing,
112
114
  `docs/style-guide.md` / `docs/web-routes.md`. This is the context you will
@@ -176,17 +178,16 @@ every decision to the shared helpers; never re-derive them in prose.
176
178
  `gh issue view <ticketNumber> --json title,body,labels`, and verify each
177
179
  surface-map path resolves with `git cat-file -e HEAD:<path>` — flag every
178
180
  miss rather than citing a path that does not exist.
179
- 4. **Compute the coverage verdict** for the surface the observation points at,
180
- via [`coverage-verdict.js`](../scripts/lib/qa/coverage-verdict.js) the
181
- deterministic seam behind the
182
- [`core/qa-coverage-mapping`](../skills/core/qa-coverage-mapping/SKILL.md)
183
- skill. Read that skill for how to assemble the `surface` input and read the
184
- per-tier `{present|absent}` verdict.
185
- 5. **Name the missing test** (if any) from that verdict: take the lowest tier
186
- the verdict marks `absent` (unit → contract → acceptance) and write one
187
- concrete sentence describing the test that would close it. Every tier
188
- `present` means no missing test. Record that sentence as the ledger item's
189
- `missingTest`.
181
+ 4. **Read the coverage tiers** for the surface the observation points at:
182
+ gather the tests that exercise it and classify each by path per
183
+ [`testing-standards.md` § The Three Tiers](../rules/testing-standards.md#the-three-tiers)
184
+ — a `.feature` file is **acceptance**, a path containing `/contract/` or
185
+ `.contract.test.` is **contract**, and a path containing `.test.` or
186
+ `__tests__/` is **unit**. A skipped test leaves its tier uncovered.
187
+ 5. **Name the missing test** (if any): take the lowest tier with no live test
188
+ (unit → contract → acceptance) and write one concrete sentence describing
189
+ the test that would close it. Every tier covered means no missing test.
190
+ Record that sentence as the ledger item's `missingTest`.
190
191
  6. **Classify** the finding via
191
192
  [`classify-finding.js`](../scripts/lib/findings/classify-finding.js) so the
192
193
  tentative `class` resolves to the correct focus/meta label set. The helper
@@ -267,10 +268,12 @@ the `/qa-assist`-specific deltas are:
267
268
  - **Persistent, resumable rolling session** — `/qa-assist` defaults to resuming
268
269
  the same session and appending; a reused session carries the untriaged backlog
269
270
  forward and never overwrites a prior ledger.
270
- - **Enrichment delegates where a helper exists** — the coverage verdict and
271
- the finding classification come from their deterministic helpers, never from
272
- prose. Context lookup and the missing-test sentence are the model's own work:
273
- they are judgments, not computations, and routing them through a module only
271
+ - **Enrichment delegates where a helper exists** — the finding classification
272
+ comes from its deterministic helper, never from prose; tier placement comes
273
+ from the three path rules in
274
+ [`testing-standards.md`](../rules/testing-standards.md#the-three-tiers).
275
+ Context lookup and the missing-test sentence are the model's own work: they
276
+ are judgments, not computations, and routing them through a module only
274
277
  bought a round-trip.
275
278
 
276
279
  ## See also
@@ -34,7 +34,7 @@ Constraints delta.
34
34
  > or Feature, a regression sweep over a risky surface before `/mandrel-deliver`, or a
35
35
  > structured agent-driven bug-hunt captured into a triageable ledger.
36
36
  >
37
- > **Skills**: `core/qa-coverage-mapping`, `stack/qa/qa-explore-driving`
37
+ > **Skills**: `stack/qa/qa-harness`
38
38
 
39
39
  ## Role framing
40
40
 
@@ -45,15 +45,16 @@ the surface shows. Apply the QA skills below; there is no separate persona pack.
45
45
  ## Driving conventions
46
46
 
47
47
  Before you drive a surface, read the
48
- [`stack/qa/qa-explore-driving`](../skills/stack/qa/qa-explore-driving/SKILL.md)
49
- skill — the **one** conventions reference for the *how* of agent-driven
50
- exploration (navigation-first driving as the default; static driving as the
51
- documented interim chosen at Plan time only where no seam resolves;
52
- authenticated driving through the resolved environment's `signInSeam`; broken
53
- navigation is a finding, not a workaround). The driving method (drive vs.
54
- static) is a **Plan-phase decision recorded in the ledger**; do not switch
55
- methods mid-surface without a new Plan note. Do not restate these conventions
56
- inline the skill owns them.
48
+ [`stack/qa/qa-harness`](../skills/stack/qa/qa-harness/SKILL.md)
49
+ skill — the **one** conventions reference for the *how* of agent-driven driving,
50
+ shared with the known-scenario sweep (navigation-first driving as the default;
51
+ static driving as the documented interim chosen at Plan time only where no seam
52
+ resolves; authenticated driving through the resolved environment's
53
+ `signInSeam`; broken navigation is a finding, not a workaround). Its § 5 carries
54
+ the exploratory-mode deltas. The driving method (drive vs. static) is a
55
+ **Plan-phase decision recorded in the ledger**; do not switch methods
56
+ mid-surface without a new Plan note. Do not restate these conventions inline —
57
+ the skill owns them.
57
58
 
58
59
  ## Slash Command
59
60
 
@@ -110,7 +111,7 @@ then the captured ledger), and wait. If the operator does not confirm, hold.
110
111
  Goal: agree on **what** will be explored and **how the agent will drive it**
111
112
  before touching the surface.
112
113
 
113
- 1. Re-read the `stack/qa/qa-explore-driving` skill and resolve the contract and
114
+ 1. Re-read the `stack/qa/qa-harness` skill and resolve the contract and
114
115
  session (above).
115
116
  2. **Resolve the target environment** via
116
117
  [`resolveQaEnvironment`](../scripts/lib/qa/resolve-qa-contract.js) — it keys
@@ -149,8 +150,8 @@ Goal: **the agent drives the confirmed surface itself** and records its
149
150
  observations. **This phase is strictly read-only.**
150
151
 
151
152
  > **Read-only invariant.** The agent observes; it never mutates. Per
152
- > [`stack/qa/qa-explore-driving`](../skills/stack/qa/qa-explore-driving/SKILL.md)
153
- > § 3 (inviolable per [`security-baseline.md`](../rules/security-baseline.md)),
153
+ > [`stack/qa/qa-harness`](../skills/stack/qa/qa-harness/SKILL.md)
154
+ > § 2 (inviolable per [`security-baseline.md`](../rules/security-baseline.md)),
154
155
  > do **not** edit source, run write commands, file or label GitHub issues,
155
156
  > change tickets, submit destructive forms, or alter the product under test. The
156
157
  > only write Capture performs is **appending ledger lines to
@@ -170,17 +171,16 @@ For each observation the agent makes while driving:
170
171
 
171
172
  1. **Redact first** (per [`helpers/qa-core.md`](helpers/qa-core.md)) — scrub the
172
173
  evidence string through `redactEvidence` before it touches disk.
173
- 2. **Compute the coverage verdict** for the surface the observation points at,
174
- via [`coverage-verdict.js`](../scripts/lib/qa/coverage-verdict.js) the
175
- deterministic seam behind the
176
- [`core/qa-coverage-mapping`](../skills/core/qa-coverage-mapping/SKILL.md)
177
- skill. Read that skill for how to assemble the `surface` input and read the
178
- per-tier `{present|absent}` verdict.
179
- 3. **Name the missing test** (if any) from that verdict: take the lowest tier
180
- the verdict marks `absent` (unit → contract → acceptance) and write one
181
- concrete sentence describing the test that would close it. Every tier
182
- `present` means no missing test. Record that sentence as the ledger item's
183
- `missingTest` (or `null`).
174
+ 2. **Read the coverage tiers** for the surface the observation points at:
175
+ gather the tests that exercise it and classify each by path per
176
+ [`testing-standards.md` § The Three Tiers](../rules/testing-standards.md#the-three-tiers)
177
+ — a `.feature` file is **acceptance**, a path containing `/contract/` or
178
+ `.contract.test.` is **contract**, and a path containing `.test.` or
179
+ `__tests__/` is **unit**. A skipped test leaves its tier uncovered.
180
+ 3. **Name the missing test** (if any): take the lowest tier with no live test
181
+ (unit → contract → acceptance) and write one concrete sentence describing
182
+ the test that would close it. Every tier covered means no missing test.
183
+ Record that sentence as the ledger item's `missingTest` (or `null`).
184
184
  4. **Append a `QaLedgerItem`** to the ledger (shape per
185
185
  [`helpers/qa-core.md`](helpers/qa-core.md)): a stable `id`, the redacted
186
186
  `evidence`, the `coverage` label (the `surface`, or `unknown`), a tentative
@@ -215,7 +215,7 @@ resumed session will pick up.
215
215
  Beyond the shared core ([`helpers/qa-core.md`](helpers/qa-core.md): contract +
216
216
  loud failure, session/ledger, redact-first, QaLedgerItem, triage, HITL gate)
217
217
  and the driving conventions
218
- ([`stack/qa/qa-explore-driving`](../skills/stack/qa/qa-explore-driving/SKILL.md)),
218
+ ([`stack/qa/qa-harness`](../skills/stack/qa/qa-harness/SKILL.md)),
219
219
  the `/qa-explore`-specific deltas are:
220
220
 
221
221
  - **Agent-led, bounded per surface.** The agent drives one named surface per
@@ -231,10 +231,11 @@ the `/qa-explore`-specific deltas are:
231
231
  and fall back to static.
232
232
  - **Broken navigation is a finding, not a workaround** — never URL-jump around a
233
233
  missing affordance, a nav 404, or a guard redirect loop.
234
- - **Delegate the coverage verdict to the helper.** Tier placement comes from
235
- [`coverage-verdict.js`](../scripts/lib/qa/coverage-verdict.js) deterministic,
236
- never re-derived in prose. The missing-test sentence is yours to write from
237
- that verdict's lowest `absent` tier.
234
+ - **Read tier placement from the rule, not from prose you invent.** The three
235
+ path rules in
236
+ [`testing-standards.md` § The Three Tiers](../rules/testing-standards.md#the-three-tiers)
237
+ decide which tier a test occupies; the missing-test sentence is yours to write
238
+ from the lowest uncovered tier.
238
239
 
239
240
  ## See also
240
241
 
@@ -29,7 +29,8 @@ the agent never invents those decisions in prose.
29
29
  > passes before `/mandrel-deliver`, or on demand while debugging a Story's
30
30
  > user-visible behavior in a live browser.
31
31
  >
32
- > **Skills**: `stack/qa/gherkin-authoring`, `stack/qa/playwright-bdd`
32
+ > **Skills**: `stack/qa/qa-harness` (driving and instrumentation
33
+ > conventions), `stack/qa/gherkin-authoring` and `stack/qa/playwright-bdd`
33
34
  > (authoring reference; this harness owns execution)
34
35
 
35
36
  ## Slash Command
package/docs/CHANGELOG.md CHANGED
@@ -15,6 +15,36 @@ All notable changes to this project will be documented in this file.
15
15
  -->
16
16
  <!-- markdownlint-disable-file MD004 MD012 MD037 -->
17
17
 
18
+ ## [2.41.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.40.0...mandrel-v2.41.0) (2026-09-06)
19
+
20
+
21
+ ### Added
22
+
23
+ * /mandrel-plan adopts an existing open Epic and declares depends_on edges on existing open Stories ([#5155](https://github.com/dsj1984/mandrel/issues/5155)) ([#5156](https://github.com/dsj1984/mandrel/issues/5156)) ([9119f31](https://github.com/dsj1984/mandrel/commit/9119f313146ab08ed676909f9b0a61671c4d6069))
24
+
25
+
26
+ ### Changed
27
+
28
+ * **agents:** retire four frontier-known rules/skills, fold two more into rules (refs [#5158](https://github.com/dsj1984/mandrel/issues/5158)) ([#5162](https://github.com/dsj1984/mandrel/issues/5162)) ([065f883](https://github.com/dsj1984/mandrel/commit/065f8839fafcc7064e4ad6d2ea30f2bfebbd5c0c))
29
+ * **qa:** fold qa-explore-driving into qa-harness (refs [#5159](https://github.com/dsj1984/mandrel/issues/5159)) ([#5163](https://github.com/dsj1984/mandrel/issues/5163)) ([2fbc8db](https://github.com/dsj1984/mandrel/commit/2fbc8db5a420450414cfd046bb6418e0c210bf7f))
30
+ * **rules:** trim surviving rules and core skills to their contracts (refs [#5160](https://github.com/dsj1984/mandrel/issues/5160)) ([#5164](https://github.com/dsj1984/mandrel/issues/5164)) ([f0e6a62](https://github.com/dsj1984/mandrel/commit/f0e6a62feaba275377c9cc435f03ea6089008148))
31
+
32
+ ## [2.40.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.39.0...mandrel-v2.40.0) (2026-09-06)
33
+
34
+
35
+ ### Added
36
+
37
+ * audit-to-stories --auto: persist the cross-run ledger via a `--ledger-commit` PR and ship the audit-sweep runbook template ([#5145](https://github.com/dsj1984/mandrel/issues/5145)) ([#5151](https://github.com/dsj1984/mandrel/issues/5151)) ([7274e6a](https://github.com/dsj1984/mandrel/commit/7274e6abe1bbf4fca6e1ed09abc8b4ebc9598d89))
38
+ * audit-to-stories: parse `####` findings under grouping headers and fail closed on a missing or mismatched `Severity tally:` line ([#5144](https://github.com/dsj1984/mandrel/issues/5144)) ([#5149](https://github.com/dsj1984/mandrel/issues/5149)) ([d9d8275](https://github.com/dsj1984/mandrel/commit/d9d827584989406e85d3e22110e6b741dab837e9))
39
+ * container Epic: /mandrel-plan offers one above 2 Stories, /mandrel-deliver expands an Epic id, /audit-to-stories requests one by default ([#5139](https://github.com/dsj1984/mandrel/issues/5139)) ([#5147](https://github.com/dsj1984/mandrel/issues/5147)) ([60dd912](https://github.com/dsj1984/mandrel/commit/60dd912f9d00dbf2fb7c17f8c98639b4008b5892))
40
+
41
+
42
+ ### Fixed
43
+
44
+ * audit-to-stories --wire-edges: carry the live provider's write ports through the dedup adapter ([#5143](https://github.com/dsj1984/mandrel/issues/5143)) ([#5146](https://github.com/dsj1984/mandrel/issues/5146)) ([380577e](https://github.com/dsj1984/mandrel/commit/380577e5e8f215bf28bb15ef8f2ac03c5958f0b8))
45
+ * **tests:** assert the report path separator-agnostically for Windows ([#5153](https://github.com/dsj1984/mandrel/issues/5153)) ([afe7fda](https://github.com/dsj1984/mandrel/commit/afe7fda7aa257bfb5e0745160363189ed84c2ad1))
46
+ * **tests:** import the provider fixture as a file URL for Windows ([#5150](https://github.com/dsj1984/mandrel/issues/5150)) ([797af46](https://github.com/dsj1984/mandrel/commit/797af46269e22e878fbd13293e5e5df6a044a1d3))
47
+
18
48
  ## [2.39.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.38.0...mandrel-v2.39.0) (2026-09-05)
19
49
 
20
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mandrel",
3
- "version": "2.39.0",
3
+ "version": "2.41.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/",
@@ -1,180 +0,0 @@
1
- # CHANGELOG Style Contract
2
-
3
- This rule governs the shape of per-release entries in the project CHANGELOG
4
- (typically `docs/CHANGELOG.md` or `CHANGELOG.md`). It applies whenever a
5
- release entry is authored or edited — most commonly inside Story #N's
6
- docs sweep before `/mandrel-deliver` opens the release PR.
7
-
8
- The contract is **guidance-tier**: no automated gate fails a close when an
9
- entry drifts off-template. It still binds every author.
10
-
11
- ## Goal
12
-
13
- A reader scanning release notes should identify what ships in a release in
14
- under 30 seconds. Breaking changes, config-shape changes, and CLI renames
15
- must be impossible to miss. Internal refactor detail belongs in commit
16
- messages and PR descriptions — not here.
17
-
18
- ## Per-Release Entry Shape
19
-
20
- Every entry starts with a version header line already produced by the
21
- release tooling:
22
-
23
- ```markdown
24
- ## [X.Y.Z] - YYYY-MM-DD
25
- ```
26
-
27
- Immediately below, the entry MUST have:
28
-
29
- 1. **A short section header** naming the theme of the release — one line,
30
- Sentence case, no trailing punctuation.
31
-
32
- ```markdown
33
- ### Epic-runner throughput & caching pass
34
- ```
35
-
36
- 2. **A 1–3 sentence theme paragraph** that tells the reader, in plain
37
- English, what the release is about and why it matters. No bullets, no
38
- sub-headers, no code fences.
39
-
40
- 3. **Bullets of user-visible changes**, grouped by natural topic if the
41
- release spans more than one theme. Each bullet leads with a bold phrase
42
- naming the change, followed by a one- or two-sentence explanation.
43
-
44
- ```markdown
45
- ## [5.21.0] - 2026-04-24
46
-
47
- ### Epic-runner throughput & caching pass
48
-
49
- Performance and observability pass across the epic-runner hot paths — wave
50
- gating, commit assertion, progress reporting, and label polling. Caching
51
- and bounded concurrency throughout; new per-phase timing surface.
52
-
53
- - **Bounded-concurrency parallelism.** Wave gating, commit assertion, and
54
- progress reporting now fan out in parallel with a configurable cap.
55
- - **Per-phase timing surface.** Story close posts a structured comment
56
- with per-phase timings; the Epic progress comment aggregates median
57
- and p95 across closed stories.
58
- ```
59
-
60
- ## Bullets: What Counts as "User-Visible"
61
-
62
- Include:
63
-
64
- - New CLI commands, flags, or scripts the operator invokes.
65
- - New or renamed labels, ticket shapes, or workflow phases the operator
66
- touches.
67
- - New or renamed configuration keys, with the old → new mapping if any.
68
- - New behavioural guarantees (e.g., "retries on transient errors").
69
- - Bug fixes the operator would otherwise trip over.
70
- - Performance changes with a user-observable magnitude.
71
-
72
- Exclude:
73
-
74
- - Internal refactors with no behavioural delta.
75
- - Test additions, coverage bumps, lint cleanups.
76
- - Module renames or file moves invisible to operators.
77
- - Per-phase implementation details ("now uses a BFS walker").
78
-
79
- ## Banned Content
80
-
81
- The following MUST NOT appear in a release entry:
82
-
83
- - **Per-ticket citations.** No `(Epic #553)`, `(resolves #612)`,
84
- `(Story #645)` in bullet text. The theme paragraph may reference the
85
- Epic once when the release is scoped to one Epic — that is the only
86
- allowed citation, and only there.
87
- - **Internal file paths** (`lib/orchestration/epic-runner/commit-assertion.js`,
88
- `.agents/scripts/story-init.js`). Callers care what changed, not
89
- where it lives.
90
- - **Internal function, class, or method names** (`finalizeMerge`,
91
- `WorkspaceProvisioner.verify`, `cascadeCompletion`). Name the behaviour,
92
- not the symbol — unless the symbol is part of the public API.
93
- - **Test counts** (`47 new tests`, `95% coverage`). Tests are a means, not
94
- a ship artefact.
95
- - **Module-sizing stats** (`shrinks epic-runner from 840 to 420 LOC`).
96
- - **Implementation mechanics** (`BFS walker`, `Promise.all over parents`,
97
- `exponential backoff with 3 attempts, 500ms base`) unless the mechanism
98
- is part of a new public contract.
99
-
100
- ## Mandatory Prominence
101
-
102
- The following categories MUST be called out visibly — typically in **bold**
103
- at the start of a bullet, or in a short dedicated section above the
104
- bullet list:
105
-
106
- - **Breaking changes.** A bullet leading with `**Breaking:**` or a
107
- `### Breaking Changes` sub-section. Include the migration path.
108
- - **Config-shape changes.** Moved, removed, renamed, or newly-required
109
- config keys. Old key → new key, or removal notice with remediation.
110
- - **CLI renames.** Old command → new command, including whether the old
111
- name remains as a deprecation alias and for how long.
112
- - **Schema shape changes** on structured comments, manifest files, or
113
- public API payloads. Readers parsing these surfaces must be told.
114
-
115
- If a release ships any of the above, they belong at the top of the bullet
116
- list (or in a dedicated sub-section), not buried mid-list.
117
-
118
- ## Line-Count Guidance
119
-
120
- Soft ceilings, not hard fails:
121
-
122
- - **Non-major release** (patch or minor): **≤60 lines**, including
123
- header, theme paragraph, blank lines, and bullets.
124
- - **Major release**: **≤150 lines**. Major releases span larger surface
125
- and warrant more prominence.
126
-
127
- If an entry exceeds the ceiling, prefer splitting a genuinely multi-theme
128
- release into grouped sub-sections over padding the bullet list. Before
129
- accepting a long entry, ask: which bullets are user-visible, and which
130
- are internal detail that migrated in from the Epic body?
131
-
132
- ## Worked Example — On-Contract
133
-
134
- Off-contract entries — the style that drove the Epic #553 retro action item —
135
- pack several `###` sub-sections into one release and leak internal function
136
- names (`finalizeMerge`, `mergeFeatureBranch`, `ensure()`, `reap()`),
137
- implementation mechanics, internal step numbering, and lock-file name lists
138
- operators cannot act on. The on-contract version collapses all of that:
139
-
140
- ```markdown
141
- ## [5.8.7] - 2026-04-15
142
-
143
- ### Parallel-wave merge robustness
144
-
145
- Parallel story waves kept tripping over each other at integration time.
146
- This release reduces the conflict surface at story close and stabilises
147
- worktree cleanup.
148
-
149
- - **Pre-merge rebase at story close** shrinks the conflict window to
150
- each story's real delta; conflicts above the triage threshold abort
151
- and surface to the operator.
152
- - **Shared-store worktrees.** Per-story worktrees link a shared
153
- `node_modules` store, so parallel waves no longer duplicate installs
154
- or leave residue that blocks reap.
155
- - **`/mandrel-deliver` auto-invokes pre-merge gates** (code review, retro)
156
- inline. `--skip-code-review` is available as an override.
157
- - **Closure sweep covers Epic Health tickets** in addition to PRD and
158
- Tech Spec tickets.
159
- - **Stale-lock sweep** on the shared `.git/` directory runs at
160
- `/mandrel-deliver` start, clearing lock files left behind by interrupted
161
- operations.
162
- ```
163
-
164
- What changed: one theme section instead of five; the paragraph gives the
165
- "why" in two sentences; each bullet leads with the user-visible behaviour
166
- and drops internal symbols, file paths, and step numbers; the override
167
- flag (`--skip-code-review`) is kept because it is part of the public CLI
168
- surface; the lock-file list is dropped because operators do not act on
169
- individual lock names.
170
-
171
- ## When to Deviate
172
-
173
- - **Major releases** may warrant multiple `###` sub-sections under a
174
- single version header when the release genuinely spans multiple themes.
175
- Keep each sub-section on-contract individually.
176
- - **Security fixes** may include CVE-style detail and remediation steps
177
- beyond normal bullet shape — those callouts are always on-contract.
178
- - **When in doubt**, cut more aggressively. A reader can always follow
179
- the Epic link for detail; they cannot un-read bullets that told them
180
- nothing.