mandrel 1.91.0 → 1.92.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/.agents/README.md +5 -5
  2. package/.agents/docs/SDLC.md +75 -107
  3. package/.agents/docs/configuration.md +1 -1
  4. package/.agents/docs/quality-gates.md +8 -7
  5. package/.agents/docs/workflows.md +4 -10
  6. package/.agents/instructions.md +2 -2
  7. package/.agents/schemas/agentrc.schema.json +1 -1
  8. package/.agents/schemas/lifecycle/README.md +2 -1
  9. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  10. package/.agents/schemas/risk-verdict.schema.json +14 -1
  11. package/.agents/scripts/README.md +0 -46
  12. package/.agents/scripts/analyze-execution.js +76 -1
  13. package/.agents/scripts/check-doc-links.js +3 -0
  14. package/.agents/scripts/check-workflow-cli-lint.js +208 -0
  15. package/.agents/scripts/epic-audit-recheck.js +1 -1
  16. package/.agents/scripts/epic-plan-clarity.js +16 -6
  17. package/.agents/scripts/epic-plan-decompose.js +37 -59
  18. package/.agents/scripts/epic-plan-healthcheck.js +39 -6
  19. package/.agents/scripts/epic-plan-spec.js +41 -168
  20. package/.agents/scripts/epic-reconcile.js +7 -1
  21. package/.agents/scripts/lib/Logger.js +4 -4
  22. package/.agents/scripts/lib/audit-suite/index.js +4 -5
  23. package/.agents/scripts/lib/audit-suite/runner.js +6 -4
  24. package/.agents/scripts/lib/audit-suite/selector.js +2 -3
  25. package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
  26. package/.agents/scripts/lib/command-header.js +20 -0
  27. package/.agents/scripts/lib/config/github.js +1 -3
  28. package/.agents/scripts/lib/config-settings-schema.js +4 -3
  29. package/.agents/scripts/lib/degraded-mode.js +1 -1
  30. package/.agents/scripts/lib/label-constants.js +18 -3
  31. package/.agents/scripts/lib/label-taxonomy.js +14 -3
  32. package/.agents/scripts/lib/mutation/baseline-snapshot.js +7 -6
  33. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +18 -8
  34. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +3 -4
  35. package/.agents/scripts/lib/orchestration/docs-digest.js +2 -2
  36. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +4 -0
  37. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +22 -12
  38. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +6 -1
  39. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +18 -2
  40. package/.agents/scripts/{lifecycle-diff.js → lib/orchestration/lifecycle/ledger-diff.js} +10 -76
  41. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +1 -1
  42. package/.agents/scripts/lib/orchestration/plan-context.js +510 -0
  43. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +177 -0
  44. package/.agents/scripts/lib/orchestration/plan-metrics.js +445 -0
  45. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +359 -0
  46. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +127 -0
  47. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +978 -0
  48. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +191 -0
  49. package/.agents/scripts/lib/orchestration/plan-reachability.js +160 -0
  50. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +3 -3
  51. package/.agents/scripts/lib/orchestration/planning-risk.js +1 -1
  52. package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
  53. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +1 -1
  54. package/.agents/scripts/lib/orchestration/ticketing/reads.js +11 -2
  55. package/.agents/scripts/lib/plan-phase-cleanup.js +16 -0
  56. package/.agents/scripts/lib/presentation/manifest-persistence.js +2 -3
  57. package/.agents/scripts/lib/templates/spec-author-prompts.js +74 -0
  58. package/.agents/scripts/plan-context.js +186 -0
  59. package/.agents/scripts/plan-critics.js +227 -0
  60. package/.agents/scripts/plan-persist.js +383 -0
  61. package/.agents/scripts/pr-watch-with-update.js +8 -7
  62. package/.agents/scripts/run-lint.js +10 -11
  63. package/.agents/scripts/story-plan.js +19 -7
  64. package/.agents/scripts/sync-claude-commands.js +10 -5
  65. package/.agents/skills/core/knowledge-transfer/SKILL.md +11 -7
  66. package/.agents/workflows/audit-documentation.md +5 -7
  67. package/.agents/workflows/audit-lighthouse.md +1 -0
  68. package/.agents/workflows/audit-security.md +1 -0
  69. package/.agents/workflows/audit-to-stories.md +16 -5
  70. package/.agents/workflows/git-deliver.md +76 -243
  71. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  72. package/.agents/workflows/helpers/code-review.md +7 -6
  73. package/.agents/workflows/helpers/deliver-epic.md +5 -4
  74. package/.agents/workflows/helpers/plan-epic-reference.md +109 -96
  75. package/.agents/workflows/helpers/plan-epic.md +246 -999
  76. package/.agents/workflows/helpers/plan-story.md +14 -14
  77. package/.agents/workflows/helpers/scope-triage-gate.md +6 -4
  78. package/.agents/workflows/helpers/single-story-deliver.md +5 -4
  79. package/.agents/workflows/helpers/worktree-lifecycle.md +9 -7
  80. package/.agents/workflows/mandrel-update.md +144 -466
  81. package/.agents/workflows/plan.md +73 -143
  82. package/docs/CHANGELOG.md +13 -0
  83. package/lib/cli/registry.js +21 -3
  84. package/package.json +1 -1
  85. package/.agents/schemas/loop-unit.schema.json +0 -70
  86. package/.agents/scripts/assert-branch.js +0 -81
  87. package/.agents/scripts/check-loop-units.js +0 -204
  88. package/.agents/scripts/detect-merges.js +0 -111
  89. package/.agents/scripts/git-pr-quality-gate.js +0 -205
  90. package/.agents/scripts/git-rebase-and-resolve.js +0 -234
  91. package/.agents/scripts/hierarchy-gate.js +0 -192
  92. package/.agents/scripts/hydrate-context.js +0 -179
  93. package/.agents/scripts/lib/loop-units/validate-loop-unit.js +0 -197
  94. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/cli.js +0 -167
  95. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/cli-args.js +0 -69
  96. package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +0 -86
  97. package/.agents/scripts/loc-delta.js +0 -205
  98. package/.agents/scripts/render-manifest.js +0 -143
  99. package/.agents/scripts/run-audit-suite.js +0 -97
  100. package/.agents/scripts/select-audits.js +0 -155
  101. package/.agents/scripts/update-mutation-baseline.js +0 -189
  102. package/.agents/workflows/explain.md +0 -118
  103. package/.agents/workflows/git-merge-pr.md +0 -377
  104. package/.agents/workflows/helpers/epic-plan-decompose.md +0 -22
  105. package/.agents/workflows/helpers/epic-plan-spec.md +0 -22
  106. package/.agents/workflows/loops/README.md +0 -65
  107. package/.agents/workflows/loops/fix-failing-tests.md +0 -74
  108. package/.agents/workflows/loops/nightly-audit.md +0 -81
  109. package/.agents/workflows/loops/watch-ci.md +0 -68
