mandrel 2.40.0 → 2.42.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 +2 -2
- package/.agents/agents/story-worker.md +24 -14
- package/.agents/docs/agentrc-reference.json +7 -2
- package/.agents/docs/configuration.md +5 -2
- package/.agents/instructions.md +5 -6
- package/.agents/rules/api-conventions.md +43 -7
- package/.agents/rules/ci-remediation.md +3 -14
- package/.agents/rules/gherkin-standards.md +21 -6
- package/.agents/rules/git-conventions.md +6 -5
- package/.agents/rules/security-baseline.md +6 -7
- package/.agents/rules/testing-standards.md +75 -198
- package/.agents/schemas/agentrc.schema.json +17 -2
- package/.agents/schemas/validation-evidence.schema.json +3 -1
- package/.agents/scripts/acceptance-eval.js +68 -3
- package/.agents/scripts/coverage-capture.js +25 -8
- package/.agents/scripts/install-matrix-assert.js +2 -2
- package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +6 -0
- package/.agents/scripts/lib/baselines/crap-preview-incremental.js +7 -2
- package/.agents/scripts/lib/baselines/git-base.js +74 -38
- package/.agents/scripts/lib/close-validation/gates.js +153 -25
- package/.agents/scripts/lib/close-validation/process.js +30 -1
- package/.agents/scripts/lib/close-validation/runner.js +5 -0
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +33 -12
- package/.agents/scripts/lib/config/quality.js +36 -21
- package/.agents/scripts/lib/config-settings-schema-delivery.js +6 -0
- package/.agents/scripts/lib/coverage-capture-incremental.js +12 -6
- package/.agents/scripts/lib/crap-baseline-join.js +11 -7
- package/.agents/scripts/lib/full-suite-lock.js +311 -0
- package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +11 -104
- package/.agents/scripts/lib/orchestration/check-baselines/phases/refresh-ack.js +320 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +8 -1
- package/.agents/scripts/lib/orchestration/dependency-candidates.js +139 -0
- package/.agents/scripts/lib/orchestration/epic-candidates.js +159 -0
- package/.agents/scripts/lib/orchestration/epic-checklist.js +103 -0
- package/.agents/scripts/lib/orchestration/epic-container.js +18 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +97 -36
- package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +80 -0
- package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +192 -0
- package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +5 -1
- package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +164 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +14 -2
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +26 -5
- package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +83 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +39 -7
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +70 -18
- package/.agents/scripts/lib/orchestration/ticket-validator.js +11 -1
- package/.agents/scripts/lib/orchestration/verify-credit.js +207 -0
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +24 -0
- package/.agents/scripts/plan-persist.js +60 -1
- package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +5 -10
- package/.agents/skills/core/browser-testing-with-devtools/reference.md +7 -46
- package/.agents/skills/core/code-review-and-quality/SKILL.md +0 -5
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +0 -3
- package/.agents/skills/core/gates-and-baselines/SKILL.md +10 -137
- package/.agents/skills/core/gates-and-baselines/reference.md +103 -0
- package/.agents/skills/core/idea-refinement/SKILL.md +2 -18
- package/.agents/skills/core/security-and-hardening/SKILL.md +2 -4
- package/.agents/skills/core/security-and-hardening/reference.md +0 -70
- package/.agents/skills/skills.index.json +10 -70
- package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +4 -10
- package/.agents/skills/stack/qa/gherkin-authoring/reference.md +9 -113
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +29 -154
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +157 -98
- package/.agents/workflows/git-cleanup.md +3 -2
- package/.agents/workflows/git-deliver.md +3 -2
- package/.agents/workflows/helpers/acceptance-self-eval.md +12 -0
- package/.agents/workflows/helpers/deliver-digest.md +31 -10
- package/.agents/workflows/helpers/deliver-story-reference.md +50 -30
- package/.agents/workflows/helpers/deliver-story.md +23 -21
- package/.agents/workflows/helpers/plan-reference.md +82 -2
- package/.agents/workflows/mandrel-plan.md +45 -45
- package/.agents/workflows/qa-assist.md +20 -17
- package/.agents/workflows/qa-explore.md +30 -29
- package/.agents/workflows/qa-run.md +2 -1
- package/docs/CHANGELOG.md +32 -0
- package/package.json +1 -1
- package/.agents/rules/changelog-style.md +0 -180
- package/.agents/rules/shell-conventions.md +0 -61
- package/.agents/scripts/lib/qa/coverage-verdict.js +0 -214
- package/.agents/skills/core/api-and-interface-design/SKILL.md +0 -55
- package/.agents/skills/core/api-and-interface-design/reference.md +0 -76
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +0 -45
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +0 -56
- package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +0 -54
- package/.agents/skills/core/idea-refinement/refinement-criteria.md +0 -155
- package/.agents/skills/core/idea-refinement/scripts/idea-refine.sh +0 -15
- package/.agents/skills/core/qa-coverage-mapping/SKILL.md +0 -105
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +0 -152
- package/.agents/skills/stack/qa/vitest/SKILL.md +0 -22
|
@@ -40,7 +40,7 @@ that dispatched the work**, never to a spawned worker.
|
|
|
40
40
|
|
|
41
41
|
**A worker returning no terminal envelope is expected, not a failure** — only
|
|
42
42
|
Step 3 mints one. Never re-dispatch the Story on it; resume per § Recovery
|
|
43
|
-
(reference § Idempotence
|
|
43
|
+
(reference § Idempotence).
|
|
44
44
|
|
|
45
45
|
## Step 0 — Initialize (`single-story-init.js`)
|
|
46
46
|
|
|
@@ -73,12 +73,8 @@ One branch, one PR to `main`, commits against the inline `acceptance[]` /
|
|
|
73
73
|
digest-first; read a caller-provided `checklistPath` first, and walk any
|
|
74
74
|
`## Slicing` rows as **intra-session checkpoints** (reference § Step 1).
|
|
75
75
|
2. Implement and commit on the Story branch, iterating with quick advisory
|
|
76
|
-
gates (`typecheck`, `lint`, scoped tests) — the full chain runs in Step 3
|
|
77
|
-
|
|
78
|
-
guards outside the Story's scoped greps are the failure class that bounces
|
|
79
|
-
deliveries. Fix and commit first, then run the self-eval loop. Run it **so
|
|
80
|
-
Step 3 credits it** — a bare `npm test` records nothing, so close re-runs
|
|
81
|
-
the identical suite (reference § Step 1, "Pre-eval full-suite discipline").
|
|
76
|
+
gates (`typecheck`, `lint`, scoped tests) — the full chain runs in Step 3,
|
|
77
|
+
and the **one** creditable full-suite run at Step 2.5.
|
|
82
78
|
|
|
83
79
|
### Step 1a — Bounded acceptance self-eval loop (**required**)
|
|
84
80
|
|
|
@@ -94,14 +90,21 @@ Ceremony is `delivery.routing.ceremonyProfile` × the **derived change level**,
|
|
|
94
90
|
never a planner-authored verdict. **Digest § 3** is the incantation (change set
|
|
95
91
|
once, derive the level, resolve critics with `ceremony-routing.js`); edge cases
|
|
96
92
|
are reference § Step 2. Hard gates always run in Step 3 — the derived level
|
|
97
|
-
never disables them; do **not** pre-run the chain here.
|
|
93
|
+
never disables them; do **not** pre-run the chain here — Step 2.5's credited
|
|
94
|
+
suite run is the sole exception.
|
|
98
95
|
|
|
99
|
-
### Step 2.5 —
|
|
96
|
+
### Step 2.5 — The creditable full-suite run, then push and hand off
|
|
100
97
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
Run the full suite **once**, after the self-eval loop's last fix commit and
|
|
99
|
+
immediately **before** the push, in the shape close credits (**digest § 5**):
|
|
100
|
+
the credit is keyed on the tree, so any later commit invalidates it, and a bare
|
|
101
|
+
`npm test` deposits none. Red → fix, commit, re-run. An inline run makes the
|
|
102
|
+
same run before Step 3.
|
|
103
|
+
|
|
104
|
+
Then (sub-agent dispatch only) push `story-<storyId>` to `origin`, confirm the
|
|
105
|
+
remote ref moved, and return the hand-off — Story id, `workCwd`, branch, pushed
|
|
106
|
+
head SHA, self-eval verdict, `verify[]` evidence — then stop. Do not open the
|
|
107
|
+
PR; do not compose a terminal envelope.
|
|
105
108
|
|
|
106
109
|
## Step 3 — Close and land (`single-story-close.js`)
|
|
107
110
|
|
|
@@ -115,7 +118,7 @@ node <main-repo>/.agents/scripts/single-story-close.js --story <storyId> --cwd <
|
|
|
115
118
|
**The whole delivery tail** — gates, PR, merge wait, `agent::done` flip,
|
|
116
119
|
post-land tail in one process. Never background it, never delegate it to a
|
|
117
120
|
child, and never end your turn while it is still running: "close is running"
|
|
118
|
-
is not a return value. Branch on the envelope's `status` per **digest §
|
|
121
|
+
is not a return value. Branch on the envelope's `status` per **digest § 6**
|
|
119
122
|
(`landed` → Step 7; `pending` → run `nextCommand`; `blocked`/`checks-failed`
|
|
120
123
|
→ Step 4; `failed` → diagnose, re-run). Gate output is captured.
|
|
121
124
|
|
|
@@ -126,7 +129,7 @@ Internals, merge-wait budgets, the slow-CI **async** confirm mode, the
|
|
|
126
129
|
|
|
127
130
|
Relay the validated envelope close emits between its
|
|
128
131
|
`--- STORY DELIVER TERMINAL ---` markers — never free-form prose, never a
|
|
129
|
-
hand-composed object. Statuses, exits and fields: **digest §
|
|
132
|
+
hand-composed object. Statuses, exits and fields: **digest § 6** (SSOT: the
|
|
130
133
|
shipped [schema](../../schemas/story-deliver-terminal.schema.json)).
|
|
131
134
|
`pending` is the only sanctioned no-merge ending.
|
|
132
135
|
|
|
@@ -139,15 +142,14 @@ so only a green on a NEW head SHA re-arms it — a re-run is refused; fix at sou
|
|
|
139
142
|
and push ([`rules/ci-remediation.md`](../../rules/ci-remediation.md)). And a
|
|
140
143
|
`tail.*: false` degrades the report, never the land.
|
|
141
144
|
|
|
142
|
-
**Watch exit codes** — `pr-watch-with-update.js` exits 0 green, 1
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
and no digest exists to read.
|
|
145
|
+
**Watch exit codes** — `pr-watch-with-update.js` exits 0 green, 1 on a genuine
|
|
146
|
+
red, 2 slow-but-not-red (still-running, unresolved, or `notYetStarted`). Never
|
|
147
|
+
route a 2 onto the red path: nothing is broken and no digest exists to read.
|
|
148
|
+
Which slow condition, and what to do: reference § Step 4.
|
|
147
149
|
|
|
148
150
|
**Lost envelope first: read it off disk.** Close persists each to
|
|
149
151
|
`temp/orchestration/story-deliver-terminal-<storyId>.json`; branch on it per
|
|
150
|
-
digest §
|
|
152
|
+
digest § 6. Otherwise do not guess — probe **read-only** with
|
|
151
153
|
`node .agents/scripts/deliver-recover.js --story <storyId>`; it prints the
|
|
152
154
|
**one** next command with its evidence, never a menu. A live close answers
|
|
153
155
|
`close-in-flight`: wait, never re-init underneath it.
|
|
@@ -234,7 +234,7 @@ Each `stories.json` entry: `slug` (`^[a-z0-9][a-z0-9-]*$`), `type: "story"`,
|
|
|
234
234
|
`title`, `body` (`goal`, optional `spec`, `changes[{path, assumption}]` —
|
|
235
235
|
`creates|refactors-existing|deletes`, `non_goals`, `reason_to_exist`),
|
|
236
236
|
top-level `acceptance[]`, `verify[]` (`… (unit|contract|e2e|validate)`), and
|
|
237
|
-
`depends_on[]` (
|
|
237
|
+
`depends_on[]` (a sibling slug, or `#<id>` for an existing open Story).
|
|
238
238
|
|
|
239
239
|
Nothing in that shape inventories the repo for the author. `changes[]` arrives
|
|
240
240
|
pre-resolved against the working tree, and Phase 8's
|
|
@@ -414,7 +414,53 @@ That is the whole point of running it first: a dry run that comes back clean
|
|
|
414
414
|
has already paid for every deterministic refusal, so the real persist has
|
|
415
415
|
nothing left to discover except network failure.
|
|
416
416
|
|
|
417
|
-
## The container Epic (Gate #3
|
|
417
|
+
## The container Epic (Gate #3)
|
|
418
|
+
|
|
419
|
+
Gate #3 has two branches, in this order: **adopt** an Epic that already exists,
|
|
420
|
+
else **create** a new one.
|
|
421
|
+
|
|
422
|
+
### Adopting an open Epic (any N)
|
|
423
|
+
|
|
424
|
+
`epicCandidates[]` in the plan-context envelope lists **every open `type::epic`
|
|
425
|
+
issue**, each `{ id, title, url, score, childIds }`, ranked by token overlap
|
|
426
|
+
between the seed and the Epic's title, `## Goal` and its children's titles. The
|
|
427
|
+
list is deliberately **complete rather than thresholded**: a low score is
|
|
428
|
+
evidence for the operator to weigh, and hiding a candidate is exactly how a
|
|
429
|
+
plan opens its second container for one body of work.
|
|
430
|
+
|
|
431
|
+
This branch fires at **any N, N=1 included** — "add this to the Epic we started
|
|
432
|
+
last week" is the single-Story case, and refusing it below three Stories would
|
|
433
|
+
leave the common follow-up plan with nowhere to file itself. The three-Story
|
|
434
|
+
threshold governs **creation** only, where it still holds: at two Stories a
|
|
435
|
+
pair of ids is as easy to carry as one container id.
|
|
436
|
+
|
|
437
|
+
On a yes, pass `--epic <id>`. Persist then:
|
|
438
|
+
|
|
439
|
+
1. resolves the id **before the first create** (dry run included) — it must be
|
|
440
|
+
**open** and carry `type::epic`, or the run hard-errors having written
|
|
441
|
+
nothing;
|
|
442
|
+
2. after the Stories exist, appends one `- [ ] #N` row per new Story to the
|
|
443
|
+
Epic's checklist via `appendEpicChildIds`, which is idempotent and preserves
|
|
444
|
+
existing rows' **checked state**, their order, and the fingerprint marker;
|
|
445
|
+
3. mirrors a native sub-issue edge per child.
|
|
446
|
+
|
|
447
|
+
The refusal posture is the **opposite** of creation's, deliberately. Creation
|
|
448
|
+
degrades (an unensurable label just skips the container) because the operator
|
|
449
|
+
never named one. Adoption cannot: the operator named a specific id, so silently
|
|
450
|
+
not adopting it would leave them believing their Stories were filed somewhere
|
|
451
|
+
they were not. Hence a hard error, raised while nothing has been written and
|
|
452
|
+
the fix is free. Once the Stories are live the posture flips back — a failed
|
|
453
|
+
checklist write or sub-issue edge only warns.
|
|
454
|
+
|
|
455
|
+
**Only open Epics are adoptable.** A closed Epic is a finished body of work;
|
|
456
|
+
joining one would reopen a container the epilogue deliberately closed and
|
|
457
|
+
re-scope a completed plan. Open a new container, or reopen the old one by hand.
|
|
458
|
+
|
|
459
|
+
`--epic` and `--epic-title`/`--epic-goal` are **mutually exclusive** — a run
|
|
460
|
+
either joins a container or opens one — and supplying both is a usage error
|
|
461
|
+
raised before any I/O.
|
|
462
|
+
|
|
463
|
+
### Creating a new container (N>2)
|
|
418
464
|
|
|
419
465
|
Above two Stories, `/mandrel-plan` offers to group them under one `type::epic`
|
|
420
466
|
container. Confirmed, persist opens it **after** the Stories — its body embeds
|
|
@@ -442,6 +488,40 @@ existing Epic carrying the same fingerprint, which is keyed on the title **and
|
|
|
442
488
|
the exact child set**, so a run grouping different Stories never adopts the
|
|
443
489
|
wrong container.
|
|
444
490
|
|
|
491
|
+
## Cross-plan `depends_on` (`#<id>`)
|
|
492
|
+
|
|
493
|
+
A `depends_on[]` entry is read **lexically**: `some-slug` is a sibling inside
|
|
494
|
+
this plan, `#<id>` an **external** blocker already live on the tracker. The
|
|
495
|
+
second form is what lets a plan authored today wait on a Story an earlier plan
|
|
496
|
+
opened and never had to name.
|
|
497
|
+
|
|
498
|
+
`dependencyCandidates[]` in the envelope is the advisory prompt for it: open
|
|
499
|
+
`type::story` issues whose declared `changes[]` footprint intersects the seed's
|
|
500
|
+
`complexitySignals.predictedPaths`, each carrying the `overlappingPaths[]` that
|
|
501
|
+
matched. Overlap is computed on **declared footprints** and not on prose, using
|
|
502
|
+
the same `storyFootprint` the wave runner uses to withhold colliding Stories at
|
|
503
|
+
dispatch — so the planner sees the collision the runtime would later enforce,
|
|
504
|
+
one layer earlier and while it is still cheap to order around. A seed naming no
|
|
505
|
+
paths short-circuits to `[]` with no provider call at all.
|
|
506
|
+
|
|
507
|
+
It stays advisory: two Stories can touch a shared barrel file with no real
|
|
508
|
+
ordering between them, and only the operator knows.
|
|
509
|
+
|
|
510
|
+
External refs are **excluded from sibling ordering and cycle detection** —
|
|
511
|
+
a Story already open is not scheduled by this run, so it has no position in the
|
|
512
|
+
topological sort and cannot close a cycle back into a Story that does not exist
|
|
513
|
+
yet. They are validated **before any create** (dry run included): each must
|
|
514
|
+
resolve to an **open `type::story`**, and a closed issue, a container Epic, a
|
|
515
|
+
missing id or a non-Story hard-errors with every bad ref named in one pass. The
|
|
516
|
+
strictness is the point — a blocker that can never be satisfied reads to the
|
|
517
|
+
delivery engine as a permanent wedge rather than as an error worth reporting.
|
|
518
|
+
|
|
519
|
+
Persist renders the entry unchanged as a `blocked by #<id>` footer line and
|
|
520
|
+
mirrors the native `blocked_by` edge, which is the same pair of surfaces a
|
|
521
|
+
sibling edge produces. `/mandrel-deliver` therefore gates on it with no engine
|
|
522
|
+
change: `resolve-stories.js` has always resolved foreign blockers from live
|
|
523
|
+
state.
|
|
524
|
+
|
|
445
525
|
## Ready means fully persisted
|
|
446
526
|
|
|
447
527
|
`agent::ready` is the **terminal** step, not part of the creating POST.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description:
|
|
3
3
|
Unified planning entry point. Interrogate → author → persist. Emits one
|
|
4
|
-
Story by default; splits into N>1 only under the default-single split
|
|
5
|
-
policy.
|
|
4
|
+
Story by default; splits into N>1 only under the default-single split policy.
|
|
6
5
|
---
|
|
7
6
|
|
|
8
7
|
# /mandrel-plan
|
|
@@ -19,20 +18,20 @@ mode from what the operator typed, announce it, act**:
|
|
|
19
18
|
| Invocation | Mode | Behavior |
|
|
20
19
|
| --- | --- | --- |
|
|
21
20
|
| `/mandrel-plan` | ask | Ask what to plan; nothing runs first. |
|
|
22
|
-
| `/mandrel-plan add a --json flag to doctor` | seed | Ideation from prose
|
|
21
|
+
| `/mandrel-plan add a --json flag to doctor` | seed | Ideation from prose → **one Story by default** → persist. |
|
|
23
22
|
| `/mandrel-plan temp/notes/idea.md` | seed-file | Same, from notes. An existing file is a path, not prose. |
|
|
24
23
|
| `/mandrel-plan 4712[,4713…]` | tickets | Fetch issue(s), analyze into proper Stories (prefer N=1 rewrite). |
|
|
25
|
-
| `/mandrel-plan 4712`, already delivered | amends | Amend a shipped Story from a **delta envelope
|
|
24
|
+
| `/mandrel-plan 4712`, already delivered | amends | Amend a shipped Story from a **delta envelope**. |
|
|
26
25
|
|
|
27
26
|
**Resolving a bare id.** Read live state rather than asking: `agent::done` can
|
|
28
|
-
only be amended, an open unplanned issue only planned. **Announce the
|
|
29
|
-
"4712 is `agent::done` → amending". Ask **only** for an open
|
|
30
|
-
`agent::ready`.
|
|
27
|
+
only be amended, an open unplanned issue only planned. **Announce the
|
|
28
|
+
derivation** — "4712 is `agent::done` → amending". Ask **only** for an open
|
|
29
|
+
Story already at `agent::ready`.
|
|
31
30
|
|
|
32
31
|
## Saying what you want
|
|
33
32
|
|
|
34
33
|
No flags to remember — state intent; the workflow fills in the CLI
|
|
35
|
-
([
|
|
34
|
+
([ref](helpers/plan-reference.md)). Run scripts with `--help`.
|
|
36
35
|
|
|
37
36
|
`--yes` is **runner-set, never operator-typed** — cron, `/loop`, and headless
|
|
38
37
|
dispatch set it to mean *nobody is at the keyboard*, which auto-proceeds the
|
|
@@ -42,8 +41,7 @@ gates below (#1 and #2) and skips #3. Never offer it to an operator.
|
|
|
42
41
|
|
|
43
42
|
Author **one Story** unless the pieces have **near-zero overlap** or sit across
|
|
44
43
|
an **architectural seam**. Coupled work stays one Story — `## Slicing`
|
|
45
|
-
checkpoints, not sibling tickets
|
|
46
|
-
([detail](helpers/plan-reference.md)). **N=1 is lean.**
|
|
44
|
+
checkpoints, not sibling tickets ([ref](helpers/plan-reference.md)).
|
|
47
45
|
|
|
48
46
|
## Procedure
|
|
49
47
|
|
|
@@ -52,19 +50,21 @@ checkpoints, not sibling tickets
|
|
|
52
50
|
```bash
|
|
53
51
|
node .agents/scripts/plan-context.js --seed "<seed>" \
|
|
54
52
|
--out temp/plan-<slug>/plan-context.json
|
|
55
|
-
# or: --seed-file <path>
|
|
53
|
+
# or: --seed-file <path> | --tickets 123,456 | --amends #<id>
|
|
56
54
|
```
|
|
57
55
|
|
|
58
56
|
**Always pass `--out`.** Persist auto-discovers the envelope from `--plan-dir`
|
|
59
|
-
and derives source ids from its `sourceTickets[]`;
|
|
57
|
+
and derives source ids from its `sourceTickets[]`; it also writes
|
|
60
58
|
**`stories.template.json`**, step 2's skeleton.
|
|
61
59
|
|
|
62
60
|
The envelope carries docs context, the story-author prompt, `sourceTickets[]`,
|
|
63
|
-
`duplicates[]` (open **Stories**, never Epics)
|
|
64
|
-
(
|
|
65
|
-
|
|
61
|
+
`duplicates[]` (open **Stories**, never Epics), `epicCandidates[]` +
|
|
62
|
+
`dependencyCandidates[]` (Gate #3; path collisions) and advisory
|
|
63
|
+
`complexitySignals` (**no routing authority**). A trivial scope can claim the
|
|
64
|
+
lite route at persist — shape-validated, failing closed to `full`
|
|
65
|
+
([ref](helpers/plan-reference.md)).
|
|
66
66
|
|
|
67
|
-
**Triage each unknown by resolver** ([
|
|
67
|
+
**Triage each unknown by resolver** ([ref](helpers/plan-reference.md)): an
|
|
68
68
|
**AFK** unknown (research settles it) is resolved before authoring, never
|
|
69
69
|
assumed; a **HITL** unknown goes to Gate #1. Under `--yes` do not ask free-form
|
|
70
70
|
operator questions — AFK unknowns are still researched; only HITL unknowns land
|
|
@@ -74,26 +74,26 @@ in Key Assumptions, each a decision-made-by-default.
|
|
|
74
74
|
duplicate-candidate review. Under `--yes`, auto-proceed.
|
|
75
75
|
|
|
76
76
|
On a truthy `memoryPoolAdvisory.recommend`, name
|
|
77
|
-
[`/memory-consolidate`](memory-consolidate.md) quoting its `reasons[]
|
|
78
|
-
advisory
|
|
77
|
+
[`/memory-consolidate`](memory-consolidate.md) quoting its `reasons[]`;
|
|
78
|
+
advisory.
|
|
79
79
|
|
|
80
80
|
On a truthy `deliverLightSuggestion.suggested`, offer — advisory, never an
|
|
81
81
|
automatic reroute — to deliver the seed instead; on confirm route **in this
|
|
82
82
|
session** into [`helpers/deliver-light.md`](helpers/deliver-light.md), its gate
|
|
83
83
|
filled from this envelope. A truthy `complexitySignals.uiSurface` names
|
|
84
|
-
[`/prototype`](prototype.md)
|
|
85
|
-
[Both
|
|
84
|
+
[`/prototype`](prototype.md); never invoke it here.
|
|
85
|
+
[Both](helpers/plan-reference.md).
|
|
86
86
|
|
|
87
87
|
### 2. Author
|
|
88
88
|
|
|
89
|
-
**One-shot authoring.**
|
|
90
|
-
|
|
89
|
+
**One-shot authoring.** From `stories.template.json`, author `stories.json`
|
|
90
|
+
in one pass. `body` is markdown **or** a structured object;
|
|
91
91
|
persist parses either, serializes canonical markdown and syncs top-level
|
|
92
|
-
`acceptance[]` / `verify[]` in — never dual-author
|
|
92
|
+
`acceptance[]` / `verify[]` in — never dual-author them.
|
|
93
93
|
|
|
94
94
|
**Grounding = your reads + Phase 8.** Nothing inventories the repo: read each
|
|
95
|
-
file you cite; persist hard-errors on any `{path, assumption}` absent from
|
|
96
|
-
|
|
95
|
+
file you cite; persist hard-errors on any `{path, assumption}` absent from the
|
|
96
|
+
tree. Fields: [ref](helpers/plan-reference.md).
|
|
97
97
|
|
|
98
98
|
Artifacts under `temp/plan-<slug>/`: `stories.json` (**length 1 by default**;
|
|
99
99
|
over-budget Specs fail closed — split or tighten, never under `docs/`); optional
|
|
@@ -112,10 +112,10 @@ node .agents/scripts/plan-critics.js \
|
|
|
112
112
|
[--tech-spec temp/plan-<slug>/techspec.md]
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
Run **before** persist — the last point a finding folds into a re-author.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
Run **before** persist — the last point a finding folds into a re-author. It
|
|
116
|
+
exits 0 on **any** verdict (verdicts route work, they do not gate) and exits
|
|
117
|
+
**1** only on a usage/IO error — no critic ran: **do not proceed to Persist**,
|
|
118
|
+
fix and re-run.
|
|
119
119
|
|
|
120
120
|
- **Both `dispatch: false`** — proceed to Persist (each skip is ledgered).
|
|
121
121
|
- **Either `dispatch: true`** — dispatch **one fresh-context, maker-blind
|
|
@@ -130,12 +130,12 @@ Persist**, fix and re-run.
|
|
|
130
130
|
**Gate #2** — STOP for approval before persist **only** when the operator asked
|
|
131
131
|
to review (`--force-review`). Under `--yes`, auto-proceed.
|
|
132
132
|
|
|
133
|
-
**Gate #3
|
|
134
|
-
|
|
135
|
-
([
|
|
133
|
+
**Gate #3 — adopt, else create.** Offer the top `epicCandidates[]` Epic at
|
|
134
|
+
**any N** (`--epic <id>`); else, at **N>2**, a new container (`--epic-title` /
|
|
135
|
+
`--epic-goal`). Never unasked ([ref](helpers/plan-reference.md)).
|
|
136
136
|
|
|
137
|
-
Run persist
|
|
138
|
-
|
|
137
|
+
Run persist `--dry-run` **first** — same command, writes suppressed; every gate
|
|
138
|
+
runs before the first `createIssue` ([list](helpers/plan-reference.md)):
|
|
139
139
|
|
|
140
140
|
```bash
|
|
141
141
|
node .agents/scripts/plan-persist.js \
|
|
@@ -144,28 +144,28 @@ node .agents/scripts/plan-persist.js \
|
|
|
144
144
|
[--plan-acceptance temp/plan-<slug>/acceptance-manifest.json] \
|
|
145
145
|
[--tech-spec temp/plan-<slug>/techspec.md] \
|
|
146
146
|
[--source-tickets 123,456] \
|
|
147
|
-
[--epic-title "<name>" --epic-goal "<one paragraph>"]
|
|
147
|
+
[--epic <id> | --epic-title "<name>" --epic-goal "<one paragraph>"]
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
At lite shape `--chain-on-clean` folds a clean dry-run into the
|
|
151
|
-
|
|
150
|
+
At lite shape `--chain-on-clean` folds a clean dry-run into the persist; a full
|
|
151
|
+
plan keeps its review trip.
|
|
152
152
|
|
|
153
153
|
Persist creates `type::story` issue(s), a **metadata-only** `plan-run::<id>`
|
|
154
|
-
label, `blocked by #<id>` footers for
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
([detail](helpers/plan-reference.md)).
|
|
154
|
+
label, `blocked by #<id>` footers for every `depends_on` edge, and on a Gate #3
|
|
155
|
+
yes links them under a `type::epic` container (adopted or new). `agent::ready`
|
|
156
|
+
is the **terminal** flip after receipts land; stdout is pure JSON. Tickets mode
|
|
157
|
+
also comments on and closes each source id ([ref](helpers/plan-reference.md)).
|
|
159
158
|
|
|
160
159
|
## Constraints
|
|
161
160
|
|
|
162
161
|
- `/mandrel-plan` starts delivery **only** through a confirmed Gate #1 light
|
|
163
|
-
route — never off its
|
|
162
|
+
route — never off its Stories, which land via
|
|
164
163
|
[`/mandrel-deliver`](mandrel-deliver.md).
|
|
165
164
|
- Duplicate search targets open Stories (`type::story`), not Epics; and
|
|
166
165
|
deterministic gates still fail closed under `--yes`.
|
|
167
|
-
- A container Epic is never a work item
|
|
168
|
-
|
|
166
|
+
- A container Epic is never a work item and only an **open** one is adoptable;
|
|
167
|
+
no Story body gains an `Epic: #N` footer (linkage is parent→child only).
|
|
168
|
+
- `depends_on` takes a sibling slug or `#<id>` (open Story).
|
|
169
169
|
|
|
170
170
|
## See also
|
|
171
171
|
|
|
@@ -42,7 +42,8 @@ Constraints delta.
|
|
|
42
42
|
> triage-ready finding without breaking stride — then, when the testing pass is
|
|
43
43
|
> done, turned into a plan in one batch.
|
|
44
44
|
>
|
|
45
|
-
> **
|
|
45
|
+
> **Rules**: [`testing-standards.md`](../rules/testing-standards.md)
|
|
46
|
+
> (§ The Three Tiers — the tier-classification rules enrichment applies)
|
|
46
47
|
|
|
47
48
|
## Role framing
|
|
48
49
|
|
|
@@ -106,7 +107,8 @@ ledger is hard-gated.**
|
|
|
106
107
|
|
|
107
108
|
Goal: become the operator's QA assistant before any observation arrives.
|
|
108
109
|
|
|
109
|
-
1. Re-read the QA role framing and
|
|
110
|
+
1. Re-read the QA role framing and the tier-classification rules in
|
|
111
|
+
[`testing-standards.md`](../rules/testing-standards.md) (§ The Three Tiers).
|
|
110
112
|
2. **Load codebase context.** Read the files in `project.docsContextFiles`
|
|
111
113
|
(architecture, decisions, patterns) and, when the testing touches UI/routing,
|
|
112
114
|
`docs/style-guide.md` / `docs/web-routes.md`. This is the context you will
|
|
@@ -176,17 +178,16 @@ every decision to the shared helpers; never re-derive them in prose.
|
|
|
176
178
|
`gh issue view <ticketNumber> --json title,body,labels`, and verify each
|
|
177
179
|
surface-map path resolves with `git cat-file -e HEAD:<path>` — flag every
|
|
178
180
|
miss rather than citing a path that does not exist.
|
|
179
|
-
4. **
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
5. **Name the missing test** (if any)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
`missingTest`.
|
|
181
|
+
4. **Read the coverage tiers** for the surface the observation points at:
|
|
182
|
+
gather the tests that exercise it and classify each by path per
|
|
183
|
+
[`testing-standards.md` § The Three Tiers](../rules/testing-standards.md#the-three-tiers)
|
|
184
|
+
— a `.feature` file is **acceptance**, a path containing `/contract/` or
|
|
185
|
+
`.contract.test.` is **contract**, and a path containing `.test.` or
|
|
186
|
+
`__tests__/` is **unit**. A skipped test leaves its tier uncovered.
|
|
187
|
+
5. **Name the missing test** (if any): take the lowest tier with no live test
|
|
188
|
+
(unit → contract → acceptance) and write one concrete sentence describing
|
|
189
|
+
the test that would close it. Every tier covered means no missing test.
|
|
190
|
+
Record that sentence as the ledger item's `missingTest`.
|
|
190
191
|
6. **Classify** the finding via
|
|
191
192
|
[`classify-finding.js`](../scripts/lib/findings/classify-finding.js) so the
|
|
192
193
|
tentative `class` resolves to the correct focus/meta label set. The helper
|
|
@@ -267,10 +268,12 @@ the `/qa-assist`-specific deltas are:
|
|
|
267
268
|
- **Persistent, resumable rolling session** — `/qa-assist` defaults to resuming
|
|
268
269
|
the same session and appending; a reused session carries the untriaged backlog
|
|
269
270
|
forward and never overwrites a prior ledger.
|
|
270
|
-
- **Enrichment delegates where a helper exists** — the
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
- **Enrichment delegates where a helper exists** — the finding classification
|
|
272
|
+
comes from its deterministic helper, never from prose; tier placement comes
|
|
273
|
+
from the three path rules in
|
|
274
|
+
[`testing-standards.md`](../rules/testing-standards.md#the-three-tiers).
|
|
275
|
+
Context lookup and the missing-test sentence are the model's own work: they
|
|
276
|
+
are judgments, not computations, and routing them through a module only
|
|
274
277
|
bought a round-trip.
|
|
275
278
|
|
|
276
279
|
## See also
|
|
@@ -34,7 +34,7 @@ Constraints delta.
|
|
|
34
34
|
> or Feature, a regression sweep over a risky surface before `/mandrel-deliver`, or a
|
|
35
35
|
> structured agent-driven bug-hunt captured into a triageable ledger.
|
|
36
36
|
>
|
|
37
|
-
> **Skills**: `
|
|
37
|
+
> **Skills**: `stack/qa/qa-harness`
|
|
38
38
|
|
|
39
39
|
## Role framing
|
|
40
40
|
|
|
@@ -45,15 +45,16 @@ the surface shows. Apply the QA skills below; there is no separate persona pack.
|
|
|
45
45
|
## Driving conventions
|
|
46
46
|
|
|
47
47
|
Before you drive a surface, read the
|
|
48
|
-
[`stack/qa/qa-
|
|
49
|
-
skill — the **one** conventions reference for the *how* of agent-driven
|
|
50
|
-
|
|
51
|
-
documented interim chosen at Plan time only where no seam
|
|
52
|
-
authenticated driving through the resolved environment's
|
|
53
|
-
navigation is a finding, not a workaround).
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
[`stack/qa/qa-harness`](../skills/stack/qa/qa-harness/SKILL.md)
|
|
49
|
+
skill — the **one** conventions reference for the *how* of agent-driven driving,
|
|
50
|
+
shared with the known-scenario sweep (navigation-first driving as the default;
|
|
51
|
+
static driving as the documented interim chosen at Plan time only where no seam
|
|
52
|
+
resolves; authenticated driving through the resolved environment's
|
|
53
|
+
`signInSeam`; broken navigation is a finding, not a workaround). Its § 5 carries
|
|
54
|
+
the exploratory-mode deltas. The driving method (drive vs. static) is a
|
|
55
|
+
**Plan-phase decision recorded in the ledger**; do not switch methods
|
|
56
|
+
mid-surface without a new Plan note. Do not restate these conventions inline —
|
|
57
|
+
the skill owns them.
|
|
57
58
|
|
|
58
59
|
## Slash Command
|
|
59
60
|
|
|
@@ -110,7 +111,7 @@ then the captured ledger), and wait. If the operator does not confirm, hold.
|
|
|
110
111
|
Goal: agree on **what** will be explored and **how the agent will drive it**
|
|
111
112
|
before touching the surface.
|
|
112
113
|
|
|
113
|
-
1. Re-read the `stack/qa/qa-
|
|
114
|
+
1. Re-read the `stack/qa/qa-harness` skill and resolve the contract and
|
|
114
115
|
session (above).
|
|
115
116
|
2. **Resolve the target environment** via
|
|
116
117
|
[`resolveQaEnvironment`](../scripts/lib/qa/resolve-qa-contract.js) — it keys
|
|
@@ -149,8 +150,8 @@ Goal: **the agent drives the confirmed surface itself** and records its
|
|
|
149
150
|
observations. **This phase is strictly read-only.**
|
|
150
151
|
|
|
151
152
|
> **Read-only invariant.** The agent observes; it never mutates. Per
|
|
152
|
-
> [`stack/qa/qa-
|
|
153
|
-
> §
|
|
153
|
+
> [`stack/qa/qa-harness`](../skills/stack/qa/qa-harness/SKILL.md)
|
|
154
|
+
> § 2 (inviolable per [`security-baseline.md`](../rules/security-baseline.md)),
|
|
154
155
|
> do **not** edit source, run write commands, file or label GitHub issues,
|
|
155
156
|
> change tickets, submit destructive forms, or alter the product under test. The
|
|
156
157
|
> only write Capture performs is **appending ledger lines to
|
|
@@ -170,17 +171,16 @@ For each observation the agent makes while driving:
|
|
|
170
171
|
|
|
171
172
|
1. **Redact first** (per [`helpers/qa-core.md`](helpers/qa-core.md)) — scrub the
|
|
172
173
|
evidence string through `redactEvidence` before it touches disk.
|
|
173
|
-
2. **
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
3. **Name the missing test** (if any)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
`missingTest` (or `null`).
|
|
174
|
+
2. **Read the coverage tiers** for the surface the observation points at:
|
|
175
|
+
gather the tests that exercise it and classify each by path per
|
|
176
|
+
[`testing-standards.md` § The Three Tiers](../rules/testing-standards.md#the-three-tiers)
|
|
177
|
+
— a `.feature` file is **acceptance**, a path containing `/contract/` or
|
|
178
|
+
`.contract.test.` is **contract**, and a path containing `.test.` or
|
|
179
|
+
`__tests__/` is **unit**. A skipped test leaves its tier uncovered.
|
|
180
|
+
3. **Name the missing test** (if any): take the lowest tier with no live test
|
|
181
|
+
(unit → contract → acceptance) and write one concrete sentence describing
|
|
182
|
+
the test that would close it. Every tier covered means no missing test.
|
|
183
|
+
Record that sentence as the ledger item's `missingTest` (or `null`).
|
|
184
184
|
4. **Append a `QaLedgerItem`** to the ledger (shape per
|
|
185
185
|
[`helpers/qa-core.md`](helpers/qa-core.md)): a stable `id`, the redacted
|
|
186
186
|
`evidence`, the `coverage` label (the `surface`, or `unknown`), a tentative
|
|
@@ -215,7 +215,7 @@ resumed session will pick up.
|
|
|
215
215
|
Beyond the shared core ([`helpers/qa-core.md`](helpers/qa-core.md): contract +
|
|
216
216
|
loud failure, session/ledger, redact-first, QaLedgerItem, triage, HITL gate)
|
|
217
217
|
and the driving conventions
|
|
218
|
-
([`stack/qa/qa-
|
|
218
|
+
([`stack/qa/qa-harness`](../skills/stack/qa/qa-harness/SKILL.md)),
|
|
219
219
|
the `/qa-explore`-specific deltas are:
|
|
220
220
|
|
|
221
221
|
- **Agent-led, bounded per surface.** The agent drives one named surface per
|
|
@@ -231,10 +231,11 @@ the `/qa-explore`-specific deltas are:
|
|
|
231
231
|
and fall back to static.
|
|
232
232
|
- **Broken navigation is a finding, not a workaround** — never URL-jump around a
|
|
233
233
|
missing affordance, a nav 404, or a guard redirect loop.
|
|
234
|
-
- **
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
- **Read tier placement from the rule, not from prose you invent.** The three
|
|
235
|
+
path rules in
|
|
236
|
+
[`testing-standards.md` § The Three Tiers](../rules/testing-standards.md#the-three-tiers)
|
|
237
|
+
decide which tier a test occupies; the missing-test sentence is yours to write
|
|
238
|
+
from the lowest uncovered tier.
|
|
238
239
|
|
|
239
240
|
## See also
|
|
240
241
|
|
|
@@ -29,7 +29,8 @@ the agent never invents those decisions in prose.
|
|
|
29
29
|
> passes before `/mandrel-deliver`, or on demand while debugging a Story's
|
|
30
30
|
> user-visible behavior in a live browser.
|
|
31
31
|
>
|
|
32
|
-
> **Skills**: `stack/qa/
|
|
32
|
+
> **Skills**: `stack/qa/qa-harness` (driving and instrumentation
|
|
33
|
+
> conventions), `stack/qa/gherkin-authoring` and `stack/qa/playwright-bdd`
|
|
33
34
|
> (authoring reference; this harness owns execution)
|
|
34
35
|
|
|
35
36
|
## Slash Command
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,38 @@ All notable changes to this project will be documented in this file.
|
|
|
15
15
|
-->
|
|
16
16
|
<!-- markdownlint-disable-file MD004 MD012 MD037 -->
|
|
17
17
|
|
|
18
|
+
## [2.42.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.41.0...mandrel-v2.42.0) (2026-09-06)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
* full-suite capture economy: default the coverage-independent skip on, and serialize concurrent captures behind a host lock ([#5173](https://github.com/dsj1984/mandrel/issues/5173)) ([#5178](https://github.com/dsj1984/mandrel/issues/5178)) ([ed79751](https://github.com/dsj1984/mandrel/commit/ed7975199b6e2a3279a5d0d02b50e3068509987f))
|
|
24
|
+
* story-worker digest carries the creditable full-suite invocation, runs it after self-eval, and the critic reuses its stamp ([#5174](https://github.com/dsj1984/mandrel/issues/5174)) ([#5175](https://github.com/dsj1984/mandrel/issues/5175)) ([1e46457](https://github.com/dsj1984/mandrel/commit/1e464574aa6305dcc8f1ff8522015ae0f9a5301a))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
* scope the baseline refresh acknowledgment to the rows the refresh commit actually refreshed ([#5179](https://github.com/dsj1984/mandrel/issues/5179)) ([#5180](https://github.com/dsj1984/mandrel/issues/5180)) ([e8758b9](https://github.com/dsj1984/mandrel/commit/e8758b909ec19ed55c0678c05f481d515937f978))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
* close fails fast: base-sync before validation, and coverage-independent baseline kinds in the parallel gate phase ([#5172](https://github.com/dsj1984/mandrel/issues/5172)) ([#5177](https://github.com/dsj1984/mandrel/issues/5177)) ([dff33d5](https://github.com/dsj1984/mandrel/commit/dff33d530965ef7da8ee3dd4f1f218d11805273f))
|
|
35
|
+
|
|
36
|
+
## [2.41.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.40.0...mandrel-v2.41.0) (2026-09-06)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
* /mandrel-plan adopts an existing open Epic and declares depends_on edges on existing open Stories ([#5155](https://github.com/dsj1984/mandrel/issues/5155)) ([#5156](https://github.com/dsj1984/mandrel/issues/5156)) ([9119f31](https://github.com/dsj1984/mandrel/commit/9119f313146ab08ed676909f9b0a61671c4d6069))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
* **agents:** retire four frontier-known rules/skills, fold two more into rules (refs [#5158](https://github.com/dsj1984/mandrel/issues/5158)) ([#5162](https://github.com/dsj1984/mandrel/issues/5162)) ([065f883](https://github.com/dsj1984/mandrel/commit/065f8839fafcc7064e4ad6d2ea30f2bfebbd5c0c))
|
|
47
|
+
* **qa:** fold qa-explore-driving into qa-harness (refs [#5159](https://github.com/dsj1984/mandrel/issues/5159)) ([#5163](https://github.com/dsj1984/mandrel/issues/5163)) ([2fbc8db](https://github.com/dsj1984/mandrel/commit/2fbc8db5a420450414cfd046bb6418e0c210bf7f))
|
|
48
|
+
* **rules:** trim surviving rules and core skills to their contracts (refs [#5160](https://github.com/dsj1984/mandrel/issues/5160)) ([#5164](https://github.com/dsj1984/mandrel/issues/5164)) ([f0e6a62](https://github.com/dsj1984/mandrel/commit/f0e6a62feaba275377c9cc435f03ea6089008148))
|
|
49
|
+
|
|
18
50
|
## [2.40.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.39.0...mandrel-v2.40.0) (2026-09-06)
|
|
19
51
|
|
|
20
52
|
|
package/package.json
CHANGED