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.
Files changed (59) hide show
  1. package/.agents/README.md +2 -2
  2. package/.agents/instructions.md +5 -6
  3. package/.agents/rules/api-conventions.md +43 -7
  4. package/.agents/rules/ci-remediation.md +3 -14
  5. package/.agents/rules/gherkin-standards.md +21 -6
  6. package/.agents/rules/git-conventions.md +6 -5
  7. package/.agents/rules/security-baseline.md +6 -7
  8. package/.agents/rules/testing-standards.md +75 -198
  9. package/.agents/scripts/install-matrix-assert.js +2 -2
  10. package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +6 -0
  11. package/.agents/scripts/lib/orchestration/dependency-candidates.js +139 -0
  12. package/.agents/scripts/lib/orchestration/epic-candidates.js +159 -0
  13. package/.agents/scripts/lib/orchestration/epic-checklist.js +103 -0
  14. package/.agents/scripts/lib/orchestration/epic-container.js +18 -2
  15. package/.agents/scripts/lib/orchestration/plan-context.js +97 -36
  16. package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +80 -0
  17. package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +192 -0
  18. package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +5 -1
  19. package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +164 -0
  20. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +14 -2
  21. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +26 -5
  22. package/.agents/scripts/lib/orchestration/ticket-validator.js +11 -1
  23. package/.agents/scripts/plan-persist.js +60 -1
  24. package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +5 -10
  25. package/.agents/skills/core/browser-testing-with-devtools/reference.md +7 -46
  26. package/.agents/skills/core/code-review-and-quality/SKILL.md +0 -5
  27. package/.agents/skills/core/documentation-and-adrs/SKILL.md +0 -3
  28. package/.agents/skills/core/gates-and-baselines/SKILL.md +10 -137
  29. package/.agents/skills/core/gates-and-baselines/reference.md +103 -0
  30. package/.agents/skills/core/idea-refinement/SKILL.md +2 -18
  31. package/.agents/skills/core/security-and-hardening/SKILL.md +2 -4
  32. package/.agents/skills/core/security-and-hardening/reference.md +0 -70
  33. package/.agents/skills/skills.index.json +10 -70
  34. package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +4 -10
  35. package/.agents/skills/stack/qa/gherkin-authoring/reference.md +9 -113
  36. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +29 -154
  37. package/.agents/skills/stack/qa/qa-harness/SKILL.md +157 -98
  38. package/.agents/workflows/git-cleanup.md +3 -2
  39. package/.agents/workflows/git-deliver.md +3 -2
  40. package/.agents/workflows/helpers/plan-reference.md +82 -2
  41. package/.agents/workflows/mandrel-plan.md +45 -45
  42. package/.agents/workflows/qa-assist.md +20 -17
  43. package/.agents/workflows/qa-explore.md +30 -29
  44. package/.agents/workflows/qa-run.md +2 -1
  45. package/docs/CHANGELOG.md +14 -0
  46. package/package.json +1 -1
  47. package/.agents/rules/changelog-style.md +0 -180
  48. package/.agents/rules/shell-conventions.md +0 -61
  49. package/.agents/scripts/lib/qa/coverage-verdict.js +0 -214
  50. package/.agents/skills/core/api-and-interface-design/SKILL.md +0 -55
  51. package/.agents/skills/core/api-and-interface-design/reference.md +0 -76
  52. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +0 -45
  53. package/.agents/skills/core/debugging-and-error-recovery/reference.md +0 -56
  54. package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +0 -54
  55. package/.agents/skills/core/idea-refinement/refinement-criteria.md +0 -155
  56. package/.agents/skills/core/idea-refinement/scripts/idea-refine.sh +0 -15
  57. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +0 -105
  58. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +0 -152
  59. package/.agents/skills/stack/qa/vitest/SKILL.md +0 -22