package/.agents/README.md CHANGED
@@ -318,7 +318,7 @@ install — so a freshly bootstrapped repo already has them. If you adopt
318
318
  to your own `package.json` (any compatible versions) and install.
319
319
 
320
320
  **Fail-fast guard.** The dependency-dependent entry points
321
- (`epic-plan-spec.js`, `epic-plan-decompose.js`, and the baseline scorers)
321
+ (`plan-context.js`, `plan-persist.js`, and the baseline scorers)
322
322
  run a presence check on their required deps before doing any work. When the
323
323
  install is missing, empty, or stale, they exit non-zero with an actionable
324
324
  message naming the missing packages and your install command — instead of a
@@ -412,11 +412,11 @@ LLM consumes downstream, and that does not turn the script into a Skill.
412
412
  The signal is whether the *output of this unit* is the product of
413
413
  judgment (Skill) or of a parseable transform (script).
414
414
 
415
- ### Worked example 1 — split: `epic-plan-decompose.js`
415
+ ### Worked example 1 — split: the plan pipeline
416
416
 
417
- [`scripts/epic-plan-decompose.js`](scripts/epic-plan-decompose.js) is a
418
- **split**: the deterministic halves stay as a script, the judgment middle
419
- moves to a Skill.
417
+ The collapsed plan pipeline (`plan-context.js` → author → `plan-persist.js`,
418
+ Epic #4474) is a **split**: the deterministic halves stay as scripts, the
419
+ judgment middle moves to a Skill.
420
420
 
421
421
  - **`--emit-context`** (script half) — fetches the Epic body (which
422
422
  carries the folded Tech Spec sections), scrapes project docs, emits a
@@ -26,70 +26,39 @@ From zero to shipped:
26
26
  Epic, and transitions the Epic to `agent::ready`.
27
27
 
28
28
  The entry point you use selects where the run begins:
29
- - With **no arguments** (or `--idea "<seed>"`), the workflow enters at
30
- Phase 1 and runs the ideation phases (1–4) to open a fresh
31
- `type::epic` Issue before authoring.
32
- - With **`<epicId>`**, the workflow skips ideation and enters at
33
- Phase 5 for an Epic Issue you have already opened.
34
-
35
- > **Phase numbering note.** The numbered phases below are
36
- > `/plan`'s **internal** phases (1–11), not the SDLC-level
37
- > Phase 0–4 used by the Mermaid diagram in [§ End-to-End
38
- > Process](#end-to-end-process). Phases 1–4 run **only** on the
39
- > ideation entry; an existing-Epic invocation starts at Phase 5.
40
-
41
- 1. **Phase 1 idea refinement** *(ideation entry only)* — the
42
- `idea-refinement` skill drives a divergent convergent → sharpen
43
- loop and emits a one-pager with the five canonical Epic sections.
44
- Stops for operator confirmation of the one-pager.
45
- 2. **Phase 2 cross-Epic duplicate search** *(ideation entry only)*
46
- — `lib/duplicate-search.js` ranks open Epics whose scope overlaps
47
- the one-pager; the operator confirms the idea is distinct or folds
48
- it into an existing Epic (in which case `/plan` exits).
49
- 3. **Phase 3 render Epic body** *(ideation entry only)* — renders
50
- the confirmed one-pager into the canonical Epic-from-idea template
51
- and stops for a final wording confirmation.
52
- 4. **Phase 4 open the Epic Issue** *(ideation entry only)* — opens
53
- the GitHub Issue with **only** the `type::epic` label; the captured
54
- id flows into the rest of the pipeline.
55
- 5. **Phase 5 re-plan detection** — checks whether the Epic body
56
- already carries the folded Tech Spec sections (keyed on the
57
- `## Delivery Slicing` managed section — Story #4324) and, if so,
58
- prompts before overwriting the Tech Spec / Acceptance Table
59
- sections in place and recreating the child Story tickets. Legacy
60
- context tickets on historical Epics are ignored (never fetched).
61
- 6. **Phase 6 — Epic clarity gate** — scores the Epic body against the
62
- five canonical sections. A `clear` verdict requires ≥ 4 of 5
63
- sections present **and** the Acceptance Criteria section present (AC
64
- is required, not optional). A `clear` verdict proceeds silently;
65
- `needs-refinement` drops into a one-shot refinement loop with a HITL
66
- diff before persisting the sharpened body.
67
- 7. **Phase 7 — Tech Spec & Acceptance Spec** — the
68
- `epic-plan-spec-author` skill authors both planning artifacts;
69
- the persist half folds them into the Epic body's managed
70
- sections, flips the Epic to `agent::review-spec`,
71
- and routes high-risk Epics to a HITL review stop (low-risk Epics
72
- auto-proceed).
73
- 8. **Phase 8 — work-breakdown decomposition** — the
74
- `epic-plan-decompose-author` skill emits the Epic → Story
75
- tree (with inline `acceptance[]` / `verify[]` per Story); the
76
- validator enforces hierarchy, DAG acyclicity, and file-assumption
77
- invariants.
78
- 9. **Phase 9 — execution roadmap** — runs the dispatcher in dry-run to
79
- compute waves and posts the `dispatch-manifest` structured comment
80
- that `/deliver` consumes.
81
- 10. **Phase 10 — readiness health check** — `epic-plan-healthcheck.js`
82
- runs the default config + git-remote checks; a non-OK result is a
83
- **blocking** exit condition for the `agent::ready` flip (overridable
84
- only via the `planning::healthcheck-waived` label).
85
- 11. **Phase 11 — plan comprehension gate** — an opt-in, advisory
86
- walkthrough of the planned backlog driven by the
87
- `core/knowledge-transfer` skill. Offered by LM judgment only on
88
- non-trivial plans, runs **after** the `agent::ready` flip, and is
89
- interruptible at every checkpoint — it never blocks the hand-off.
90
- 12. **Phase 12 — notification & hand-off** — posts the backlog summary
91
- comment, @mentions the operator, and names `/deliver` as the
92
- next step.
29
+ - With **no arguments** (or `--idea "<seed>"`), the workflow enters the
30
+ ideation form of the interrogate step; the Epic Issue itself is opened
31
+ by the persist step.
32
+ - With **`<epicId>`**, the workflow interrogates against an Epic Issue
33
+ you have already opened.
34
+
35
+ > **Step note.** `/plan`'s Epic path runs **three steps** (Epic #4474):
36
+ > all GitHub reads happen in `plan-context.js`, all GitHub writes in
37
+ > `plan-persist.js`, and two HITL gates bracket the authoring middle.
38
+
39
+ 1. **Interrogate** the `idea-refinement` skill (ideation) or the
40
+ envelope's clarity/re-plan signals (existing Epic) drive a
41
+ question-at-a-time interrogation; `plan-context.js` emits the single
42
+ authoring envelope (duplicate candidates, clarity rubric, re-plan
43
+ signals, codebase snapshot, system prompts, delivery-shape signal).
44
+ The scope-triage verdict, duplicate review, and re-plan / refined-body
45
+ decisions fold into **gate #1**, one operator confirm at the step's
46
+ exit.
47
+ 2. **Author** — the `epic-plan-spec-author` skill writes the Tech Spec
48
+ (opening `## Delivery Slicing`), the risk verdict (with its
49
+ `deliveryShape`), and the Acceptance Table; the
50
+ `epic-plan-decompose-author` skill writes `tickets.json` in fan-out
51
+ shape (a single-delivery plan authors no tickets). Fresh-context
52
+ consolidation and pre-mortem critics run conditionally before the
53
+ review.
54
+ 3. **Persist** **gate #2** (risk-routed) shows spec + tickets + risk +
55
+ `deliveryShape` in one view; then `plan-persist.js` runs every
56
+ deterministic gate in one ordered, fail-closed pass (section gate,
57
+ ticket validator, file-assumption gate, DAG, budget, Epic lease,
58
+ managed sections, story creation or the `delivery::single` marker,
59
+ inline healthcheck) and flips the Epic to `agent::ready` **once** —
60
+ no intermediate `agent::review-spec` closing with a `plan-summary`
61
+ comment that carries the dry-run wave table.
93
62
 
94
63
  2. **Deliver the Epic.** Run `/deliver <epicId>` in your IDE. The
95
64
  skill drives the merged execute + close flow end-to-end.
@@ -343,7 +312,7 @@ mode:
343
312
  convergent → sharpen loop and emits a markdown one-pager with the
344
313
  five canonical Epic sections (Context, Goal, Non-Goals, Scope,
345
314
  Acceptance Criteria).
346
- 2. **Scope triage (Phase 1.5).** Before the ceremony is paid for, the
315
+ 2. **Scope triage.** Before the ceremony is paid for, the
347
316
  one-pager is judged against the story-vs-epic rubric (see the
348
317
  subsection below). On a `story` / `borderline` verdict the operator may
349
318
  route the work to `/plan` instead of opening an Epic.
@@ -353,16 +322,18 @@ mode:
353
322
  new idea is genuinely distinct or folds it into an existing Epic
354
323
  (`/plan` exits and the operator resumes work on the existing
355
324
  id).
356
- 4. **Render and confirm the Epic body.** The one-pager is rendered into
357
- the canonical Epic-from-idea template; the operator confirms before
358
- the GitHub Issue is opened.
359
- 5. **Open the Epic.** The Issue is opened with **only** the `type::epic`
360
- label no `state::*` label is applied at creation. Spec authoring in
361
- Phase 1b advances it to `agent::review-spec`.
325
+ 4. **Confirm at gate #1.** The one-pager, the triage verdict, and the
326
+ duplicate review fold into one operator confirmation at the exit of
327
+ the interrogate step.
328
+ 5. **Open the Epic (persist step).** `plan-persist.js` renders the
329
+ one-pager into the canonical Epic-from-idea template and opens the
330
+ Issue with **only** the `type::epic` label — no `state::*` label at
331
+ creation; the same persist pass folds in the authored sections and
332
+ flips the Epic straight to `agent::ready`.
362
333
 
363
334
  #### Scope triage
364
335
 
365
- `/plan` Phase 1.5 runs the
336
+ The `/plan` Epic path's interrogate step runs the
366
337
  [`core/scope-triage`](../skills/core/scope-triage/SKILL.md) rubric over the
367
338
  sharpened one-pager so a story-sized scope is not pushed through the full Epic
368
339
  ceremony (Tech Spec + Acceptance Spec + Story backlog +
@@ -374,20 +345,21 @@ verdicts — `epic` | `story` | `borderline`.
374
345
 
375
346
  The verdict is **host-LLM judgment** (no scorer, no schema, no label
376
347
  transition) and **advisory** — the operator always decides. It folds into the
377
- existing Phase 1 HITL confirmation rather than adding a second stop: an `epic`
348
+ existing gate #1 confirmation rather than adding a second stop: an `epic`
378
349
  verdict proceeds with a plain confirm, while a `story` / `borderline` verdict
379
350
  offers a three-way choice (single Story / plan as Epic anyway / abort). On an
380
351
  accepted `story`, `/plan` hands the one-pager off to
381
- `/plan --from-notes` as a scope-triage handoff and exits. Phase 1.5 is
352
+ `/plan --from-notes` as a scope-triage handoff and exits. The ideation triage is
382
353
  skipped when `/plan` is itself entered via a scope-triage handoff, so the
383
354
  two workflows never ping-pong a settled decision.
384
355
 
385
356
  The same rubric also guards the **existing-Epic entry** (1b) as the
386
- **Phase 5.5 story-sized advisory**, which catches a story-sized scope that was
387
- hand-opened directly as a `type::epic` issue (the Phase 6 Epic Clarity Gate
357
+ **story-sized advisory**, which catches a story-sized scope that was
358
+ hand-opened directly as a `type::epic` issue (the Epic Clarity Gate rubric
388
359
  scores section *presence*, not scope *size*, so a clear-but-thin Epic would
389
- otherwise sail through). The advisory fires **only** when Phase 5 found no
390
- folded Tech Spec sections **and** the Epic has no open Story children, so
360
+ otherwise sail through). The advisory fires **only** when the envelope's
361
+ re-plan signal found no folded Tech Spec sections **and** the Epic has no
362
+ open Story children, so
391
363
  it never re-triages an Epic that is being re-planned. An `epic` verdict
392
364
  proceeds silently; a `story` / `borderline` verdict STOPs with the same
393
365
  three-way choice (convert to a standalone Story / proceed as Epic anyway /
@@ -410,10 +382,10 @@ draft-confirmation HITL stop with no extra stop on a `story` verdict; an `epic`
410
382
  verdict offers a three-way choice (escalate to `/plan --idea` as a
411
383
  scope-triage handoff / persist as a standalone Story anyway / abort). On an
412
384
  accepted escalation, `/plan` abandons the draft and hands the notes off to
413
- `/plan --idea`, marked as a handoff so `/plan` skips its own Phase 1.5
414
- gate. This gate is itself skipped when `/plan` was entered via a
415
- scope-triage handoff (from `/plan` Phase 1.5 or the Phase 5.5 conversion
416
- path), so the two workflows never ping-pong a settled decision. As with the
385
+ `/plan --idea`, marked as a handoff so `/plan` skips its own ideation
386
+ triage gate. This gate is itself skipped when `/plan` was entered via a
387
+ scope-triage handoff (from the Epic path's ideation triage or its
388
+ story-sized conversion path), so the two workflows never ping-pong a settled decision. As with the
417
389
  inbound gates, the verdict is advisory and host-LLM judgment — no auto-routing,
418
390
  no scorer, no schema, and no label transition.
419
391
 
@@ -450,7 +422,7 @@ The framework reads the Epic and autonomously builds the entire work breakdown.
450
422
  > "do not modify existing issues without permission" Constraint — every
451
423
  > body rewrite is operator-confirmed.
452
424
 
453
- 1. **Epic Planner** (`epic-plan-spec.js`):
425
+ 1. **Epic Planner** (the spec half of `plan-persist.js`):
454
426
  - Synthesizes the Epic body with project documentation.
455
427
  - Folds the authored **Tech Spec** (opening with `## Delivery
456
428
  Slicing`) and the **Acceptance Table** (the AC-ID table) into
@@ -488,8 +460,8 @@ BDD runner + pending-tag (e.g. `playwright-bdd supports @skip`) for the
488
460
  features-first Story to consume.
489
461
 
490
462
  The spec is persisted by
491
- `epic-plan-spec.js --epic [Epic_ID] --tech-spec ... --acceptance-table ...`
492
- — the persist half folds both artifacts into the Epic body's managed
463
+ `plan-persist.js --epic [Epic_ID] --tech-spec ... --acceptance-table ...`
464
+ — the persist step folds both artifacts into the Epic body's managed
493
465
  sections in one atomic, section-scoped write (everything outside the
494
466
  managed regions is byte-preserved) and fails loudly if any input is
495
467
  missing or empty. At delivery time, hydration strips the
@@ -502,7 +474,7 @@ authoring/close-time machinery, not delivery context.
502
474
  **`planningRisk`** envelope from a **planner-authored risk verdict**
503
475
  (`risk-verdict.json`, the third planning artifact the
504
476
  `epic-plan-spec-author` Skill writes from the Epic body / Tech Spec it just
505
- authored). The persist half of `epic-plan-spec.js` validates the verdict
477
+ authored). `plan-persist.js` validates the verdict
506
478
  against `risk-verdict.schema.json` — a malformed verdict fails closed —
507
479
  then derives the envelope via `deriveRiskEnvelope`
508
480
  (`lib/orchestration/planning-risk.js`). The verdict is recorded as a
@@ -546,8 +518,8 @@ on the Epic ticket records the waiver. There are two routes to the label:
546
518
  - **Planner-selected** — `/plan`'s `planning.spec-authoring` state derives a
547
519
  `planningRisk` envelope from the planner-authored risk verdict
548
520
  (see § Adaptive planning risk routing) and,
549
- when `acceptanceDisposition === 'not-applicable'`, the persist half
550
- of `epic-plan-spec.js` applies `acceptance::n-a` on the Epic and skips
521
+ when `acceptanceDisposition === 'not-applicable'`, the persist step
522
+ of `plan-persist.js` applies `acceptance::n-a` on the Epic and skips
551
523
  the Acceptance Table section for that run (stripping a stale one on a
552
524
  re-plan). The disposition is also
553
525
  recorded in the `epic-plan-state` checkpoint so the decision is
@@ -568,7 +540,7 @@ The waiver is binary — there is no partial opt-out. If an Epic later
568
540
  warrants spec coverage, remove the label and run `/plan`'s
569
541
  `planning.spec-authoring` state to author the spec.
570
542
 
571
- 1. **Ticket Decomposer** (`epic-plan-decompose.js`):
543
+ 1. **Ticket Decomposer** (the fan-out half of `plan-persist.js`):
572
544
  - Decomposes specs into the **2-tier hierarchy**
573
545
  (Epic → Story):
574
546
 
@@ -593,16 +565,17 @@ Story-branch → Epic-branch merge model are unchanged; the Feature and
593
565
  Task layers are gone, and thematic grouping lives as prose in the Epic
594
566
  body (which also carries the folded Tech Spec sections).
595
567
 
596
- When decomposition completes the Epic flips to `agent::ready` and the
597
- dispatch manifest is posted as a structured comment on the Epic. That
598
- manifest is the source of truth for the wave layout `/deliver`
599
- consumes in the `delivery.snapshot` state.
568
+ When the persist step completes the Epic flips to `agent::ready` and the
569
+ `plan-summary` structured comment (with the dry-run wave table) lands on
570
+ the Epic. The live wave manifest is written at deliver time by the
571
+ prepare phase planning posts no separate dispatch-manifest comment
572
+ (Epic #4474).
600
573
 
601
574
  ### `agent::ready` exit conditions
602
575
 
603
576
  The planning → delivery handoff is governed by an explicit checklist.
604
- The persist half of `epic-plan-decompose.js` refuses to flip the Epic
605
- to `agent::ready` unless **every** condition below is true. The
577
+ `plan-persist.js` refuses to flip the Epic to `agent::ready`
578
+ unless **every** condition below is true. The
606
579
  contract is enforced at the planner boundary so `/deliver` can
607
580
  treat `agent::ready` as a load-bearing precondition rather than a
608
581
  hopeful signal.
@@ -616,18 +589,13 @@ hopeful signal.
616
589
  the Epic's child-Story backlog and written the spec to
617
590
  `.agents/epics/<epicId>.yaml`. The `epic-plan-state` checkpoint
618
591
  comment records `phase: ready`.
619
- - **Dispatch manifest posted.** A single `epic-dispatch` structured
620
- comment exists on the Epic and validates against
621
- `.agents/schemas/dispatch-manifest.json`. The dispatch manifest is
622
- the source of truth `/deliver` reads during
623
- `delivery.snapshot`.
624
- - **Healthcheck green.** `epic-plan-healthcheck.js` (run during
625
- `/plan` Phase 10) returned `ok: true`. A failing healthcheck
592
+ - **Healthcheck green.** The inline `epic-plan-healthcheck` pass run
593
+ by the persist CLI returned `ok: true`. A failing healthcheck
626
594
  blocks the handoff — there is no advisory degrade-mode for
627
595
  `agent::ready`.
628
- - **Notification posted.** The planner has posted the
629
- `planning.handoff` notification on the Epic so the operator and any
630
- subscribed listeners know the Epic is ready to fan out.
596
+ - **Summary posted.** The persist CLI has posted the `plan-summary`
597
+ structured comment (backlog stats + the dry-run wave table) so the
598
+ operator knows the Epic is ready to fan out.
631
599
 
632
600
  **Operator override.** The `planning::healthcheck-waived` label, applied
633
601
  to the Epic by the operator, is the documented escape hatch for cases
@@ -865,8 +833,8 @@ an exclusive, time-bounded claim on the ticket via
865
833
  rides the ticket's GitHub `assignees` field — a substrate every clone can
866
834
  read — so a live foreign claim is visible to, and refuses, a second
867
835
  operator regardless of which machine they are on. All three delivery and
868
- planning entry points take the claim: `/plan` acquires the Epic lease
869
- before Phase 7 (spec) and releases it after Phase 8 (decompose),
836
+ planning entry points take the claim: `/plan`'s persist CLI acquires the
837
+ Epic lease before its first mutation and releases it on every exit path,
870
838
  `/deliver` acquires the Epic lease in its prepare guard, and
871
839
  `/single-story-deliver` acquires the Story lease at init. For
872
840
  `/deliver` and `/single-story-deliver`, liveness is decided by the
@@ -117,7 +117,7 @@ top-level keys are validation errors.
117
117
  | `failOnLargeFanOut` | No | `boolean` | — | — |
118
118
  | `largeFanOutThreshold` | No | `integer` | — | — |
119
119
  | `crossCuttingRegistries` | No | `string[]` or `{ append?, prepend? }` | — | — |
120
- | `navigation` | No | `object` | — | Navigability-reachability config consumed by the epic-plan-healthcheck --paranoid reachability check. Opt-in: absent or empty routeGlobs degrades to a silent no-op. |
120
+ | `navigation` | No | `object` | — | Navigability-reachability config consumed by the plan-persist draft reachability gate (Epic #4474 PR6; also the manual epic-plan-healthcheck --paranoid re-check). Opt-in: absent or empty routeGlobs degrades to a silent no-op. |
121
121
  | `navigation.routeGlobs` | No | `array<string>` | — | Glob patterns (pages/**, app/**/route.ts) marking paths that add a user-facing route. |
122
122
  | `navigation.navRegistry` | No | `array<string>` | — | Tokens identifying the nav-registry SSOT a route-adding Story is expected to reference. |
123
123
 
@@ -121,10 +121,11 @@ The same files-out-of-scope list as before, declared in `.c8rc.cjs`:
121
121
  unit-tested hydration engine; end-to-end coverage requires a real
122
122
  provider tree and Story prompt context, which lives in integration
123
123
  tests.
124
- - `epic-plan-decompose.js`, `epic-plan-spec.js`,
125
- `epic-plan-healthcheck.js` `/epic-plan` slash-command CLI shells
126
- with no unit-test seam; the meaningful orchestration logic lives in
127
- `lib/orchestration/plan-runner/*` and is unit-tested there.
124
+ - `plan-context.js`, `plan-persist.js`, `epic-plan-healthcheck.js` —
125
+ `/plan` CLI shells with no unit-test seam; the meaningful
126
+ orchestration logic lives in `lib/orchestration/plan-context.js`,
127
+ `lib/orchestration/plan-persist/*`, and the plan phase modules, and is
128
+ unit-tested there.
128
129
  - A larger Story #1702 carve-out of top-level CLI gates, orchestration
129
130
  CLIs, git-manipulation CLIs, and `lib/*` glue (e.g. `lint-baseline.js`,
130
131
  `story-close.js`, `dispatcher.js`, `run-tests.js`,
@@ -581,9 +582,9 @@ Cross-references:
581
582
  - [`.agents/README.md`](../README.md) — consumer onboarding.
582
583
 
583
584
  > The `mutation` gate ships **dormant** (built-but-unwired, intentionally
584
- > opt-in). The cost/fit analysis behind deferring its activation lives in
585
- > the header comment of
586
- > [`.agents/scripts/update-mutation-baseline.js`](../scripts/update-mutation-baseline.js).
585
+ > opt-in). The former `update-mutation-baseline.js` refresh CLI was retired
586
+ > with the rest of the zero-consumer script surface (#4482); the
587
+ > `lib/mutation/` snapshot machinery remains for a future activation.
587
588
 
588
589
  ### Envelope
589
590
 
@@ -32,7 +32,7 @@ by `node .agents/scripts/generate-workflows-doc.js`; `npm run docs:check`
32
32
  fails when it drifts from the on-disk workflow set. To change a command’s
33
33
  description, edit the workflow file’s front-matter and regenerate.
34
34
 
35
- ## Commands (25)
35
+ ## Commands (23)
36
36
 
37
37
  | Command | Description |
38
38
  | --- | --- |
@@ -52,24 +52,18 @@ description, edit the workflow file’s front-matter and regenerate.
52
52
  | `/audit-to-stories` | Convert findings produced by the audit-\* workflows into actionable GitHub Stories. Reads temp/audits/audit-\*-results.md, groups findings cross-audit, deduplicates against existing Issues by fingerprint, and either chains into /plan --idea or opens standalone Stories. |
53
53
  | `/audit-ux-ui` | Audit UX/UI consistency and design system adherence |
54
54
  | `/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. |
55
- | `/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. |
56
55
  | `/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. |
57
56
  | `/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. |
58
- | `/git-merge-pr` | Analyze, validate, resolve conflicts, and merge a given pull request by number. |
59
57
  | `/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. |
60
- | `/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 (sectioned Epic body: Tech Spec + Acceptance Table, then decomposition) or the standalone-Story authoring path — and absorbs every planning flag. |
58
+ | `/plan` | Unified planning entry point. Routes a seed idea (via scope triage) or an existing Epic ID to the right planning path — the 3-step Epic path (interrogate author persist) or the standalone-Story authoring path — and absorbs every planning flag. |
61
59
  | `/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. |
62
60
  | `/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/ |
63
61
  | `/qa-run` | Drive Gherkin scenarios through a real browser as an agent-driven QA sweep |
64
62
 
65
- ## Loops namespace (3)
63
+ ## Loops namespace (0)
66
64
 
67
65
  Loop units project to `.claude/commands/loops/<name>.md` and are invoked
68
66
  as `/loops:<name>` (flat fallback `/loops-<name>` on hosts that flatten
69
67
  subdirectory commands).
70
68
 
71
- | Command | Description |
72
- | --- | --- |
73
- | `/loops:fix-failing-tests` | Self-paced convergence loop that drives a red test suite to green. Each round reads the latest failure, applies the smallest fix, and re-runs the verify oracle (`npm test`); the loop terminates when the oracle exits 0. The host (`/loop`) owns iteration and pacing — mandrel supplies the action, the goal, and the terminating oracle. |
74
- | `/loops:nightly-audit` | Cron maintenance loop that runs a nightly audit sweep over the repository and files actionable findings. Each run executes the audit workflows and routes the results; the host (`/schedule` or a cron-driven `/loop`) owns the cadence. verify is optional for a cron loop — the scheduler owns iteration, so this unit ships the action and goal, not a terminating oracle. |
75
- | `/loops:watch-ci` | Interval watch loop that polls a pull request's CI checks until they settle. Each round runs `gh pr checks` and reports the delta; the host (`/loop 5m`) owns the cadence and re-invokes the unit on its schedule. verify is optional for an interval loop — the externally-scheduled host owns iteration, so this unit ships the action and goal, not a terminating oracle. |
69
+ > No loop units are shipped yet.
@@ -273,8 +273,8 @@ budget grounds.
273
273
  ensures (generates or reuses) a per-Epic docs digest — a single compact
274
274
  outline (path, byte size, heading outline with line numbers, and the
275
275
  first paragraph under each `##`) built from `project.docsContextFiles`
276
- — at `temp/epic-<epicId>/docs-digest.md` (`epic-plan-spec.js
277
- --emit-context`, via the shared generator in
276
+ — at `temp/epic-<epicId>/docs-digest.md` (`plan-context.js`, via the
277
+ shared generator in
278
278
  `.agents/scripts/lib/orchestration/docs-digest.js`; the same file the
279
279
  `/deliver` story sub-agents below already consume). Use the digest to
280
280
  decide which docs bear on the task at hand, then **pull the full file
@@ -393,7 +393,7 @@
393
393
  },
394
394
  "navigation": {
395
395
  "type": "object",
396
- "description": "Navigability-reachability config consumed by the epic-plan-healthcheck --paranoid reachability check. Opt-in: absent or empty routeGlobs degrades to a silent no-op.",
396
+ "description": "Navigability-reachability config consumed by the plan-persist draft reachability gate (Epic #4474 PR6; also the manual epic-plan-healthcheck --paranoid re-check). Opt-in: absent or empty routeGlobs degrades to a silent no-op.",
397
397
  "properties": {
398
398
  "routeGlobs": {
399
399
  "type": "array",
@@ -10,7 +10,8 @@ throw.
10
10
  Each event in the Tech Spec taxonomy has a `<event>.schema.json`
11
11
  file. The ledger record (`emitted | completed | failed` union)
12
12
  lives in `ledger-record.schema.json` and is consumed by
13
- `ledger-writer.js` and the `lifecycle-diff` CLI.
13
+ `ledger-writer.js` and the `lib/orchestration/lifecycle/ledger-diff.js`
14
+ assertion helpers.
14
15
 
15
16
  Schemas are intentionally permissive (`additionalProperties: true`)
16
17
  on inner objects whose shape is dictated by upstream tooling (e.g.
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/ledger-record.schema.json",
4
4
  "title": "Lifecycle ledger record (emitted | completed | failed)",
5
- "description": "Append-only NDJSON record shape for temp/epic-<id>/lifecycle.ndjson. Three discriminated kinds; consumers (LedgerWriter, lifecycle-diff CLI, TraceLogger) discriminate on `kind`.",
5
+ "description": "Append-only NDJSON record shape for temp/epic-<id>/lifecycle.ndjson. Three discriminated kinds; consumers (LedgerWriter, the ledger-diff assertion helpers, TraceLogger) discriminate on `kind`.",
6
6
  "oneOf": [
7
7
  { "$ref": "#/$defs/emitted" },
8
8
  { "$ref": "#/$defs/completed" },
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "risk-verdict",
4
4
  "title": "Planning Risk Verdict",
5
- "description": "Planner-authored risk judgment for an Epic, produced by the epic-plan-spec-author Skill as the fourth planning artifact (risk-verdict.json) alongside the PRD, Tech Spec, and Acceptance Spec (Epic #3865). epic-plan-spec.js validates the verdict against this schema, derives the deterministic planningRisk envelope via deriveRiskEnvelope (lib/orchestration/planning-risk.js), and records the verdict as a risk-verdict structured comment plus the epic-plan-state checkpoint riskVerdict field. The model supplies the judgment input (axes); the harness owns the gate decision. A malformed verdict fails closed to the validation-error path — it is never silently coerced.",
5
+ "description": "Planner-authored risk judgment for an Epic, produced by the epic-plan-spec-author Skill as the fourth planning artifact (risk-verdict.json) alongside the PRD, Tech Spec, and Acceptance Spec (Epic #3865). plan-persist.js validates the verdict against this schema, derives the deterministic planningRisk envelope via deriveRiskEnvelope (lib/orchestration/planning-risk.js), and records the verdict as a risk-verdict structured comment plus the epic-plan-state checkpoint riskVerdict field. The model supplies the judgment input (axes); the harness owns the gate decision. A malformed verdict fails closed to the validation-error path — it is never silently coerced.",
6
6
  "type": "object",
7
7
  "required": ["axes", "summary"],
8
8
  "properties": {
@@ -47,7 +47,20 @@
47
47
  "type": "string",
48
48
  "minLength": 1,
49
49
  "description": "One-paragraph overall risk narrative for the audit trail (the rationale the retired regex classifier could never produce)."
50
+ },
51
+ "deliveryShape": {
52
+ "type": "string",
53
+ "enum": ["fan-out", "single"],
54
+ "description": "Planner-judged delivery shape for the Epic (Epic #4474 PR4, design §2 mode matrix). 'fan-out' persists a Story tree (the default when the field is absent — existing verdicts stay valid); 'single' is the spec-only single-delivery mode: no tickets are authored, the ticket validator + DAG are skipped, and plan-persist applies the delivery::single routing marker instead of a Story tree. The marker is inert until #4475 lands the deliver-side reader."
55
+ },
56
+ "deliveryShapeRationale": {
57
+ "type": "string",
58
+ "minLength": 1,
59
+ "description": "Concrete justification for the declared deliveryShape, grounded in the Delivery Slicing table (slice count / chain shape). Required whenever deliveryShape is present; surfaced as the routingReasons of the single-mode plan summary."
50
60
  }
51
61
  },
62
+ "dependentRequired": {
63
+ "deliveryShape": ["deliveryShapeRationale"]
64
+ },
52
65
  "additionalProperties": false
53
66
  }
@@ -17,29 +17,6 @@ These scripts are kept in the distributed product but are intentionally
17
17
  not invoked by `npm test`, `npm run verify`, CI, or any Husky hook. They
18
18
  are optional operator tools; run them by hand when you need them.
19
19
 
20
- ### `loc-delta.js`
21
-
22
- **Purpose.** Verify the Skills-migration LOC budget — the signed line
23
- delta between `main` and `HEAD` across the four SSOT directories
24
- (`.agents/scripts/`, `.agents/skills/`, `.agents/workflows/`,
25
- `.agents/README.md`) must be `< 0`.
26
-
27
- **When to run.** Optional spot-check during framework refactors that
28
- claim to retire code rather than add it. Originally an acceptance
29
- criterion of Epic #1181 / Story #1441; kept available because the same
30
- "net-negative LOC" check is occasionally useful when reviewing
31
- maintenance Epics.
32
-
33
- **Usage.**
34
-
35
- ```bash
36
- node .agents/scripts/loc-delta.js # main...HEAD
37
- node .agents/scripts/loc-delta.js --base main # explicit base
38
- node .agents/scripts/loc-delta.js --json # machine output
39
- ```
40
-
41
- Exits `0` iff total LOC delta `< 0`; exits `1` otherwise.
42
-
43
20
  ### `validate-docs-freshness.js`
44
21
 
45
22
  **Purpose.** Per-Epic documentation freshness gate. For each doc in
@@ -58,29 +35,6 @@ node .agents/scripts/validate-docs-freshness.js --epic <id> \
58
35
  [--base main] [--docs <comma-separated>] [--json]
59
36
  ```
60
37
 
61
- ### `update-mutation-baseline.js`
62
-
63
- **Purpose.** Refresh `baselines/mutation.json` from a fresh Stryker
64
- run. Reads `delivery.quality.gates.mutation` from `.agentrc.json`,
65
- invokes the in-repo Stryker runner, and atomically rewrites the
66
- baseline.
67
-
68
- **When to run.** Optional. Mutation testing is opt-in per consumer;
69
- this is the equivalent of `npm run coverage:update` /
70
- `npm run crap:update` / `npm run maintainability:update` for the
71
- mutation gate. It is intentionally not wired into `package.json`
72
- because most consumers do not configure Stryker.
73
-
74
- **Usage.**
75
-
76
- ```bash
77
- node .agents/scripts/update-mutation-baseline.js [--full-scope]
78
- ```
79
-
80
- Exits `0` whether or not the baseline changed; exits `0` (with a
81
- stderr explainer) when no Stryker config is present; exits `1` only
82
- when Stryker itself fails to run.
83
-
84
38
  ## See Also
85
39
 
86
40
  - [`/.agents/README.md`](../README.md) — consumer user guide.