mandrel 2.7.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/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 +10 -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
|
@@ -35,14 +35,13 @@ it once and reuse the context as you read through any individual gate.
|
|
|
35
35
|
|
|
36
36
|
## Concurrent close safety
|
|
37
37
|
|
|
38
|
-
`/deliver` may close multiple Stories from separate
|
|
39
|
-
succession
|
|
40
|
-
|
|
38
|
+
`/deliver` may close multiple Stories from separate branches in quick
|
|
39
|
+
succession; each rebases onto the latest `main` in its own base-sync phase
|
|
40
|
+
(`phases/base-sync.js`) before the push, so concurrent closes serialize
|
|
41
41
|
through their own worktrees rather than racing one shared branch. The push
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
clean for manual resolution.
|
|
42
|
+
does not retry — a rejected push or a real content conflict fails the close
|
|
43
|
+
non-zero and leaves the tree clean for manual resolution. See
|
|
44
|
+
[`SDLC.md` § Concurrent close](SDLC.md#concurrent-close).
|
|
46
45
|
|
|
47
46
|
---
|
|
48
47
|
|
|
@@ -50,24 +49,18 @@ clean for manual resolution.
|
|
|
50
49
|
|
|
51
50
|
`npm test` (via [`.agents/scripts/run-tests.js`](../scripts/run-tests.js))
|
|
52
51
|
derives `--test-concurrency` from `os.availableParallelism()` at startup,
|
|
53
|
-
clamped into
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
from shared FS fixtures (`memfs` mounts, `temp/` snapshot dirs, the
|
|
59
|
-
`coverage/` artifact directory shared with the CRAP gate).
|
|
52
|
+
clamped into `[1, 16]` (`resolveTestConcurrency`). The clamp keeps the value
|
|
53
|
+
sane at both extremes: on the GitHub Actions 2-vCPU runner the derived value
|
|
54
|
+
matches the host, and on very-wide dev hosts the cap of 16 bounds the
|
|
55
|
+
filesystem-race surface from shared FS fixtures (`memfs` mounts, `temp/`
|
|
56
|
+
snapshot dirs, the `coverage/` artifact directory shared with the CRAP gate).
|
|
60
57
|
|
|
61
58
|
The coverage run is the exception: `npm run test:coverage`
|
|
62
|
-
([`.agents/scripts/run-coverage.js`](../scripts/run-coverage.js))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
that settled on 8 as the project house-style ceiling. Any change to the
|
|
68
|
-
clamp bounds or the coverage pin must be paired with a benchmark run on
|
|
69
|
-
both a Windows dev host and a GitHub Actions runner to confirm it
|
|
70
|
-
doesn't reintroduce concurrency flakes.
|
|
59
|
+
([`.agents/scripts/run-coverage.js`](../scripts/run-coverage.js)) pins
|
|
60
|
+
`--test-concurrency=8` so coverage timings stay comparable across hosts. Any
|
|
61
|
+
change to the clamp bounds or the coverage pin should be validated on both a
|
|
62
|
+
Windows dev host and a GitHub Actions runner to confirm it doesn't reintroduce
|
|
63
|
+
concurrency flakes.
|
|
71
64
|
|
|
72
65
|
---
|
|
73
66
|
|
|
@@ -108,33 +101,14 @@ npm run coverage:update # writes baselines/coverage.json from the run
|
|
|
108
101
|
`coverage-final.json` artifact (useful from CI hooks or close-validation
|
|
109
102
|
runners that orchestrate coverage capture separately).
|
|
110
103
|
|
|
111
|
-
The
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
orchestration logic lives in `lib/orchestration/plan-context.js`,
|
|
120
|
-
`lib/orchestration/plan-persist/*`, and the plan phase modules, and is
|
|
121
|
-
unit-tested there.
|
|
122
|
-
- A larger Story #1702 carve-out of top-level CLI gates, orchestration
|
|
123
|
-
CLIs, git-manipulation CLIs, and `lib/*` glue (e.g. `lint-baseline.js`,
|
|
124
|
-
`single-story-init.js`, `run-tests.js`,
|
|
125
|
-
`lib/config-schema.js`) — see the `.c8rc.cjs` header comment for the
|
|
126
|
-
per-category rationale and the authoritative entry list.
|
|
127
|
-
|
|
128
|
-
Each excluded file also carries `/* node:coverage ignore file */` at
|
|
129
|
-
the top of its source as a second line of defence; the full
|
|
130
|
-
justification for each exclusion lives in the header comment of
|
|
131
|
-
[`.c8rc.cjs`](../../.c8rc.cjs) and MUST be updated when the list changes.
|
|
132
|
-
|
|
133
|
-
The current shape of this pipeline (NODE_V8_COVERAGE +
|
|
134
|
-
`c8 report` instead of wrapping the run in `c8 <cmd>`) was chosen
|
|
135
|
-
after a one-off A/B benchmark showed it was ~19 % faster end-to-end
|
|
136
|
-
on a Windows dev host while producing the same `coverage-final.json`
|
|
137
|
-
artifact.
|
|
104
|
+
The files-out-of-scope list is declared in [`.c8rc.cjs`](../../.c8rc.cjs) —
|
|
105
|
+
thin CLI shells (e.g. `agents-bootstrap-github.js`, `plan-context.js`,
|
|
106
|
+
`plan-persist.js`) plus the larger Story #1702 carve-out of
|
|
107
|
+
top-level/orchestration/git CLIs and `lib/*` glue, each with a per-entry
|
|
108
|
+
rationale in the `.c8rc.cjs` header comment (the authoritative list). Every
|
|
109
|
+
excluded file also carries `/* node:coverage ignore file */` at the top of its
|
|
110
|
+
source as a second line of defence; the header comment MUST be updated when the
|
|
111
|
+
list changes.
|
|
138
112
|
|
|
139
113
|
---
|
|
140
114
|
|
|
@@ -217,66 +191,31 @@ enforced by review (and partially by the audit suite):
|
|
|
217
191
|
risk the floor gate exists to surface; the audit suite spot-checks
|
|
218
192
|
the callee map at exclude-list churn time.
|
|
219
193
|
|
|
220
|
-
Story #1602 audit pass (2026-05-13) removed two stale exclude entries
|
|
221
|
-
(`epic-runner.js`, `ticket-decomposer.js`) whose source files had already
|
|
222
|
-
been deleted in earlier refactors. Every remaining entry was re-verified
|
|
223
|
-
against requirements 1 and 2 above.
|
|
224
|
-
|
|
225
|
-
### Discontinuity with v5 baselines
|
|
226
|
-
|
|
227
|
-
The floor gate landed alongside a fresh baseline reset
|
|
228
|
-
(Tasks #1623, #1625, #1626, #1629). Any direct numeric comparison
|
|
229
|
-
against pre-floor-gate baseline snapshots is meaningless because the
|
|
230
|
-
pre-rebrand scope included files the current tree excludes (CLI shells,
|
|
231
|
-
generated artifacts) and because the absolute-floor gate is new —
|
|
232
|
-
historical files that were "green" on the ratchet may now show as below
|
|
233
|
-
floor and require either real test additions or an intentional
|
|
234
|
-
`.c8rc.cjs` exclude. The Story #1602 close-out lists every file that
|
|
235
|
-
flipped category in the reset.
|
|
236
|
-
|
|
237
194
|
---
|
|
238
195
|
|
|
239
196
|
## Anti-thrashing protocol
|
|
240
197
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
the
|
|
245
|
-
[`.agents/instructions.md`](../instructions.md) are tripped, the
|
|
246
|
-
friction logger flips the Story to `agent::blocked` and
|
|
247
|
-
posts a structured `friction` comment on the Story so the operator has
|
|
248
|
-
the trace.
|
|
198
|
+
The qualitative anti-thrashing cues are owned by
|
|
199
|
+
[`.agents/instructions.md`](../instructions.md) § 1.I. When they trip, the
|
|
200
|
+
friction logger flips the Story to `agent::blocked` and posts a structured
|
|
201
|
+
`friction` comment on the Story so the operator has the trace.
|
|
249
202
|
|
|
250
203
|
---
|
|
251
204
|
|
|
252
205
|
## Per-Story acceptance self-eval gate
|
|
253
206
|
|
|
254
|
-
After a Story's implementation commits land and **before**
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
[`
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
- **proceed** — all criteria met; the Story continues to close.
|
|
268
|
-
- **redraft** — unmet criteria are redrafted and re-implemented, then
|
|
269
|
-
re-evaluated in the next round.
|
|
270
|
-
- **block** — criteria remain unmet after the round cap; the Story
|
|
271
|
-
escalates to the blocked path (`agent::blocked`) for operator review.
|
|
272
|
-
|
|
273
|
-
The loop is always on (hard cutover, no enable flag) and bounded by
|
|
274
|
-
`delivery.acceptanceEval.maxRounds` (default 2, clamped to a minimum of
|
|
275
|
-
1 so the cap cannot be disabled). This gate is complementary to the
|
|
276
|
-
close-validation chain above: that chain proves the code is *healthy*;
|
|
277
|
-
this loop proves it satisfies *this Story's* acceptance criteria. See
|
|
278
|
-
[`.agents/docs/configuration.md`](../docs/configuration.md) for
|
|
279
|
-
the `delivery.acceptanceEval` field reference.
|
|
207
|
+
After a Story's implementation commits land and **before** it proceeds to
|
|
208
|
+
close, delivery runs a bounded acceptance self-eval loop: a fresh-context
|
|
209
|
+
critic scores the caller-injected change set against every inline
|
|
210
|
+
`acceptance[]` item (using `verify[]` output as evidence) and yields
|
|
211
|
+
**proceed** / **redraft** / **block**. This gate is complementary to the
|
|
212
|
+
close-validation chain above — that chain proves the code is *healthy*, this
|
|
213
|
+
loop proves it satisfies *this Story's* acceptance criteria. The per-round
|
|
214
|
+
mechanic is owned by
|
|
215
|
+
[`helpers/acceptance-self-eval`](../workflows/helpers/acceptance-self-eval.md)
|
|
216
|
+
(Step 1a of [`helpers/deliver-story`](../workflows/helpers/deliver-story.md));
|
|
217
|
+
the `delivery.acceptanceEval` field reference is in
|
|
218
|
+
[`configuration.md`](../docs/configuration.md).
|
|
280
219
|
|
|
281
220
|
---
|
|
282
221
|
|
|
@@ -298,8 +237,8 @@ node .agents/scripts/lint-baseline.js capture
|
|
|
298
237
|
|
|
299
238
|
Refresh commits should use a `baseline-refresh:` subject + non-empty body so
|
|
300
239
|
the operator can spot baseline edits in review — same convention as the CRAP
|
|
301
|
-
and maintainability ratchets.
|
|
302
|
-
|
|
240
|
+
and maintainability ratchets. There is no CI guardrail enforcing the
|
|
241
|
+
convention; the operator is the gate.
|
|
303
242
|
|
|
304
243
|
---
|
|
305
244
|
|
|
@@ -316,8 +255,8 @@ between Stories.
|
|
|
316
255
|
Refresh with `npm run maintainability:update`.
|
|
317
256
|
|
|
318
257
|
`delivery.quality.gates.maintainability.targetDirs` controls the scanned
|
|
319
|
-
directories
|
|
320
|
-
|
|
258
|
+
directories (see [`configuration.md`](../docs/configuration.md) for the
|
|
259
|
+
default and the deep-merge extender form).
|
|
321
260
|
|
|
322
261
|
---
|
|
323
262
|
|
|
@@ -354,10 +293,8 @@ generate `baselines/crap.json`, and commit the file with a
|
|
|
354
293
|
`baseline-refresh:` tagged subject + non-empty body so the
|
|
355
294
|
refresh-guardrail accepts it on the next PR.
|
|
356
295
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
indeterminate window. If your test runner doesn't produce per-method
|
|
360
|
-
coverage, see "Disabling the gate" below.
|
|
296
|
+
If your test runner doesn't produce per-method coverage, see "Disabling the
|
|
297
|
+
gate" below.
|
|
361
298
|
|
|
362
299
|
### Disabling the gate (single-flag opt-out)
|
|
363
300
|
|
|
@@ -381,28 +318,11 @@ source edits required. The maintainability ratchet keeps running.
|
|
|
381
318
|
|
|
382
319
|
### Extending `targetDirs` without re-listing framework defaults
|
|
383
320
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
"delivery": {
|
|
390
|
-
"quality": {
|
|
391
|
-
"gates": {
|
|
392
|
-
"crap": {
|
|
393
|
-
"targetDirs": { "append": ["packages/foo/src", "packages/bar/src"] }
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
`{ "append": [...] }` and `{ "prepend": [...] }` are the deep-merge forms.
|
|
402
|
-
Passing a plain array replaces the default entirely — useful when you
|
|
403
|
-
want exactly your dirs and not the framework's. Unknown keys under
|
|
404
|
-
`delivery.quality.gates.crap` warn but don't fail resolution, so you can
|
|
405
|
-
extend forward-compatibly.
|
|
321
|
+
`targetDirs` (like the other list-valued gate keys) accepts the deep-merge
|
|
322
|
+
extender form — `{ "append": [...] }` / `{ "prepend": [...] }` add to the
|
|
323
|
+
framework default (`["src"]`), while a plain array replaces it entirely. The
|
|
324
|
+
worked example and the general rule live once in
|
|
325
|
+
[`configuration.md` § How to extend](../docs/configuration.md#how-to-extend).
|
|
406
326
|
|
|
407
327
|
### Interpreting the JSON report
|
|
408
328
|
|
|
@@ -437,11 +357,9 @@ should land in a commit whose:
|
|
|
437
357
|
`baseline-refresh:`).
|
|
438
358
|
2. Body is non-empty and explains why the refresh is justified.
|
|
439
359
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
self-policing is the operator's job during `/deliver`'s Phase 7
|
|
444
|
-
watch loop — an unjustified baseline ratchet is no longer caught by CI.
|
|
360
|
+
There is no CI guardrail rejecting unlabeled baseline edits; the convention is
|
|
361
|
+
preserved so the operator can grep refresh commits in a PR diff, but
|
|
362
|
+
self-policing is the operator's job during `/deliver`'s watch loop.
|
|
445
363
|
|
|
446
364
|
---
|
|
447
365
|
|
|
@@ -508,50 +426,11 @@ correct shape for a gate with no rescoring path of its own.
|
|
|
508
426
|
|
|
509
427
|
## HITL blocker escalation
|
|
510
428
|
|
|
511
|
-
`risk::high` is
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
lacking explicit authorization), it flips the ticket to
|
|
517
|
-
`agent::blocked`, posts friction context, and waits for operator resume
|
|
518
|
-
(`agent::executing`).
|
|
519
|
-
|
|
520
|
-
`planning.riskHeuristics` remains the rubric for identifying
|
|
521
|
-
high-impact operations that should trigger blocker escalation.
|
|
522
|
-
|
|
523
|
-
---
|
|
524
|
-
|
|
525
|
-
## Post-floor-gate baseline reset (Story #1701)
|
|
526
|
-
|
|
527
|
-
**Date:** 2026-05-14
|
|
528
|
-
**Commit:** `0657272` (Story #1701, Epic #1653)
|
|
529
|
-
**Files refreshed:** `baselines/coverage.json`,
|
|
530
|
-
`baselines/maintainability.json`, `baselines/crap.json`.
|
|
531
|
-
|
|
532
|
-
A one-time baseline reset captured fresh coverage, maintainability, and
|
|
533
|
-
CRAP snapshots on the post-remediation `main` HEAD. The ratchet
|
|
534
|
-
continues from this new floor, not from any pre-floor-gate history.
|
|
535
|
-
|
|
536
|
-
**Policy:** these baselines are **non-comparable** to any prior
|
|
537
|
-
baseline. Do not diff per-file numbers against pre-reset entries to
|
|
538
|
-
reason about regressions — the post-remediation tree contains refactors,
|
|
539
|
-
extractions, and coverage gains that shift the absolute numbers in ways
|
|
540
|
-
the per-file ratchet cannot reconcile across the discontinuity. Use the
|
|
541
|
-
post-reset capture as the new floor; ratchet from there.
|
|
542
|
-
|
|
543
|
-
**Why:** Epic #1184 closed the floor-gate rollout. The absolute-floor
|
|
544
|
-
gate (coverage 90/85/90, MI ≥ 70, CRAP ≤ 20) is wired into
|
|
545
|
-
`.husky/pre-push` and the CI coverage workflow (see
|
|
546
|
-
[`§ Absolute quality floors`](#absolute-quality-floors-epic-1184)).
|
|
547
|
-
With the floor enforced on every in-scope file, every per-file baseline
|
|
548
|
-
entry must clear the absolute floor — this snapshot is the first
|
|
549
|
-
capture that holds that invariant repository-wide.
|
|
550
|
-
|
|
551
|
-
**Operator action:** none. The baseline is committed and
|
|
552
|
-
`maintainability:check` / `coverage:check` / `crap:check` pass against
|
|
553
|
-
it out of the box. The next regression you see will be diffed against
|
|
554
|
-
this baseline, not against pre-reset history.
|
|
429
|
+
`risk::high` is planning/audit metadata only — it never pauses runtime. The
|
|
430
|
+
sole runtime HITL pause point is `agent::blocked`; `planning.riskHeuristics`
|
|
431
|
+
is the rubric for what should escalate. The full model is owned by
|
|
432
|
+
[`.agents/instructions.md`](../instructions.md) § 1.J and
|
|
433
|
+
[`SDLC.md` § HITL model](SDLC.md#hitl-human-in-the-loop-model).
|
|
555
434
|
|
|
556
435
|
---
|
|
557
436
|
|