mandrel 1.82.0 → 1.83.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 +41 -0
- package/.agents/docs/SDLC.md +4 -2
- package/.agents/docs/agentrc-reference.json +10 -2
- package/.agents/docs/execution-reference.md +52 -0
- package/.agents/instructions.md +76 -38
- package/.agents/schemas/agentrc.schema.json +31 -3
- package/.agents/schemas/qa-ledger.schema.json +2 -2
- package/.agents/scripts/epic-deliver-prepare.js +41 -1
- package/.agents/scripts/lib/config/explain.js +4 -1
- package/.agents/scripts/lib/config-settings-schema.js +25 -1
- package/.agents/scripts/lib/epic-body-sections.js +88 -0
- package/.agents/scripts/lib/findings/promote-finding.js +3 -3
- package/.agents/scripts/lib/findings/severity.js +5 -6
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +65 -2
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +96 -11
- package/.agents/scripts/lib/orchestration/doc-reader.js +29 -0
- package/.agents/scripts/lib/orchestration/docs-digest.js +134 -0
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +15 -1
- package/.agents/scripts/lib/qa/console-allowlist.js +5 -4
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +144 -8
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +7 -5
- package/.agents/skills/core/epic-plan-consolidate/examples.md +51 -0
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +4 -22
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +47 -0
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +9 -8
- package/.agents/skills/core/epic-plan-premortem/examples.md +53 -0
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +21 -81
- package/.agents/skills/core/epic-plan-spec-author/examples.md +91 -0
- package/.agents/skills/skills.index.json +3 -3
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +52 -38
- package/.agents/workflows/helpers/deliver-epic-reference.md +514 -0
- package/.agents/workflows/helpers/deliver-epic.md +164 -469
- package/.agents/workflows/helpers/epic-deliver-story.md +35 -11
- package/.agents/workflows/helpers/plan-epic-reference.md +136 -0
- package/.agents/workflows/helpers/plan-epic.md +56 -186
- package/.agents/workflows/helpers/plan-story.md +31 -61
- package/.agents/workflows/helpers/qa-run-scenario.md +194 -0
- package/.agents/workflows/helpers/scope-triage-gate.md +97 -0
- package/.agents/workflows/helpers/single-story-deliver-reference.md +423 -0
- package/.agents/workflows/helpers/single-story-deliver.md +128 -392
- package/.agents/workflows/qa-explore.md +63 -32
- package/.agents/workflows/qa-run.md +293 -130
- package/docs/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/.agents/schemas/qa-finding.schema.json +0 -133
|
@@ -30,11 +30,13 @@ allowed_tools:
|
|
|
30
30
|
## Role
|
|
31
31
|
|
|
32
32
|
Senior Project Manager + Orchestrator, acting as a **holistic critic** with
|
|
33
|
-
fresh context
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
fresh context — deliberately *separate* from `epic-plan-decompose-author` (the
|
|
34
|
+
generator) so the pass is a fresh-context review, not a same-pass self-critique.
|
|
35
|
+
|
|
36
|
+
> **Read [`examples.md`](./examples.md) on demand** for the extended rationale:
|
|
37
|
+
> why this critic runs with fresh context, why scope conservation is your
|
|
38
|
+
> contract rather than a runtime guarantee, and how the below-ceiling
|
|
39
|
+
> coarsening case is reported.
|
|
38
40
|
|
|
39
41
|
## When to use
|
|
40
42
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# epic-plan-consolidate — examples & extended rationale
|
|
2
|
+
|
|
3
|
+
Read this file on demand. The SKILL.md carries the operating contract (Policy
|
|
4
|
+
Capsule, Inputs / Outputs, Procedure, Constraints); this file carries the
|
|
5
|
+
extended rationale behind the consolidation pass — why it is a separate,
|
|
6
|
+
fresh-context critic and how the scope-conservation invariant is enforced by
|
|
7
|
+
you rather than by the runtime.
|
|
8
|
+
|
|
9
|
+
## Why a separate fresh-context critic
|
|
10
|
+
|
|
11
|
+
This Skill acts as a **holistic critic** with fresh context (a Senior Project
|
|
12
|
+
Manager + Orchestrator lens). It is deliberately *separate* from
|
|
13
|
+
`epic-plan-decompose-author` (the generator): a same-pass self-critique is the
|
|
14
|
+
weak mode this is built to escape. The generator maps Epic capabilities to
|
|
15
|
+
Stories ~1:1; this critic steps back and looks at the *whole* decomposition
|
|
16
|
+
against the Tech Spec's intentional grouping before any GitHub write.
|
|
17
|
+
|
|
18
|
+
## Scope conservation is your contract, not a machine guarantee
|
|
19
|
+
|
|
20
|
+
Scope conservation is the load-bearing invariant: you MUST NOT add scope,
|
|
21
|
+
invent tickets, or drop acceptance criteria. Every acceptance item and every
|
|
22
|
+
`verify` entry present in the draft MUST survive into the consolidated array
|
|
23
|
+
(possibly re-homed onto a merged Story).
|
|
24
|
+
|
|
25
|
+
**This is your contract, not a machine guarantee.** There is **no runtime
|
|
26
|
+
acceptance-union diff** on your output. The only deterministic runtime backstop
|
|
27
|
+
the validator applies after you run is the standard ticket-structure
|
|
28
|
+
validation — it does not re-derive the pre-consolidation acceptance/verify
|
|
29
|
+
union, so a critic that silently dropped an acceptance item would **not** be
|
|
30
|
+
caught downstream. (The repo's unit test exercises a *pure model* of the merge
|
|
31
|
+
over an over-fragmented fixture to document the intended invariant; it does not
|
|
32
|
+
inspect this Skill's actual output.) Conserve scope yourself, deliberately, on
|
|
33
|
+
every merge — and if you cannot preserve an item, you have over-reached, so back
|
|
34
|
+
the operation out.
|
|
35
|
+
|
|
36
|
+
## Ceiling, not target — the below-ceiling coarsening case
|
|
37
|
+
|
|
38
|
+
Consume the Tech Spec **"Delivery Slicing"** section as a **ceiling, not a
|
|
39
|
+
target** when present: the Architect's proposed N shippable Stories is an
|
|
40
|
+
*upper bound*, not a floor. Cluster the draft's Stories toward that grouping,
|
|
41
|
+
and go **below** N when slices form dependent single-consumer chains — a slice
|
|
42
|
+
whose "Independent? No" row carries no justification (parallelism, risk
|
|
43
|
+
isolation, or delivery-envelope pressure) folds into its consumer. You **never**
|
|
44
|
+
split above N.
|
|
45
|
+
|
|
46
|
+
When the consolidated count drops **below** the Delivery-Slicing count, the
|
|
47
|
+
consolidation report MUST surface that fact explicitly — e.g.
|
|
48
|
+
`Below ceiling: N (Delivery Slicing) → M (consolidated)` — and attach a one-line
|
|
49
|
+
rationale to each below-ceiling merge (which dependent single-consumer slice
|
|
50
|
+
folded into which consumer, and why it was unjustified), so the operator sees
|
|
51
|
+
the coarsening at the Phase 8.3 advisory diff.
|
|
@@ -302,28 +302,10 @@ When the Acceptance Table contains **one or more `Disposition: new` rows**, you
|
|
|
302
302
|
|
|
303
303
|
When the Acceptance Table contains **zero `new`-disposition rows** (every row is `updated` or `unchanged`), do NOT emit a scaffold Story — there is nothing to create.
|
|
304
304
|
|
|
305
|
-
**
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
"type": "story",
|
|
310
|
-
"title": "Scaffold @skip-tagged billing feature files",
|
|
311
|
-
"depends_on": [],
|
|
312
|
-
"labels": ["type::story", "persona::qa-engineer"],
|
|
313
|
-
"acceptance": [
|
|
314
|
-
"tests/features/billing/invoice.feature and tests/features/billing/refund.feature both exist on the branch",
|
|
315
|
-
"every Scenario in the two new feature files is preceded by an @skip tag (grep for un-skipped scenarios returns zero matches)",
|
|
316
|
-
"the invoice.feature scenario carries @epic-42-ac-1 and the refund.feature scenario carries @epic-42-ac-2"
|
|
317
|
-
],
|
|
318
|
-
"verify": [
|
|
319
|
-
"test -f tests/features/billing/invoice.feature && test -f tests/features/billing/refund.feature (validate)",
|
|
320
|
-
"test -z \"$(grep -rL '@skip' tests/features/billing/*.feature)\" (validate)",
|
|
321
|
-
"grep -q '@epic-42-ac-1' tests/features/billing/invoice.feature && grep -q '@epic-42-ac-2' tests/features/billing/refund.feature (validate)"
|
|
322
|
-
],
|
|
323
|
-
"body": "## Goal\nbdd-scaffold: create the @skip-tagged, @epic-42-ac-N-tagged feature files the billing-flows implementation Stories verify against, so wave-0 lands them before any implementation Story runs.\n\n## Changes\n- {\"path\": \"tests/features/billing/invoice.feature\", \"assumption\": \"creates\"}\n- {\"path\": \"tests/features/billing/refund.feature\", \"assumption\": \"creates\"}\n\n## Acceptance\n- [ ] tests/features/billing/invoice.feature and tests/features/billing/refund.feature both exist on the branch\n- [ ] every Scenario in the two new feature files is preceded by an @skip tag\n- [ ] the invoice.feature scenario carries @epic-42-ac-1 and the refund.feature scenario carries @epic-42-ac-2\n\n## Verify\n- test -f tests/features/billing/invoice.feature && test -f tests/features/billing/refund.feature (validate)\n- test -z \"$(grep -rL '@skip' tests/features/billing/*.feature)\" (validate)\n- grep -q '@epic-42-ac-1' tests/features/billing/invoice.feature && grep -q '@epic-42-ac-2' tests/features/billing/refund.feature (validate)\n"
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
The implementation Stories that later un-skip and flesh out these scenarios each carry `depends_on: ["scaffold-billing-feature-files"]`, placing them in a later wave than the scaffold. They MUST NOT add the `@epic-42-ac-N` tag themselves — it is already present from the scaffold pass; their job is to remove `@skip` once the scenario passes.
|
|
305
|
+
> **Read [`examples.md`](./examples.md) on demand** for a fully worked wave-0
|
|
306
|
+
> scaffold Story (Epic #42, two `new` rows) showing the serialized string
|
|
307
|
+
> `body`, the top-level `acceptance`/`verify` arrays, the empty `depends_on`,
|
|
308
|
+
> and the paired `@skip` + `@epic-<id>-ac-N` tagging.
|
|
327
309
|
|
|
328
310
|
### SCOPE-OVERLAP FLAGGING (docs/runbook downstream of config work)
|
|
329
311
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# epic-plan-decompose-author — examples & extended rationale
|
|
2
|
+
|
|
3
|
+
Read this file on demand while authoring the ticket array. The SKILL.md carries
|
|
4
|
+
the operating contract (Policy Capsule, Inputs / Outputs, Procedure, the
|
|
5
|
+
authoring guidance that complements the rendered decomposer prompt, and
|
|
6
|
+
Constraints); this file carries the worked WAVE-0 BDD scaffold Story and the
|
|
7
|
+
extended reasoning behind it.
|
|
8
|
+
|
|
9
|
+
## WAVE-0 BDD scaffold Story — worked example
|
|
10
|
+
|
|
11
|
+
The contract lives in SKILL.md under **WAVE-0 BDD SCAFFOLD STORY**: when the
|
|
12
|
+
Epic body's `## Acceptance Table` carries one or more `Disposition: new` rows,
|
|
13
|
+
emit **exactly one** dedicated wave-0 scaffold Story whose sole job is to create
|
|
14
|
+
those `.feature` files with `@skip`-tagged scenarios (each also carrying its
|
|
15
|
+
namespaced `@epic-<id>-ac-N` tag) BEFORE any implementation Story runs.
|
|
16
|
+
|
|
17
|
+
**Worked example.** Epic #42, Acceptance Table with two `new` rows
|
|
18
|
+
(`AC-1` -> `tests/features/billing/invoice.feature`,
|
|
19
|
+
`AC-2` -> `tests/features/billing/refund.feature`). The scaffold Story below
|
|
20
|
+
uses a serialized string `body`, top-level `acceptance`/`verify` arrays, an
|
|
21
|
+
empty `depends_on`, and tags each scenario with both `@skip` and its namespaced
|
|
22
|
+
`@epic-42-ac-N` tag:
|
|
23
|
+
|
|
24
|
+
{
|
|
25
|
+
"slug": "scaffold-billing-feature-files",
|
|
26
|
+
"type": "story",
|
|
27
|
+
"title": "Scaffold @skip-tagged billing feature files",
|
|
28
|
+
"depends_on": [],
|
|
29
|
+
"labels": ["type::story", "persona::qa-engineer"],
|
|
30
|
+
"acceptance": [
|
|
31
|
+
"tests/features/billing/invoice.feature and tests/features/billing/refund.feature both exist on the branch",
|
|
32
|
+
"every Scenario in the two new feature files is preceded by an @skip tag (grep for un-skipped scenarios returns zero matches)",
|
|
33
|
+
"the invoice.feature scenario carries @epic-42-ac-1 and the refund.feature scenario carries @epic-42-ac-2"
|
|
34
|
+
],
|
|
35
|
+
"verify": [
|
|
36
|
+
"test -f tests/features/billing/invoice.feature && test -f tests/features/billing/refund.feature (validate)",
|
|
37
|
+
"test -z \"$(grep -rL '@skip' tests/features/billing/*.feature)\" (validate)",
|
|
38
|
+
"grep -q '@epic-42-ac-1' tests/features/billing/invoice.feature && grep -q '@epic-42-ac-2' tests/features/billing/refund.feature (validate)"
|
|
39
|
+
],
|
|
40
|
+
"body": "## Goal\nbdd-scaffold: create the @skip-tagged, @epic-42-ac-N-tagged feature files the billing-flows implementation Stories verify against, so wave-0 lands them before any implementation Story runs.\n\n## Changes\n- {\"path\": \"tests/features/billing/invoice.feature\", \"assumption\": \"creates\"}\n- {\"path\": \"tests/features/billing/refund.feature\", \"assumption\": \"creates\"}\n\n## Acceptance\n- [ ] tests/features/billing/invoice.feature and tests/features/billing/refund.feature both exist on the branch\n- [ ] every Scenario in the two new feature files is preceded by an @skip tag\n- [ ] the invoice.feature scenario carries @epic-42-ac-1 and the refund.feature scenario carries @epic-42-ac-2\n\n## Verify\n- test -f tests/features/billing/invoice.feature && test -f tests/features/billing/refund.feature (validate)\n- test -z \"$(grep -rL '@skip' tests/features/billing/*.feature)\" (validate)\n- grep -q '@epic-42-ac-1' tests/features/billing/invoice.feature && grep -q '@epic-42-ac-2' tests/features/billing/refund.feature (validate)\n"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
The implementation Stories that later un-skip and flesh out these scenarios each
|
|
44
|
+
carry `depends_on: ["scaffold-billing-feature-files"]`, placing them in a later
|
|
45
|
+
wave than the scaffold. They MUST NOT add the `@epic-42-ac-N` tag themselves —
|
|
46
|
+
it is already present from the scaffold pass; their job is to remove `@skip`
|
|
47
|
+
once the scenario passes.
|
|
@@ -28,14 +28,15 @@ allowed_tools:
|
|
|
28
28
|
|
|
29
29
|
## Role
|
|
30
30
|
|
|
31
|
-
Senior Engineer + Architect, acting as a **fresh-context pre-mortem critic
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
a same-pass self-critique
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
Senior Engineer + Architect, acting as a **fresh-context pre-mortem critic** —
|
|
32
|
+
deliberately *separate* from `epic-plan-decompose-author` (the generator) and
|
|
33
|
+
`epic-plan-consolidate` (the scope-preserving merge critic) so it is a
|
|
34
|
+
fresh-context, code-reading review, not a same-pass self-critique.
|
|
35
|
+
|
|
36
|
+
> **Read [`examples.md`](./examples.md) on demand** for the extended rationale:
|
|
37
|
+
> why this critic opens the actual cited code, why it is additive-recommendation
|
|
38
|
+
> (not scope-preserving) unlike consolidation, and the three predicted-rework
|
|
39
|
+
> finding classes in full.
|
|
39
40
|
|
|
40
41
|
## When to use
|
|
41
42
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# epic-plan-premortem — examples & extended rationale
|
|
2
|
+
|
|
3
|
+
Read this file on demand. The SKILL.md carries the operating contract (Policy
|
|
4
|
+
Capsule, Inputs / Outputs, Procedure, Constraints); this file carries the
|
|
5
|
+
extended rationale behind the pre-mortem critic — why it is a separate,
|
|
6
|
+
fresh-context, code-reading pass and how its three predicted-rework finding
|
|
7
|
+
classes differ from the structural gates.
|
|
8
|
+
|
|
9
|
+
## Why a separate fresh-context code-reading critic
|
|
10
|
+
|
|
11
|
+
This Skill acts as a Senior Engineer + Architect in the role of a
|
|
12
|
+
**fresh-context pre-mortem critic**. It is deliberately *separate* from
|
|
13
|
+
`epic-plan-decompose-author` (the generator) and from `epic-plan-consolidate`
|
|
14
|
+
(the scope-preserving merge critic): a same-pass self-critique is the weak mode
|
|
15
|
+
this is built to escape. The generator maps Epic capabilities to Stories
|
|
16
|
+
against the spec text; this critic opens the **actual cited code** and asks "if
|
|
17
|
+
I tried to deliver this exact backlog, where would it rework?" — before any
|
|
18
|
+
GitHub write makes the rework expensive.
|
|
19
|
+
|
|
20
|
+
**You MUST read the actual cited code surfaces.** This is the load-bearing
|
|
21
|
+
difference between this critic and the structural file-assumption gate: that
|
|
22
|
+
gate proves a path **exists** (or does not); this critic reads what the file
|
|
23
|
+
actually **contains**. A pre-mortem that did not open the cited files has not
|
|
24
|
+
run.
|
|
25
|
+
|
|
26
|
+
## Not scope-preserving (unlike consolidation)
|
|
27
|
+
|
|
28
|
+
Unlike `epic-plan-consolidate` (merge-and-rewire only), this critic MAY
|
|
29
|
+
recommend splitting an under-specified Story, tightening or rewording an
|
|
30
|
+
acceptance criterion, or flagging an over-specified Story — because it only
|
|
31
|
+
*recommends* in a report; it never applies the change itself. The conservation
|
|
32
|
+
invariant belongs to consolidation; this pass is deliberately a separate,
|
|
33
|
+
additive-recommendation lens. It never writes to GitHub, never persists
|
|
34
|
+
`tickets.json`, and never flips a label — re-authoring on its findings is the
|
|
35
|
+
author skill's job (the workflow re-runs `epic-plan-decompose-author` on the
|
|
36
|
+
report before the persist call).
|
|
37
|
+
|
|
38
|
+
## The three predicted-rework finding classes
|
|
39
|
+
|
|
40
|
+
Hunt for the three classes the structural gates cannot catch:
|
|
41
|
+
|
|
42
|
+
1. **Unverifiable acceptance criteria** — an AC no `verify[]` command or
|
|
43
|
+
readable code state can prove. Recommend a concrete verify command or a
|
|
44
|
+
reworded, checkable AC.
|
|
45
|
+
2. **Over- or under-specified Stories** — a Story whose `acceptance[]` is far
|
|
46
|
+
broader or narrower than its `changes[]` footprint and the cited code
|
|
47
|
+
support. Recommend a split (under-specified: one Story doing the work of
|
|
48
|
+
several) or a tightening.
|
|
49
|
+
3. **Semantically-wrong assumptions** — the cited file exists (so the
|
|
50
|
+
file-assumption gate passes) but does not contain the seam / export /
|
|
51
|
+
function / data shape the Story assumes — the file-assumption gate passes,
|
|
52
|
+
the work would still rework. Recommend the corrected target or an explicit
|
|
53
|
+
"create the seam first" Story.
|
|
@@ -181,88 +181,28 @@ before reaching for names that appear only in the documentation. Write to
|
|
|
181
181
|
|
|
182
182
|
#### Delivery Slicing section (authoritative ceiling for Phase 8 consolidation)
|
|
183
183
|
|
|
184
|
-
The Tech Spec MUST carry a `## Delivery Slicing` section
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
the Phase 8 consolidation pass
|
|
184
|
+
The Tech Spec MUST carry a `## Delivery Slicing` section proposing how the
|
|
185
|
+
Epic's enumerated capabilities **cluster into N shippable Stories** — the
|
|
186
|
+
intentional grouping the Phase 8 consolidation pass
|
|
188
187
|
([`epic-plan-consolidate`](../epic-plan-consolidate/SKILL.md)) reconciles the
|
|
189
|
-
decomposer
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
**The
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
other sections.
|
|
208
|
-
|
|
209
|
-
Author the section as a table — one row per proposed slice — naming the
|
|
210
|
-
capability cluster each slice would deliver, what ships in it, and whether it
|
|
211
|
-
can ship independently. Use **noun phrases** for slice names ("Foundation",
|
|
212
|
-
"Transport seam", "Send helper") so they map cleanly onto Feature titles in the
|
|
213
|
-
resulting decomposition — never verb phrases ("Add transport") or file names
|
|
214
|
-
("`sender.ts`"). Do **not** coarsen the Epic's capability enumeration to produce
|
|
215
|
-
the slicing: the granularity lever is *this* grouping recommendation, not a
|
|
216
|
-
dumbed-down Epic enumeration.
|
|
217
|
-
|
|
218
|
-
**What "Independent?" means:** can this slice ship to production and provide
|
|
219
|
-
value *without the next slice landing*? A `Yes` slice is releasable on its own;
|
|
220
|
-
a `No` slice only becomes valuable once a later slice lands on top of it.
|
|
221
|
-
|
|
222
|
-
**"Independent? No" is a smell that must be justified.** A dependent,
|
|
223
|
-
single-consumer slice (one that only feeds the next slice) folds into its
|
|
224
|
-
consumer by default — it is not worth its own delivery session's hydration,
|
|
225
|
-
branch, PR, and CI ceremony. Mark a slice `No` only when you can name a
|
|
226
|
-
one-line reason to keep it separate anyway: **parallelism** (two `No` slices
|
|
227
|
-
that can be delivered concurrently by different sessions), **risk isolation**
|
|
228
|
-
(a blast-radius or reviewability reason to land it as its own reviewable PR),
|
|
229
|
-
or **delivery-envelope pressure** (folding it in would push the consumer past a
|
|
230
|
-
single-session sizing envelope). Absent such a justification, do not author the
|
|
231
|
-
slice as its own row — fold it into its consumer and let the merged slice carry
|
|
232
|
-
the combined capability.
|
|
233
|
-
|
|
234
|
-
Worked example:
|
|
235
|
-
|
|
236
|
-
```text
|
|
237
|
-
## Delivery Slicing
|
|
238
|
-
|
|
239
|
-
Proposed shippable slices (consolidation ceiling for Phase 8):
|
|
240
|
-
|
|
241
|
-
| Slice | What ships | Independent? |
|
|
242
|
-
| -------------- | ------------------------------------------------------ | ------------ |
|
|
243
|
-
| Foundation | Config schema, types, and the no-op default path | Yes |
|
|
244
|
-
| Transport seam | The pluggable transport interface + in-memory adapter | Yes |
|
|
245
|
-
| Send helper | The send() helper + retries, built on the transport | No (justified: risk isolation) |
|
|
246
|
-
|
|
247
|
-
- **Foundation** folds Epic capabilities "config surface" + "type model" — they
|
|
248
|
-
share a reason to exist and ship as one reviewable PR.
|
|
249
|
-
- **Transport seam** is the pluggable boundary; it provides value on its own
|
|
250
|
-
(in-memory adapter is usable for tests) so it is independently shippable.
|
|
251
|
-
- **Send helper** depends on the transport seam landing first, so it is *not*
|
|
252
|
-
independent. It stays its own slice only because the retry/backoff logic is a
|
|
253
|
-
large, high-blast-radius surface worth isolating in its own reviewable PR
|
|
254
|
-
(risk isolation). Absent that justification it would fold into Transport
|
|
255
|
-
seam — a bare "depends on the previous slice" is not a reason to keep it
|
|
256
|
-
separate.
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
The consolidation pass degrades gracefully when this section is absent (it
|
|
260
|
-
falls back to cohesion + single-Story-Feature rules only), so authoring it is
|
|
261
|
-
how the Architect steers the decomposition toward fewer, right-sized Stories.
|
|
262
|
-
Because the count is a **ceiling**, an over-sliced table is coarsened back
|
|
263
|
-
during consolidation — but only where the extra slices are dependent
|
|
264
|
-
single-consumer chains, so an unjustified `No` slice is the one you should fold
|
|
265
|
-
in yourself rather than leaning on the consolidator to catch.
|
|
188
|
+
decomposer draft against before any GitHub write. Author it as a table (one row
|
|
189
|
+
per slice: `Slice | What ships | Independent?`), using **noun-phrase** slice
|
|
190
|
+
names, and **write it before any other section** — it is the primary input to
|
|
191
|
+
consolidation and the section the model most often omits when it drafts it last.
|
|
192
|
+
|
|
193
|
+
- **The count is a ceiling, not a target.** Consolidation may merge below it
|
|
194
|
+
(dependent single-consumer chains) but never splits above it.
|
|
195
|
+
- **"Independent?"** answers: can this slice ship to production and provide
|
|
196
|
+
value without the next slice landing? Mark a slice `No` only with a one-line
|
|
197
|
+
justification (parallelism, risk isolation, or delivery-envelope pressure);
|
|
198
|
+
an unjustified dependent single-consumer slice folds into its consumer.
|
|
199
|
+
- Do **not** coarsen the Epic's capability enumeration to produce the slicing;
|
|
200
|
+
the grouping recommendation is the granularity lever.
|
|
201
|
+
|
|
202
|
+
> **Read [`examples.md`](./examples.md) on demand** for the worked Delivery
|
|
203
|
+
> Slicing table and the extended rationale behind these rules (what
|
|
204
|
+
> "Independent?" means, why an unjustified `No` slice is a smell, and how the
|
|
205
|
+
> consolidation pass degrades gracefully when the section is absent).
|
|
266
206
|
|
|
267
207
|
#### Tech Spec system prompt (authoritative)
|
|
268
208
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# epic-plan-spec-author — examples & extended rationale
|
|
2
|
+
|
|
3
|
+
Read this file on demand while authoring the Tech Spec. The SKILL.md carries
|
|
4
|
+
the operating contract (Policy Capsule, Inputs / Outputs, Procedure, the two
|
|
5
|
+
authoritative system prompts, and Constraints); this file carries the worked
|
|
6
|
+
Delivery Slicing example and the extended rationale behind the slicing rules.
|
|
7
|
+
|
|
8
|
+
## Delivery Slicing — extended rationale
|
|
9
|
+
|
|
10
|
+
The Tech Spec MUST carry a `## Delivery Slicing` section in which the Architect
|
|
11
|
+
— who holds the full design — proposes how the Epic's enumerated capabilities
|
|
12
|
+
**cluster into N shippable Stories**. This section is the intentional grouping
|
|
13
|
+
the Phase 8 consolidation pass
|
|
14
|
+
([`epic-plan-consolidate`](../epic-plan-consolidate/SKILL.md)) reconciles the
|
|
15
|
+
decomposer's draft against before any GitHub write. Without it, the decompose
|
|
16
|
+
phase maps Epic capabilities to Stories ~1:1 and cannot produce a coarser,
|
|
17
|
+
holistic plan; with it, the consolidation critic has a well-defined reference
|
|
18
|
+
instead of a guess.
|
|
19
|
+
|
|
20
|
+
**The proposed count is a ceiling, not a target.** Consolidation reconciles
|
|
21
|
+
the draft *toward* your grouping, but it treats the count as an upper bound: it
|
|
22
|
+
may **merge below** your proposed count when slices form dependent
|
|
23
|
+
single-consumer chains, and it **never splits above** it. Over-slicing here
|
|
24
|
+
therefore locks in fragmentation only when the extra slices are genuinely
|
|
25
|
+
independent — so keep a slice separate only when it earns its own delivery
|
|
26
|
+
session.
|
|
27
|
+
|
|
28
|
+
**Write the Delivery Slicing section before any other section — it is the
|
|
29
|
+
primary input to Phase 8 consolidation.** Author it first so the rest of the
|
|
30
|
+
spec (Core Components, API Changes, Data Models) hangs off a deliberate
|
|
31
|
+
slicing decision rather than being reverse-engineered into one at the end.
|
|
32
|
+
Drafting it last is exactly how the model omits it under the weight of the
|
|
33
|
+
other sections.
|
|
34
|
+
|
|
35
|
+
Author the section as a table — one row per proposed slice — naming the
|
|
36
|
+
capability cluster each slice would deliver, what ships in it, and whether it
|
|
37
|
+
can ship independently. Use **noun phrases** for slice names ("Foundation",
|
|
38
|
+
"Transport seam", "Send helper") so they map cleanly onto Feature titles in the
|
|
39
|
+
resulting decomposition — never verb phrases ("Add transport") or file names
|
|
40
|
+
("`sender.ts`"). Do **not** coarsen the Epic's capability enumeration to produce
|
|
41
|
+
the slicing: the granularity lever is *this* grouping recommendation, not a
|
|
42
|
+
dumbed-down Epic enumeration.
|
|
43
|
+
|
|
44
|
+
**What "Independent?" means:** can this slice ship to production and provide
|
|
45
|
+
value *without the next slice landing*? A `Yes` slice is releasable on its own;
|
|
46
|
+
a `No` slice only becomes valuable once a later slice lands on top of it.
|
|
47
|
+
|
|
48
|
+
**"Independent? No" is a smell that must be justified.** A dependent,
|
|
49
|
+
single-consumer slice (one that only feeds the next slice) folds into its
|
|
50
|
+
consumer by default — it is not worth its own delivery session's hydration,
|
|
51
|
+
branch, PR, and CI ceremony. Mark a slice `No` only when you can name a
|
|
52
|
+
one-line reason to keep it separate anyway: **parallelism** (two `No` slices
|
|
53
|
+
that can be delivered concurrently by different sessions), **risk isolation**
|
|
54
|
+
(a blast-radius or reviewability reason to land it as its own reviewable PR),
|
|
55
|
+
or **delivery-envelope pressure** (folding it in would push the consumer past a
|
|
56
|
+
single-session sizing envelope). Absent such a justification, do not author the
|
|
57
|
+
slice as its own row — fold it into its consumer and let the merged slice carry
|
|
58
|
+
the combined capability.
|
|
59
|
+
|
|
60
|
+
### Worked example
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
## Delivery Slicing
|
|
64
|
+
|
|
65
|
+
Proposed shippable slices (consolidation ceiling for Phase 8):
|
|
66
|
+
|
|
67
|
+
| Slice | What ships | Independent? |
|
|
68
|
+
| -------------- | ------------------------------------------------------ | ------------ |
|
|
69
|
+
| Foundation | Config schema, types, and the no-op default path | Yes |
|
|
70
|
+
| Transport seam | The pluggable transport interface + in-memory adapter | Yes |
|
|
71
|
+
| Send helper | The send() helper + retries, built on the transport | No (justified: risk isolation) |
|
|
72
|
+
|
|
73
|
+
- **Foundation** folds Epic capabilities "config surface" + "type model" — they
|
|
74
|
+
share a reason to exist and ship as one reviewable PR.
|
|
75
|
+
- **Transport seam** is the pluggable boundary; it provides value on its own
|
|
76
|
+
(in-memory adapter is usable for tests) so it is independently shippable.
|
|
77
|
+
- **Send helper** depends on the transport seam landing first, so it is *not*
|
|
78
|
+
independent. It stays its own slice only because the retry/backoff logic is a
|
|
79
|
+
large, high-blast-radius surface worth isolating in its own reviewable PR
|
|
80
|
+
(risk isolation). Absent that justification it would fold into Transport
|
|
81
|
+
seam — a bare "depends on the previous slice" is not a reason to keep it
|
|
82
|
+
separate.
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The consolidation pass degrades gracefully when this section is absent (it
|
|
86
|
+
falls back to cohesion + single-Story-Feature rules only), so authoring it is
|
|
87
|
+
how the Architect steers the decomposition toward fewer, right-sized Stories.
|
|
88
|
+
Because the count is a **ceiling**, an over-sliced table is coarsened back
|
|
89
|
+
during consolidation — but only where the extra slices are dependent
|
|
90
|
+
single-consumer chains, so an unjustified `No` slice is the one you should fold
|
|
91
|
+
in yourself rather than leaning on the consolidator to catch.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-07-
|
|
2
|
+
"generatedAt": "2026-07-04T23:12:38.376Z",
|
|
3
3
|
"generator": "generate-skills-index.js@1",
|
|
4
4
|
"skills": [
|
|
5
5
|
{
|
|
@@ -567,8 +567,8 @@
|
|
|
567
567
|
"tier": "stack",
|
|
568
568
|
"category": "qa",
|
|
569
569
|
"path": ".agents/skills/stack/qa/qa-explore-driving/SKILL.md",
|
|
570
|
-
"description": "Conventions for agent-driven exploratory QA driving — how the agent itself drives a surface during `/qa-explore` (agent-led), as opposed to the human-led `/qa-assist`. Use when the agent explores a running app via the browser MCP (navigation-first, the default) or walks a static surface (the documented interim
|
|
571
|
-
"policyCapsuleBullets":
|
|
570
|
+
"description": "Conventions for agent-driven exploratory QA driving — how the agent itself drives a surface during `/qa-explore` (agent-led), as opposed to the human-led `/qa-assist`. Use when the agent explores a running app via the browser MCP (navigation-first, the default) — including authenticated deployed surfaces reached through the resolved environment's sign-in seam — or walks a static surface (the documented interim where no seam resolves), under a strictly read-only capture invariant. The exploration procedure lives in `.agents/workflows/qa-explore.md`; this skill is the driving-conventions reference it leans on.",
|
|
571
|
+
"policyCapsuleBullets": 9,
|
|
572
572
|
"allowedTools": null,
|
|
573
573
|
"vendor": null
|
|
574
574
|
},
|
|
@@ -4,9 +4,10 @@ description:
|
|
|
4
4
|
Conventions for agent-driven exploratory QA driving — how the agent itself
|
|
5
5
|
drives a surface during `/qa-explore` (agent-led), as opposed to the
|
|
6
6
|
human-led `/qa-assist`. Use when the agent explores a running app via the
|
|
7
|
-
browser MCP (navigation-first, the default)
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
10
11
|
`.agents/workflows/qa-explore.md`; this skill is the driving-conventions
|
|
11
12
|
reference it leans on.
|
|
12
13
|
---
|
|
@@ -16,9 +17,10 @@ description:
|
|
|
16
17
|
## Policy Capsule
|
|
17
18
|
|
|
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.
|
|
19
|
-
-
|
|
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.
|
|
20
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.
|
|
21
|
-
- Authenticated driving
|
|
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.
|
|
22
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.
|
|
23
25
|
- Every phase transition and every GitHub write is HITL-gated; the agent drives and captures, but never files or promotes findings autonomously.
|
|
24
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.
|
|
@@ -65,15 +67,14 @@ state rather than an artifact of a deep link.
|
|
|
65
67
|
|
|
66
68
|
## 2. Static Driving — the Documented Interim
|
|
67
69
|
|
|
68
|
-
Static driving is the **explicitly documented interim** method for when
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
running browser.
|
|
70
|
+
Static driving is the **explicitly documented interim** method for when **no
|
|
71
|
+
seam resolves** for the target environment — the resolved environment carries
|
|
72
|
+
no `signInSeam` the agent can drive through (§ 4). It walks the surface from
|
|
73
|
+
source, route definitions, and rendered markup rather than a running browser.
|
|
73
74
|
|
|
74
75
|
- **Choose it at Plan time, never silently.** Static is a deliberate Plan-phase
|
|
75
|
-
decision recorded in the ledger ("
|
|
76
|
-
|
|
76
|
+
decision recorded in the ledger ("environment: preview, method: static,
|
|
77
|
+
reason: no seam resolves"), not an unannounced fallback the agent slips into
|
|
77
78
|
when the browser MCP hiccups.
|
|
78
79
|
- **It is interim, not equivalent.** Static driving cannot exercise real
|
|
79
80
|
authorization, routing guards, or runtime console/network signal. Treat its
|
|
@@ -81,10 +82,10 @@ running browser.
|
|
|
81
82
|
same coverage a driven pass would.
|
|
82
83
|
- **Same read-only invariant.** Static driving reads source and routes; it makes
|
|
83
84
|
no edits. The read-only capture invariant (§ 3) applies identically.
|
|
84
|
-
- **Promote to driving when
|
|
85
|
-
|
|
86
|
-
possible. When that lands, re-run the surface
|
|
87
|
-
permanently static when it could be driven.
|
|
85
|
+
- **Promote to driving when a seam lands.** Static is the bridge until the
|
|
86
|
+
target environment resolves a `signInSeam` (§ 4) that makes driven
|
|
87
|
+
authenticated exploration possible. When that lands, re-run the surface
|
|
88
|
+
driven; do not leave a surface permanently static when it could be driven.
|
|
88
89
|
|
|
89
90
|
## 3. The Read-Only Capture Invariant
|
|
90
91
|
|
|
@@ -109,29 +110,42 @@ and the Epic's security considerations — it is not a soft preference.
|
|
|
109
110
|
(ticket creation, promotion) happen only behind an operator confirmation gate.
|
|
110
111
|
The agent never files or promotes findings autonomously.
|
|
111
112
|
|
|
112
|
-
## 4. Authenticated Driving
|
|
113
|
-
|
|
114
|
-
Driving an **authenticated** surface requires signing in
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- **
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
113
|
+
## 4. Authenticated Driving Follows the Per-Environment Seam
|
|
114
|
+
|
|
115
|
+
Driving an **authenticated** surface requires signing in. The resolved target
|
|
116
|
+
environment (via `resolveQaEnvironment`, § Policy Capsule) carries the
|
|
117
|
+
`signInSeam` the agent drives through — the same discriminated-union shape
|
|
118
|
+
`qa-harness` resolves via its contract. When a seam resolves, authenticated
|
|
119
|
+
deployed surfaces are **driven**, not statically deferred.
|
|
120
|
+
|
|
121
|
+
- **Drive the authenticated surface through the seam.** When the target
|
|
122
|
+
environment carries a `signInSeam`, sign in via that seam and then reach the
|
|
123
|
+
authenticated surface navigation-first — including authenticated **deployed**
|
|
124
|
+
hosts. The two seam kinds:
|
|
125
|
+
- **`kind: 'url'` (dev impersonation).** Substitute the persona **name** into
|
|
126
|
+
the seam's URL template and navigate there. The persona name is the sole
|
|
127
|
+
input; no per-persona auth material is read.
|
|
128
|
+
- **`kind: 'skill'` (procedural / credential).** Invoke the named consumer
|
|
129
|
+
sign-in skill, which reads a per-persona **`credentialRef`** — an indirect
|
|
130
|
+
handle to a stored credential, never an inline secret. Read the skill's
|
|
131
|
+
`SKILL.md` and follow it.
|
|
132
|
+
- **Never enter real credentials inline.** The agent MUST NOT type real
|
|
133
|
+
usernames, passwords, or tokens to reach an authenticated surface, and MUST
|
|
134
|
+
NOT fabricate or forge a session. Sign-in flows only through the seam, which
|
|
135
|
+
consumes a persona name or a `credentialRef` indirection — never a
|
|
136
|
+
hand-typed secret. This is a hard security boundary, not a convenience to
|
|
127
137
|
work around.
|
|
128
|
-
- **
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
138
|
+
- **Redaction is mandatory.** Every captured evidence string — console,
|
|
139
|
+
network, headers — passes through the shared redaction path (§ 3) before it
|
|
140
|
+
reaches disk or GitHub; bearer tokens, session cookies, `Authorization`
|
|
141
|
+
headers, and PII are masked. Authenticated driving raises the stakes on
|
|
142
|
+
redaction, it does not relax it.
|
|
143
|
+
- **Static only where no seam resolves.** When the target environment resolves
|
|
144
|
+
**no** `signInSeam`, drive only the unauthenticated surface or fall back to
|
|
145
|
+
static driving (§ 2), and record the gap in the ledger so the partial
|
|
146
|
+
coverage is visible. A surface that could not be driven because the
|
|
147
|
+
environment carries no seam is itself a coverage signal worth recording, not
|
|
148
|
+
a silent skip.
|
|
135
149
|
|
|
136
150
|
## 5. Cross-References
|
|
137
151
|
|