mandrel 2.40.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.
- package/.agents/README.md +2 -2
- package/.agents/instructions.md +5 -6
- package/.agents/rules/api-conventions.md +43 -7
- package/.agents/rules/ci-remediation.md +3 -14
- package/.agents/rules/gherkin-standards.md +21 -6
- package/.agents/rules/git-conventions.md +6 -5
- package/.agents/rules/security-baseline.md +6 -7
- package/.agents/rules/testing-standards.md +75 -198
- package/.agents/scripts/install-matrix-assert.js +2 -2
- package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +6 -0
- package/.agents/scripts/lib/orchestration/dependency-candidates.js +139 -0
- package/.agents/scripts/lib/orchestration/epic-candidates.js +159 -0
- package/.agents/scripts/lib/orchestration/epic-checklist.js +103 -0
- package/.agents/scripts/lib/orchestration/epic-container.js +18 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +97 -36
- package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +80 -0
- package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +192 -0
- package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +5 -1
- package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +164 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +14 -2
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +26 -5
- package/.agents/scripts/lib/orchestration/ticket-validator.js +11 -1
- package/.agents/scripts/plan-persist.js +60 -1
- package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +5 -10
- package/.agents/skills/core/browser-testing-with-devtools/reference.md +7 -46
- package/.agents/skills/core/code-review-and-quality/SKILL.md +0 -5
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +0 -3
- package/.agents/skills/core/gates-and-baselines/SKILL.md +10 -137
- package/.agents/skills/core/gates-and-baselines/reference.md +103 -0
- package/.agents/skills/core/idea-refinement/SKILL.md +2 -18
- package/.agents/skills/core/security-and-hardening/SKILL.md +2 -4
- package/.agents/skills/core/security-and-hardening/reference.md +0 -70
- package/.agents/skills/skills.index.json +10 -70
- package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +4 -10
- package/.agents/skills/stack/qa/gherkin-authoring/reference.md +9 -113
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +29 -154
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +157 -98
- package/.agents/workflows/git-cleanup.md +3 -2
- package/.agents/workflows/git-deliver.md +3 -2
- package/.agents/workflows/helpers/plan-reference.md +82 -2
- package/.agents/workflows/mandrel-plan.md +45 -45
- package/.agents/workflows/qa-assist.md +20 -17
- package/.agents/workflows/qa-explore.md +30 -29
- package/.agents/workflows/qa-run.md +2 -1
- package/docs/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/.agents/rules/changelog-style.md +0 -180
- package/.agents/rules/shell-conventions.md +0 -61
- package/.agents/scripts/lib/qa/coverage-verdict.js +0 -214
- package/.agents/skills/core/api-and-interface-design/SKILL.md +0 -55
- package/.agents/skills/core/api-and-interface-design/reference.md +0 -76
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +0 -45
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +0 -56
- package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +0 -54
- package/.agents/skills/core/idea-refinement/refinement-criteria.md +0 -155
- package/.agents/skills/core/idea-refinement/scripts/idea-refine.sh +0 -15
- package/.agents/skills/core/qa-coverage-mapping/SKILL.md +0 -105
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +0 -152
- package/.agents/skills/stack/qa/vitest/SKILL.md +0 -22
|
@@ -1,8 +1,7 @@
|
|
|
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
|
|
@@ -19,20 +18,20 @@ mode from what the operator typed, announce it, act**:
|
|
|
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
|
|
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
|
|
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 only planned. **Announce the
|
|
29
|
-
"4712 is `agent::done` → amending". Ask **only** for an open
|
|
30
|
-
`agent::ready`.
|
|
27
|
+
only be amended, an open unplanned issue only planned. **Announce the
|
|
28
|
+
derivation** — "4712 is `agent::done` → amending". Ask **only** for an open
|
|
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
|
-
([
|
|
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
|
|
@@ -42,8 +41,7 @@ gates below (#1 and #2) and skips #3. Never offer it to an operator.
|
|
|
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,19 +50,21 @@ 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>
|
|
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[]`;
|
|
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)
|
|
64
|
-
(
|
|
65
|
-
|
|
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)).
|
|
66
66
|
|
|
67
|
-
**Triage each unknown by resolver** ([
|
|
67
|
+
**Triage each unknown by resolver** ([ref](helpers/plan-reference.md)): an
|
|
68
68
|
**AFK** unknown (research settles it) is resolved before authoring, never
|
|
69
69
|
assumed; a **HITL** unknown goes to Gate #1. Under `--yes` do not ask free-form
|
|
70
70
|
operator questions — AFK unknowns are still researched; only HITL unknowns land
|
|
@@ -74,26 +74,26 @@ in Key Assumptions, each a decision-made-by-default.
|
|
|
74
74
|
duplicate-candidate review. Under `--yes`, auto-proceed.
|
|
75
75
|
|
|
76
76
|
On a truthy `memoryPoolAdvisory.recommend`, name
|
|
77
|
-
[`/memory-consolidate`](memory-consolidate.md) quoting its `reasons[]
|
|
78
|
-
advisory
|
|
77
|
+
[`/memory-consolidate`](memory-consolidate.md) quoting its `reasons[]`;
|
|
78
|
+
advisory.
|
|
79
79
|
|
|
80
80
|
On a truthy `deliverLightSuggestion.suggested`, offer — advisory, never an
|
|
81
81
|
automatic reroute — to deliver the seed instead; on confirm route **in this
|
|
82
82
|
session** into [`helpers/deliver-light.md`](helpers/deliver-light.md), its gate
|
|
83
83
|
filled from this envelope. A truthy `complexitySignals.uiSurface` names
|
|
84
|
-
[`/prototype`](prototype.md)
|
|
85
|
-
[Both
|
|
84
|
+
[`/prototype`](prototype.md); never invoke it here.
|
|
85
|
+
[Both](helpers/plan-reference.md).
|
|
86
86
|
|
|
87
87
|
### 2. Author
|
|
88
88
|
|
|
89
|
-
**One-shot authoring.**
|
|
90
|
-
|
|
89
|
+
**One-shot authoring.** From `stories.template.json`, author `stories.json`
|
|
90
|
+
in one pass. `body` is markdown **or** a structured object;
|
|
91
91
|
persist parses either, serializes canonical markdown and syncs top-level
|
|
92
|
-
`acceptance[]` / `verify[]` in — never dual-author
|
|
92
|
+
`acceptance[]` / `verify[]` in — never dual-author them.
|
|
93
93
|
|
|
94
94
|
**Grounding = your reads + Phase 8.** Nothing inventories the repo: read each
|
|
95
|
-
file you cite; persist hard-errors on any `{path, assumption}` absent from
|
|
96
|
-
|
|
95
|
+
file you cite; persist hard-errors on any `{path, assumption}` absent from the
|
|
96
|
+
tree. Fields: [ref](helpers/plan-reference.md).
|
|
97
97
|
|
|
98
98
|
Artifacts under `temp/plan-<slug>/`: `stories.json` (**length 1 by default**;
|
|
99
99
|
over-budget Specs fail closed — split or tighten, never under `docs/`); optional
|
|
@@ -112,10 +112,10 @@ node .agents/scripts/plan-critics.js \
|
|
|
112
112
|
[--tech-spec temp/plan-<slug>/techspec.md]
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
Run **before** persist — the last point a finding folds into a re-author.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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.
|
|
119
119
|
|
|
120
120
|
- **Both `dispatch: false`** — proceed to Persist (each skip is ledgered).
|
|
121
121
|
- **Either `dispatch: true`** — dispatch **one fresh-context, maker-blind
|
|
@@ -130,12 +130,12 @@ Persist**, fix and re-run.
|
|
|
130
130
|
**Gate #2** — STOP for approval before persist **only** when the operator asked
|
|
131
131
|
to review (`--force-review`). Under `--yes`, auto-proceed.
|
|
132
132
|
|
|
133
|
-
**Gate #3
|
|
134
|
-
|
|
135
|
-
([
|
|
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
136
|
|
|
137
|
-
Run persist
|
|
138
|
-
|
|
137
|
+
Run persist `--dry-run` **first** — same command, writes suppressed; every gate
|
|
138
|
+
runs before the first `createIssue` ([list](helpers/plan-reference.md)):
|
|
139
139
|
|
|
140
140
|
```bash
|
|
141
141
|
node .agents/scripts/plan-persist.js \
|
|
@@ -144,28 +144,28 @@ node .agents/scripts/plan-persist.js \
|
|
|
144
144
|
[--plan-acceptance temp/plan-<slug>/acceptance-manifest.json] \
|
|
145
145
|
[--tech-spec temp/plan-<slug>/techspec.md] \
|
|
146
146
|
[--source-tickets 123,456] \
|
|
147
|
-
[--epic-title "<name>" --epic-goal "<one paragraph>"]
|
|
147
|
+
[--epic <id> | --epic-title "<name>" --epic-goal "<one paragraph>"]
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
At lite shape `--chain-on-clean` folds a clean dry-run into the
|
|
151
|
-
|
|
150
|
+
At lite shape `--chain-on-clean` folds a clean dry-run into the persist; a full
|
|
151
|
+
plan keeps its review trip.
|
|
152
152
|
|
|
153
153
|
Persist creates `type::story` issue(s), a **metadata-only** `plan-run::<id>`
|
|
154
|
-
label, `blocked by #<id>` footers for
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
([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)).
|
|
159
158
|
|
|
160
159
|
## Constraints
|
|
161
160
|
|
|
162
161
|
- `/mandrel-plan` starts delivery **only** through a confirmed Gate #1 light
|
|
163
|
-
route — never off its
|
|
162
|
+
route — never off its Stories, which land via
|
|
164
163
|
[`/mandrel-deliver`](mandrel-deliver.md).
|
|
165
164
|
- Duplicate search targets open Stories (`type::story`), not Epics; and
|
|
166
165
|
deterministic gates still fail closed under `--yes`.
|
|
167
|
-
- A container Epic is never a work item
|
|
168
|
-
|
|
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).
|
|
169
169
|
|
|
170
170
|
## See also
|
|
171
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
|
-
> **
|
|
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
|
|
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. **
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
5. **Name the missing test** (if any)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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**: `
|
|
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-
|
|
49
|
-
skill — the **one** conventions reference for the *how* of agent-driven
|
|
50
|
-
|
|
51
|
-
documented interim chosen at Plan time only where no seam
|
|
52
|
-
authenticated driving through the resolved environment's
|
|
53
|
-
navigation is a finding, not a workaround).
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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-
|
|
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-
|
|
153
|
-
> §
|
|
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. **
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
3. **Name the missing test** (if any)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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-
|
|
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
|
-
- **
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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/
|
|
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,20 @@ 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
|
+
|
|
18
32
|
## [2.40.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.39.0...mandrel-v2.40.0) (2026-09-06)
|
|
19
33
|
|
|
20
34
|
|
package/package.json
CHANGED
|
@@ -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.
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# Shell & Terminal Conventions
|
|
2
|
-
|
|
3
|
-
This rule applies when running shell commands during agent execution. The host
|
|
4
|
-
shell varies — agents must adapt to the environment.
|
|
5
|
-
|
|
6
|
-
## Detecting the Shell
|
|
7
|
-
|
|
8
|
-
Before chaining commands, check the host shell. Common signals:
|
|
9
|
-
|
|
10
|
-
- `$env:COMSPEC` set / `pwsh.exe` or `powershell.exe` → PowerShell
|
|
11
|
-
- `$SHELL` set to `/bin/bash`, `/bin/zsh`, etc. → POSIX shell
|
|
12
|
-
- Claude Code system prompt or harness directive announces the shell
|
|
13
|
-
|
|
14
|
-
## PowerShell (Windows)
|
|
15
|
-
|
|
16
|
-
PowerShell 5.1 (default on Windows) does **not** support `&&` as a statement
|
|
17
|
-
separator and will throw a parser error. PowerShell 7+ does, but agents
|
|
18
|
-
running on Windows should not assume version 7+.
|
|
19
|
-
|
|
20
|
-
- **Standard separator**: `;` runs the next command regardless of the first's
|
|
21
|
-
exit status.
|
|
22
|
-
- **Success chaining (logical AND)**: `; if ($?) { ... }` runs the second
|
|
23
|
-
command only when the first succeeded.
|
|
24
|
-
- **Example**: `git add . ; if ($?) { git commit -m "..." }`
|
|
25
|
-
|
|
26
|
-
Other PowerShell-isms agents must respect:
|
|
27
|
-
|
|
28
|
-
- Use `$null` (not `/dev/null`).
|
|
29
|
-
- Use `$env:VAR` (not `$VAR`).
|
|
30
|
-
- Use backtick (`` ` ``) for line continuation, not backslash.
|
|
31
|
-
|
|
32
|
-
## POSIX Shells (bash / zsh)
|
|
33
|
-
|
|
34
|
-
`&&` and `||` work natively. No translation needed.
|
|
35
|
-
|
|
36
|
-
- **Success chaining**: `cmd1 && cmd2`
|
|
37
|
-
- **Fallback**: `cmd1 || cmd2`
|
|
38
|
-
|
|
39
|
-
## Cross-Platform Tips
|
|
40
|
-
|
|
41
|
-
- Prefer the host's tool wrappers (Bash tool, etc.) over raw shell strings
|
|
42
|
-
when the harness exposes them — they normalize quoting and escaping.
|
|
43
|
-
- For multi-step pipelines that must run identically across platforms, write
|
|
44
|
-
a Node/Python script and invoke that, rather than chaining shell builtins.
|
|
45
|
-
|
|
46
|
-
## Searching the Workspace
|
|
47
|
-
|
|
48
|
-
Prefer, in order: the host's dedicated grep tool (ripgrep-backed — normalizes
|
|
49
|
-
quoting, respects `.gitignore`, streams results), then `git grep` in a git
|
|
50
|
-
repo (`-l` for filenames only), then `rg` outside a git repo or when you need
|
|
51
|
-
multiline / type filters. Do not read whole files to scan for a pattern.
|
|
52
|
-
|
|
53
|
-
### PowerShell-specific anti-patterns
|
|
54
|
-
|
|
55
|
-
- If you must use `Select-String`, pass `-List` when you only need to
|
|
56
|
-
detect existence or collect file paths — without it, every match streams
|
|
57
|
-
through the pipeline.
|
|
58
|
-
- NEVER chain `Select-Object -Unique` or `Sort-Object` directly after a
|
|
59
|
-
highly recursive `Get-ChildItem` on large trees. Both block the pipeline,
|
|
60
|
-
hold every result in memory, and frequently hang the terminal. Stream
|
|
61
|
-
through `Where-Object` filters first, or pre-narrow with a glob.
|