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.
Files changed (78) hide show
  1. package/.agents/README.md +104 -330
  2. package/.agents/agents/auditor.md +135 -0
  3. package/.agents/agents/plan-critic.md +80 -0
  4. package/.agents/audit-checklists/dependencies.md +7 -0
  5. package/.agents/audit-checklists/documentation.md +1 -0
  6. package/.agents/docs/SDLC.md +69 -162
  7. package/.agents/docs/configuration.md +133 -499
  8. package/.agents/docs/quality-gates.md +59 -180
  9. package/.agents/instructions.md +170 -295
  10. package/.agents/rules/changelog-style.md +8 -66
  11. package/.agents/rules/ci-remediation.md +65 -124
  12. package/.agents/rules/gherkin-standards.md +10 -31
  13. package/.agents/rules/git-conventions-reference.md +28 -61
  14. package/.agents/rules/git-conventions.md +1 -1
  15. package/.agents/rules/orchestration-error-handling.md +5 -15
  16. package/.agents/rules/security-baseline.md +7 -13
  17. package/.agents/rules/shell-conventions.md +4 -13
  18. package/.agents/rules/test-seams.md +2 -2
  19. package/.agents/rules/testing-standards.md +7 -17
  20. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +7 -2
  21. package/.agents/scripts/lib/feedback-loop/graduator-core.js +144 -12
  22. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +11 -1
  23. package/.agents/scripts/lib/observability/runtime-friction.js +97 -36
  24. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +29 -5
  25. package/.agents/skills/core/api-and-interface-design/SKILL.md +23 -297
  26. package/.agents/skills/core/api-and-interface-design/reference.md +76 -0
  27. package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +20 -327
  28. package/.agents/skills/core/browser-testing-with-devtools/reference.md +74 -0
  29. package/.agents/skills/core/code-review-and-quality/reference.md +16 -398
  30. package/.agents/skills/core/debugging-and-error-recovery/reference.md +14 -281
  31. package/.agents/skills/core/documentation-and-adrs/reference.md +42 -338
  32. package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +28 -326
  33. package/.agents/skills/core/idea-refinement/SKILL.md +67 -193
  34. package/.agents/skills/core/security-and-hardening/SKILL.md +15 -31
  35. package/.agents/skills/core/security-and-hardening/reference.md +15 -273
  36. package/.agents/skills/skills.index.json +5 -5
  37. package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +16 -222
  38. package/.agents/skills/stack/qa/gherkin-authoring/reference.md +157 -0
  39. package/.agents/skills/stack/qa/playwright/SKILL.md +0 -29
  40. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +19 -23
  41. package/.agents/skills/stack/qa/qa-harness/SKILL.md +35 -53
  42. package/.agents/skills/stack/qa/vitest/SKILL.md +0 -29
  43. package/.agents/workflows/audit-accessibility.md +34 -108
  44. package/.agents/workflows/audit-architecture.md +35 -123
  45. package/.agents/workflows/audit-clean-code.md +19 -78
  46. package/.agents/workflows/audit-data-model.md +32 -100
  47. package/.agents/workflows/audit-dependencies.md +47 -111
  48. package/.agents/workflows/audit-devops.md +16 -83
  49. package/.agents/workflows/audit-documentation.md +46 -93
  50. package/.agents/workflows/audit-navigability.md +26 -80
  51. package/.agents/workflows/audit-performance.md +40 -106
  52. package/.agents/workflows/audit-privacy.md +17 -80
  53. package/.agents/workflows/audit-quality.md +35 -99
  54. package/.agents/workflows/audit-security.md +20 -78
  55. package/.agents/workflows/audit-seo.md +20 -98
  56. package/.agents/workflows/audit-sre.md +20 -88
  57. package/.agents/workflows/audit-to-stories.md +1 -8
  58. package/.agents/workflows/audit-ux-ui.md +17 -80
  59. package/.agents/workflows/deliver.md +54 -9
  60. package/.agents/workflows/git-cleanup.md +50 -275
  61. package/.agents/workflows/helpers/audit-lens-core.md +230 -0
  62. package/.agents/workflows/helpers/code-review.md +11 -23
  63. package/.agents/workflows/helpers/deliver-story-reference.md +114 -17
  64. package/.agents/workflows/helpers/deliver-story.md +26 -186
  65. package/.agents/workflows/helpers/qa-core.md +174 -0
  66. package/.agents/workflows/helpers/qa-run-scenario-reference.md +35 -0
  67. package/.agents/workflows/helpers/qa-run-scenario.md +11 -25
  68. package/.agents/workflows/helpers/worktree-lifecycle.md +6 -67
  69. package/.agents/workflows/mandrel-update.md +7 -13
  70. package/.agents/workflows/plan.md +17 -15
  71. package/.agents/workflows/qa-assist.md +140 -269
  72. package/.agents/workflows/qa-explore.md +125 -316
  73. package/.agents/workflows/qa-run.md +180 -380
  74. package/docs/CHANGELOG.md +18 -0
  75. package/package.json +1 -1
  76. package/.agents/workflows/helpers/audit-dual-path.md +0 -59
  77. package/.agents/workflows/helpers/audit-self-check.md +0 -70
  78. 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