@@ -1,105 +0,0 @@
1
- ---
2
- name: qa-coverage-mapping
3
- description:
4
- Map a quality finding to a per-tier coverage verdict (unit / contract /
5
- acceptance) aligned to `.agents/rules/testing-standards.md`. Use when a
6
- finding points at a symbol or surface and you need to know which test tiers
7
- already cover it and which are missing, so remediation lands the right tier.
8
- Delegates the verdict to the deterministic
9
- `lib/qa/coverage-verdict.js#coverageVerdict` helper.
10
- allowed_tools:
11
- - Read
12
- - Bash
13
- ---
14
-
15
- # qa-coverage-mapping
16
-
17
- ## Policy Capsule
18
-
19
- - The three-tier taxonomy (unit / contract / acceptance), tier-placement rules, and assertion-placement constraints live in `.agents/rules/testing-standards.md`; that rule is the SSOT and wins on any conflict — this skill only maps a finding onto those tiers.
20
- - Compute the verdict through the deterministic helper `coverageVerdict(...)` in `.agents/scripts/lib/qa/coverage-verdict.js`; never re-derive tier placement by hand in prose.
21
- - Build the `surface` input by gathering the finding's symbol and the colocated/contract/acceptance tests that exercise it — pass test paths (or `{path, tier}` descriptors) so the helper classifies each one.
22
- - Read the verdict as a `{unit, contract, acceptance}` object: each tier is `{status: 'present'|'absent', note}`. A surface with only a colocated unit test reports `unit: present` and `contract`/`acceptance`: `absent` with explanatory notes.
23
- - Route remediation by the absent tiers, honoring the assertion-placement rule: wire-shape and status-code gaps become **contract** tests, user-visible journey gaps become **acceptance** scenarios — never push those into unit tests or `.feature` files incorrectly.
24
- - Treat `absent` as a coverage gap to surface, not an automatic failure: some surfaces legitimately need only one tier (a pure formatter needs no acceptance scenario). Use the notes to justify, not to mandate, the missing tier.
25
- - This skill is read + classify only: it does not author tests, mutate tickets, or run the suite. Hand the verdict to the TDD cycle in `.agents/rules/testing-standards.md` to actually write the missing tier.
26
-
27
- ## Role
28
-
29
- You are the coverage cartographer. Given a finding that names a code surface
30
- (a symbol — function, class, or module export — plus the tests around it), you
31
- produce a structured per-tier verdict that says, for each of the three test
32
- tiers in [`.agents/rules/testing-standards.md`](../../../rules/testing-standards.md),
33
- whether coverage is **present** or **absent**, and why. You do not write the
34
- missing tests; you tell the operator (or the next skill) exactly which tier is
35
- missing so remediation is aimed correctly.
36
-
37
- ## When to use
38
-
39
- - A quality / audit finding points at a specific symbol and you need to know
40
- whether it is already tested, and at which tier.
41
- - Before remediating a coverage gap, to decide whether the missing test is a
42
- **unit**, **contract**, or **acceptance** test (the assertion-placement rule
43
- makes this decision load-bearing — a status-code gap must become a contract
44
- test, not a unit test).
45
- - During a test-pyramid audit, to roll up many surfaces into a tier-by-tier
46
- gap report.
47
-
48
- **When NOT to use:** for authoring tests (use the TDD cycle in
49
- [`.agents/rules/testing-standards.md`](../../../rules/testing-standards.md#applying-the-standards)),
50
- for measuring line/branch coverage percentages (that is the unit-tier coverage
51
- config, not this skill), or for anything that requires running the suite.
52
-
53
- ## The verdict shape
54
-
55
- `coverageVerdict(surface)` returns:
56
-
57
- ```json
58
- {
59
- "unit": { "status": "present" | "absent", "note": "…" },
60
- "contract": { "status": "present" | "absent", "note": "…" },
61
- "acceptance": { "status": "present" | "absent", "note": "…" }
62
- }
63
- ```
64
-
65
- - `status` is `present` when at least one classified test exercises the surface
66
- at that tier, `absent` otherwise.
67
- - `note` is always populated. For `present` tiers it summarizes the count; for
68
- `absent` tiers it explains the gap and echoes the symbol so the report reads
69
- cleanly.
70
-
71
- ## How to apply
72
-
73
- 1. **Identify the surface.** From the finding, capture the `symbol` and the
74
- list of tests that touch it — colocated `*.test.*`, anything under
75
- `tests/contract/**`, and any `.feature` scenario.
76
- 2. **Classify and verdict.** Pass the surface to `coverageVerdict`. Each test
77
- is classified by path (`.feature` → acceptance, `…/contract/…` or
78
- `.contract.test.*` → contract, `.test.*` or `__tests__/` → unit) or by an
79
- explicit `tier` field when you already know it.
80
- 3. **Read the gaps.** Every `absent` tier is a candidate gap. Apply judgment
81
- from the Policy Capsule: not every surface needs all three tiers.
82
- 4. **Route remediation.** For real gaps, hand off to the TDD cycle in
83
- `.agents/rules/testing-standards.md` with the missing tier named, honoring
84
- the assertion-placement rule so each assertion lands in its correct tier.
85
-
86
- ## Example
87
-
88
- ```js
89
- import { coverageVerdict } from '../../../scripts/lib/qa/coverage-verdict.js';
90
-
91
- const verdict = coverageVerdict({
92
- symbol: 'parseInvoice',
93
- tests: ['src/invoice/parse-invoice.test.js'],
94
- });
95
-
96
- // verdict.unit.status === 'present'
97
- // verdict.contract.status === 'absent' // wire-shape gap → contract test
98
- // verdict.acceptance.status === 'absent' // no user journey covered here
99
- ```
100
-
101
- A colocated-unit-only surface like `parseInvoice` reports `unit` present and
102
- both `contract` and `acceptance` absent with explanatory notes — exactly the
103
- signal you need to decide whether the boundary (`contract`) or a user-visible
104
- journey (`acceptance`) still needs a test, or whether a pure parser is
105
- legitimately unit-only.
@@ -1,152 +0,0 @@
1
- ---
2
- name: qa-explore-driving
3
- description:
4
- Conventions for agent-driven exploratory QA driving — how the agent itself
5
- drives a surface during `/qa-explore` (agent-led), as opposed to the
6
- human-led `/qa-assist`. Use when the agent explores a running app via the
7
- browser MCP (navigation-first, the default) — including authenticated
8
- deployed surfaces reached through the resolved environment's sign-in seam —
9
- or walks a static surface (the documented interim where no seam resolves),
10
- under a strictly read-only capture invariant. The exploration procedure lives in
11
- `.agents/workflows/qa-explore.md`; this skill is the driving-conventions
12
- reference it leans on.
13
- ---
14
-
15
- # Skill: qa-explore-driving
16
-
17
- ## Policy Capsule
18
-
19
- - Drive the running app **by default** through the browser MCP, navigation-first: start at a root and reach each surface only via UI affordances — never URL-jump to a deep link.
20
- - Resolve the target **environment** at Plan time (via `resolveQaEnvironment`) and record its name in the ledger; each environment keys its own `baseUrl`, `signInSeam`, and `allowWrites`.
21
- - Treat **static driving** (reading source, routes, and rendered markup without a live runtime) as the **documented interim** method, chosen at Plan time **only where no seam resolves** for the target environment — never the silent fallback.
22
- - Hold the **read-only capture invariant** absolutely: the agent makes no source edits and no product mutations while driving; the only write is appending to the `temp/qa/<sessionId>` ledger.
23
- - Authenticated driving follows the resolved environment's **`signInSeam`**: sign in through a dev `url` seam (persona name substituted into the template) or a `skill` seam (a stored `credentialRef` read by the named sign-in skill), with **mandatory redaction** of all captured evidence. Never type real credentials inline or fabricate a session; where an environment resolves no seam, drive the unauthenticated surface or fall back to static and record the gap.
24
- - Pick the driving method explicitly in the Plan phase (drive vs. static) and record it in the ledger; do not switch methods mid-surface without a new Plan note.
25
- - Every phase transition and every GitHub write is HITL-gated; the agent drives and captures, but never files or promotes findings autonomously.
26
- - Broken navigation, a missing affordance, or a guard redirect loop is a **finding**, not a workaround — record it and move on; do not route around it with a direct URL.
27
- - Scrub captured evidence (tokens, session cookies, PII) at the boundary via the shared redaction path before any finding reaches disk or GitHub.
28
-
29
- Guidance for the **agent-driven** half of exploratory QA. `/qa-explore` is the
30
- agent-led front-end (the agent drives, the operator watches); its human-led
31
- sibling is `/qa-assist` (the human drives, the agent scribes). The exploration
32
- **procedure** — argument parsing, phase gates, contract resolution, ledger
33
- plumbing — is the SSOT in
34
- [`qa-explore.md`](../../../../workflows/qa-explore.md); this skill shows **how**
35
- to apply the driving conventions that procedure depends on. The
36
- navigation-first execution and per-surface capture discipline are shared with
37
- [`qa-harness`](../qa-harness/SKILL.md) (the known-scenario sweep); browser
38
- instrumentation lives in
39
- [`browser-testing-with-devtools`](../../../core/browser-testing-with-devtools/SKILL.md);
40
- the read-only and no-PII boundaries are inviolable per
41
- [`security-baseline.md`](../../../../rules/security-baseline.md). Read this
42
- skill before driving a live surface; read the workflow for the phase order.
43
-
44
- ## 1. Navigation-First Driving (the default) — one prose home
45
-
46
- Navigation-first driving is the default and load-bearing convention: reach every
47
- surface the way a real user would so findings reflect a user-reachable state,
48
- not an artifact of a deep link. Its full prose statement lives once in
49
- [`qa-run-scenario.md`](../../../../workflows/helpers/qa-run-scenario.md) (shared
50
- with the known-scenario sweep) — apply it from there rather than restating it.
51
- In capsule:
52
-
53
- - **Drive the running app by default** through the browser MCP; static (§ 2) is
54
- the interim alternative, not the norm.
55
- - **Start at a root and never URL-jump** — reach the surface under test by
56
- clicking the affordances a real user has, never by deep-linking a starting
57
- state.
58
- - **Broken navigation is a finding, not a workaround** — a missing affordance, a
59
- nav 404, or a guard redirect loop is recorded; do not route around it.
60
- - **Observe, do not fabricate** — never script the runtime to manufacture an
61
- outcome the exploration is meant to discover.
62
-
63
- ## 2. Static Driving — the Documented Interim
64
-
65
- Static driving is the **explicitly documented interim** method for when **no
66
- seam resolves** for the target environment — the resolved environment carries
67
- no `signInSeam` the agent can drive through (§ 4). It walks the surface from
68
- source, route definitions, and rendered markup rather than a running browser.
69
-
70
- - **Choose it at Plan time, never silently.** Static is a deliberate Plan-phase
71
- decision recorded in the ledger ("environment: preview, method: static,
72
- reason: no seam resolves"), not an unannounced fallback the agent slips into
73
- when the browser MCP hiccups.
74
- - **It is interim, not equivalent.** Static driving cannot exercise real
75
- authorization, routing guards, or runtime console/network signal. Treat its
76
- coverage as partial and say so in the ledger; a static pass does not close the
77
- same coverage a driven pass would.
78
- - **Same read-only invariant.** Static driving reads source and routes; it makes
79
- no edits. The read-only capture invariant (§ 3) applies identically.
80
- - **Promote to driving when a seam lands.** Static is the bridge until the
81
- target environment resolves a `signInSeam` (§ 4) that makes driven
82
- authenticated exploration possible. When that lands, re-run the surface
83
- driven; do not leave a surface permanently static when it could be driven.
84
-
85
- ## 3. The Read-Only Capture Invariant
86
-
87
- The agent-driven Capture phase is **strictly read-only**. This invariant is
88
- inviolable per [`security-baseline.md`](../../../../rules/security-baseline.md)
89
- and the Story's security considerations — it is not a soft preference.
90
-
91
- - **No source edits.** The agent does not modify application code, config, or
92
- tests while driving. Exploration observes; it never repairs.
93
- - **No product mutations.** The agent does not create, update, or delete product
94
- data, submit destructive forms, or trigger irreversible actions to "see what
95
- happens". When a surface's only path forward is a mutating action, record the
96
- boundary as the finding and stop — do not cross it.
97
- - **The only write is the ledger.** The single permitted side effect of Capture
98
- is appending finding lines to the session ledger under
99
- `temp/qa/<sessionId>`. Everything else is observation.
100
- - **Scrub before persisting.** Strip tokens, session cookies, Authorization
101
- headers, and PII from captured console and network evidence via the shared
102
- redaction path **before** any finding reaches disk or GitHub. Captured
103
- evidence is untrusted until scrubbed.
104
- - **HITL gates every write outward.** Phase transitions and GitHub writes
105
- (ticket creation, promotion) happen only behind an operator confirmation gate.
106
- The agent never files or promotes findings autonomously.
107
-
108
- ## 4. Authenticated Driving Follows the Per-Environment Seam
109
-
110
- Driving an **authenticated** surface requires signing in. The resolved target
111
- environment (via `resolveQaEnvironment`, § Policy Capsule) carries the
112
- `signInSeam` the agent drives through — the same discriminated-union shape
113
- `qa-harness` resolves via its contract. When a seam resolves, authenticated
114
- deployed surfaces are **driven**, not statically deferred.
115
-
116
- - **Drive the authenticated surface through the seam.** When the target
117
- environment carries a `signInSeam`, sign in via that seam and then reach the
118
- authenticated surface navigation-first — including authenticated **deployed**
119
- hosts. The two seam kinds:
120
- - **`kind: 'url'` (dev impersonation).** Substitute the persona **name** into
121
- the seam's URL template and navigate there. The persona name is the sole
122
- input; no per-persona auth material is read.
123
- - **`kind: 'skill'` (procedural / credential).** Invoke the named consumer
124
- sign-in skill, which reads a per-persona **`credentialRef`** — an indirect
125
- handle to a stored credential, never an inline secret. Read the skill's
126
- `SKILL.md` and follow it.
127
- - **Never enter real credentials inline.** The agent MUST NOT type real
128
- usernames, passwords, or tokens to reach an authenticated surface, and MUST
129
- NOT fabricate or forge a session. Sign-in flows only through the seam, which
130
- consumes a persona name or a `credentialRef` indirection — never a
131
- hand-typed secret. This is a hard security boundary, not a convenience to
132
- work around.
133
- - **Redaction is mandatory.** Every captured evidence string — console,
134
- network, headers — passes through the shared redaction path (§ 3) before it
135
- reaches disk or GitHub; bearer tokens, session cookies, `Authorization`
136
- headers, and PII are masked. Authenticated driving raises the stakes on
137
- redaction, it does not relax it.
138
- - **Static only where no seam resolves.** When the target environment resolves
139
- **no** `signInSeam`, drive only the unauthenticated surface or fall back to
140
- static driving (§ 2), and record the gap in the ledger so the partial
141
- coverage is visible. A surface that could not be driven because the
142
- environment carries no seam is itself a coverage signal worth recording, not
143
- a silent skip.
144
-
145
- ## 5. Cross-References
146
-
147
- - Run procedure (SSOT): [`qa-explore.md`](../../../../workflows/qa-explore.md).
148
- - Driving rules (one prose home): [`qa-run-scenario.md`](../../../../workflows/helpers/qa-run-scenario.md).
149
- - Known-scenario sibling sweep: [`qa-harness`](../qa-harness/SKILL.md).
150
- - Browser instrumentation: [`browser-testing-with-devtools`](../../../core/browser-testing-with-devtools/SKILL.md).
151
- - Read-only / no-PII boundary: [`security-baseline.md`](../../../../rules/security-baseline.md).
152
- - Assertion-tier rules: [`testing-standards.md`](../../../../rules/testing-standards.md).
@@ -1,22 +0,0 @@
1
- ---
2
- name: vitest
3
- description:
4
- Writes fast, isolated unit and integration tests with Vitest. Use when each
5
- test must run on file-save without shared state — `vi.mock()` for external
6
- deps, `vi.spyOn()` for call monitoring, AAA structure, and edge-case
7
- coverage for null/undefined/boundary inputs.
8
- vendor: vitest
9
- ---
10
-
11
- # Skill: Vitest
12
-
13
- ## Policy Capsule
14
-
15
- - Keep each test independent — never share mutable state between tests; reset mocks in `afterEach`.
16
- - Mock external dependencies with `vi.mock()`; use `vi.spyOn()` only to observe call shape, not to replace logic.
17
- - Structure tests as Arrange / Act / Assert — do not interleave the three phases.
18
- - Use descriptive titles in the `describe('Component', () => { it('should [action] when [condition]') })` form.
19
- - Cover error paths, null/undefined inputs, and boundary conditions, not just the happy path.
20
- - Use snapshots only for large, stable data structures; avoid them for frequently changing UI to prevent snapshot fatigue.
21
- - Aim for 80%+ coverage on business logic and edge cases; audit with `vitest --coverage`.
22
- - Test observable behavior, not internal implementation details; refactors should not require rewriting passing tests.