mandrel 2.6.0 → 2.8.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 +104 -330
- package/.agents/agents/auditor.md +135 -0
- package/.agents/agents/plan-critic.md +80 -0
- package/.agents/audit-checklists/dependencies.md +7 -0
- package/.agents/audit-checklists/documentation.md +1 -0
- package/.agents/docs/SDLC.md +69 -162
- package/.agents/docs/configuration.md +133 -499
- package/.agents/docs/quality-gates.md +59 -180
- package/.agents/instructions.md +170 -295
- package/.agents/rules/changelog-style.md +8 -66
- package/.agents/rules/ci-remediation.md +65 -124
- package/.agents/rules/gherkin-standards.md +10 -31
- package/.agents/rules/git-conventions-reference.md +28 -61
- package/.agents/rules/git-conventions.md +1 -1
- package/.agents/rules/orchestration-error-handling.md +5 -15
- package/.agents/rules/security-baseline.md +7 -13
- package/.agents/rules/shell-conventions.md +4 -13
- package/.agents/rules/test-seams.md +2 -2
- package/.agents/rules/testing-standards.md +7 -17
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +7 -2
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +144 -12
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +11 -1
- package/.agents/scripts/lib/observability/runtime-friction.js +97 -36
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +29 -5
- package/.agents/skills/core/api-and-interface-design/SKILL.md +23 -297
- package/.agents/skills/core/api-and-interface-design/reference.md +76 -0
- package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +20 -327
- package/.agents/skills/core/browser-testing-with-devtools/reference.md +74 -0
- package/.agents/skills/core/code-review-and-quality/reference.md +16 -398
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +14 -281
- package/.agents/skills/core/documentation-and-adrs/reference.md +42 -338
- package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +28 -326
- package/.agents/skills/core/idea-refinement/SKILL.md +67 -193
- package/.agents/skills/core/security-and-hardening/SKILL.md +15 -31
- package/.agents/skills/core/security-and-hardening/reference.md +15 -273
- package/.agents/skills/skills.index.json +5 -5
- package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +16 -222
- package/.agents/skills/stack/qa/gherkin-authoring/reference.md +157 -0
- package/.agents/skills/stack/qa/playwright/SKILL.md +0 -29
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +19 -23
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +35 -53
- package/.agents/skills/stack/qa/vitest/SKILL.md +0 -29
- package/.agents/workflows/audit-accessibility.md +34 -108
- package/.agents/workflows/audit-architecture.md +35 -123
- package/.agents/workflows/audit-clean-code.md +19 -78
- package/.agents/workflows/audit-data-model.md +32 -100
- package/.agents/workflows/audit-dependencies.md +47 -111
- package/.agents/workflows/audit-devops.md +16 -83
- package/.agents/workflows/audit-documentation.md +46 -93
- package/.agents/workflows/audit-navigability.md +26 -80
- package/.agents/workflows/audit-performance.md +40 -106
- package/.agents/workflows/audit-privacy.md +17 -80
- package/.agents/workflows/audit-quality.md +35 -99
- package/.agents/workflows/audit-security.md +20 -78
- package/.agents/workflows/audit-seo.md +20 -98
- package/.agents/workflows/audit-sre.md +20 -88
- package/.agents/workflows/audit-to-stories.md +1 -8
- package/.agents/workflows/audit-ux-ui.md +17 -80
- package/.agents/workflows/deliver.md +54 -9
- package/.agents/workflows/git-cleanup.md +50 -275
- package/.agents/workflows/helpers/audit-lens-core.md +230 -0
- package/.agents/workflows/helpers/code-review.md +11 -23
- package/.agents/workflows/helpers/deliver-story-reference.md +114 -17
- package/.agents/workflows/helpers/deliver-story.md +26 -186
- package/.agents/workflows/helpers/qa-core.md +174 -0
- package/.agents/workflows/helpers/qa-run-scenario-reference.md +35 -0
- package/.agents/workflows/helpers/qa-run-scenario.md +11 -25
- package/.agents/workflows/helpers/worktree-lifecycle.md +6 -67
- package/.agents/workflows/mandrel-update.md +7 -13
- package/.agents/workflows/plan.md +17 -15
- package/.agents/workflows/qa-assist.md +140 -269
- package/.agents/workflows/qa-explore.md +125 -316
- package/.agents/workflows/qa-run.md +180 -380
- package/docs/CHANGELOG.md +18 -0
- package/package.json +1 -1
- package/.agents/workflows/helpers/audit-dual-path.md +0 -59
- package/.agents/workflows/helpers/audit-self-check.md +0 -70
- package/.agents/workflows/helpers/audit-severity-scale.md +0 -19
|
@@ -4,8 +4,8 @@ description: Human-led QA assist loop — set up, then ride a rolling multi-obse
|
|
|
4
4
|
|
|
5
5
|
# /qa-assist
|
|
6
6
|
|
|
7
|
-
Drive a **human-led, rolling QA-assist session**. The operator tests; the
|
|
8
|
-
|
|
7
|
+
Drive a **human-led, rolling QA-assist session**. The operator tests; the agent
|
|
8
|
+
rides alongside as the QA engineer and captures what they see into a
|
|
9
9
|
high-quality, triage-ready ledger. The session has four movements:
|
|
10
10
|
|
|
11
11
|
1. **Setup & Ready** (Phase 0) — load codebase context, resolve the contract,
|
|
@@ -13,32 +13,29 @@ high-quality, triage-ready ledger. The session has four movements:
|
|
|
13
13
|
and that it is **ready for observations**.
|
|
14
14
|
2. **Rolling intake** (Phases 1–3, looped) — the operator reports observations
|
|
15
15
|
**in any order and any quantity**: one at a time, or a **brain dump** of many
|
|
16
|
-
at once
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
at once. The agent splits a multi-observation message into discrete items and
|
|
17
|
+
runs each through **Intake → Enrich → Record**, then **loops straight back**
|
|
18
|
+
for more. It **records and enriches only — it never plans or fixes during
|
|
19
|
+
intake.**
|
|
20
20
|
3. **Done** — when the operator says they have finished testing, the agent does
|
|
21
21
|
a final review of the **entire** ledger and asks any last clarifying
|
|
22
22
|
questions.
|
|
23
|
-
4. **Triage & Plan** (Phase 4) — only then does
|
|
24
|
-
|
|
23
|
+
4. **Triage & Plan** (Phase 4) — only then does it route the full ledger through
|
|
24
|
+
[`/plan`](plan.md) to generate Stories.
|
|
25
25
|
|
|
26
26
|
Unlike [`/qa-explore`](qa-explore.md) (where the *agent* drives open-ended
|
|
27
27
|
exploration of a named surface), `/qa-assist` is **human-led**: the human owns
|
|
28
28
|
the signal, the agent owns the enrichment. It is the front door for "I'm
|
|
29
|
-
testing — ride along and capture everything well." Each observation is
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
resolution, context hydration, redaction, coverage verdict, classification,
|
|
40
|
-
dedup/route, and promotion. **The agent consumes the shared core helpers; it
|
|
41
|
-
never reimplements those decisions in prose.**
|
|
29
|
+
testing — ride along and capture everything well." Each observation is a
|
|
30
|
+
`QaLedgerItem` on the same ledger `/qa-explore` produces, so a `/qa-assist` item
|
|
31
|
+
flows through the identical dedup, classification, and promotion machinery in
|
|
32
|
+
Phase 4.
|
|
33
|
+
|
|
34
|
+
The shared machinery — contract resolution + loud failure, the session & ledger
|
|
35
|
+
contract, redact-first, the `QaLedgerItem` shape, the triage procedure, and the
|
|
36
|
+
HITL write gate — lives once in [`helpers/qa-core.md`](helpers/qa-core.md); this
|
|
37
|
+
workflow states only the `/qa-assist`-specific phases (Intake / Enrich) plus a
|
|
38
|
+
Constraints delta.
|
|
42
39
|
|
|
43
40
|
> **When to run**: a developer or operator is about to test (or is mid-test) and
|
|
44
41
|
> wants every bug and enhancement idea captured as a high-quality,
|
|
@@ -50,9 +47,9 @@ never reimplements those decisions in prose.**
|
|
|
50
47
|
## Role framing
|
|
51
48
|
|
|
52
49
|
You are the quality gatekeeper for this run: value coverage, hermetic
|
|
53
|
-
environments, and deterministic results. **Never invent the signal** — the
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
environments, and deterministic results. **Never invent the signal** — the human
|
|
51
|
+
owns what was observed; you enrich it. Apply the QA skills; there is no separate
|
|
52
|
+
persona pack.
|
|
56
53
|
|
|
57
54
|
## Slash Command
|
|
58
55
|
|
|
@@ -67,66 +64,37 @@ no separate persona pack.
|
|
|
67
64
|
| `observation` | no | `"sync-commands wipes .claude on a reused name"` | An optional first observation, or a brain dump of several. **Usually omitted** — the normal launch is a bare `/qa-assist`, which does Setup and then waits. If supplied, run Setup first, then feed it in as the first intake (splitting it if it carries multiple observations). |
|
|
68
65
|
|
|
69
66
|
A bare `/qa-assist` is the expected entry point. **Do not** demand an
|
|
70
|
-
observation up front and **do not** synthesize one — the QA Golden
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
## Project contract
|
|
67
|
+
observation up front and **do not** synthesize one — the QA Golden Rule forbids
|
|
68
|
+
inventing the signal. Set up, announce ready, and wait.
|
|
74
69
|
|
|
75
|
-
|
|
76
|
-
[`resolve-qa-contract.js`](../scripts/lib/qa/resolve-qa-contract.js):
|
|
77
|
-
|
|
78
|
-
```js
|
|
79
|
-
import { resolveQaContract } from '../scripts/lib/qa/resolve-qa-contract.js';
|
|
80
|
-
const contract = resolveQaContract(config); // throws loudly if unbound
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
The resolver fails **loudly** when the project has not bound the QA harness
|
|
84
|
-
(no `qa` block in `.agentrc.json`) — there is no silent fallback. If it throws
|
|
85
|
-
the "this project has not bound the QA harness" message, surface that verbatim
|
|
86
|
-
to the operator and stop; do not pretend a contract exists.
|
|
87
|
-
|
|
88
|
-
## Session & ledger (temp/qa/) — persistent, resumable, rolling
|
|
70
|
+
## Contract & session — persistent, resumable, rolling
|
|
89
71
|
|
|
72
|
+
Resolve the `qa` contract and the session per
|
|
73
|
+
[`helpers/qa-core.md`](helpers/qa-core.md) during Setup — the resolver fails
|
|
74
|
+
**loudly** when the harness is unbound; surface that verbatim and stop.
|
|
90
75
|
`/qa-assist` **defaults to a persistent rolling session**: the same session is
|
|
91
76
|
resumed across invocations so an operator can top up the same ledger across a
|
|
92
|
-
working day or a multi-launch
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
```js
|
|
97
|
-
import { resolveQaSession } from '../scripts/lib/qa/qa-session.js';
|
|
98
|
-
const { sessionId, ledgerPath, reused, untriaged } = resolveQaSession({ config });
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
- The ledger is always written under **`temp/qa/<sessionId>.ndjson`**
|
|
102
|
-
(`<tempRoot>/qa/`, resolved from `project.paths.tempRoot`). It is one
|
|
103
|
-
`QaLedgerItem` per line (ndjson). **Never** write the ledger anywhere else,
|
|
104
|
-
and never commit it — `temp/` is gitignored per
|
|
105
|
-
[`.agents/instructions.md` § 6](../instructions.md).
|
|
106
|
-
- When `reused` is `true`, a prior session of the same id exists: **append**,
|
|
107
|
-
never overwrite, and surface the carried `untriaged` items as the rolling
|
|
108
|
-
backlog so the operator sees what is still open. Pass `--session-id <id>`
|
|
109
|
-
(or `QA_SESSION_ID`) to resume or fork a named session. A `/qa-assist` run is
|
|
110
|
-
additive to the prior ledger by default — this is the resumable rolling
|
|
111
|
-
session contract.
|
|
77
|
+
working day or a multi-launch pass. A reused session **appends** (never
|
|
78
|
+
overwrites) and surfaces the carried `untriaged` items as the rolling backlog so
|
|
79
|
+
the operator sees what is still open. Pass `--session-id <id>` (or
|
|
80
|
+
`QA_SESSION_ID`) to resume or fork a named session.
|
|
112
81
|
|
|
113
82
|
## Phase gates (HITL)
|
|
114
83
|
|
|
115
|
-
|
|
116
|
-
|
|
84
|
+
Gating is deliberately **light during intake and firm at the boundary**, so the
|
|
85
|
+
rolling loop stays fluid:
|
|
117
86
|
|
|
118
87
|
- **Within a single observation, Intake → Enrich → Record is fluid.** The agent
|
|
119
|
-
restates, enriches, and appends the ledger item without
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- **Two things always require explicit operator confirmation
|
|
125
|
-
|
|
126
|
-
|
|
88
|
+
restates, enriches, and appends the ledger item without ceremony, pausing only
|
|
89
|
+
to **ask clarifying questions when the observation is ambiguous**. After each
|
|
90
|
+
append it **echoes the recorded item** for correction, then **loops back** for
|
|
91
|
+
the next observation. It does **not** triage, route, file tickets, or invoke
|
|
92
|
+
`/plan` during intake.
|
|
93
|
+
- **Two things always require explicit operator confirmation** (the HITL write
|
|
94
|
+
gate in [`helpers/qa-core.md`](helpers/qa-core.md)). First, the session-level
|
|
95
|
+
transition into **Phase 4 — Triage & Plan** — the operator must say they are
|
|
127
96
|
done. Second, **every write that leaves the local ledger** — filing a ticket,
|
|
128
|
-
invoking `/plan`, or mutating a label. Present the artifact, ask, and wait.
|
|
129
|
-
the operator does not confirm, hold.
|
|
97
|
+
invoking `/plan`, or mutating a label. Present the artifact, ask, and wait.
|
|
130
98
|
|
|
131
99
|
In short: appending to the rolling ledger is the natural product of intake and
|
|
132
100
|
needs no gate beyond the echo-back; **planning and anything that leaves the
|
|
@@ -145,88 +113,69 @@ Goal: become the operator's QA assistant before any observation arrives.
|
|
|
145
113
|
draw on to enrich observations without guessing.
|
|
146
114
|
3. **Resolve the `qa` contract and the rolling session** (above). Compute the
|
|
147
115
|
ledger path and load any carried `untriaged` backlog.
|
|
148
|
-
4. **Announce readiness.** Tell the operator, in one short message:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
otherwise wait for the operator's first report.
|
|
116
|
+
4. **Announce readiness.** Tell the operator, in one short message: which
|
|
117
|
+
session this is (new vs. resumed) and how many items are already on the
|
|
118
|
+
ledger; what you will do with each observation (enrich bugs with repro +
|
|
119
|
+
root-cause `file:line` + coverage; enrich enhancements with analysis +
|
|
120
|
+
options + a recommendation) and that you will **record only, not plan**; and
|
|
121
|
+
that you are **ready for observations, in any order** and they should tell you
|
|
122
|
+
when they are **done testing**.
|
|
123
|
+
5. **Wait.** Do not invent an observation. If launched with an `observation`
|
|
124
|
+
argument, treat it as the first intake and proceed to Phase 1; otherwise wait
|
|
125
|
+
for the operator's first report.
|
|
159
126
|
|
|
160
127
|
---
|
|
161
128
|
|
|
162
129
|
## Phase 1 — Intake (per observation, looped)
|
|
163
130
|
|
|
164
131
|
Goal: understand **exactly what the human observed** before enriching it. The
|
|
165
|
-
operator's message may carry **one observation or a brain dump of many**;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
enrich anything — this is the only confirmation intake requires. A
|
|
177
|
-
single-observation message is just the N = 1 case; skip the echo when it is
|
|
132
|
+
operator's message may carry **one observation or a brain dump of many**; split
|
|
133
|
+
first, then run Intake for **each** before returning for the next message.
|
|
134
|
+
|
|
135
|
+
1. **Split a brain dump into discrete observations.** Parse the message into the
|
|
136
|
+
distinct things observed — one ledger item per distinct symptom, surface, or
|
|
137
|
+
idea. Use the operator's own structure (numbered/bulleted list, blank-line
|
|
138
|
+
paragraphs, "and another thing…") as the split boundary; do **not** merge two
|
|
139
|
+
unrelated symptoms or split one symptom into several. **Echo the parsed list
|
|
140
|
+
back** ("I read N observations: …") and let the operator correct the split
|
|
141
|
+
before you enrich anything — the only confirmation intake requires. A
|
|
142
|
+
single-observation message is the N = 1 case; skip the echo when it is
|
|
178
143
|
unambiguously one item.
|
|
179
144
|
2. **Process each observation in turn** through the rest of this phase and
|
|
180
145
|
Phases 2–3. For each one:
|
|
181
146
|
- **Restate the observation** in your own words — the surface it touches, the
|
|
182
147
|
action taken, the actual result, and (for a bug) the expected result, or
|
|
183
|
-
(for an enhancement) the desired improvement.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
observation is already clear, **do not interrogate** — move straight to
|
|
192
|
-
Enrich. Batch the questions across the brain dump into one message rather
|
|
193
|
-
than interrogating item-by-item, so the operator answers them all at once.
|
|
148
|
+
(for an enhancement) the desired improvement.
|
|
149
|
+
- **Ask clarifying questions only when that observation is ambiguous.** If you
|
|
150
|
+
cannot confidently fill in the load-bearing facts, **ask** — do not paper
|
|
151
|
+
over the gap with an assumption. Typical gaps: which surface/command/flow;
|
|
152
|
+
the exact steps and whether it reproduces; what was expected and why that is
|
|
153
|
+
the contract; the environment (OS, shell, branch, fresh vs. reused state).
|
|
154
|
+
When the observation is already clear, **do not interrogate**. Batch the
|
|
155
|
+
questions across the brain dump into one message.
|
|
194
156
|
|
|
195
157
|
---
|
|
196
158
|
|
|
197
159
|
## Phase 2 — Enrich (per observation)
|
|
198
160
|
|
|
199
161
|
Goal: turn the observation into a high-quality, triage-ready finding. Delegate
|
|
200
|
-
every decision to the shared
|
|
201
|
-
|
|
202
|
-
1. **Redact first.** Before any evidence string touches disk or GitHub, scrub
|
|
203
|
-
it through [`redact-evidence.js`](../scripts/lib/qa/redact-evidence.js):
|
|
204
|
-
|
|
205
|
-
```js
|
|
206
|
-
import { redactEvidence } from '../scripts/lib/qa/redact-evidence.js';
|
|
207
|
-
const evidence = redactEvidence(rawObservation);
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
This is mandatory per [`security-baseline.md`](../rules/security-baseline.md)
|
|
211
|
-
(§ Data Leakage & Logging, § Secrets Management) — bearer tokens, session
|
|
212
|
-
cookies, and emails are masked. The pass is idempotent, so redact eagerly.
|
|
162
|
+
every decision to the shared helpers; never re-derive them in prose.
|
|
213
163
|
|
|
164
|
+
1. **Redact first** (per [`helpers/qa-core.md`](helpers/qa-core.md)) — scrub the
|
|
165
|
+
evidence string through `redactEvidence` before it touches disk or GitHub.
|
|
214
166
|
2. **Branch on what kind of observation it is.**
|
|
215
167
|
- **Bug.** Establish a clean, minimal, deterministic **repro**. Investigate
|
|
216
|
-
the **root cause
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
Still pin the relevant `file:line` anchor(s) where the change would land.
|
|
224
|
-
|
|
168
|
+
the **root cause** (read the relevant code, console, and logs) and pin the
|
|
169
|
+
locus as a concrete **`file:line`** reference (say so explicitly if you
|
|
170
|
+
cannot pin it rather than inventing a locus). Then run the coverage steps.
|
|
171
|
+
- **Enhancement / suggestion.** Analyze **how** the change would be made: the
|
|
172
|
+
surfaces it touches, the **options**, and a brief **recommendation** with
|
|
173
|
+
trade-offs. Still pin the relevant `file:line` anchor(s) where the change
|
|
174
|
+
would land.
|
|
225
175
|
3. **Hydrate the QA context** to locate code precisely, via
|
|
226
176
|
[`qa-context-hydrator.js`](../scripts/lib/qa/qa-context-hydrator.js) — it
|
|
227
|
-
resolves the source ticket body, the
|
|
228
|
-
|
|
229
|
-
map, and recent git log:
|
|
177
|
+
resolves the source ticket body, the feature-file set, the surface map, and
|
|
178
|
+
recent git log:
|
|
230
179
|
|
|
231
180
|
```js
|
|
232
181
|
import { hydrateQaContext } from '../scripts/lib/qa/qa-context-hydrator.js';
|
|
@@ -237,22 +186,18 @@ every decision to the shared core helpers; never re-derive them in prose.
|
|
|
237
186
|
via [`coverage-verdict.js`](../scripts/lib/qa/coverage-verdict.js) — the
|
|
238
187
|
deterministic seam behind the
|
|
239
188
|
[`core/qa-coverage-mapping`](../skills/core/qa-coverage-mapping/SKILL.md)
|
|
240
|
-
skill. Read that skill for how to assemble the `surface` input and
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
[`coverage-report.js`](../scripts/lib/qa/coverage-report.js).
|
|
244
|
-
|
|
189
|
+
skill. Read that skill for how to assemble the `surface` input and read the
|
|
190
|
+
per-tier `{present|absent}` verdict. Optionally render a human-readable
|
|
191
|
+
summary via [`coverage-report.js`](../scripts/lib/qa/coverage-report.js).
|
|
245
192
|
5. **Propose the missing test** (if any) from that verdict, via
|
|
246
|
-
[`propose-missing-test.js`](../scripts/lib/qa/propose-missing-test.js)
|
|
193
|
+
[`propose-missing-test.js`](../scripts/lib/qa/propose-missing-test.js) — it
|
|
247
194
|
names the lowest absent tier, or returns `null` when every tier is covered.
|
|
248
|
-
Record
|
|
249
|
-
|
|
195
|
+
Record its `description` as the ledger item's `missingTest`.
|
|
250
196
|
6. **Classify** the finding via
|
|
251
197
|
[`classify-finding.js`](../scripts/lib/findings/classify-finding.js) so the
|
|
252
|
-
tentative `class` resolves to the correct focus/meta label set
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
class — fix the finding's class rather than defaulting.
|
|
198
|
+
tentative `class` resolves to the correct focus/meta label set. The helper
|
|
199
|
+
**throws** on an absent/unknown class — fix the finding's class rather than
|
|
200
|
+
defaulting.
|
|
256
201
|
|
|
257
202
|
---
|
|
258
203
|
|
|
@@ -262,21 +207,20 @@ Goal: persist the enriched finding to the rolling ledger and **return to
|
|
|
262
207
|
intake**. **No triage, routing, ticket-filing, or `/plan` happens here** — that
|
|
263
208
|
is Phase 4, and only after the operator says they are done.
|
|
264
209
|
|
|
265
|
-
1. **Append a `QaLedgerItem`** to
|
|
266
|
-
[`qa-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
`
|
|
271
|
-
does
|
|
210
|
+
1. **Append a `QaLedgerItem`** to the ledger (shape per
|
|
211
|
+
[`helpers/qa-core.md`](helpers/qa-core.md)): a stable `id` (appended after any
|
|
212
|
+
carried backlog), the redacted `evidence`, the repro and root-cause
|
|
213
|
+
`file:line` notes (or the enhancement analysis/options/recommendation), the
|
|
214
|
+
`coverage` label, the `class` and `severity`, the `missingTest`, and a
|
|
215
|
+
`disposition` of **untriaged** (intake does not decide disposition — Phase 4
|
|
216
|
+
does).
|
|
272
217
|
2. **Echo the recorded item** back in one short line — its `class`, `severity`,
|
|
273
|
-
root-cause locus or recommendation, and coverage verdict — so the operator
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
in any order — until they say they are done testing.
|
|
218
|
+
root-cause locus or recommendation, and coverage verdict — so the operator can
|
|
219
|
+
correct it on the spot. When a brain dump produced several items, append them
|
|
220
|
+
all, then echo a **compact batch summary** (one line per new `Lx` item).
|
|
221
|
+
3. **Loop back to Phase 1** and wait for the next message. Keep doing this for as
|
|
222
|
+
many observations as the operator reports — one at a time or in batches, in
|
|
223
|
+
any order — until they say they are done testing.
|
|
280
224
|
|
|
281
225
|
---
|
|
282
226
|
|
|
@@ -286,69 +230,20 @@ Goal: when the operator says they have finished testing, turn the **whole**
|
|
|
286
230
|
ledger into a plan. This is the only phase that triages, routes, or plans, and
|
|
287
231
|
its transition is **explicitly operator-gated**.
|
|
288
232
|
|
|
289
|
-
1. **Final ledger review.** Read the entire rolling ledger back to the
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
`
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
```js
|
|
303
|
-
import { routeFinding, fingerprintFooter } from '../scripts/lib/findings/route-finding.js';
|
|
304
|
-
const { decision, matchedIssue, fingerprint } =
|
|
305
|
-
await routeFinding(finding, { searchIssues });
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
`decision` is one of `new` / `update-existing` / `duplicate` /
|
|
309
|
-
`regression-of-closed`. Stamp the `fingerprintFooter(sha)` marker into any
|
|
310
|
-
Issue body so future runs dedup against it.
|
|
311
|
-
|
|
312
|
-
3. **Promote the full ledger through `/plan`** (never a raw GitHub Issue) via
|
|
313
|
-
[`promote-finding.js`](../scripts/lib/findings/promote-finding.js), which
|
|
314
|
-
clusters, sizes, routes, and files through the same ports `/qa-explore` and
|
|
315
|
-
`/audit-to-stories` consume — never hand-roll the promotion, the clustering,
|
|
316
|
-
or the sizing:
|
|
317
|
-
|
|
318
|
-
```js
|
|
319
|
-
import { promoteFindings } from '../scripts/lib/findings/promote-finding.js';
|
|
320
|
-
const { promotions } = await promoteFindings(ledgerItems, {
|
|
321
|
-
searchIssues, // GitHub provider, open + closed
|
|
322
|
-
createStory, // tight cluster (≤2 surfaces): seed → /plan --seed-file
|
|
323
|
-
createPlanSeed, // broad cluster (>2 surfaces): same /plan --seed-file path (may N>1)
|
|
324
|
-
});
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
- **Sizing is delegated, not decided in prose.** `promoteFindings` runs
|
|
328
|
-
`clusterLedgerItems` + `targetForCluster`: a cluster spanning **≤2**
|
|
329
|
-
distinct coverage surfaces routes to `createStory`; **>2** routes to
|
|
330
|
-
`createPlanSeed`. Neither port opens an Epic ticket — both chain
|
|
331
|
-
`/plan --seed-file`. Do not re-cluster, re-size, or re-dedup in the
|
|
332
|
-
workflow —
|
|
333
|
-
[`route-finding.js`](../scripts/lib/findings/route-finding.js) /
|
|
334
|
-
[`promote-finding.js`](../scripts/lib/findings/promote-finding.js) are the
|
|
335
|
-
single implementation.
|
|
336
|
-
- **`createStory` / `createPlanSeed` (`/plan --seed-file`)** — render a
|
|
337
|
-
**redacted** plan seed from the cluster (reuse the `/audit-to-stories`
|
|
338
|
-
Phase 5a seed shape; redaction already ran in Phase 2), **stamp the
|
|
339
|
-
cluster's `fingerprintFooter(sha)` verbatim into the seed body**, then
|
|
340
|
-
chain `/plan --seed-file <seed>`. Prefer one Story; split only under
|
|
341
|
-
the default-single policy. The footer must survive into the issue body
|
|
342
|
-
so a later `routeFinding` dedups the same finding instead of re-filing
|
|
343
|
-
it.
|
|
344
|
-
- **A `file` disposition never opens a raw GitHub Issue.** Every `file`
|
|
345
|
-
finding flows through `promoteFindings` → `/plan`; only `defer` (carry
|
|
346
|
-
forward as backlog) and `dismiss` (non-actionable) skip the handoff.
|
|
347
|
-
|
|
348
|
-
4. **Gate:** the move into this phase, and every write inside it (seed write,
|
|
233
|
+
1. **Final ledger review.** Read the entire rolling ledger back to the operator:
|
|
234
|
+
every item, its class/severity, root-cause or recommendation, and coverage
|
|
235
|
+
verdict. Confirm it is complete and ask any **last clarifying questions** —
|
|
236
|
+
missing repro, an item that should be split or merged, a severity to adjust.
|
|
237
|
+
Let the operator set each item's disposition (`file` / `defer` / `dismiss`).
|
|
238
|
+
2. **Triage the ledger** through the shared classify → route → disposition →
|
|
239
|
+
promote procedure in [`helpers/qa-core.md`](helpers/qa-core.md): dedup/route
|
|
240
|
+
each `file` finding against open + closed Issues, then promote the
|
|
241
|
+
`file`-dispositioned findings through `promoteFindings` → `/plan` (never a raw
|
|
242
|
+
Issue), stamping each cluster's `fingerprintFooter(sha)` into the seed.
|
|
243
|
+
`defer` carries an item forward as backlog; `dismiss` marks it non-actionable.
|
|
244
|
+
3. **Gate:** the move into this phase, and every write inside it (seed write,
|
|
349
245
|
`/plan` invocation, ticket-filing, label mutation), is **operator-gated** —
|
|
350
|
-
confirm each one. The plan→deliver hard stop is preserved
|
|
351
|
-
chain pauses at its own HITL gates and never auto-delivers. Redaction has
|
|
246
|
+
confirm each one. The plan→deliver hard stop is preserved; redaction has
|
|
352
247
|
already run, so nothing unredacted reaches disk or GitHub.
|
|
353
248
|
|
|
354
249
|
After planning, summarize: the findings recorded, the route/promotion decisions
|
|
@@ -360,60 +255,36 @@ resumed session will pick up.
|
|
|
360
255
|
|
|
361
256
|
## Constraints
|
|
362
257
|
|
|
258
|
+
Beyond the shared core ([`helpers/qa-core.md`](helpers/qa-core.md): contract +
|
|
259
|
+
loud failure, session/ledger, redact-first, QaLedgerItem, triage, HITL gate),
|
|
260
|
+
the `/qa-assist`-specific deltas are:
|
|
261
|
+
|
|
363
262
|
- **Human-led, rolling, multi-observation.** The operator owns the signal and
|
|
364
|
-
reports
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
`/plan`. All of that is **Phase 4**, entered only after explicit operator
|
|
372
|
-
confirmation that testing is done.
|
|
263
|
+
reports in any order and quantity — one at a time or a brain dump. The agent
|
|
264
|
+
splits a brain dump (echoing the split for correction), then enriches and
|
|
265
|
+
records each. **Never invent an observation**; ask clarifying questions only
|
|
266
|
+
when one is ambiguous, batched across the dump.
|
|
267
|
+
- **Record during intake; plan only on "done".** Phases 1–3 enrich, append, and
|
|
268
|
+
loop — never triage, route, file, or invoke `/plan`. All of that is Phase 4,
|
|
269
|
+
entered only on explicit operator confirmation that testing is done.
|
|
373
270
|
- **Light intake gate, firm boundary gate.** Intake → Enrich → Record is fluid
|
|
374
|
-
(echo-back, no ceremony); the
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
[`qa-session.js`](../scripts/lib/qa/qa-session.js) and never overwrites a
|
|
381
|
-
prior ledger.
|
|
382
|
-
- **The ledger lives under `temp/qa/` only**, one `QaLedgerItem` per ndjson
|
|
383
|
-
line, conforming to [`qa-ledger.schema.json`](../schemas/qa-ledger.schema.json).
|
|
384
|
-
Never commit it.
|
|
385
|
-
- **Redact before persist.** Every evidence string passes through
|
|
386
|
-
[`redact-evidence.js`](../scripts/lib/qa/redact-evidence.js) before it
|
|
387
|
-
reaches disk or GitHub, per [`security-baseline.md`](../rules/security-baseline.md).
|
|
388
|
-
- **Consume the shared core; never reimplement.** Context hydration
|
|
271
|
+
(echo-back, no ceremony); the move into Phase 4 and every write that leaves the
|
|
272
|
+
ledger are hard-gated.
|
|
273
|
+
- **Persistent, resumable rolling session** — `/qa-assist` defaults to resuming
|
|
274
|
+
the same session and appending; a reused session carries the untriaged backlog
|
|
275
|
+
forward and never overwrites a prior ledger.
|
|
276
|
+
- **Enrichment helpers are deterministic** — context hydration
|
|
389
277
|
([`qa-context-hydrator.js`](../scripts/lib/qa/qa-context-hydrator.js)),
|
|
390
|
-
coverage verdict
|
|
391
|
-
|
|
392
|
-
missing-test ([`propose-missing-test.js`](../scripts/lib/qa/propose-missing-test.js)),
|
|
393
|
-
classification ([`classify-finding.js`](../scripts/lib/findings/classify-finding.js)),
|
|
394
|
-
dedup/route ([`route-finding.js`](../scripts/lib/findings/route-finding.js)),
|
|
395
|
-
semantic search ([`semantic-issue-search.js`](../scripts/lib/findings/semantic-issue-search.js)),
|
|
396
|
-
promotion ([`promote-finding.js`](../scripts/lib/findings/promote-finding.js)),
|
|
397
|
-
and session resolution ([`qa-session.js`](../scripts/lib/qa/qa-session.js))
|
|
398
|
-
are deterministic — never re-derive them in prose.
|
|
399
|
-
- **Promote through `/plan`, never a raw Issue.** A `file`-dispositioned
|
|
400
|
-
finding is promoted via `promoteFindings`, which chains into
|
|
401
|
-
[`/plan`](plan.md) (`--seed-file` for a tight cluster, `--seed` for a broad
|
|
402
|
-
one) — mirroring [`/audit-to-stories`](audit-to-stories.md). `/qa-assist`
|
|
403
|
-
never opens a bare GitHub Issue for a `file` finding. The cluster's
|
|
404
|
-
`fingerprintFooter(sha)` is stamped verbatim into the seed so a future
|
|
405
|
-
`routeFinding` dedups it.
|
|
278
|
+
coverage verdict/report, missing-test, and classification are never re-derived
|
|
279
|
+
in prose.
|
|
406
280
|
|
|
407
281
|
## See also
|
|
408
282
|
|
|
409
|
-
- [`/plan`](plan.md) — the planning pipeline `/qa-assist` chains into in
|
|
410
|
-
|
|
411
|
-
hard stop is preserved across the handoff.
|
|
283
|
+
- [`/plan`](plan.md) — the planning pipeline `/qa-assist` chains into in Phase 4.
|
|
284
|
+
The plan→deliver hard stop is preserved across the handoff.
|
|
412
285
|
- [`/qa-explore`](qa-explore.md) — the agent-led sibling that drives a named
|
|
413
286
|
surface and triages through the same `/plan` handoff.
|
|
414
287
|
- [`/audit-to-stories`](audit-to-stories.md) — the precedent for the
|
|
415
288
|
findings → `/plan` handoff and the shared fingerprint-footer dedup contract.
|
|
416
|
-
- [`
|
|
417
|
-
|
|
418
|
-
cluster/size/promote and dedup/route/fingerprint-footer helpers. There is no
|
|
419
|
-
second clustering, sizing, or dedup implementation.
|
|
289
|
+
- [`helpers/qa-core.md`](helpers/qa-core.md) — the shared contract/session/
|
|
290
|
+
redaction/QaLedgerItem/triage/HITL core.
|