- agent rides alongside as the QA engineer and captures what they see into a
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 in a single message. The agent splits a multi-observation message
17
- into discrete items and runs each through **Intake → Enrich → Record**, then
18
- **loops straight back** to wait for more. It **records and enriches only — it
19
- never plans or fixes during intake.**
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 the agent route the full ledger
24
- into [`/plan`](plan.md) to generate Stories.
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 recorded
30
- as a `QaLedgerItem` against the
31
- [`qa-ledger.schema.json`](../schemas/qa-ledger.schema.json) contract the same
32
- ledger `/qa-explore` and the triage/promotion path consume — so a `/qa-assist`
33
- item flows through the identical dedup, classification, and promotion machinery
34
- in Phase 4.
35
-
36
- This is a **prose workflow**, not a Node orchestrator: the host LLM executes
37
- the procedure; deterministic Node helpers under `.agents/scripts/lib/qa/` and
38
- `.agents/scripts/lib/findings/` do the contract resolution, session/ledger
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
- human owns what was observed; you enrich it. Apply the QA skills; there is
55
- no separate persona pack.
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
- Rule forbids inventing the signal. Set up, announce ready, and wait.
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
- Resolve the consumer's `qa` contract during Setup, via
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 testing pass. Resolve the session and its ledger
93
- path **once**, during Setup, via
94
- [`qa-session.js`](../scripts/lib/qa/qa-session.js):
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
- This is a HITL workflow, but the gating is deliberately **light during intake
116
- and firm at the boundary**, so the rolling loop stays fluid:
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 a ceremony, pausing
120
- only to **ask clarifying questions when the observation is ambiguous**. After
121
- each append it **echoes the recorded item** so the operator can correct it,
122
- then **loops back to wait for the next observation**. The agent does **not**
123
- triage, route, file tickets, or invoke `/plan` during intake.
124
- - **Two things always require explicit operator confirmation.** First, the
125
- session-level transition from rolling intake into **Phase 4 — Triage & Plan**
126
- the agent never starts planning on its own; the operator must say they are
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. If
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
- - which session this is (new vs. resumed) and how many items are already on
150
- the ledger;
151
- - what you will do with each observation (enrich bugs with repro +
152
- root-cause `file:line` + coverage; enrich enhancements with analysis +
153
- options + a recommendation) and that you will **record only, not plan**;
154
- - that you are **ready for observations, in any order**, and that they
155
- should tell you when they are **done testing** to move into triage/planning.
156
- 5. **Wait.** Do not invent an observation. If `/qa-assist` was launched with an
157
- `observation` argument, treat it as the first intake and proceed to Phase 1;
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**; this
166
- phase first splits the message into discrete observations, then runs Intake for
167
- **each** of them, before returning here for the next message.
168
-
169
- 1. **Split a brain dump into discrete observations.** Parse the operator's
170
- message into the distinct things they observed one ledger item per
171
- distinct symptom, surface, or idea. Use their own structure (numbered or
172
- bulleted list, blank-line-separated paragraphs, "and another thing…") as the
173
- split boundary; do **not** merge two unrelated symptoms into one item or
174
- split a single symptom into several. **Echo the parsed list back** ("I read
175
- N observations: …") and let the operator correct the split before you
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. This restatement is your read
184
- of the signal.
185
- - **Ask clarifying questions only when that observation is ambiguous.** If
186
- you cannot confidently fill in the load-bearing facts, **ask** — do not
187
- paper over the gap with an assumption. Typical gaps: which
188
- surface/command/flow; the exact steps and whether it reproduces or is
189
- intermittent; what was expected and why that is the contract; the
190
- environment (OS, shell, branch, fresh vs. reused state). When the
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 core helpers; never re-derive them in prose.
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**: read the relevant code, console output, and logs for
217
- errors, and pin the locus as a concrete **`file:line`** reference (say so
218
- explicitly if you cannot pin it rather than inventing a locus). Then run
219
- the coverage steps below.
220
- - **Enhancement / suggestion.** Analyze **how** the change would be made:
221
- the surfaces it touches, the **options** for implementing it, and a brief
222
- **recommendation** with trade-offs. Record these notes on the ledger item.
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
- feature-file set, the surface
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 how to
241
- read the per-tier `{present|absent}` verdict. Optionally render a
242
- human-readable summary via
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). It
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 the proposal's `description` as the ledger item's `missingTest`.
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
- (`tooling-dx` carries `meta::framework-gap`; `enhancement` carries
254
- `meta::consumer-improvement`). The helper **throws** on an absent/unknown
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 `temp/qa/<sessionId>.ndjson`, conforming to
266
- [`qa-ledger.schema.json`](../schemas/qa-ledger.schema.json): a stable `id`
267
- (`L1`, `L2`, … appended after any carried backlog), the redacted `evidence`,
268
- the repro and root-cause `file:line` notes (or the enhancement
269
- analysis/options/recommendation), the `coverage` label, the `class` and
270
- `severity`, the `missingTest`, and a `disposition` of **untriaged** (intake
271
- does not decide disposition — Phase 4 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
- can correct it on the spot. When a brain dump produced several items, append
275
- them all, then echo a **compact batch summary** (one line per new `Lx` item)
276
- instead of a separate message per item.
277
- 3. **Loop back to Phase 1** and wait for the next message. Keep doing this for
278
- as many observations as the operator reports one at a time or in batches,
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 orderuntil 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
- operator: every item, its class/severity, root-cause or recommendation, and
291
- coverage verdict. Confirm it is complete and ask any **last clarifying
292
- questions** — missing repro, an item that should be split or merged, a
293
- severity to adjust. Let the operator set each item's disposition
294
- (`file` / `defer` / `dismiss`).
295
-
296
- 2. **Dedup / route** each `file`-dispositioned finding against existing GitHub
297
- Issues via [`route-finding.js`](../scripts/lib/findings/route-finding.js)
298
- (the **single** dedup implementation shared with `/qa-explore` and
299
- `audit-to-stories`), backed by
300
- [`semantic-issue-search.js`](../scripts/lib/findings/semantic-issue-search.js):
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: each `/plan`
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 observations in any order and any quantity — one at a time or a brain
365
- dump of many in a single message. The agent splits a brain dump into discrete
366
- ledger items (echoing the split for correction), then enriches and records
367
- each one. Never invent an observation; **ask clarifying questions** only when
368
- an observation is ambiguous, batched across the dump.
369
- - **Record during intake; plan only on "done".** Phases 1–3 enrich and append
370
- to the ledger and loop they never triage, route, file tickets, or invoke
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 session-level move into Phase 4 and **every
375
- write** that leaves the local ledger (ticket, `/plan`, label) require
376
- **explicit operator confirmation**.
377
- - **Persistent, resumable rolling session.** `/qa-assist` defaults to resuming
378
- the same session and **appending** to its ledger; a reused session carries
379
- the un-triaged backlog forward via
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 ([`coverage-verdict.js`](../scripts/lib/qa/coverage-verdict.js)),
391
- coverage report ([`coverage-report.js`](../scripts/lib/qa/coverage-report.js)),
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
- Phase 4 (`--seed-file` / `--seed`). The plan→deliver
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
- - [`promote-finding.js`](../scripts/lib/findings/promote-finding.js) /
417
- [`route-finding.js`](../scripts/lib/findings/route-finding.js) — the shared
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.