mandrel 1.70.0 → 1.72.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 +6 -6
- package/.agents/docs/SDLC.md +4 -5
- package/.agents/docs/configuration.md +9 -9
- package/.agents/docs/workflows.md +4 -6
- package/.agents/schemas/qa-finding.schema.json +1 -1
- package/.agents/scripts/apply-quality-bootstrap.js +2 -2
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +1 -1
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +1 -1
- package/.agents/scripts/lib/config/defaults.js +1 -1
- package/.agents/scripts/lib/config/sync-agentrc.js +1 -1
- package/.agents/scripts/lib/config-resolver.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +35 -5
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +1 -1
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +1 -1
- package/.agents/scripts/{agents-update-preflight.js → mandrel-update-preflight.js} +11 -11
- package/.agents/scripts/sync-agentrc.js +2 -2
- package/.agents/skills/skills.index.json +2 -2
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +3 -3
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +4 -4
- package/.agents/workflows/git-deliver.md +298 -0
- package/.agents/workflows/helpers/epic-testing.md +6 -6
- package/.agents/workflows/helpers/{agents-sync-config.md → mandrel-sync-config.md} +5 -4
- package/.agents/workflows/helpers/plan-epic.md +51 -8
- package/.agents/workflows/helpers/plan-story.md +18 -2
- package/.agents/workflows/{agents-update.md → mandrel-update.md} +8 -8
- package/.agents/workflows/plan.md +71 -3
- package/.agents/workflows/qa-explore.md +1 -1
- package/.agents/workflows/{qa-run-harness.md → qa-run.md} +5 -5
- package/README.md +20 -0
- package/docs/CHANGELOG.md +23 -0
- package/package.json +1 -1
- package/.agents/workflows/git-commit-all.md +0 -15
- package/.agents/workflows/git-pr-all.md +0 -281
- package/.agents/workflows/git-push.md +0 -63
package/.agents/README.md
CHANGED
|
@@ -333,7 +333,7 @@ See [`docs/SDLC.md` § Ticket hierarchy](docs/SDLC.md) for the diagram and execu
|
|
|
333
333
|
| Check registry authoring rules | [§ Self-healing checks](#self-healing-checks) |
|
|
334
334
|
| JSON Schema conventions | [§ Schemas](#schemas) |
|
|
335
335
|
| Bootstrap script (project + GitHub setup) | [`scripts/bootstrap.js`](scripts/bootstrap.js) |
|
|
336
|
-
| Adopt the QA workflows (`/qa-explore`, `/qa-assist`, `/qa-run
|
|
336
|
+
| Adopt the QA workflows (`/qa-explore`, `/qa-assist`, `/qa-run`) in your project | [§ Adopting the QA harness](#adopting-the-qa-harness) |
|
|
337
337
|
| Coordinate two operators on the same repo (lease model) | [§ Multi-developer coordination](#multi-developer-coordination) |
|
|
338
338
|
|
|
339
339
|
---
|
|
@@ -890,12 +890,12 @@ known scenario set:
|
|
|
890
890
|
`/qa-assist` when you hit something mid-flight and want it captured well
|
|
891
891
|
without breaking stride; reach for `/qa-explore` when you want the agent to
|
|
892
892
|
go hunt a named surface.
|
|
893
|
-
- **`/qa-run
|
|
893
|
+
- **`/qa-run <selector>`** — the **automated complement**: it drives a
|
|
894
894
|
consumer's Gherkin `.feature` scenarios through a real browser (the
|
|
895
895
|
`chrome-devtools` MCP surface), captures per-surface console/network into
|
|
896
896
|
structured `F#` findings, and drafts follow-up tickets for operator
|
|
897
897
|
sign-off. The end-to-end procedure is the SSOT in
|
|
898
|
-
[`workflows/qa-run
|
|
898
|
+
[`workflows/qa-run.md`](workflows/qa-run.md); the
|
|
899
899
|
instrumentation conventions live in the
|
|
900
900
|
[`skills/stack/qa/qa-harness`](skills/stack/qa/qa-harness/SKILL.md) skill; the
|
|
901
901
|
architectural overview (run pipeline, contract fields, finding shape) is in
|
|
@@ -904,7 +904,7 @@ known scenario set:
|
|
|
904
904
|
Reach for `/qa-explore` when you want the **agent** to hunt a freshly delivered
|
|
905
905
|
Story/Feature or run a structured bug-hunt captured into a triageable ledger;
|
|
906
906
|
reach for `/qa-assist` when **you** hit something mid-flight and want it
|
|
907
|
-
enriched into a single triage-ready ledger item; reach for `/qa-run
|
|
907
|
+
enriched into a single triage-ready ledger item; reach for `/qa-run` to
|
|
908
908
|
step a **known** scenario set through the browser for a regression pass.
|
|
909
909
|
|
|
910
910
|
Binding the QA contract is **opt-in**. All three workflows resolve the
|
|
@@ -989,8 +989,8 @@ environment, never inlined) and `{ signInSkill }` points at a per-persona
|
|
|
989
989
|
sign-in skill.
|
|
990
990
|
|
|
991
991
|
Once these three `qa.*` keys are in place, `/qa-explore <surface>`,
|
|
992
|
-
`/qa-assist`, and `/qa-run
|
|
993
|
-
operate against the bound surface. For `/qa-run
|
|
992
|
+
`/qa-assist`, and `/qa-run <selector>` all resolve the contract and
|
|
993
|
+
operate against the bound surface. For `/qa-run`, the `chrome-devtools`
|
|
994
994
|
MCP surface is a host-provided runtime dependency; when it is unavailable the
|
|
995
995
|
harness degrades with a clear error rather than falling back to a headless
|
|
996
996
|
runner. `/qa-explore` and `/qa-assist` read the same `qa.*` keys to scope their
|
package/.agents/docs/SDLC.md
CHANGED
|
@@ -1103,7 +1103,7 @@ for the acceptance tier is governed by
|
|
|
1103
1103
|
[`rules/gherkin-standards.md`](../rules/gherkin-standards.md).
|
|
1104
1104
|
|
|
1105
1105
|
The acceptance tier is executed and reported via
|
|
1106
|
-
[`workflows/qa-run
|
|
1106
|
+
[`workflows/qa-run.md`](../workflows/qa-run.md) and consumed as
|
|
1107
1107
|
epic evidence by
|
|
1108
1108
|
[`workflows/helpers/epic-testing.md`](../workflows/helpers/epic-testing.md).
|
|
1109
1109
|
|
|
@@ -1146,8 +1146,8 @@ set:
|
|
|
1146
1146
|
(`qa-ledger.schema.json`) and reuses the same `scripts/lib/qa/` and
|
|
1147
1147
|
`scripts/lib/findings/` decision seams, so a `/qa-assist` item flows through
|
|
1148
1148
|
the identical dedup, classification, and promotion machinery later.
|
|
1149
|
-
- **[`workflows/qa-run
|
|
1150
|
-
(`/qa-run
|
|
1149
|
+
- **[`workflows/qa-run.md`](../workflows/qa-run.md)**
|
|
1150
|
+
(`/qa-run`) — the **automated complement**: it steps a *known* set of
|
|
1151
1151
|
Gherkin `.feature` scenarios through a real browser, asserting `Then`
|
|
1152
1152
|
outcomes semantically against the accessibility snapshot and bundling
|
|
1153
1153
|
console/network problems into structured `F#` findings for operator sign-off.
|
|
@@ -1420,6 +1420,5 @@ For Stories already in flight, use one of the three options above.
|
|
|
1420
1420
|
| *helper* `workflows/helpers/epic-deliver-story` | Per-Story worker called by `/deliver`'s wave loop; not an operator slash command. See [`helpers/epic-deliver-story.md`](../workflows/helpers/epic-deliver-story.md). |
|
|
1421
1421
|
| *helper* `workflows/helpers/single-story-deliver` | Per-Story worker called by `/deliver`; not an operator slash command. See [`helpers/single-story-deliver.md`](../workflows/helpers/single-story-deliver.md). |
|
|
1422
1422
|
| *helper* `workflows/helpers/code-review.md` | Auto-invoked by `/deliver`'s `delivery.code-review` state (scope: epic); not a slash command. |
|
|
1423
|
-
| `/git-
|
|
1424
|
-
| `/git-push` | Stage, commit, and push to remote |
|
|
1423
|
+
| `/git-deliver` | Ad-hoc delivery of working-tree changes — detects the git setup and escalates to commit, commit + push, or commit + push + PR (auto-merge armed). |
|
|
1425
1424
|
| `epic-reconcile.js --explicit-delete` | Hard reset — close orphaned Epic-scoped issues per `.agents/epics/<id>.yaml` |
|
|
@@ -748,8 +748,8 @@ number of keys.
|
|
|
748
748
|
| `github.operatorHandle` | Committed as the `@[USERNAME]` placeholder; each contributor overrides it in gitignored `.agentrc.local.json` | `@[USERNAME]` | Schema-required, but per-contributor: the committed placeholder resolves to null and the lease guards fail closed until you set your own handle locally (see [Per-machine local overrides](#per-machine-local-overrides)). |
|
|
749
749
|
| `delivery.worktreeIsolation.nodeModulesStrategy` | `per-worktree` | `per-worktree` | npm-only repo (`package-lock.json`); worktree init runs `npm ci` per tree. |
|
|
750
750
|
|
|
751
|
-
When a consumer runs `/
|
|
752
|
-
[`
|
|
751
|
+
When a consumer runs `/mandrel-update`, the
|
|
752
|
+
[`mandrel-sync-config`](../workflows/helpers/mandrel-sync-config.md)
|
|
753
753
|
helper validates the project config against the schema, then adds any
|
|
754
754
|
template-introduced keys the project does not already define. Project-side
|
|
755
755
|
values that validate are preserved unconditionally — including optional keys
|
|
@@ -821,10 +821,10 @@ project-specific knob:
|
|
|
821
821
|
1. Confirm the key is **already declared in the schema** at
|
|
822
822
|
[`.agents/schemas/agentrc.schema.json`](../schemas/agentrc.schema.json)
|
|
823
823
|
— if it isn't, the AJV validators will reject it on the next
|
|
824
|
-
`/
|
|
824
|
+
`/mandrel-update`.
|
|
825
825
|
2. Set the key in `.agentrc.json`. Don't add it to the template unless it
|
|
826
826
|
should ship to all consumers.
|
|
827
|
-
3. Run `/
|
|
827
|
+
3. Run `/mandrel-update` to confirm the helper preserves the key on round-trip.
|
|
828
828
|
|
|
829
829
|
### Extending list-valued keys without losing template defaults
|
|
830
830
|
|
|
@@ -898,7 +898,7 @@ This is a framework-level change, not a project-level one. The path is:
|
|
|
898
898
|
[`config-resolver.js`](../scripts/lib/config-resolver.js).
|
|
899
899
|
4. Add tests under `tests/lib/config-*.test.js` and confirm
|
|
900
900
|
`tests/config-schema-mirror-drift.test.js` passes.
|
|
901
|
-
5. Document the key in this file and update `
|
|
901
|
+
5. Document the key in this file and update `mandrel-sync-config.md` only if
|
|
902
902
|
the merge semantics differ from the default (project-wins) rule.
|
|
903
903
|
|
|
904
904
|
---
|
|
@@ -979,10 +979,10 @@ allowlists drift project-to-project.
|
|
|
979
979
|
|
|
980
980
|
### Cadence
|
|
981
981
|
|
|
982
|
-
Run `/fewer-permission-prompts` **once per `/
|
|
982
|
+
Run `/fewer-permission-prompts` **once per `/mandrel-update`
|
|
983
983
|
invocation**, immediately after the package upgrade re-materializes
|
|
984
984
|
`.agents/` and before the bump commit lands. The cadence is codified in
|
|
985
|
-
[`/
|
|
985
|
+
[`/mandrel-update` Step 3.6](../workflows/mandrel-update.md). The
|
|
986
986
|
operator who just bumped `.agents/` has the freshest transcript context
|
|
987
987
|
in the active session, which is exactly what the skill scans, so this
|
|
988
988
|
is the cheapest time to surface new high-frequency calls.
|
|
@@ -1024,7 +1024,7 @@ on the next cadence run if they remain high-frequency, so the cost of
|
|
|
1024
1024
|
deferral is bounded.
|
|
1025
1025
|
|
|
1026
1026
|
Stage the accepted `.claude/settings.json` diff alongside the
|
|
1027
|
-
`/
|
|
1027
|
+
`/mandrel-update` bump commit so the reviewer sees the framework pointer
|
|
1028
1028
|
move and the allowlist response in the same diff.
|
|
1029
1029
|
|
|
1030
1030
|
---
|
|
@@ -1093,7 +1093,7 @@ mandrel uninstall --include-github # acknowledge GitHub-side follow-ups
|
|
|
1093
1093
|
- Resolver entry point —
|
|
1094
1094
|
[`config-resolver.js`](../scripts/lib/config-resolver.js)
|
|
1095
1095
|
- Sync helper —
|
|
1096
|
-
[`
|
|
1096
|
+
[`mandrel-sync-config.md`](../workflows/helpers/mandrel-sync-config.md)
|
|
1097
1097
|
- Bootstrap script —
|
|
1098
1098
|
[`bootstrap.js`](../scripts/bootstrap.js)
|
|
1099
1099
|
- Quality gates runbook (CRAP onboarding, MI ratchet, lint ratchet) —
|
|
@@ -25,11 +25,10 @@ by `node .agents/scripts/generate-workflows-doc.js`; `npm run docs:check`
|
|
|
25
25
|
fails when it drifts from the on-disk workflow set. To change a command’s
|
|
26
26
|
description, edit the workflow file’s front-matter and regenerate.
|
|
27
27
|
|
|
28
|
-
## Commands (
|
|
28
|
+
## Commands (25)
|
|
29
29
|
|
|
30
30
|
| Command | Description |
|
|
31
31
|
| --- | --- |
|
|
32
|
-
| `/agents-update` | npm-era upgrade wraparound for a Mandrel consumer. Runs `npx mandrel update` (resolve newest published version → install → re-materialize `.agents/` → migrate → doctor → surface changelog) as the single mechanical step, then walks the operator through the judgment wraparound the CLI deliberately leaves unowned: reconcile `.agentrc.json`, install the Epic #1386 quality-gate surface, refresh the harness permission allowlist, reconcile the consumer's `AGENTS.md` / runbooks against the surfaced changelog, and stage + commit the staged lockfile bump. |
|
|
33
32
|
| `/audit-architecture` | Audit architectural boundaries, module coupling, and layering violations; emit a structured findings report keyed to High/Medium/Low severity. |
|
|
34
33
|
| `/audit-clean-code` | Audit code smells, dead code, complexity hotspots, and maintainability-index outliers; emit a structured findings report. |
|
|
35
34
|
| `/audit-dependencies` | Audit `package.json` for unused, outdated, and major-version-stale dependencies; surface Node-engine drift and propose upgrade batches. |
|
|
@@ -48,11 +47,10 @@ description, edit the workflow file’s front-matter and regenerate.
|
|
|
48
47
|
| `/deliver` | Unified delivery entry point. Inspects the ticket type(s) and Epic-reference state of the supplied IDs, composes a sequential segment plan over any mix of Epics and standalone Stories, then delegates each segment to the Epic wave loop or the standalone multi-Story fan-out — preserving every flag and the parallel-delivery contract of the retired commands. |
|
|
49
48
|
| `/explain` | Walk the operator through a code change until they genuinely understand it. Targets a PR, a branch, or the working-tree diff, then drives the `core/knowledge-transfer` skill (restate-first, why-ladder, mastery gates, persistent checklist) with an operator-controlled stop at every checkpoint. |
|
|
50
49
|
| `/git-cleanup` | Tidy the local checkout in four phases: fast-forward `main`, prune stale remote-tracking refs, sweep merged branches (squash-aware), and triage `git stash` entries — each step gated by operator confirmation. |
|
|
51
|
-
| `/git-
|
|
50
|
+
| `/git-deliver` | Single ad-hoc delivery command for working-tree changes. Detects the git setup and escalates to the right terminal step — commit only, commit + push, or commit + push + open a PR with native auto-merge — picking the default from observable state and letting flags pin any level explicitly. Replaces the retired git-commit-all, git-push, and git-pr-all trio. |
|
|
52
51
|
| `/git-merge-pr` | Analyze, validate, resolve conflicts, and merge a given pull request by number. |
|
|
53
|
-
| `/
|
|
54
|
-
| `/git-push` | Commit all outstanding changes then push to the remote repository. |
|
|
52
|
+
| `/mandrel-update` | npm-era upgrade wraparound for a Mandrel consumer. Runs `npx mandrel update` (resolve newest published version → install → re-materialize `.agents/` → migrate → doctor → surface changelog) as the single mechanical step, then walks the operator through the judgment wraparound the CLI deliberately leaves unowned: reconcile `.agentrc.json`, install the Epic #1386 quality-gate surface, refresh the harness permission allowlist, reconcile the consumer's `AGENTS.md` / runbooks against the surfaced changelog, and stage + commit the staged lockfile bump. |
|
|
55
53
|
| `/plan` | Unified planning entry point. Routes a seed idea (via scope triage) or an existing Epic ID to the right planning path — the full Epic pipeline (PRD, Tech Spec, Acceptance Spec, decomposition) or the standalone-Story authoring path — and absorbs every planning flag. |
|
|
56
54
|
| `/qa-assist` | Human-led QA assist loop — set up, then ride a rolling multi-observation intake session. The operator reports observations in any order; the agent enriches each (repro + root-cause file:line + coverage verdict for bugs; analysis + options + recommendation for enhancements), asks clarifying questions only when ambiguous, and appends a redacted ledger item — recording, never planning — to a persistent, resumable session under temp/qa/. Only when the operator says they are done does it review the full ledger and hand off to /plan. |
|
|
57
55
|
| `/qa-explore` | Agent-led exploratory-QA loop — the agent Plans a surface with an explicit static-vs-drive method choice, drives it (browser MCP or static), and captures ledger items read-only, then Triages — a bounded per-surface session, HITL-gated at every phase transition, routed through the shared dedup/coverage/classification/missing-test/redaction/session core under temp/qa/ |
|
|
58
|
-
| `/qa-run
|
|
56
|
+
| `/qa-run` | Drive Gherkin scenarios through a real browser as an agent-driven QA sweep |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"title": "QaFinding",
|
|
4
|
-
"description": "Structured `F#` finding emitted by the agent-driven QA harness (`.agents/workflows/qa-run
|
|
4
|
+
"description": "Structured `F#` finding emitted by the agent-driven QA harness (`.agents/workflows/qa-run.md`, Epic #3214). One object per genuine problem surfaced while sweeping a consumer's Gherkin scenarios through chrome-devtools MCP: a non-allowlisted console error, a failed/error-status network request, or a gross design-token violation. Findings are validated against this schema before they are bundled by likely root cause into operator-approved follow-up ticket drafts (the harness never files tickets autonomously). The shape mirrors the F# convergence in Tech Spec #3285 and is produced in its console-derived subset by `.agents/scripts/lib/qa/console-allowlist.js`.",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"additionalProperties": false,
|
|
7
7
|
"required": [
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* apply-quality-bootstrap.js — Story #4171
|
|
5
|
-
* (refactor(
|
|
5
|
+
* (refactor(mandrel-update): extract the quality-bootstrap heredoc into a
|
|
6
6
|
* tested script)
|
|
7
7
|
*
|
|
8
8
|
* Replaces the inline `node -e "Promise.all([...])"` heredoc that Step 3.5 of
|
|
9
|
-
* the `/
|
|
9
|
+
* the `/mandrel-update` workflow used to carry. That shape was fragile in three
|
|
10
10
|
* ways: it broke across shells (PowerShell vs bash quoting / backticks), it
|
|
11
11
|
* had no test so it silently drifted when the two helper signatures moved, and
|
|
12
12
|
* it could not be invoked or dry-run independently.
|
|
@@ -180,7 +180,7 @@ export const CI_WORKFLOW_RELATIVE_PATH = '.github/workflows/ci.yml';
|
|
|
180
180
|
* `unchanged`. When the file is absent the action is `created`. When the
|
|
181
181
|
* file exists with operator-authored differences the helper preserves it
|
|
182
182
|
* and returns `custom-workflow-skip` along with the rendered body so the
|
|
183
|
-
* bootstrap caller (or `/
|
|
183
|
+
* bootstrap caller (or `/mandrel-update`) can offer a side-by-side diff.
|
|
184
184
|
*
|
|
185
185
|
* Network-free; safe to invoke under tests with a tmp `projectRoot`.
|
|
186
186
|
*
|
|
@@ -242,7 +242,7 @@ export function ensureQualityNpmScripts(ctx) {
|
|
|
242
242
|
* underneath the project config at read time, so a key whose intended
|
|
243
243
|
* value equals the framework default would be written redundantly — and
|
|
244
244
|
* would then be flagged `[REDUNDANT]` by the sync-agentrc helper on the
|
|
245
|
-
* next /
|
|
245
|
+
* next /mandrel-update. Default-aware seeding keeps the two helpers from
|
|
246
246
|
* contradicting each other.
|
|
247
247
|
*
|
|
248
248
|
* Returns `{ merged, addedKeys[] }` so the caller can report exactly
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* (tests/config/full-agentrc-runtime-parity.test.js) keeps the two in
|
|
10
10
|
* lockstep.
|
|
11
11
|
*
|
|
12
|
-
* Story #1995: the `/
|
|
12
|
+
* Story #1995: the `/mandrel-update` sync helper consults this module
|
|
13
13
|
* (not the template directly) to decide whether a project value is
|
|
14
14
|
* "just the default" and therefore safe to omit from `.agentrc.json`.
|
|
15
15
|
*
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* untouched. Operators who want a leaner config can prune the
|
|
17
17
|
* redundant keys by hand.
|
|
18
18
|
*
|
|
19
|
-
* Outcome: after `/
|
|
19
|
+
* Outcome: after `/mandrel-update`, `.agentrc.json` contains only keys
|
|
20
20
|
* that materially diverge from framework defaults, plus the
|
|
21
21
|
* consumer-identity keys with no sensible framework default (owner,
|
|
22
22
|
* repo, operatorHandle).
|
|
@@ -199,7 +199,7 @@ function applyDefaults(raw) {
|
|
|
199
199
|
// `#/$defs/qa`). It needs no default-layering — the harness resolver
|
|
200
200
|
// (`resolveQaContract`) owns normalization and required-field
|
|
201
201
|
// enforcement — it only needs to survive the reshape so
|
|
202
|
-
// `/qa-run
|
|
202
|
+
// `/qa-run` Step 0 can read it off the resolved wrapper.
|
|
203
203
|
...(raw.qa !== undefined ? { qa: raw.qa } : {}),
|
|
204
204
|
};
|
|
205
205
|
}
|
|
@@ -26,6 +26,15 @@
|
|
|
26
26
|
* "clean sprint" retro trailer), emit `epic.merge.ready`. Otherwise emit
|
|
27
27
|
* `epic.merge.blocked` with a non-empty reason.
|
|
28
28
|
*
|
|
29
|
+
* Code-review parse-miss policy (Story #4222): a code-review comment that is
|
|
30
|
+
* present but whose severity bullets cannot be parsed is treated as a DISTINCT
|
|
31
|
+
* condition — surfaced via the `codeReviewUnparseable` signal — and FAILS OPEN
|
|
32
|
+
* rather than blocking. Failing closed on a format miss is indistinguishable,
|
|
33
|
+
* to the operator and to downstream telemetry, from a real disqualifying
|
|
34
|
+
* finding; a parser miss must never masquerade as "the signal said no" inside
|
|
35
|
+
* a generic `epic.merge.blocked`. Genuine critical/high findings still block,
|
|
36
|
+
* because those require the counts to have parsed.
|
|
37
|
+
*
|
|
29
38
|
* Critical contract:
|
|
30
39
|
* - The verdict for any given input set is byte-identical to the
|
|
31
40
|
* pre-inlining legacy module's output — this file is its
|
|
@@ -229,11 +238,30 @@ function evaluateCodeReviewSignals(codeReview, reasons) {
|
|
|
229
238
|
: { critical: null, high: null, medium: null, suggestion: null };
|
|
230
239
|
if (!codeReviewFound) {
|
|
231
240
|
reasons.push('code-review structured comment not found on Epic');
|
|
232
|
-
return { codeReviewFound, severity };
|
|
241
|
+
return { codeReviewFound, codeReviewUnparseable: false, severity };
|
|
233
242
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
243
|
+
// "Present but unparseable" is a DISTINCT condition from "present and says
|
|
244
|
+
// no" (Story #4222). The canonical renderer
|
|
245
|
+
// (`review-providers/findings-renderer.js`) always emits all four severity
|
|
246
|
+
// bullets, so a body whose critical/high counts we cannot extract is a
|
|
247
|
+
// FORMAT MISS, not a disqualifying signal. Failing closed here — pushing a
|
|
248
|
+
// generic block reason — is indistinguishable, to the operator and to
|
|
249
|
+
// downstream telemetry (the mandrel-bench Autonomy dimension), from a real
|
|
250
|
+
// critical finding: it stalls an otherwise-clean unattended run for a
|
|
251
|
+
// non-reason.
|
|
252
|
+
//
|
|
253
|
+
// Chosen policy: FAIL OPEN on an unparseable code-review body. We surface
|
|
254
|
+
// the condition explicitly via the `codeReviewUnparseable` signal so
|
|
255
|
+
// telemetry can tell a parser miss from a true HITL hand-off, but we do NOT
|
|
256
|
+
// add a disqualifying `reasons[]` entry — the absence of a parseable
|
|
257
|
+
// critical/high count cannot, on its own, block a run whose other signals
|
|
258
|
+
// are clean. Genuine disqualifying review findings (critical > 0 /
|
|
259
|
+
// high > 0) still block below, because those require the counts to have
|
|
260
|
+
// parsed successfully.
|
|
261
|
+
const codeReviewUnparseable =
|
|
262
|
+
severity.critical === null || severity.high === null;
|
|
263
|
+
if (codeReviewUnparseable) {
|
|
264
|
+
return { codeReviewFound, codeReviewUnparseable, severity };
|
|
237
265
|
}
|
|
238
266
|
if (severity.critical > 0) {
|
|
239
267
|
reasons.push(`code-review has ${severity.critical} 🔴 Critical Blocker(s)`);
|
|
@@ -241,7 +269,7 @@ function evaluateCodeReviewSignals(codeReview, reasons) {
|
|
|
241
269
|
if (severity.high > 0) {
|
|
242
270
|
reasons.push(`code-review has ${severity.high} 🟠 High Risk finding(s)`);
|
|
243
271
|
}
|
|
244
|
-
return { codeReviewFound, severity };
|
|
272
|
+
return { codeReviewFound, codeReviewUnparseable, severity };
|
|
245
273
|
}
|
|
246
274
|
|
|
247
275
|
function evaluateRetroSignals(retro, reasons) {
|
|
@@ -287,6 +315,7 @@ function evaluateRetroSignals(retro, reasons) {
|
|
|
287
315
|
* storyStatuses: string[],
|
|
288
316
|
* storyBlockers: number,
|
|
289
317
|
* severity: { critical: number|null, high: number|null, medium: number|null, suggestion: number|null },
|
|
318
|
+
* codeReviewUnparseable: boolean,
|
|
290
319
|
* retroCompact: boolean,
|
|
291
320
|
* codeReviewFound: boolean,
|
|
292
321
|
* retroFound: boolean,
|
|
@@ -308,6 +337,7 @@ export function deriveAutoMergeVerdict({ state, codeReview, retro }) {
|
|
|
308
337
|
storyStatuses: stateSig.storyStatuses,
|
|
309
338
|
storyBlockers: stateSig.storyBlockers,
|
|
310
339
|
severity: reviewSig.severity,
|
|
340
|
+
codeReviewUnparseable: reviewSig.codeReviewUnparseable,
|
|
311
341
|
retroCompact: retroSig.retroCompact,
|
|
312
342
|
codeReviewFound: reviewSig.codeReviewFound,
|
|
313
343
|
retroFound: retroSig.retroFound,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* QA context hydrator — Story #3805, Epic #3798 (f1-shared-qa-core).
|
|
3
3
|
*
|
|
4
|
-
* Both QA front-ends (`/qa-explore` and `/qa-run
|
|
4
|
+
* Both QA front-ends (`/qa-explore` and `/qa-run`) need to load the
|
|
5
5
|
* *grounded* surface context for an Epic before they reason about what to test:
|
|
6
6
|
* the Epic body, its linked context tickets (PRD / Tech Spec / Acceptance
|
|
7
7
|
* Spec), the project's `.feature` files, the implementation files the surface
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `qa` contract resolver — Epic #3214, Story #3294.
|
|
3
3
|
*
|
|
4
|
-
* The agent-driven QA harness (`/qa-run
|
|
4
|
+
* The agent-driven QA harness (`/qa-run`) needs the
|
|
5
5
|
* consumer's `.agentrc.json` `qa` block to know where the `.feature` root
|
|
6
6
|
* lives, how to sign in, and which personas the seam accepts. The block is
|
|
7
7
|
* *optional in the schema* (most repos never bind the harness, so config
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* (feat(
|
|
4
|
+
* mandrel-update-preflight.js — Story #4170
|
|
5
|
+
* (feat(mandrel-update): add a first-run preflight before the updater)
|
|
6
6
|
*
|
|
7
|
-
* A first-run preflight for the `/
|
|
7
|
+
* A first-run preflight for the `/mandrel-update` workflow. The workflow
|
|
8
8
|
* otherwise jumps straight to `npx mandrel update` with no guard rails;
|
|
9
9
|
* this preflight catches three day-0 failure modes *before* the version
|
|
10
10
|
* bump:
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* `lib/cli/update.js` itself — the CLI stays git-free and
|
|
34
34
|
* side-effect-scoped; this is a workflow-layer concern.
|
|
35
35
|
*
|
|
36
|
-
* The detection logic is a pure function (`
|
|
36
|
+
* The detection logic is a pure function (`runMandrelUpdatePreflight`) that
|
|
37
37
|
* takes injectable probes so it is unit-testable without touching the real
|
|
38
38
|
* filesystem, git index, or network. The CLI wrapper wires the real probes
|
|
39
39
|
* and maps a blocker finding to a non-zero exit code.
|
|
@@ -128,7 +128,7 @@ export function makeProbes(projectRoot) {
|
|
|
128
128
|
* consumer-shape hard stop). `ok` is true when there are no findings of
|
|
129
129
|
* any severity.
|
|
130
130
|
*/
|
|
131
|
-
export function
|
|
131
|
+
export function runMandrelUpdatePreflight({ probes }) {
|
|
132
132
|
/** @type {PreflightFinding[]} */
|
|
133
133
|
const findings = [];
|
|
134
134
|
|
|
@@ -153,7 +153,7 @@ export function runAgentsUpdatePreflight({ probes }) {
|
|
|
153
153
|
findings.push({
|
|
154
154
|
id: 'consumer-shape',
|
|
155
155
|
severity: 'blocker',
|
|
156
|
-
summary: `Not a Mandrel consumer project (${missing.join('; ')}). Run /
|
|
156
|
+
summary: `Not a Mandrel consumer project (${missing.join('; ')}). Run /mandrel-update from a consumer repo that depends on "mandrel" and has a materialized .agents/ tree — not the framework repo itself or an unrelated project.`,
|
|
157
157
|
fix: 'cd into the consumer project root, or run `npm install -D mandrel && npx mandrel sync` to bootstrap one.',
|
|
158
158
|
});
|
|
159
159
|
}
|
|
@@ -194,7 +194,7 @@ export function runAgentsUpdatePreflight({ probes }) {
|
|
|
194
194
|
export function reportPreflight(result, logger) {
|
|
195
195
|
if (result.ok) {
|
|
196
196
|
logger.info(
|
|
197
|
-
'✅ [
|
|
197
|
+
'✅ [mandrel-update-preflight] All checks passed — safe to run `npx mandrel update`.',
|
|
198
198
|
);
|
|
199
199
|
return;
|
|
200
200
|
}
|
|
@@ -208,11 +208,11 @@ export function reportPreflight(result, logger) {
|
|
|
208
208
|
}
|
|
209
209
|
if (result.blocked) {
|
|
210
210
|
logger.error(
|
|
211
|
-
'[
|
|
211
|
+
'[mandrel-update-preflight] Hard stop: do not run `npx mandrel update` until the blocker above is resolved (exit 2).',
|
|
212
212
|
);
|
|
213
213
|
} else {
|
|
214
214
|
logger.warn(
|
|
215
|
-
'[
|
|
215
|
+
'[mandrel-update-preflight] Warnings only — review them, then proceed if intentional.',
|
|
216
216
|
);
|
|
217
217
|
}
|
|
218
218
|
}
|
|
@@ -220,7 +220,7 @@ export function reportPreflight(result, logger) {
|
|
|
220
220
|
async function main() {
|
|
221
221
|
const projectRoot = process.cwd();
|
|
222
222
|
const probes = makeProbes(projectRoot);
|
|
223
|
-
const result =
|
|
223
|
+
const result = runMandrelUpdatePreflight({ probes });
|
|
224
224
|
reportPreflight(result, Logger);
|
|
225
225
|
// Machine-parsable JSON envelope on stdout for tooling / the workflow to
|
|
226
226
|
// read. Use process.stdout.write (not console.log) per the no-console
|
|
@@ -230,6 +230,6 @@ async function main() {
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
runAsCli(import.meta.url, main, {
|
|
233
|
-
source: '
|
|
233
|
+
source: 'mandrel-update-preflight',
|
|
234
234
|
propagateExitCode: true,
|
|
235
235
|
});
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* sync-agentrc.js — default-aware `.agentrc.json` reconciliation (Story #1995).
|
|
5
5
|
*
|
|
6
6
|
* Replaces the manual procedure formerly described in
|
|
7
|
-
* `.agents/workflows/helpers/
|
|
8
|
-
* `/
|
|
7
|
+
* `.agents/workflows/helpers/mandrel-sync-config.md`. Invoked by
|
|
8
|
+
* `/mandrel-update` Step 3 after the package upgrade re-materializes `.agents/`.
|
|
9
9
|
*
|
|
10
10
|
* Contract:
|
|
11
11
|
* - Validates the project config against the framework schema. On
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-06-
|
|
2
|
+
"generatedAt": "2026-06-16T16:35:27.286Z",
|
|
3
3
|
"generator": "generate-skills-index.js@1",
|
|
4
4
|
"skills": [
|
|
5
5
|
{
|
|
@@ -577,7 +577,7 @@
|
|
|
577
577
|
"tier": "stack",
|
|
578
578
|
"category": "qa",
|
|
579
579
|
"path": ".agents/skills/stack/qa/qa-harness/SKILL.md",
|
|
580
|
-
"description": "Conventions for the agent-driven QA harness that drives Gherkin scenarios through a real browser. Use when executing `/qa-run
|
|
580
|
+
"description": "Conventions for the agent-driven QA harness that drives Gherkin scenarios through a real browser. Use when executing `/qa-run` or instrumenting a live surface — covers navigation-first execution, per-surface console and network capture, design-token visual checks, and the framework-generic heuristic cards for turning signal into findings. The harness procedure lives in `.agents/workflows/qa-run.md`; this skill is the conventions reference it leans on.",
|
|
581
581
|
"policyCapsuleBullets": 8,
|
|
582
582
|
"allowedTools": null,
|
|
583
583
|
"vendor": null
|
|
@@ -71,7 +71,7 @@ authoring.
|
|
|
71
71
|
single `defineBddConfig` block that lists `features` and `steps` paths.
|
|
72
72
|
- Register the Cucumber HTML/JSON reporter alongside the Playwright HTML
|
|
73
73
|
reporter so a headless CI invocation emits machine-readable evidence
|
|
74
|
-
alongside the agent-driven `/qa-run
|
|
74
|
+
alongside the agent-driven `/qa-run` sweep.
|
|
75
75
|
- Use Playwright projects (not Cucumber profiles) for browser matrix fan-out —
|
|
76
76
|
keeps sharding, retries, and trace config in one place.
|
|
77
77
|
|
|
@@ -99,7 +99,7 @@ authoring.
|
|
|
99
99
|
tag vocabularies in the runner config; extend via `@domain-*` only.
|
|
100
100
|
- Wire tag-filtered headless runs to a single npm script so operators never
|
|
101
101
|
reconstruct the generate-then-run sequence by hand; the agent-driven
|
|
102
|
-
`/qa-run
|
|
102
|
+
`/qa-run` selector mirrors the same tag expressions for browser sweeps.
|
|
103
103
|
- Fail the run if generation produces zero matching scenarios — a silent empty
|
|
104
104
|
suite is worse than a red build.
|
|
105
105
|
|
|
@@ -184,5 +184,5 @@ those outcomes.
|
|
|
184
184
|
|
|
185
185
|
- Scenario authoring rules: `.agents/rules/gherkin-standards.md`.
|
|
186
186
|
- Browser-level conventions: `.agents/skills/stack/qa/playwright/SKILL.md`.
|
|
187
|
-
- Operator entry point: `.agents/workflows/qa-run
|
|
187
|
+
- Operator entry point: `.agents/workflows/qa-run.md`.
|
|
188
188
|
- Evidence handoff: `.agents/workflows/helpers/epic-testing.md`.
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
name: qa-harness
|
|
3
3
|
description:
|
|
4
4
|
Conventions for the agent-driven QA harness that drives Gherkin scenarios
|
|
5
|
-
through a real browser. Use when executing `/qa-run
|
|
5
|
+
through a real browser. Use when executing `/qa-run` or instrumenting
|
|
6
6
|
a live surface — covers navigation-first execution, per-surface console and
|
|
7
7
|
network capture, design-token visual checks, and the framework-generic
|
|
8
8
|
heuristic cards for turning signal into findings. The harness procedure lives
|
|
9
|
-
in `.agents/workflows/qa-run
|
|
9
|
+
in `.agents/workflows/qa-run.md`; this skill is the conventions
|
|
10
10
|
reference it leans on.
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -26,7 +26,7 @@ description:
|
|
|
26
26
|
Guidance for executing the agent-driven QA harness through a real browser (the
|
|
27
27
|
chrome-devtools MCP surface). The harness **procedure** — argument parsing,
|
|
28
28
|
step ordering, contract resolution sequence — is the SSOT in
|
|
29
|
-
[`.agents/workflows/qa-run
|
|
29
|
+
[`.agents/workflows/qa-run.md`](../../../../workflows/qa-run.md);
|
|
30
30
|
this skill shows **how** to apply the instrumentation and inspection
|
|
31
31
|
conventions that procedure depends on. The assertion-tier rules it enforces
|
|
32
32
|
live in [`testing-standards.md`](../../../../rules/testing-standards.md)
|
|
@@ -212,7 +212,7 @@ QA evidence ticket.
|
|
|
212
212
|
|
|
213
213
|
## 7. Cross-References
|
|
214
214
|
|
|
215
|
-
- Run procedure (SSOT): [`qa-run
|
|
215
|
+
- Run procedure (SSOT): [`qa-run.md`](../../../../workflows/qa-run.md).
|
|
216
216
|
- Console filter module: [`console-allowlist.js`](../../../../scripts/lib/qa/console-allowlist.js).
|
|
217
217
|
- Assertion-tier rules: [`testing-standards.md`](../../../../rules/testing-standards.md).
|
|
218
218
|
- Scenario prose: [`gherkin-authoring`](../gherkin-authoring/SKILL.md).
|