mandrel 2.25.0 → 2.26.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/agents/acceptance-critic.md +10 -6
- package/.agents/audit-checklists/baselines.md +21 -0
- package/.agents/docs/quality-gates.md +80 -18
- package/.agents/docs/workflows.md +3 -1
- package/.agents/instructions.md +1 -1
- package/.agents/schemas/audit-rules.json +15 -0
- package/.agents/schemas/baselines/audit-baselines-envelope.schema.json +242 -0
- package/.agents/schemas/baselines/baseline-envelope.schema.json +4 -0
- package/.agents/schemas/baselines/crap.schema.json +8 -0
- package/.agents/schemas/model-attribution.schema.json +4 -0
- package/.agents/scripts/acceptance-eval.js +89 -6
- package/.agents/scripts/audit-baselines.js +136 -0
- package/.agents/scripts/check-arch-cycles.js +12 -93
- package/.agents/scripts/check-baseline-drift.js +16 -3
- package/.agents/scripts/check-baselines.js +19 -3
- package/.agents/scripts/check-cyclomatic.js +214 -0
- package/.agents/scripts/check-schema-references.js +392 -0
- package/.agents/scripts/check-test-temp-hygiene.js +38 -1
- package/.agents/scripts/check-workflow-timeouts.js +291 -0
- package/.agents/scripts/diagnose-friction.js +85 -19
- package/.agents/scripts/lib/audit-baselines/engine.js +177 -0
- package/.agents/scripts/lib/audit-baselines/gate-surface.js +63 -0
- package/.agents/scripts/lib/audit-baselines/headroom.js +72 -0
- package/.agents/scripts/lib/audit-baselines/hotspots.js +69 -0
- package/.agents/scripts/lib/audit-baselines/kinds.js +313 -0
- package/.agents/scripts/lib/audit-baselines/outliers.js +100 -0
- package/.agents/scripts/lib/audit-baselines/read.js +87 -0
- package/.agents/scripts/lib/audit-baselines/staleness.js +123 -0
- package/.agents/scripts/lib/audit-baselines/surface-entry.js +106 -0
- package/.agents/scripts/lib/audit-baselines/trend.js +125 -0
- package/.agents/scripts/lib/audit-baselines/weights.js +193 -0
- package/.agents/scripts/lib/audit-suite/index.js +0 -5
- package/.agents/scripts/lib/audit-suite/selector.js +9 -62
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +1 -0
- package/.agents/scripts/lib/baseline-schema-registry.js +13 -1
- package/.agents/scripts/lib/baselines/diff-scope-cli.js +22 -160
- package/.agents/scripts/lib/baselines/duplication-scanner.js +27 -0
- package/.agents/scripts/lib/baselines/git-base.js +26 -4
- package/.agents/scripts/lib/baselines/kinds/crap.js +112 -15
- package/.agents/scripts/lib/baselines/refresh-service.js +69 -11
- package/.agents/scripts/lib/baselines/scope.js +39 -90
- package/.agents/scripts/lib/baselines/writer.js +16 -11
- package/.agents/scripts/lib/changed-files.js +8 -1
- package/.agents/scripts/lib/cli-args.js +115 -1
- package/.agents/scripts/lib/close-validation/runner.js +70 -25
- package/.agents/scripts/lib/crap-engine.js +32 -13
- package/.agents/scripts/lib/crap-method-identity.js +153 -0
- package/.agents/scripts/lib/crap-utils.js +13 -0
- package/.agents/scripts/lib/cyclomatic-ceiling.js +265 -0
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -2
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +0 -2
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +0 -2
- package/.agents/scripts/lib/git-utils.js +136 -80
- package/.agents/scripts/lib/import-graph.js +156 -0
- package/.agents/scripts/lib/observability/runtime-friction.js +17 -2
- package/.agents/scripts/lib/observability/source-classifier.js +175 -2
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +17 -12
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +36 -6
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +5 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +12 -1
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +8 -1
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +10 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +39 -3
- package/.agents/scripts/lib/orchestration/plan-context.js +119 -66
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +31 -5
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +209 -109
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +48 -12
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +79 -22
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +51 -20
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +70 -74
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +231 -0
- package/.agents/scripts/lib/orchestration/resolve-stories.js +18 -17
- package/.agents/scripts/lib/orchestration/run-epilogue.js +12 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +29 -3
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +6 -6
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +42 -38
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -1
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +245 -140
- package/.agents/scripts/lib/orchestration/spec-budget.js +16 -5
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +182 -95
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +22 -0
- package/.agents/scripts/lib/orchestration/ticket-validator.js +5 -11
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +4 -4
- package/.agents/scripts/lib/story-adjacency.js +3 -3
- package/.agents/scripts/lib/test-runner-contract.js +134 -0
- package/.agents/scripts/lib/test-tiers.js +11 -2
- package/.agents/scripts/lib/util/concurrent-map.js +17 -0
- package/.agents/scripts/lib/util/parse-id-list.js +103 -0
- package/.agents/scripts/lib/wave-runner/live-probe.js +24 -14
- package/.agents/scripts/lib/wave-runner/ready-set.js +189 -42
- package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +4 -10
- package/.agents/scripts/lib/workers/crap-worker.js +2 -10
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +4 -10
- package/.agents/scripts/lib/workers/maintainability-worker.js +4 -10
- package/.agents/scripts/lib/workers/serve-worker-messages.js +35 -0
- package/.agents/scripts/lib/worktree/git-hooks.js +206 -0
- package/.agents/scripts/lib/worktree/lifecycle/creation.js +6 -0
- package/.agents/scripts/lib/worktree-manager.js +14 -0
- package/.agents/scripts/plan-run-epilogue.js +17 -5
- package/.agents/scripts/providers/github/tickets.js +33 -10
- package/.agents/scripts/provision-git-hooks.js +85 -0
- package/.agents/scripts/quality-preview.js +112 -28
- package/.agents/scripts/resolve-stories.js +4 -1
- package/.agents/scripts/run-coverage.js +86 -35
- package/.agents/scripts/run-lint.js +20 -0
- package/.agents/scripts/run-tests.js +26 -36
- package/.agents/scripts/single-story-close.js +28 -2
- package/.agents/scripts/single-story-confirm-merge.js +22 -6
- package/.agents/scripts/stories-wave-tick.js +214 -38
- package/.agents/scripts/update-coverage-baseline.js +34 -4
- package/.agents/scripts/update-duplication-baseline.js +209 -83
- package/.agents/scripts/validate-docs-freshness.js +1 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +4 -1
- package/.agents/skills/core/gates-and-baselines/SKILL.md +17 -11
- package/.agents/skills/skills.index.json +2 -2
- package/.agents/workflows/audit-baselines.md +289 -0
- package/.agents/workflows/audit-navigability.md +5 -4
- package/.agents/workflows/deliver.md +13 -4
- package/.agents/workflows/helpers/acceptance-self-eval.md +47 -10
- package/.agents/workflows/helpers/code-quality-guardrails.md +9 -2
- package/.agents/workflows/helpers/deliver-digest.md +41 -21
- package/.agents/workflows/helpers/deliver-reference.md +77 -1
- package/.agents/workflows/helpers/deliver-story-reference.md +47 -6
- package/.agents/workflows/helpers/plan-reference.md +15 -5
- package/.agents/workflows/memory-consolidate.md +116 -0
- package/.agents/workflows/plan.md +3 -0
- package/README.md +13 -6
- package/docs/CHANGELOG.md +64 -0
- package/package.json +9 -4
- package/.agents/schemas/friction-event.schema.json +0 -56
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +0 -707
|
@@ -12,6 +12,34 @@ Reference-only detail split out of [`deliver.md`](../deliver.md) so the
|
|
|
12
12
|
always-resident spine stays lean. Nothing here is a new MUST —
|
|
13
13
|
it is the mechanics an operator consults when the matching lever is engaged.
|
|
14
14
|
|
|
15
|
+
## Ranges (`4922 - 4926`) {#ranges}
|
|
16
|
+
|
|
17
|
+
A contiguous span is how an operator reads a plan run, so the dash range is a
|
|
18
|
+
first-class id shape rather than prose to interpret — `/deliver 4922 - 4926`
|
|
19
|
+
means exactly the five ids in it.
|
|
20
|
+
|
|
21
|
+
**Pass the span through; never expand it by hand.** Every id-list flag on the
|
|
22
|
+
delivery path takes range tokens — `resolve-stories.js --ids`,
|
|
23
|
+
`stories-wave-tick.js --stories` and `--dispatched`, and
|
|
24
|
+
`plan-run-epilogue.js --stories`. Normalize the operator's spacing away and hand
|
|
25
|
+
the scripts one unspaced token (`--ids 4922-4926`), mixed freely with singles
|
|
26
|
+
and commas (`--ids 4901,4922-4926`); overlaps dedupe. A hand-typed enumeration
|
|
27
|
+
is where an id gets dropped or invented, and the drop is silent.
|
|
28
|
+
|
|
29
|
+
The shared expander (`lib/util/parse-id-list.js`) refuses rather than guesses,
|
|
30
|
+
so a typo fails where it was typed instead of resolving the wrong set:
|
|
31
|
+
|
|
32
|
+
| Input | Outcome |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| `4922-4926`, `4922 - 4926` | Expands to the inclusive span. En and em dashes, and a `#` on either endpoint, are accepted too. |
|
|
35
|
+
| `4926-4922` | Refused — write it low-to-high. |
|
|
36
|
+
| `1-4926` | Refused — above the 50-id span cap (`MAX_RANGE_SPAN`). |
|
|
37
|
+
| `4922-`, `-4926`, `4922-4923-4924` | Refused as a malformed token. |
|
|
38
|
+
|
|
39
|
+
The cap is per range token, not per run: a genuine 60-Story delivery is still
|
|
40
|
+
expressible as two ranges, but a slipped digit cannot fan out into a live
|
|
41
|
+
resolution sweep of thousands of issues.
|
|
42
|
+
|
|
15
43
|
## Sequencing edge cases (`stories-wave-tick.js`)
|
|
16
44
|
|
|
17
45
|
**What "discovered, not declared" means concretely.** `resolve-stories.js` reads
|
|
@@ -63,6 +91,18 @@ different operator holds, unless you pass `--steal`. Assignee-based withholding
|
|
|
63
91
|
needs `github.operatorHandle` set (in `.agentrc.local.json`); without it the
|
|
64
92
|
probe logs a warning and leans on init's lease refusal alone.
|
|
65
93
|
|
|
94
|
+
**Overlapping footprints are reserved across beats, not just within one.** A
|
|
95
|
+
Story sharing a **concrete** path with a still-implementing Story is withheld
|
|
96
|
+
and named in `inFlightReservation: { available, withheld: [{ id, blockedBy,
|
|
97
|
+
reason }], note }`, where `reason` is `in-flight-earlier-beat` or
|
|
98
|
+
`foreign-lease`. Like `foreignHeld` this is neither a failure nor a wedge — the
|
|
99
|
+
Story re-admits automatically once its blocker leaves the in-flight set — and
|
|
100
|
+
it exists so an unfilled slot is explained rather than mysterious. A **glob**
|
|
101
|
+
footprint (or the UNKNOWN sentinel for an unparseable body) reserves nothing
|
|
102
|
+
across beats; it still serializes its own beat. Reservation needs the in-flight
|
|
103
|
+
Stories' footprints, so it is a `--probe-live` capability: under `--dag` the
|
|
104
|
+
report is `available: false` and selection de-conflicts within the beat only.
|
|
105
|
+
|
|
66
106
|
## Dispatch mechanics (role-scoped by default)
|
|
67
107
|
|
|
68
108
|
**A single-Story run executes inline.** Sub-agent isolation is
|
|
@@ -96,6 +136,18 @@ footprint keeps the fresh acceptance critic), and the `route::lite` label
|
|
|
96
136
|
remains a human-visible hint only, never the control signal — a lost or
|
|
97
137
|
never-written label cannot misroute delivery.
|
|
98
138
|
|
|
139
|
+
**Issue a beat's spawns in one turn.** A wave tick hands you a ready set, not a
|
|
140
|
+
queue: those Stories have no dependency edge between them (the resolver already
|
|
141
|
+
withheld any that do) and no shared write paths (each owns its own worktree and
|
|
142
|
+
branch). Dispatch them the way
|
|
143
|
+
[`parallel-tooling.md`](parallel-tooling.md) Rule 3 prescribes — **N `Agent`
|
|
144
|
+
calls issued together in a single assistant turn**, one per ready Story, not
|
|
145
|
+
`Agent` → wait → `Agent`. Serial dispatch is compliant with every other rule on
|
|
146
|
+
this page and costs the run a full Story's implementation time per sibling for
|
|
147
|
+
nothing; the wave aggregator is built for the parallel shape. Respect
|
|
148
|
+
`delivery.deliverRunner.concurrencyCap`: when the ready set exceeds it, slice
|
|
149
|
+
into batches of `cap` and dispatch each batch in its own turn.
|
|
150
|
+
|
|
99
151
|
**Dispatch each `ready` Story (role-scoped by default).** When
|
|
100
152
|
`delivery.routing.roleScopedAgents` is enabled (the **default**) and the host
|
|
101
153
|
exposes agent dispatch, spawn each ready Story as its own
|
|
@@ -235,8 +287,32 @@ A slow-CI consumer can opt the close into `"async"` mode so the merge wait
|
|
|
235
287
|
probes once for ~60s (catching an instant merge or an instantly-red required
|
|
236
288
|
check) and then returns `pending` instead of burning ~5 minutes of the host
|
|
237
289
|
tool slot polling a merge that lands after the wait would have expired anyway.
|
|
238
|
-
When a
|
|
290
|
+
When a close returns that `pending` envelope, launch its `nextCommand` as a
|
|
239
291
|
**background** invocation (host background Bash — its completion re-invokes the
|
|
240
292
|
agent) and move on to the next Story; `single-story-confirm-merge.js` is
|
|
241
293
|
idempotent and owns the whole tail. Do not foreground-poll the merge. The
|
|
242
294
|
default `"sync"` behaviour is unchanged.
|
|
295
|
+
|
|
296
|
+
**On a multi-Story run, pass `--merge-watch-mode async` on every close.** Close
|
|
297
|
+
sees one Story and cannot see run topology, so it cannot make this call for
|
|
298
|
+
itself — you can. Implementation runs in parallel but the close tail is
|
|
299
|
+
serialized one at a time, and under `sync` each of those closes holds the
|
|
300
|
+
foreground for its full merge wait before the next Story's close may start.
|
|
301
|
+
That is the run's dominant serialized cost, and it is paid per sibling:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
node <main-repo>/.agents/scripts/single-story-close.js \
|
|
305
|
+
--story <storyId> --cwd <main-repo> --merge-watch-mode async
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
The flag overrides `delivery.mergeWatch.mode` for that invocation only — the
|
|
309
|
+
config default stays `"sync"`, which is right for the solo delivery that has no
|
|
310
|
+
sibling waiting behind it. It composes with `--max-wait-seconds`: pass both and
|
|
311
|
+
the explicit bound still wins over the async probe cap. An unrecognized value
|
|
312
|
+
exits non-zero before any phase runs, so a typo cannot silently drop the run
|
|
313
|
+
back onto synchronous waiting. Expect a `pending` envelope from each async
|
|
314
|
+
close — that is the designed ending here, not a failure; background its
|
|
315
|
+
`nextCommand` and move to the next Story's close immediately.
|
|
316
|
+
|
|
317
|
+
A one-Story run should keep the `sync` default: there is no sibling to unblock,
|
|
318
|
+
and the foreground wait is the cheapest path to `landed`.
|
|
@@ -203,6 +203,29 @@ round cap, proceed / redraft / block — not an independent additional pass
|
|
|
203
203
|
over the criteria. The M4-B floor holds: one verdict per cluster, the
|
|
204
204
|
cluster count owned by `acceptance-clusters.js` alone.
|
|
205
205
|
|
|
206
|
+
**One round = N cluster critics → ONE merged verdict → ONE gate call.** The
|
|
207
|
+
clusters are how a round is _authored_; they are not how it is _scored_.
|
|
208
|
+
Concatenate every cluster's records into a single `criteria[]` ordered by
|
|
209
|
+
`index` — exactly one per `acceptance[]` item, under one `storyId`,
|
|
210
|
+
`schemaVersion`, `round` and `commitSha` — and hand that merged file to the
|
|
211
|
+
gate once, with `--expected-criteria` set to the Story's `acceptance[]` count:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
node <main-repo>/.agents/scripts/acceptance-eval.js \
|
|
215
|
+
--story <storyId> --verdict <merged-verdict-path> \
|
|
216
|
+
--expected-criteria <acceptance[] count>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The flag is what makes the merge enforceable: `assertCriteriaCoverage` returns
|
|
220
|
+
early on the `null` default, so **omitting it leaves the guard inert** and a
|
|
221
|
+
single cluster's verdict handed over unmerged scores a fraction of the criteria
|
|
222
|
+
and still reports `proceed`. A length mismatch is rejected before scoring and
|
|
223
|
+
consumes no round. Calling the gate once per cluster instead spends a round
|
|
224
|
+
_per cluster_ — a Story past the cluster ceiling would burn its whole redraft
|
|
225
|
+
budget on cluster arithmetic — and N concurrent calls race the Story-scoped
|
|
226
|
+
round ledger. Full per-round mechanics, including the parallel dispatch and the
|
|
227
|
+
merge shape: [`acceptance-self-eval.md`](acceptance-self-eval.md).
|
|
228
|
+
|
|
206
229
|
**Critic evidence-share.** When the critic runs a `verify[]`
|
|
207
230
|
command that is byte-identical to a close gate (`lint` / `typecheck`), it
|
|
208
231
|
records the pass into the Story evidence keyspace via `--standalone` so
|
|
@@ -318,12 +341,23 @@ The wait probes the checks every poll: a red required check fails fast as
|
|
|
318
341
|
base is brought up to date within `updateAttempts` tries.
|
|
319
342
|
|
|
320
343
|
**Async merge-confirm mode (`delivery.mergeWatch.mode: "async"`).** Under
|
|
321
|
-
the default `"sync"` the merge wait runs in the foreground as
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
344
|
+
the default `"sync"` the merge wait runs in the foreground as described above.
|
|
345
|
+
|
|
346
|
+
**On a multi-Story run, async is the posture — pass `--merge-watch-mode async`
|
|
347
|
+
on every close.** This is not a slow-CI opt-in. Implementation fans out, but
|
|
348
|
+
the close tail is serialized one Story at a time, and under `sync` each close
|
|
349
|
+
holds the foreground for its full merge wait before the next may start; that
|
|
350
|
+
is the run's dominant serialized cost, paid once per sibling. Close sees one
|
|
351
|
+
Story and cannot see run topology, so the orchestrator — which can — makes the
|
|
352
|
+
call per invocation while the config default stays `"sync"`, which is right for
|
|
353
|
+
a solo delivery with no sibling waiting behind it
|
|
354
|
+
([`deliver-reference.md`](deliver-reference.md) § Async merge-confirm mode).
|
|
355
|
+
A slow-CI consumer reaches for the same mode for the separate reason that a
|
|
356
|
+
foreground wait longer than the host tool ceiling (~10 min) almost always
|
|
357
|
+
expires `pending` after burning ~5 minutes of the slot — `"async"` makes that
|
|
358
|
+
confirm a designed ending instead of an expiry accident.
|
|
359
|
+
|
|
360
|
+
In async mode the close arms auto-merge, runs one short **~60s
|
|
327
361
|
probe window** (long enough to catch an instant merge and, via the
|
|
328
362
|
head-anchored required-check predicate, an instantly-red required check),
|
|
329
363
|
then returns the standard `pending` terminal with a `nextCommand`. When you
|
|
@@ -362,6 +396,13 @@ judgment that help text cannot carry.
|
|
|
362
396
|
- `--max-wait-seconds <n>` — from a headless caller with no host
|
|
363
397
|
tool-invocation ceiling, to keep single-block semantics
|
|
364
398
|
without editing the consumer's config.
|
|
399
|
+
- `--merge-watch-mode <sync|async>` — the per-invocation override of
|
|
400
|
+
`delivery.mergeWatch.mode`. **Pass `async` on every close of a multi-Story
|
|
401
|
+
run** (above); leave it off for a solo delivery. It composes with
|
|
402
|
+
`--max-wait-seconds` — pass both and the explicit bound still wins over the
|
|
403
|
+
async probe cap. An unrecognized value is refused before any phase runs, so a
|
|
404
|
+
typo cannot silently drop the run back onto synchronous waiting; the refusal
|
|
405
|
+
reports a `failed` terminal envelope at `phase: init`, mutating nothing.
|
|
365
406
|
|
|
366
407
|
---
|
|
367
408
|
|
|
@@ -215,12 +215,14 @@ ceilings on `STORY_SHAPE_CEILINGS` in
|
|
|
215
215
|
against the repo before overriding one (authoring `creates` for a file
|
|
216
216
|
that exists at base is a validator rejection). The persist gates stay
|
|
217
217
|
authoritative: they probe the base branch ref, not the working tree.
|
|
218
|
-
- **Keep `## Spec` near contract-level prose.**
|
|
219
|
-
|
|
220
|
-
|
|
218
|
+
- **Keep `## Spec` near contract-level prose.** **Aim for ~250 words; an
|
|
219
|
+
advisory warning fires past 350** (`SPEC_SOFT_WORD_BUDGET`). Two numbers,
|
|
220
|
+
two jobs: ~250 is the authoring target — the nudge toward a contract-level
|
|
221
221
|
Spec (interfaces, invariants, load-bearing constraints; no per-file
|
|
222
|
-
behavior narration)
|
|
223
|
-
|
|
222
|
+
behavior narration) — while 350 is the slacker threshold at which persist
|
|
223
|
+
actually warns, so the warning marks a real outlier instead of ordinary
|
|
224
|
+
variance. Neither fails the persist. The hard fail-closed ceiling
|
|
225
|
+
(~1500 tokens, `spec-spill.js`) is unchanged.
|
|
224
226
|
|
|
225
227
|
A faithfully-filled skeleton — placeholders replaced, pre-resolved entries
|
|
226
228
|
kept, tags valid — passes the persist ticket validators with no
|
|
@@ -313,6 +315,14 @@ output shape standalone. When the kill-switch is off
|
|
|
313
315
|
(`roleScopedAgents: false`) or the host cannot spawn at this depth, fall back
|
|
314
316
|
to a generic sub-agent and hand it the same charter (the `consolidation` /
|
|
315
317
|
`pre-mortem` definitions in [`plan-critic.md`](../../agents/plan-critic.md)).
|
|
318
|
+
**When both critics fire, dispatch them in a single turn.** Consolidation and
|
|
319
|
+
pre-mortem read the same immutable draft, share no write path, and neither
|
|
320
|
+
consumes the other's verdict — the textbook independent fan-out of
|
|
321
|
+
[`parallel-tooling.md`](parallel-tooling.md) Rule 3. Issue both `Agent` calls
|
|
322
|
+
together in one assistant turn rather than awaiting the first verdict before
|
|
323
|
+
spawning the second; serialized critics double the round's wall clock and buy
|
|
324
|
+
nothing, because you fold both verdicts into the same re-author round anyway.
|
|
325
|
+
|
|
316
326
|
Either way the critic is **maker-blind**: hand it the draft artifacts
|
|
317
327
|
(`stories.json`, and `techspec.md` when present) — never the authoring
|
|
318
328
|
transcript or the reasons the planner believed its own draft is sound. A
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: >-
|
|
3
|
+
Attended consolidation pass over this project's agent memory pool — merge
|
|
4
|
+
duplicates, verify claims against the current tree, prune with operator
|
|
5
|
+
confirmation, rewrite the index, and stamp the pool so the /plan advisory
|
|
6
|
+
goes quiet.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /memory-consolidate [--dry-run]
|
|
10
|
+
|
|
11
|
+
Agent memory drifts as the codebase moves: a workaround gets fixed, a budget
|
|
12
|
+
changes, two sessions save the same lesson twice. This is the sweep that
|
|
13
|
+
corrects it — and the **only** sanctioned writer of the memory pool outside a
|
|
14
|
+
session's own point-of-write corrections.
|
|
15
|
+
|
|
16
|
+
**Attended by contract.** Mandrel ships the trigger, the grounding and the
|
|
17
|
+
receipt; it never mutates the operator's personal memory store unsupervised.
|
|
18
|
+
Nothing here runs on a schedule, and no step deletes a file before Gate #2.
|
|
19
|
+
|
|
20
|
+
## Step 0 — Resolve the pool
|
|
21
|
+
|
|
22
|
+
`MANDREL_MEMORY_DIR` wins outright; otherwise the pool is
|
|
23
|
+
`~/.claude/projects/<cwd-slug>/memory/`, where `<cwd-slug>` is the absolute
|
|
24
|
+
working directory with every `/` and `.` replaced by `-`.
|
|
25
|
+
|
|
26
|
+
Report the resolved path and the entry count. **No pool → say so in one line
|
|
27
|
+
and stop** — an absent substrate is a clean no-op, never an error, and never a
|
|
28
|
+
reason to create one.
|
|
29
|
+
|
|
30
|
+
Each project (and each worktree) has its own pool: consolidate the pool of the
|
|
31
|
+
checkout you are in, and never reach across into another.
|
|
32
|
+
|
|
33
|
+
## Step 1 — Read the pool
|
|
34
|
+
|
|
35
|
+
Read `MEMORY.md` and every `*.md` entry. Group them by subject so duplicates
|
|
36
|
+
and supersessions surface together. Do not judge an entry from its index line —
|
|
37
|
+
the index is a pointer, the file is the claim.
|
|
38
|
+
|
|
39
|
+
## Step 2 — Classify each entry
|
|
40
|
+
|
|
41
|
+
Verify before you keep. Run `ls` / `grep` against the **current tree** for the
|
|
42
|
+
paths, flags, budgets and gate names an entry cites; re-measure a number rather
|
|
43
|
+
than trusting it (`wc -c` a file whose byte budget is quoted).
|
|
44
|
+
|
|
45
|
+
| Verdict | Means | Action |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| `fresh` | Claims re-confirmed against the tree | Leave byte-identical |
|
|
48
|
+
| `correct` | Core lesson holds, a detail has moved | Rewrite the detail in place, keep the entry |
|
|
49
|
+
| `duplicate` | Same lesson as another entry | Merge into the richer one, propose the thinner for pruning |
|
|
50
|
+
| `superseded` | The thing it warns about is fixed or retired | Strike the claim, keep the correction visible |
|
|
51
|
+
| `dead` | Subject no longer exists at all | Propose for pruning |
|
|
52
|
+
|
|
53
|
+
**A closed issue is the subject of a retrospective, never evidence of
|
|
54
|
+
staleness.** These pools are largely delivery write-ups — "delivered this
|
|
55
|
+
Story", "fixed by that PR". The referenced issue being closed is what the
|
|
56
|
+
memory is *about*: the normal, healthy shape. A retired predecessor of this
|
|
57
|
+
workflow marked exactly that pattern stale, which is why it no longer exists.
|
|
58
|
+
Use `github.owner` / `github.repo` from `.agentrc.json` when an issue
|
|
59
|
+
genuinely needs probing, and treat an unreachable probe as unknown — never
|
|
60
|
+
as dead.
|
|
61
|
+
|
|
62
|
+
Prefer `correct` over `dead`. A rewritten entry keeps hard-won context; a
|
|
63
|
+
deleted one costs a future session the same mistake.
|
|
64
|
+
|
|
65
|
+
## Step 3 — Gate #1: present the plan
|
|
66
|
+
|
|
67
|
+
Write the full proposal to `temp/memory/consolidation-<date>.md` — per entry:
|
|
68
|
+
verdict, evidence, and the exact edit or merge proposed. Summarize inline:
|
|
69
|
+
counts per verdict and the specific prune candidates by name.
|
|
70
|
+
|
|
71
|
+
**STOP.** Do not edit until the operator responds.
|
|
72
|
+
|
|
73
|
+
## Step 4 — Apply the edits
|
|
74
|
+
|
|
75
|
+
On confirmation, apply the `correct`, `duplicate` and `superseded` rewrites.
|
|
76
|
+
Preserve each entry's frontmatter contract (`name`, `description`, `metadata`)
|
|
77
|
+
and keep `[[wiki-link]]` references resolvable — a merge that orphans a link
|
|
78
|
+
has moved the problem, not fixed it.
|
|
79
|
+
|
|
80
|
+
## Step 5 — Gate #2: confirm every deletion
|
|
81
|
+
|
|
82
|
+
**Deletion is never implied by Gate #1.** Name each file proposed for pruning
|
|
83
|
+
with its one-line reason, and offer **mark-vs-delete**: marking the claim
|
|
84
|
+
superseded in place is the default and always available. Wait for an explicit
|
|
85
|
+
yes; delete only what the operator names. Silence is not consent.
|
|
86
|
+
|
|
87
|
+
## Step 6 — Rewrite the index and stamp
|
|
88
|
+
|
|
89
|
+
Rewrite `MEMORY.md` so it holds exactly one pointer line per surviving entry —
|
|
90
|
+
title, link, hook. It is loaded into context every session, so it carries
|
|
91
|
+
pointers only, never memory content.
|
|
92
|
+
|
|
93
|
+
Then write the receipt to `.consolidation-stamp.json` in the pool root:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{ "lastConsolidatedAt": "<ISO-8601 timestamp>" }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The `/plan` Phase 0 advisory reads this file; until it is written, the nudge
|
|
100
|
+
keeps firing. Write it **only** after Gate #2 — the stamp asserts an operator
|
|
101
|
+
reviewed the pass, so writing it early makes it a lie.
|
|
102
|
+
|
|
103
|
+
Close with counts: entries read, corrected, merged, pruned, and the new total.
|
|
104
|
+
|
|
105
|
+
## Constraints
|
|
106
|
+
|
|
107
|
+
- `--dry-run` runs Steps 0–3 and stops: the report is written, nothing mutates.
|
|
108
|
+
- Never delete an entry the operator did not name. Never write the stamp on a
|
|
109
|
+
dry run or a declined gate.
|
|
110
|
+
- Never invent memories here — this pass corrects and prunes what sessions
|
|
111
|
+
wrote; new memories come from the sessions that learned them.
|
|
112
|
+
|
|
113
|
+
## See also
|
|
114
|
+
|
|
115
|
+
[`/plan`](plan.md) (surfaces the advisory at its Gate #1),
|
|
116
|
+
[`/deliver`](deliver.md) (point-of-write corrections as work lands).
|
|
@@ -75,6 +75,9 @@ decision-made-by-default.
|
|
|
75
75
|
**Gate #1** — STOP to confirm the sharpened plan intent and any
|
|
76
76
|
duplicate-candidate review. Under `--yes`, auto-proceed.
|
|
77
77
|
|
|
78
|
+
On a truthy `memoryPoolAdvisory.recommend`, name [`/memory-consolidate`](memory-consolidate.md)
|
|
79
|
+
as an operator option, quoting its `reasons[]` — advisory, never invoked here.
|
|
80
|
+
|
|
78
81
|
On a truthy `deliverLightSuggestion.suggested`, offer — advisory, never an
|
|
79
82
|
automatic reroute — to deliver the seed instead; on confirm, route **in this
|
|
80
83
|
session** into [`helpers/deliver-light.md`](helpers/deliver-light.md), its gate
|
package/README.md
CHANGED
|
@@ -182,7 +182,9 @@ dimensions, run model, and how to benchmark a new version.
|
|
|
182
182
|
## Contributors
|
|
183
183
|
|
|
184
184
|
The published `mandrel` package ships three directories — `.agents/`, `bin/`,
|
|
185
|
-
and `lib/`
|
|
185
|
+
and `lib/` — plus the single file `docs/CHANGELOG.md`, and excludes the
|
|
186
|
+
`__tests__` subtrees under `.agents/` and `lib/` (see the `files` array in
|
|
187
|
+
[`package.json`](package.json)).
|
|
186
188
|
`.agents/` is the payload `mandrel sync` materializes into a consumer's
|
|
187
189
|
`./.agents/` directory; `bin/mandrel.js` and its `lib/` implementation stay
|
|
188
190
|
inside `node_modules/mandrel/` and back the `npx mandrel …` CLI used
|
|
@@ -193,8 +195,8 @@ tooling and is not published.
|
|
|
193
195
|
Common commands while developing the framework itself:
|
|
194
196
|
|
|
195
197
|
```bash
|
|
196
|
-
npm run lint #
|
|
197
|
-
npm run format #
|
|
198
|
+
npm run lint # biome + markdownlint + repo ratchets + generated-doc drift
|
|
199
|
+
npm run format # biome format — JavaScript/JSON only, not markdown
|
|
198
200
|
npm test # framework tests
|
|
199
201
|
npm run test:coverage # tests with coverage gate
|
|
200
202
|
```
|
|
@@ -226,9 +228,14 @@ against malicious lifecycle scripts in compromised transitive packages
|
|
|
226
228
|
install scripts for a specific install, run
|
|
227
229
|
`npm install --ignore-scripts=false` for that invocation only.
|
|
228
230
|
|
|
229
|
-
CRAP and Maintainability gates fire at
|
|
230
|
-
(
|
|
231
|
-
|
|
231
|
+
CRAP and Maintainability gates fire at four sites — `.husky/pre-commit`
|
|
232
|
+
(`quality-preview.js --staged`, scored on the staged index), `.husky/pre-push`
|
|
233
|
+
(diff-scoped against `origin/main`), close-validation (story close), and CI
|
|
234
|
+
(`ci.yml`, push + PR) — against the same thresholds from
|
|
235
|
+
`delivery.quality.*` in `.agentrc.json`. All four are **blocking**: the
|
|
236
|
+
pre-commit hook fires earliest and refuses the commit on a threshold
|
|
237
|
+
violation, and a green `npm run lint` / `npm test` / `check-baselines.js`
|
|
238
|
+
run does not predict it.
|
|
232
239
|
|
|
233
240
|
## License
|
|
234
241
|
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,70 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
<!--
|
|
6
|
+
Machine-generated by release-please (`changelog-path` in
|
|
7
|
+
`release-please-config.json`); only the header above is hand-owned — every
|
|
8
|
+
release prepends a section beneath it. The three rules below are properties
|
|
9
|
+
of conventional-changelog-writer's output, not of this repository's prose
|
|
10
|
+
style: `*` list markers (MD004), a double blank line before each `###`
|
|
11
|
+
section (MD012), and `*`-wrapped commit subjects that read as unbalanced
|
|
12
|
+
emphasis (MD037). They would be reintroduced on every release cut, failing
|
|
13
|
+
lint on release-please's own PR, so they are exempted file-wide rather than
|
|
14
|
+
hand-repaired. Do not extend this list to cover hand-written prose defects.
|
|
15
|
+
-->
|
|
16
|
+
<!-- markdownlint-disable-file MD004 MD012 MD037 -->
|
|
17
|
+
|
|
18
|
+
## [2.26.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.25.0...mandrel-v2.26.0) (2026-08-03)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
* /audit-baselines lens: ratchet-tightening audit workflow over the committed baseline surface ([#4903](https://github.com/dsj1984/mandrel/issues/4903)) ([#4913](https://github.com/dsj1984/mandrel/issues/4913)) ([420fb09](https://github.com/dsj1984/mandrel/commit/420fb09df605edfd8ace86e6b2295c7bd6909c3f))
|
|
24
|
+
* **acceptance-eval:** merge parallel cluster verdicts into one gate call per round (refs [#4951](https://github.com/dsj1984/mandrel/issues/4951)) ([#4954](https://github.com/dsj1984/mandrel/issues/4954)) ([56b69dd](https://github.com/dsj1984/mandrel/commit/56b69dde0a5faee418d5f49f4b0c3eab5f682245))
|
|
25
|
+
* **audit:** add the read-only baseline hotspot engine (refs [#4902](https://github.com/dsj1984/mandrel/issues/4902)) ([#4910](https://github.com/dsj1984/mandrel/issues/4910)) ([22a2245](https://github.com/dsj1984/mandrel/commit/22a22458645823705a2cfcf94ea6d1a7acb4546e))
|
|
26
|
+
* **deliver:** accept dash ranges in delivery Story-id lists (refs [#4927](https://github.com/dsj1984/mandrel/issues/4927)) ([#4928](https://github.com/dsj1984/mandrel/issues/4928)) ([9000044](https://github.com/dsj1984/mandrel/commit/90000442d5f578a4895b5950784e2fb8493d316a))
|
|
27
|
+
* **deliver:** add --merge-watch-mode and mandate one-turn fan-out dispatch (refs [#4949](https://github.com/dsj1984/mandrel/issues/4949)) ([#4957](https://github.com/dsj1984/mandrel/issues/4957)) ([fa1c426](https://github.com/dsj1984/mandrel/commit/fa1c426c181cb3696b4ea34166c99719cea877c2))
|
|
28
|
+
* make the coverage instrument measure: widen CI's run to every test tier, configure the gate, and reseed the baseline ([#4922](https://github.com/dsj1984/mandrel/issues/4922)) ([#4931](https://github.com/dsj1984/mandrel/issues/4931)) ([bc94fbf](https://github.com/dsj1984/mandrel/commit/bc94fbf65b41d53098606aff7f7b58dc1679ea5d))
|
|
29
|
+
* repair the inert quality instruments and tighten the ratchets behind the reclaimed slack ([#4923](https://github.com/dsj1984/mandrel/issues/4923)) ([#4933](https://github.com/dsj1984/mandrel/issues/4933)) ([3cc3a30](https://github.com/dsj1984/mandrel/commit/3cc3a30b5e54b3dac78649dd9536ad617086ee0c))
|
|
30
|
+
* retire friction-event.schema.json or wire it, and stop four docs citing a schema nothing compiles ([#4938](https://github.com/dsj1984/mandrel/issues/4938)) ([#4941](https://github.com/dsj1984/mandrel/issues/4941)) ([259f6e6](https://github.com/dsj1984/mandrel/commit/259f6e6cc47db88434b0612aa9327638afb73911))
|
|
31
|
+
* retire the memory-freshness scanner and ship the visible memory-hygiene loop ([#4919](https://github.com/dsj1984/mandrel/issues/4919)) ([#4921](https://github.com/dsj1984/mandrel/issues/4921)) ([54cf87c](https://github.com/dsj1984/mandrel/commit/54cf87c1a4e929681f194fc899decb24636bd5f2))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
* **baselines:** settle the exit through runAsCli so a piped report is not truncated ([#4932](https://github.com/dsj1984/mandrel/issues/4932)) ([d3670de](https://github.com/dsj1984/mandrel/commit/d3670dec493c2ba60a60e365c1ab809bde58ce43)), closes [#4783](https://github.com/dsj1984/mandrel/issues/4783)
|
|
37
|
+
* close three harness gaps: unbounded CI jobs, divergent runner flags, and inert pretest hooks ([#4936](https://github.com/dsj1984/mandrel/issues/4936)) ([#4942](https://github.com/dsj1984/mandrel/issues/4942)) ([d71040d](https://github.com/dsj1984/mandrel/commit/d71040dc0b558906a42327dcd9bd88ccfc26694c))
|
|
38
|
+
* exclude transpiled-coordinate rows from the 0%-coverage fill, and refuse a baseline that predates provenance stamping ([#4901](https://github.com/dsj1984/mandrel/issues/4901)) ([#4905](https://github.com/dsj1984/mandrel/issues/4905)) ([adc135b](https://github.com/dsj1984/mandrel/commit/adc135b3338550e2911e7139d638be8670eb5bab))
|
|
39
|
+
* **friction:** refuse a quoted --cmd as a usage error and split ENOBUFS from timeout (refs [#4915](https://github.com/dsj1984/mandrel/issues/4915)) ([#4918](https://github.com/dsj1984/mandrel/issues/4918)) ([64989aa](https://github.com/dsj1984/mandrel/commit/64989aa4a5cf746d959b649e760bf93f96f2ead0))
|
|
40
|
+
* **git:** give the git runners an explicit 64 MB stdout ceiling, unblocking Story close ([#4953](https://github.com/dsj1984/mandrel/issues/4953)) ([75160a4](https://github.com/dsj1984/mandrel/commit/75160a491704acc2de127d9135bcfcbc846bdfee))
|
|
41
|
+
* give the raised GitHub write fan-outs transient-retry backoff and single-source their concurrency bound ([#4961](https://github.com/dsj1984/mandrel/issues/4961)) ([#4964](https://github.com/dsj1984/mandrel/issues/4964)) ([459a3f1](https://github.com/dsj1984/mandrel/commit/459a3f12da0280881b757c0855d33d0a89221320))
|
|
42
|
+
* let a dangling-citation anchor count inside a code span (refs [#4906](https://github.com/dsj1984/mandrel/issues/4906)) ([#4911](https://github.com/dsj1984/mandrel/issues/4911)) ([a96ae9f](https://github.com/dsj1984/mandrel/commit/a96ae9fbed4b701ff45d13e268d91e960ebbe595))
|
|
43
|
+
* **lint:** lint docs/ so the gate matches the code-review lens ([#4971](https://github.com/dsj1984/mandrel/issues/4971)) ([b1f4e65](https://github.com/dsj1984/mandrel/commit/b1f4e6551670f145fa6f6e688a16130e8da644d7))
|
|
44
|
+
* make git hooks fire in linked worktrees and stop bypassing pre-push at close ([#4943](https://github.com/dsj1984/mandrel/issues/4943)) ([#4946](https://github.com/dsj1984/mandrel/issues/4946)) ([2ac0597](https://github.com/dsj1984/mandrel/commit/2ac05979241ca2ad061e14fbeda2b71c1b299da7))
|
|
45
|
+
* make the ratchet trend roll-up count what it measures and baseline staleness commit-aware ([#4962](https://github.com/dsj1984/mandrel/issues/4962)) ([#4967](https://github.com/dsj1984/mandrel/issues/4967)) ([fff36bf](https://github.com/dsj1984/mandrel/commit/fff36bf79ab4c75a2f4274c60228ab0942ded65a))
|
|
46
|
+
* **observability:** attribute terminal friction to the emitting CLI ([#4966](https://github.com/dsj1984/mandrel/issues/4966)) ([5aa986a](https://github.com/dsj1984/mandrel/commit/5aa986aaee97e858329ab8f948a1a59db8aeb1c4))
|
|
47
|
+
* **observability:** classify a bare framework-script basename as framework (refs [#4916](https://github.com/dsj1984/mandrel/issues/4916)) ([#4920](https://github.com/dsj1984/mandrel/issues/4920)) ([a8e0bbc](https://github.com/dsj1984/mandrel/commit/a8e0bbc22ad1cc8e0ab3ce117e597c537be96d7c))
|
|
48
|
+
* **plan-persist:** re-carry audit provenance onto dependent Stories (refs [#4935](https://github.com/dsj1984/mandrel/issues/4935)) ([#4939](https://github.com/dsj1984/mandrel/issues/4939)) ([6866b0c](https://github.com/dsj1984/mandrel/commit/6866b0c368de0ff438b565d5049a38273b56ef8c))
|
|
49
|
+
* **quality:** key anonymous CRAP methods by enclosing scope, not escomplex ordinal (refs [#4969](https://github.com/dsj1984/mandrel/issues/4969)) ([#4970](https://github.com/dsj1984/mandrel/issues/4970)) ([ca5da99](https://github.com/dsj1984/mandrel/commit/ca5da9940da57aaf20d34844afa835f6a8b127f0))
|
|
50
|
+
* read prior baseline rows per kind so duplication's diff-scope preservation and epsilon damping actually work ([#4937](https://github.com/dsj1984/mandrel/issues/4937)) ([#4940](https://github.com/dsj1984/mandrel/issues/4940)) ([e7d13b5](https://github.com/dsj1984/mandrel/commit/e7d13b551fb958c38833a7946785929dd17907a3))
|
|
51
|
+
* retune the advisory Spec word budget to 350 and repair its report channel (refs [#4907](https://github.com/dsj1984/mandrel/issues/4907)) ([#4909](https://github.com/dsj1984/mandrel/issues/4909)) ([3c914ba](https://github.com/dsj1984/mandrel/commit/3c914ba9430743f2e5399ded6ac74aee4c4148d1))
|
|
52
|
+
* **scripts:** make --help short-circuit before check-test-temp-hygiene does work ([#4968](https://github.com/dsj1984/mandrel/issues/4968)) ([5e873ac](https://github.com/dsj1984/mandrel/commit/5e873acbc316a37e5a173a94bb2fe52090614493))
|
|
53
|
+
* stop check-baselines silently disabling its compare arm when the base baseline cannot be read ([#4914](https://github.com/dsj1984/mandrel/issues/4914)) ([#4917](https://github.com/dsj1984/mandrel/issues/4917)) ([d62a334](https://github.com/dsj1984/mandrel/commit/d62a334555bccd605bd37bd9d8a544fdcc4e3710))
|
|
54
|
+
* stop the git-cleanup branches phase announcing a DRY RUN before it deletes ([#4898](https://github.com/dsj1984/mandrel/issues/4898)) ([3edad1e](https://github.com/dsj1984/mandrel/commit/3edad1e8c9a8906c1abc5f02e79e7ee4792775b2))
|
|
55
|
+
* **wave-runner:** exempt glob footprints from cross-beat reservation (refs [#4960](https://github.com/dsj1984/mandrel/issues/4960)) ([#4963](https://github.com/dsj1984/mandrel/issues/4963)) ([ca935e2](https://github.com/dsj1984/mandrel/commit/ca935e223f211340c671668a53738de634c12c04))
|
|
56
|
+
* **wave-runner:** reserve in-flight Story footprints in the ready-set guard (refs [#4950](https://github.com/dsj1984/mandrel/issues/4950)) ([#4955](https://github.com/dsj1984/mandrel/issues/4955)) ([7f8ffb3](https://github.com/dsj1984/mandrel/commit/7f8ffb31c523dba01fb9cffe376a5149d92d7c08))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### Performance
|
|
60
|
+
|
|
61
|
+
* **plan:** run the /plan path's independent gathers and write loops concurrently (refs [#4952](https://github.com/dsj1984/mandrel/issues/4952)) ([#4956](https://github.com/dsj1984/mandrel/issues/4956)) ([8c8ec6c](https://github.com/dsj1984/mandrel/commit/8c8ec6c1134f23fbf8214d138438b3febc6014c8))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
|
|
66
|
+
* **baselines:** migrate the duplication CLI onto refreshBaseline (refs [#4944](https://github.com/dsj1984/mandrel/issues/4944)) ([#4945](https://github.com/dsj1984/mandrel/issues/4945)) ([38e43d2](https://github.com/dsj1984/mandrel/commit/38e43d2362031cfaebbfeeaa8bec75c3c5ecf56b))
|
|
67
|
+
* burn down the cross-gate hotspot clusters and remove the shipped seams nothing calls ([#4926](https://github.com/dsj1984/mandrel/issues/4926)) ([#4934](https://github.com/dsj1984/mandrel/issues/4934)) ([970c7f8](https://github.com/dsj1984/mandrel/commit/970c7f88f5d198b685f90ede5358beea5b2896ce))
|
|
68
|
+
|
|
5
69
|
## [2.25.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.24.0...mandrel-v2.25.0) (2026-08-01)
|
|
6
70
|
|
|
7
71
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mandrel",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.26.0",
|
|
4
4
|
"description": "Claude Code-first opinionated workflow framework: instructions, skills, rules, and SDLC workflows that govern AI coding assistants.",
|
|
5
5
|
"files": [
|
|
6
6
|
".agents/",
|
|
@@ -15,9 +15,7 @@
|
|
|
15
15
|
"provenance": true
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"
|
|
19
|
-
"pretest:quick": "node .agents/scripts/test-wrapper.js",
|
|
20
|
-
"pretest:integration": "node .agents/scripts/test-wrapper.js",
|
|
18
|
+
"//test-preflight": "There are deliberately NO pretest* scripts (Story #4936). .npmrc sets ignore-scripts=true as supply-chain defence (CWE-1357), and that suppresses every pre*/post* lifecycle script for `npm run` too — so a pretest entry here would look like a gate and never execute. Each tier's preflight is declared once in .agents/scripts/lib/test-runner-contract.js and invoked by the runners themselves, which is why it fires for `npm test`, `npm run test:coverage` and a bare `node .agents/scripts/run-tests.js` alike.",
|
|
21
19
|
"test": "node .agents/scripts/run-tests.js",
|
|
22
20
|
"test:quick": "node .agents/scripts/run-tests.js --tier quick",
|
|
23
21
|
"test:integration": "node .agents/scripts/run-tests.js --tier integration",
|
|
@@ -28,6 +26,7 @@
|
|
|
28
26
|
"test:coverage": "node .agents/scripts/run-coverage.js",
|
|
29
27
|
"coverage:check": "node .agents/scripts/check-baselines.js --gate coverage",
|
|
30
28
|
"coverage:update": "node .agents/scripts/update-coverage-baseline.js",
|
|
29
|
+
"coverage:reanchor": "node .agents/scripts/update-coverage-baseline.js --full-scope",
|
|
31
30
|
"baseline:agents-loc": "node baselines/agents-loc-baseline.mjs",
|
|
32
31
|
"lint:md": "markdownlint-cli2 \".agents/**/*.md\" \"*.md\" \"!node_modules/**\" \"!.worktrees/**\"",
|
|
33
32
|
"lint": "node .agents/scripts/run-lint.js && npm run docs:check",
|
|
@@ -39,13 +38,19 @@
|
|
|
39
38
|
"format:check": "biome ci .",
|
|
40
39
|
"maintainability:check": "node .agents/scripts/check-baselines.js --gate maintainability",
|
|
41
40
|
"maintainability:update": "node .agents/scripts/update-maintainability-baseline.js",
|
|
41
|
+
"maintainability:reanchor": "node .agents/scripts/update-maintainability-baseline.js --full-scope",
|
|
42
42
|
"check:arch": "node .agents/scripts/check-arch-cycles.js",
|
|
43
43
|
"check:context-budget": "node .agents/scripts/check-context-budget.js",
|
|
44
|
+
"check:cyclomatic": "node .agents/scripts/check-cyclomatic.js",
|
|
45
|
+
"cyclomatic:update": "node .agents/scripts/check-cyclomatic.js --update",
|
|
46
|
+
"check:schema-refs": "node .agents/scripts/check-schema-references.js",
|
|
44
47
|
"check:workflow-citations": "node .agents/scripts/check-workflow-citations.js",
|
|
45
48
|
"crap:check": "node .agents/scripts/check-baselines.js --gate crap",
|
|
46
49
|
"crap:update": "node .agents/scripts/update-crap-baseline.js",
|
|
50
|
+
"crap:reanchor": "node .agents/scripts/update-crap-baseline.js --full-scope",
|
|
47
51
|
"duplication:check": "node .agents/scripts/check-baselines.js --gate duplication",
|
|
48
52
|
"duplication:update": "node .agents/scripts/update-duplication-baseline.js",
|
|
53
|
+
"duplication:reanchor": "node .agents/scripts/update-duplication-baseline.js --full-scope",
|
|
49
54
|
"quality:preview": "node .agents/scripts/check-dead-exports.js && node .agents/scripts/quality-preview.js",
|
|
50
55
|
"quality:watch": "node .agents/scripts/quality-watch.js",
|
|
51
56
|
"sync:commands": "node bin/mandrel.js sync-commands",
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"title": "FrictionEvent",
|
|
4
|
-
"type": "object",
|
|
5
|
-
"additionalProperties": false,
|
|
6
|
-
"properties": {
|
|
7
|
-
"eventId": {
|
|
8
|
-
"type": "string",
|
|
9
|
-
"format": "uuid"
|
|
10
|
-
},
|
|
11
|
-
"timestamp": {
|
|
12
|
-
"type": "string",
|
|
13
|
-
"format": "date-time"
|
|
14
|
-
},
|
|
15
|
-
"sprintId": {
|
|
16
|
-
"type": "string"
|
|
17
|
-
},
|
|
18
|
-
"category": {
|
|
19
|
-
"type": "string",
|
|
20
|
-
"enum": [
|
|
21
|
-
"Prompt Ambiguity",
|
|
22
|
-
"Missing Skill",
|
|
23
|
-
"Incorrect Persona",
|
|
24
|
-
"Tool Limitation",
|
|
25
|
-
"Execution Error"
|
|
26
|
-
]
|
|
27
|
-
},
|
|
28
|
-
"source": {
|
|
29
|
-
"type": "object",
|
|
30
|
-
"additionalProperties": false,
|
|
31
|
-
"properties": {
|
|
32
|
-
"tool": {
|
|
33
|
-
"type": "string"
|
|
34
|
-
},
|
|
35
|
-
"command": {
|
|
36
|
-
"type": "string"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
"details": {
|
|
41
|
-
"type": "string",
|
|
42
|
-
"description": "Specific error message or observation."
|
|
43
|
-
},
|
|
44
|
-
"context": {
|
|
45
|
-
"type": "object",
|
|
46
|
-
"additionalProperties": false,
|
|
47
|
-
"properties": {
|
|
48
|
-
"protocolFile": {
|
|
49
|
-
"type": "string",
|
|
50
|
-
"description": "Path to relevant protocol file, e.g., '.agents/skills/core/tdd.md'"
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
"required": ["eventId", "timestamp", "sprintId", "category", "details"]
|
|
56
|
-
}
|