mandrel 2.14.0 → 2.16.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 (75) hide show
  1. package/.agents/audit-checklists/navigability.md +1 -1
  2. package/.agents/docs/workflows.md +4 -4
  3. package/.agents/scripts/acceptance-eval.js +18 -1
  4. package/.agents/scripts/agents-bootstrap-github.js +22 -1
  5. package/.agents/scripts/apply-quality-bootstrap.js +6 -0
  6. package/.agents/scripts/audit-labels-bootstrap.js +15 -1
  7. package/.agents/scripts/audit-to-stories.js +26 -1
  8. package/.agents/scripts/boot-sweep.js +4 -1
  9. package/.agents/scripts/bootstrap.js +1 -0
  10. package/.agents/scripts/check-arch-cycles.js +20 -0
  11. package/.agents/scripts/check-baselines.js +8 -2
  12. package/.agents/scripts/check-context-budget.js +40 -5
  13. package/.agents/scripts/check-dead-exports.js +21 -0
  14. package/.agents/scripts/check-doc-links.js +12 -1
  15. package/.agents/scripts/check-lifecycle-doc-drift.js +9 -0
  16. package/.agents/scripts/check-workflow-citations.js +332 -0
  17. package/.agents/scripts/deliver-light.js +32 -3
  18. package/.agents/scripts/deliver-recover.js +4 -1
  19. package/.agents/scripts/diagnose-friction.js +17 -1
  20. package/.agents/scripts/diagnose.js +20 -14
  21. package/.agents/scripts/drain-pending-cleanup.js +20 -1
  22. package/.agents/scripts/evidence-gate.js +20 -1
  23. package/.agents/scripts/generate-config-docs.js +14 -1
  24. package/.agents/scripts/generate-lifecycle-docs.js +14 -1
  25. package/.agents/scripts/generate-workflows-doc.js +14 -1
  26. package/.agents/scripts/git-cleanup.js +32 -1
  27. package/.agents/scripts/lib/cli-usage.js +174 -0
  28. package/.agents/scripts/lib/cli-utils.js +12 -0
  29. package/.agents/scripts/lib/close-validation/process.js +61 -15
  30. package/.agents/scripts/lib/doc-tiers.js +53 -10
  31. package/.agents/scripts/lib/orchestration/complexity-gate.js +307 -89
  32. package/.agents/scripts/lib/orchestration/light-suitability.js +31 -9
  33. package/.agents/scripts/lib/orchestration/plan-context.js +205 -20
  34. package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +87 -13
  35. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +24 -15
  36. package/.agents/scripts/lib/workflow-closure.js +431 -0
  37. package/.agents/scripts/mandrel-update-preflight.js +9 -0
  38. package/.agents/scripts/nav-registry-diff.js +13 -0
  39. package/.agents/scripts/plan-context.js +21 -2
  40. package/.agents/scripts/plan-critics.js +10 -0
  41. package/.agents/scripts/plan-persist.js +33 -1
  42. package/.agents/scripts/plan-run-epilogue.js +12 -1
  43. package/.agents/scripts/quality-preview.js +17 -1
  44. package/.agents/scripts/resolve-doc-tiers.js +13 -0
  45. package/.agents/scripts/resolve-stories.js +1 -0
  46. package/.agents/scripts/resync-status-column.js +4 -1
  47. package/.agents/scripts/signals-view.js +11 -0
  48. package/.agents/scripts/single-story-close.js +24 -0
  49. package/.agents/scripts/single-story-confirm-merge.js +16 -0
  50. package/.agents/scripts/single-story-init.js +21 -1
  51. package/.agents/scripts/stories-wave-tick.js +1 -0
  52. package/.agents/scripts/sync-agentrc.js +16 -4
  53. package/.agents/scripts/update-ticket-state.js +23 -2
  54. package/.agents/workflows/audit-navigability.md +2 -2
  55. package/.agents/workflows/audit-to-stories.md +1 -1
  56. package/.agents/workflows/deliver.md +80 -81
  57. package/.agents/workflows/git-cleanup.md +9 -14
  58. package/.agents/workflows/helpers/acceptance-self-eval.md +14 -13
  59. package/.agents/workflows/helpers/audit-lens-core.md +2 -2
  60. package/.agents/workflows/helpers/code-review.md +11 -11
  61. package/.agents/workflows/helpers/deliver-digest.md +7 -8
  62. package/.agents/workflows/helpers/deliver-light.md +222 -0
  63. package/.agents/workflows/helpers/deliver-reference.md +46 -14
  64. package/.agents/workflows/helpers/deliver-story-reference.md +55 -63
  65. package/.agents/workflows/helpers/deliver-story.md +22 -22
  66. package/.agents/workflows/helpers/mandrel-sync-config.md +2 -2
  67. package/.agents/workflows/helpers/parallel-tooling.md +1 -2
  68. package/.agents/workflows/helpers/plan-reference.md +96 -17
  69. package/.agents/workflows/helpers/worktree-lifecycle.md +1 -4
  70. package/.agents/workflows/mandrel-update.md +6 -6
  71. package/.agents/workflows/plan.md +90 -85
  72. package/.agents/workflows/prototype.md +104 -0
  73. package/docs/CHANGELOG.md +32 -0
  74. package/package.json +2 -1
  75. package/.agents/workflows/deliver-light.md +0 -148
@@ -108,10 +108,7 @@ PowerShell `Get-CimInstance Win32_Process`, terminating them with
108
108
 
109
109
  > **Not a slash command (decision overturned).** The drain is **not** a
110
110
  > `/drain-pending-cleanup` slash command — it was demoted to a
111
- > directly-runnable script (Story #3706, overturning the
112
- > `docs/decisions.md` matrix row that originally kept it as a command).
113
- > The wave-era automatic callers were deleted with the epic-runner in
114
- > the v2 cutover, so the drain is now operator-driven:
111
+ > directly-runnable script. The drain is operator-driven:
115
112
  > `node .agents/scripts/drain-pending-cleanup.js`.
116
113
 
117
114
  ### When to run it manually
@@ -4,7 +4,7 @@ description: >-
4
4
  (resolve newest published version → install → re-materialize `.agents/` →
5
5
  migrate → doctor → surface changelog) as the single mechanical step, then
6
6
  walks the operator through the judgment wraparound the CLI deliberately
7
- leaves unowned: reconcile `.agentrc.json`, install the Epic #1386
7
+ leaves unowned: reconcile `.agentrc.json`, install the stabilized
8
8
  quality-gate surface, refresh the harness permission allowlist, reconcile
9
9
  the consumer's `AGENTS.md` / runbooks against the surfaced changelog, and
10
10
  stage + commit the staged lockfile bump.
@@ -14,10 +14,10 @@ description: >-
14
14
 
15
15
  > **Upgrade owner.** The mechanical upgrade is owned end to end by the
16
16
  > [`mandrel update`](../../lib/cli/update.js) CLI under the npm distribution
17
- > model (#3436/#3437). This workflow wraps that CLI: it runs
17
+ > model. This workflow wraps that CLI: it runs
18
18
  > `npx mandrel update`, then walks the operator through the
19
19
  > **distribution-agnostic judgment steps** the CLI deliberately does **not**
20
- > perform — config reconciliation, the Epic #1386 quality-gate installs, the
20
+ > perform — config reconciliation, the quality-gate installs, the
21
21
  > permission-allowlist refresh, the consumer-side changelog reconciliation,
22
22
  > and the stage-and-commit of the staged lockfile bump.
23
23
 
@@ -125,7 +125,7 @@ Recovery sequence: run the matching remedy, then **re-run
125
125
  `npx mandrel update`** — it is idempotent (the install already landed, so a
126
126
  clean re-run short-circuits the bump and re-drives the post-install
127
127
  phases). Repeat until it reports success; only then proceed. A dedicated
128
- `--resume` entrypoint was evaluated and deferred (Story #4172) — the
128
+ `--resume` entrypoint was evaluated and deferred — the
129
129
  per-phase remedies plus the idempotent re-run already cover every recovery
130
130
  case.
131
131
 
@@ -135,7 +135,7 @@ case.
135
135
  node .agents/scripts/sync-agentrc.js
136
136
  ```
137
137
 
138
- The helper (Story #1995) is default-aware and **read-only**: it validates
138
+ The helper is default-aware and **read-only**: it validates
139
139
  the consumer config against the new schema (non-zero exit → fix the
140
140
  validation error and re-run before proceeding), never auto-fills missing
141
141
  optional keys (the runtime layers defaults at read time), and flags
@@ -144,7 +144,7 @@ advisory rows you may optionally delete by hand (commit alongside the bump
144
144
  in Step 5). Full procedure:
145
145
  [`helpers/mandrel-sync-config.md`](helpers/mandrel-sync-config.md).
146
146
 
147
- ## Step 3.5 — Upgrade the stabilized-quality-gates surface (Epic #1386)
147
+ ## Step 3.5 — Upgrade the stabilized-quality-gates surface
148
148
 
149
149
  ```bash
150
150
  node .agents/scripts/apply-quality-bootstrap.js
@@ -5,48 +5,50 @@ description:
5
5
  policy.
6
6
  ---
7
7
 
8
- # /plan --seed "<text>" | --seed-file <path> | --tickets <ids>
8
+ # /plan
9
9
 
10
10
  > **Lean spine.** Happy path + gate list; edge-case detail lives in on-demand
11
11
  > [`helpers/plan-reference.md`](helpers/plan-reference.md).
12
12
 
13
13
  ## Inputs
14
14
 
15
- Single planning path — there is no
16
- Epic/Story router, no scope-triage `epic|story` verdict:
15
+ Single planning path — there is no Epic/Story router, no scope-triage
16
+ `epic|story` verdict. **Derive the mode from what the operator typed, announce
17
+ it, then act**; there is nothing for them to remember:
17
18
 
18
- | Invocation | Behavior |
19
- | --- | --- |
20
- | `/plan --seed "<text>"` / `--seed-file <path>` | Ideation from chat text or on-disk notes: interrogate → author **one Story by default** → persist. |
21
- | `/plan --tickets 123[,456…]` | Fetch issue(s), analyze into proper Stories (prefer N=1 rewrite). |
22
- | `/plan --amends #<id>` | Amend a shipped Story from a **delta envelope** (prior body + acceptance + delivered file map), not a from-scratch re-interrogation (#4741). |
19
+ | Invocation | Mode | Behavior |
20
+ | --- | --- | --- |
21
+ | `/plan` | ask | Ask what to plan; nothing runs first. |
22
+ | `/plan add a --json flag to doctor` | seed | Ideation from the prose: interrogate author **one Story by default** → persist. |
23
+ | `/plan temp/notes/idea.md` | seed-file | Same, from notes. An argument resolving to an existing file is a path, never prose. |
24
+ | `/plan 4712[,4713…]` | tickets | Fetch issue(s), analyze into proper Stories (prefer N=1 rewrite). |
25
+ | `/plan 4712`, already delivered | amends | Amend a shipped Story from a **delta envelope**, not a re-interrogation. |
23
26
 
24
- `--body` is **not** a `/plan` entry; persist always goes through `plan-persist.js`.
27
+ **Resolving a bare id.** Ids alone are ambiguous between *amend* and *tickets*,
28
+ so read live state rather than asking: `agent::done` can only be amended, an
29
+ open unplanned issue can only be planned. **Announce the derivation** — "4712
30
+ is `agent::done` → amending" — so a wrong read costs one correction, not a
31
+ wasted run. Ask **only** for an open Story already at `agent::ready`.
25
32
 
26
- ## Flags
33
+ `--body` is **not** a `/plan` entry; persist goes through `plan-persist.js`.
27
34
 
28
- | Flag | Meaning |
29
- | --- | --- |
30
- | `--seed "<text>"` / `--seed-file <path>` | Seed text / pre-authored notes path. |
31
- | `--tickets <ids>` | Issue ids to analyze; closed as superseded at persist. |
32
- | `--amends #<id>` | Prior Story to amend; emits a delta envelope, not a full re-interrogation (#4741). |
33
- | `--chain-on-clean` | Persist: chain a clean lite dry-run into the real persist in one round-trip; full-route plans keep the review round-trip (#4741). |
34
- | `--no-close-superseded` | Keep the source issues open no supersede comment, no close. |
35
- | `--force-review` | STOP at gate #2 for operator review — the only review gate (#4542). |
36
- | `--route-downgrade-reason "<text>"` | Authored `lite` verdict + reason (#4722); shape-validated, fails closed to `full`. |
37
- | `--allow-over-budget` | Permit a plan exceeding `maxTickets`. |
38
- | `--yes` | Non-interactive: auto-proceed gate #1 and gate #2 HITL waits. |
39
- | `--dry-run` | Author + validate without GitHub writes; run as a pre-pass. |
35
+ ## Saying what you want
36
+
37
+ No flags to remember state intent and the workflow fills in the CLI
38
+ ([reference](helpers/plan-reference.md)). Run any script with `--help` rather
39
+ than copying its surface here.
40
+
41
+ `--yes` is **runner-set, never operator-typed**cron, `/loop`, and headless
42
+ dispatch set it to mean *nobody is at the keyboard*, which is what auto-proceeds
43
+ the gates below. Never offer it to an operator or add it to an attended run.
40
44
 
41
45
  ## Default-single split policy
42
46
 
43
- Author **one Story** unless the pieces have **near-zero overlap** (genuinely
44
- independent capabilities) or sit across an **architectural seam** (different
45
- deployables, migration vs consumer). Coupled work stays one Story —
46
- `## Slicing` intra-session checkpoints, not sibling tickets; when N>1 every
47
- acceptance criterion belongs to exactly one Story
48
- (`assertAcceptancePartition` refuses coupled splits). **N=1 is the lean
49
- path:** one authoring prompt, folded `## Spec`, no Epic-scale ceremony.
47
+ Author **one Story** unless the pieces have **near-zero overlap** or sit across
48
+ an **architectural seam** (different deployables, migration vs consumer).
49
+ Coupled work stays one Story — `## Slicing` checkpoints, not sibling tickets;
50
+ when N>1 every acceptance criterion belongs to exactly one Story
51
+ (`assertAcceptancePartition` refuses coupled splits). **N=1 is the lean path.**
50
52
 
51
53
  ## Procedure
52
54
 
@@ -58,49 +60,53 @@ node .agents/scripts/plan-context.js --seed "<seed>" \
58
60
  # or: --seed-file <path> | --tickets 123,456 | --amends #<id>
59
61
  ```
60
62
 
61
- **Always pass `--out`.** Persist auto-discovers that envelope from `--plan-dir`
62
- and derives source-ticket ids from its `sourceTickets[]` (#4554); the CLI also
63
- writes **`stories.template.json`** the authoring skeleton step 2 starts from.
63
+ **Always pass `--out`.** Persist auto-discovers the envelope from `--plan-dir`
64
+ and derives source ids from its `sourceTickets[]`; the CLI also writes
65
+ **`stories.template.json`**, the skeleton step 2 starts from.
64
66
 
65
67
  The envelope carries docs context, the codebase snapshot, the story-author
66
68
  prompt, `sourceTickets[]`, `duplicates[]` (open **Stories**, never Epics), and
67
- advisory `complexitySignals` (**no routing authority**, #4722). A trivial scope
68
- earns `--route-downgrade-reason "<why>"` at persist — shape-validated, failing
69
- closed to `full`
70
- ([detail](helpers/plan-reference.md)).
71
- Under `--yes`, do not ask free-form operator questions — unresolved unknowns
72
- land in Key Assumptions.
69
+ advisory `complexitySignals` (**no routing authority**). A trivial scope earns
70
+ `--route-downgrade-reason "<why>"` at persist — shape-validated, failing closed
71
+ to `full` ([detail](helpers/plan-reference.md)). Under `--yes`, do not ask
72
+ free-form operator questions — unknowns land in Key Assumptions.
73
73
 
74
74
  **Gate #1** — STOP to confirm the sharpened plan intent and any
75
- duplicate-candidate review. Under `--yes`, auto-proceed. When
76
- `complexitySignals.deliverLightSuggestion.suggested` is `true`, surface an
77
- **advisory** `/deliver-light` suggestion the operator decides; under `--yes`
78
- it is recorded and planning proceeds, **never an automatic reroute** (#4741).
75
+ duplicate-candidate review. Under `--yes`, auto-proceed.
76
+
77
+ When `complexitySignals.deliverLightSuggestion.suggested` is `true`, offer
78
+ **advisory, never an automatic reroute** — to deliver the seed instead of
79
+ planning it. On confirm, route **in this session** into
80
+ [`helpers/deliver-light.md`](helpers/deliver-light.md), filling its gate from
81
+ this envelope, not the raw seed; an `ask-operator` verdict returns here to
82
+ step 2 with the interrogation intact. Under `--yes` it is recorded and planning
83
+ proceeds — never auto-downgraded to light.
84
+
85
+ A truthy `complexitySignals.uiSurface` marks a UI-touching plan: name
86
+ [`/prototype`](prototype.md) as an operator option — never invoke it here.
79
87
 
80
88
  ### 2. Author
81
89
 
82
- **One-shot authoring (Story #4707).** Start from `stories.template.json`;
83
- author `stories.json` in one pass. Entries are pre-resolved (#4723); keep
84
- tiers/assumptions valid. `body` is a markdown string **or** a structured
85
- object; persist parses either, serializes the canonical markdown, and syncs the
86
- top-level `acceptance[]` / `verify[]` into it — never dual-author those lists.
90
+ **One-shot authoring.** Start from `stories.template.json`; author
91
+ `stories.json` in one pass. Entries are pre-resolved; keep tiers/assumptions
92
+ valid. `body` is a markdown string **or** a structured object; persist parses
93
+ either, serializes the canonical markdown, and syncs top-level `acceptance[]` /
94
+ `verify[]` into it — never dual-author those lists.
87
95
 
88
96
  Each entry (the `stories.template.json` shape): `slug`
89
97
  (`^[a-z0-9][a-z0-9-]*$`), `type: "story"`, `title`, `body` (`goal`, optional
90
98
  `spec`, `changes[{path, assumption}]` — `creates|refactors-existing|deletes`,
91
- `non_goals`, `reason_to_exist`), top-level `acceptance[]`, `verify[]`
92
- (`… (unit|contract|e2e|validate)`), `depends_on[]` (N>1 only).
99
+ `non_goals`, `reason_to_exist`), top-level `acceptance[]`, `verify[]` (`…
100
+ (unit|contract|e2e|validate)`), `depends_on[]` (N>1 only).
93
101
 
94
- Artifacts under `temp/plan-<slug>/`: `stories.json`
95
- (**length 1 by default**; over-budget Specs fail closed — split or tighten,
96
- never under `docs/`); optional `techspec.md` (**N===1 only** — folded into
97
- `## Spec`); optional `acceptance-manifest.json` (N>1 partition list — pass as
98
- `--plan-acceptance`). For N=1, use the envelope `systemPrompts.story` and emit
99
- one cohesive Story. Split only under the policy above.
102
+ Artifacts under `temp/plan-<slug>/`: `stories.json` (**length 1 by default**;
103
+ over-budget Specs fail closed — split or tighten, never under `docs/`);
104
+ optional `techspec.md` (**N===1 only** — folded into `## Spec`); optional
105
+ `acceptance-manifest.json` (N>1 partition list — `--plan-acceptance`). For N=1
106
+ use the envelope `systemPrompts.story`; split only under the policy above.
100
107
 
101
- **Tickets mode:** every Story authors a top-level `supersedes[]` claiming the
102
- source issues it replaces; persist refuses a partial map
103
- ([shape](helpers/plan-reference.md)).
108
+ **Tickets mode:** every Story authors a top-level `supersedes[]`; persist
109
+ refuses a partial map ([shape](helpers/plan-reference.md)).
104
110
 
105
111
  ### 2.5 Critics
106
112
 
@@ -110,29 +116,28 @@ node .agents/scripts/plan-critics.js \
110
116
  [--tech-spec temp/plan-<slug>/techspec.md]
111
117
  ```
112
118
 
113
- Run **before** persist — the last point a finding folds into a re-author
114
- round. It exits 0 on **any** verdict (verdicts route work, they do not
115
- gate) and exits **1** only on a usage/IO error — no critic ran, no skip
116
- ledgered: **do not proceed to Persist**; fix and re-run.
119
+ Run **before** persist — the last point a finding folds into a re-author round.
120
+ It exits 0 on **any** verdict (verdicts route work, they do not gate) and exits
121
+ **1** only on a usage/IO error — no critic ran, no skip ledgered: **do not
122
+ proceed to Persist**; fix and re-run.
117
123
 
118
124
  - **Both `dispatch: false`** — proceed to Persist (each skip is ledgered).
119
125
  - **Either `dispatch: true`** — dispatch **one fresh-context, maker-blind
120
- sub-agent per firing critic** (hand it only the draft artifacts,
121
- never the authoring transcript), fold findings into Gate #2 or a
122
- re-author round, re-run this step. Pre-mortem triggers (incl. the
123
- external-dependency probe, #4700), folding the advisory-only
124
- `textHygiene.findings[]` lints, and the role-scoped dispatch shape:
126
+ sub-agent per firing critic** (hand it only the draft artifacts, never the
127
+ authoring transcript), fold findings into Gate #2 or a re-author round, re-run
128
+ this step. Pre-mortem triggers (incl. the external-dependency probe), the
129
+ advisory-only `textHygiene.findings[]` lints, and the dispatch shape:
125
130
  [`helpers/plan-reference.md` § Critic dispatch detail](helpers/plan-reference.md).
126
131
 
127
132
  ### 3. Persist
128
133
 
129
- **Gate #2** — with `--force-review`, STOP for approval before persist (the
130
- **only** trigger). Under `--yes`, auto-proceed.
134
+ **Gate #2** — STOP for approval before persist **only** when the operator asked
135
+ to review (`--force-review`). Under `--yes`, auto-proceed.
131
136
 
132
- Run persist with `--dry-run` **first** — same command, GitHub writes
133
- suppressed; every gate (validator, body parse, DAG, capacity, budget,
134
- reachability, split/supersede partitions, Spec fold) runs before the first
135
- `createIssue`. Then:
137
+ Run persist with `--dry-run` **first** — same command, GitHub writes suppressed;
138
+ every gate (validator, body parse, DAG, capacity, budget, reachability,
139
+ split/supersede partitions, Spec fold) runs before the first `createIssue`.
140
+ Then:
136
141
 
137
142
  ```bash
138
143
  node .agents/scripts/plan-persist.js \
@@ -140,27 +145,27 @@ node .agents/scripts/plan-persist.js \
140
145
  --plan-dir temp/plan-<slug> \
141
146
  [--plan-acceptance temp/plan-<slug>/acceptance-manifest.json] \
142
147
  [--tech-spec temp/plan-<slug>/techspec.md] \
143
- [--source-tickets 123,456] [...flags from the table above]
148
+ [--source-tickets 123,456]
144
149
  ```
145
150
 
146
151
  At lite shape, `--chain-on-clean` chains that dry-run into the real persist in
147
- one round-trip **only** when it is clean and `lite`; a full-route plan keeps
148
- its review round-trip (#4741).
152
+ one round-trip **only** when it is clean and `lite`; a full plan keeps its
153
+ review round-trip.
149
154
 
150
155
  Persist creates `type::story` issue(s) plus a `plan-run::<id>` grouping label
151
- (**metadata only**, #4692); N>1 `depends_on` edges become `blocked by #<id>`
152
- footers. `agent::ready` is the **terminal** flip after all receipts land a
153
- ready Story is fully persisted (#4541). stdout is pure JSON.
156
+ (**metadata only**); N>1 `depends_on` edges become `blocked by #<id>` footers.
157
+ `agent::ready` is the **terminal** flip after all receipts land. stdout is pure
158
+ JSON.
154
159
 
155
- In `--tickets` mode persist resolves source ids **envelope-first** and closes
156
- each as `not_planned` with a comment (default on;
157
- [detail](helpers/plan-reference.md)). On a stranded persist, re-run the same
158
- command — never hand-delete issues.
160
+ In tickets mode persist resolves source ids **envelope-first** and closes each
161
+ as `not_planned` with a comment (default on;
162
+ [detail](helpers/plan-reference.md)).
159
163
 
160
164
  ## Constraints
161
165
 
162
- - `/plan` never starts delivery no Epic ticket, no reconciler. Duplicate
163
- search targets open Stories (`type::story`), not Epics.
166
+ - `/plan` starts delivery **only** through a confirmed Gate #1 light route —
167
+ never off its own authored Stories, which land via [`/deliver`](deliver.md).
168
+ - Duplicate search targets open Stories (`type::story`), not Epics.
164
169
  - Deterministic gates still fail closed under `--yes`.
165
170
 
166
171
  ## See also
@@ -0,0 +1,104 @@
1
+ ---
2
+ description: >-
3
+ Operator-invoked UI prototype pass. Discovers the consumer's design-system
4
+ SSOT first, then — only after the operator confirms — writes exactly one
5
+ self-contained HTML file under the gitignored workspace-root temp tree, so a
6
+ layout can be reviewed before its UI acceptance criteria are authored.
7
+ ---
8
+
9
+ # /prototype [what to prototype]
10
+
11
+ UI acceptance criteria are otherwise authored blind: "the dashboard shows the
12
+ active runs" says nothing about layout, density, or interaction, so delivery
13
+ resolves those by taste. `/prototype` puts a reviewable artifact in front of the
14
+ operator before the criteria are written.
15
+
16
+ **Operator-invoked only.** `/plan` may report that a plan touches UI and that
17
+ this command exists; it must never run it. No workflow, gate, or script invokes
18
+ `/prototype` — the whole design rests on the operator asking for it.
19
+
20
+ ## Procedure
21
+
22
+ ### Step 0 — Discover the design-system SSOT (first, before anything is drawn)
23
+
24
+ You cannot prototype *in the project's visual language* until you have found the
25
+ language. Locate and read the consumer's sources of truth — the same set
26
+ [`/audit-ux-ui`](audit-ux-ui.md) Step 0 mandates:
27
+
28
+ - **Design tokens / theme** — a `tailwind.config.{js,ts}`, CSS custom properties
29
+ (`:root { --color-*, --space-* }`), a `theme/` / `tokens/` /
30
+ `design-system/` directory, or a CSS-in-JS theme object.
31
+ - **Component roster** — the shared component directory (`components/ui/**`, a
32
+ published design-system package) that raw elements are expected to defer to.
33
+ - **Documented conventions** — `docs/style-guide.md`, plus `docs/web-routes.md`
34
+ when the surface is a route, whenever they exist in the consumer checkout.
35
+
36
+ Report what you found — token names, the component roster, the style-guide rules
37
+ — and draw only against that discovered baseline. **No artifact is drawn until
38
+ this step has run.**
39
+
40
+ ### Step 0a — When no design-system SSOT is discoverable
41
+
42
+ Report the absence explicitly, then emit a **low-fidelity frame**: boxes,
43
+ labels, and hierarchy, in the host's default typography with no colour system.
44
+ Do **not** invent a visual language. A prototype in a palette the project never
45
+ adopted reviews the invention rather than the layout, and the operator cannot
46
+ tell which of the two they are approving.
47
+
48
+ ### Step 1 — Confirm before writing (**hard gate**)
49
+
50
+ Describe the layout you intend — surfaces, hierarchy, states, and which
51
+ discovered tokens and components it reuses — and **STOP**. Nothing is written to
52
+ disk until the operator confirms; never write silently. This is the disk-write
53
+ policy [`core/idea-refinement`](../skills/core/idea-refinement/SKILL.md) already
54
+ applies to its one-pager.
55
+
56
+ ### Step 2 — Write exactly one self-contained HTML file
57
+
58
+ On confirm, write **exactly one** self-contained `.html` file — inline CSS, no
59
+ build step, no fetched external assets — under the **gitignored workspace-root
60
+ temp tree** (`temp/prototypes/<slug>.html`). One file, because a prototype is a
61
+ thing to look at, not a codebase to maintain; self-contained, because it has to
62
+ open from disk with no server and no install.
63
+
64
+ Report the path, and iterate in place on that same file.
65
+
66
+ ### Step 3 — Optional: publish to a host
67
+
68
+ Host publishing is an **optional upgrade of that same file** and never the
69
+ artifact of record — the file under the temp tree stays authoritative. Publish
70
+ only when the operator asks, and keep the two identical by re-publishing the
71
+ file rather than editing a published copy.
72
+
73
+ ### Step 4 — Carry the review through to the Story
74
+
75
+ The **default carry-through is a fold into the Story's `## Spec`.** Delivery
76
+ reads the Story body and never the temp tree, so a layout that exists only as a
77
+ temp artifact is a layout delivery cannot see. Record the reviewed decisions —
78
+ surfaces, hierarchy, states, and the named tokens and components — as contract
79
+ prose in `## Spec`, and turn the observable ones into UI acceptance criteria.
80
+
81
+ **Committing a prototype is opt-in, per Story.** Ask; never default to it. A
82
+ prototype is wrong the moment the real UI ships, and a repository with a
83
+ documentation-freshness gate already carries that failure mode.
84
+
85
+ ## Constraint
86
+
87
+ - **Nothing reaches disk without a confirm.** Step 1 is a hard gate, not a
88
+ courtesy.
89
+ - **One file, under the temp tree.** Never a second artifact, never outside the
90
+ gitignored workspace-root temp tree, and never a committed prototype
91
+ directory by default.
92
+ - **Never invoked automatically.** `/plan` records the offer and proceeds with
93
+ planning; no workflow, gate, or script may call this command.
94
+ - **Read-only over the codebase.** The prototype file is the only write. Do not
95
+ edit application source, tokens, or components to make a prototype render.
96
+ - **Discovered baseline only.** No invented palette, type scale, or component
97
+ vocabulary when the project defines none.
98
+
99
+ ## See also
100
+
101
+ - [`/audit-ux-ui`](audit-ux-ui.md) — the same design-system SSOT discovery,
102
+ applied as a review lens after the UI ships.
103
+ - [`/plan`](plan.md) — where the advisory `complexitySignals.uiSurface` offer
104
+ surfaces. It names this command; it never runs it.
package/docs/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.16.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.15.0...mandrel-v2.16.0) (2026-07-25)
6
+
7
+
8
+ ### Added
9
+
10
+ * **workflows:** add operator-invoked /prototype and an advisory uiSurface offer (refs [#4765](https://github.com/dsj1984/mandrel/issues/4765)) ([#4769](https://github.com/dsj1984/mandrel/issues/4769)) ([d3f7173](https://github.com/dsj1984/mandrel/commit/d3f71734ef8573ffa40187b5f4f8a97be6e32041))
11
+
12
+
13
+ ### Fixed
14
+
15
+ * **close-validation:** drain gate output without stalling the child's pipe (refs [#4766](https://github.com/dsj1984/mandrel/issues/4766)) ([#4770](https://github.com/dsj1984/mandrel/issues/4770)) ([fd75550](https://github.com/dsj1984/mandrel/commit/fd75550288411a4c92831ac7c9b946e2cce5a686))
16
+
17
+
18
+ ### Changed
19
+
20
+ * **routing:** scope the light path by effort and risk (refs [#4764](https://github.com/dsj1984/mandrel/issues/4764)) ([#4767](https://github.com/dsj1984/mandrel/issues/4767)) ([c4851ab](https://github.com/dsj1984/mandrel/commit/c4851abe218721145daaeb4353af400223b588e6))
21
+
22
+ ## [2.15.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.14.0...mandrel-v2.15.0) (2026-07-25)
23
+
24
+
25
+ ### Added
26
+
27
+ * gate the workflow read-tier with a transitive mandatory-closure ratchet ([#4752](https://github.com/dsj1984/mandrel/issues/4752)) ([#4755](https://github.com/dsj1984/mandrel/issues/4755)) ([ac0f1e0](https://github.com/dsj1984/mandrel/commit/ac0f1e038560f4d69146f6dae46c2eb97ae2dbb2))
28
+ * make workflow-invoked orchestration scripts self-describing via --help ([#4750](https://github.com/dsj1984/mandrel/issues/4750)) ([#4756](https://github.com/dsj1984/mandrel/issues/4756)) ([922c278](https://github.com/dsj1984/mandrel/commit/922c278ed15f77761c88366ce6d166e0a0dd9157))
29
+ * **workflows:** one delivery door and derived invocation intent (refs [#4760](https://github.com/dsj1984/mandrel/issues/4760)) ([#4761](https://github.com/dsj1984/mandrel/issues/4761)) ([36bff50](https://github.com/dsj1984/mandrel/commit/36bff502b7d4e475569da7cae2eb0ec66d24b85d))
30
+
31
+
32
+ ### Fixed
33
+
34
+ * **deps:** bump brace-expansion to 5.0.8 for GHSA-mh99-v99m-4gvg ([#4753](https://github.com/dsj1984/mandrel/issues/4753)) ([3351100](https://github.com/dsj1984/mandrel/commit/3351100801b70e9e17cf3ed99245b3d81e162232))
35
+ * **tests:** resolve cli-usage argv[1] with fileURLToPath for Windows ([#4759](https://github.com/dsj1984/mandrel/issues/4759)) ([7fa3ee1](https://github.com/dsj1984/mandrel/commit/7fa3ee1e17c46995b9043fa879970a768b04b298))
36
+
5
37
  ## [2.14.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.13.0...mandrel-v2.14.0) (2026-07-24)
6
38
 
7
39
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mandrel",
3
- "version": "2.14.0",
3
+ "version": "2.16.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/",
@@ -41,6 +41,7 @@
41
41
  "maintainability:update": "node .agents/scripts/update-maintainability-baseline.js",
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:workflow-citations": "node .agents/scripts/check-workflow-citations.js",
44
45
  "crap:check": "node .agents/scripts/check-baselines.js --gate crap",
45
46
  "crap:update": "node .agents/scripts/update-crap-baseline.js",
46
47
  "duplication:check": "node .agents/scripts/check-baselines.js --gate duplication",
@@ -1,148 +0,0 @@
1
- ---
2
- description:
3
- Single-session delivery for genuinely small work. Judges a prompt's
4
- predicted footprint, authors a receipt Story, then lands it through the same
5
- single-story-init / single-story-close engine — every close gate unchanged.
6
- ---
7
-
8
- # /deliver-light "<prompt>" | --amends '#<id>' "<prompt>"
9
-
10
- > **Thin entry point, not a second engine.** `/deliver-light` removes the
11
- > `/plan` session for small work — nothing else. It runs a suitability gate,
12
- > authors a minimal receipt Story, then hands off to the SAME scripts
13
- > [`/deliver`](deliver.md) uses. Read
14
- > [`helpers/deliver-digest.md`](helpers/deliver-digest.md) once first — the
15
- > engine invariants, gates, and terminal-envelope contract below are its.
16
-
17
- ## Role
18
-
19
- For a genuinely trivial change — a one-file fix, a small addition, a small
20
- amendment — the multi-session plan→deliver ceremony buys nothing the bare model
21
- lacks except **gates and landing**. `/deliver-light` keeps exactly those: one
22
- session straight to execution from an operator prompt, landing through the
23
- unchanged close path. It never relaxes a close gate, never bypasses the PR to
24
- `main`, and never lands over-scope work silently.
25
-
26
- ## Four invariants (do not skip one)
27
-
28
- 1. **Suitability gate.** The prompt's predicted footprint is judged by the
29
- shared shape machinery (`deriveStoryShape` / `deriveChangeLevel`) **and** a
30
- ledgered model verdict with a recorded reason. Both must agree on `lite`.
31
- 2. **Over-scope stops — it never hard-fails.** An over-ceiling prompt STOPS and
32
- asks the operator to escalate to `/plan` or proceed light. Under `--yes` it
33
- fails closed to an **`escalated` terminal envelope** that ends the session
34
- (§ Escalation is terminal).
35
- 3. **Diff-derived backstop.** After implementation the ACTUAL change set is
36
- re-checked — the diff is the real scope signal — and an over-ceiling diff is
37
- blocked rather than landed.
38
- 4. **Minimal receipt Story.** A `type::story` is authored inline so `refs #`,
39
- history, telemetry, and the `agent::executing → agent::done` state machine
40
- all survive.
41
-
42
- ## Procedure
43
-
44
- 1. **Predict + gate.** Form the predicted footprint (new files, edited files,
45
- acceptance count) and your ledgered verdict (a recorded reason for `lite`),
46
- then run the gate:
47
-
48
- ```bash
49
- node .agents/scripts/deliver-light.js --prompt "<prompt>" \
50
- --creates <csv> --refactors <csv> --acceptance <n> \
51
- --route lite --reason "<why this is trivial>" [--amends '#<id>'] [--yes]
52
- ```
53
-
54
- Branch on `action` in the JSON envelope:
55
- - **`proceed-light`** — the receipt Story is authored; read `storyId` and
56
- `nextCommands`. Continue to step 2.
57
- - **`ask-operator`** — predicted scope exceeds the light ceilings. STOP and
58
- ask the operator to escalate to `/plan` or proceed light. Do not proceed
59
- on your own. This is a **question, not a terminal** — wait for the answer.
60
- - **over-scope under `--yes`** — no `action` to branch on: the gate emits an
61
- **`escalated` terminal envelope** instead (exit 2). § Escalation is
62
- terminal governs; you are finished.
63
-
64
- `--amends '#<id>'` is the canonical light case — shape-checked identically; a
65
- heavy amendment escalates to `/plan` like any other over-scope prompt.
66
-
67
- 2. **Init (same engine).** From the main checkout, synchronously, with the
68
- maximum Bash timeout:
69
-
70
- ```bash
71
- node .agents/scripts/single-story-init.js --story <storyId>
72
- ```
73
-
74
- Capture `workCwd`; `remoteVerified: false` → flip `agent::blocked` and stop.
75
- This is [`/deliver`](deliver.md)'s worktree/branch/lease/label engine,
76
- invoked, not reimplemented.
77
-
78
- 3. **Implement + self-eval.** `cd` into `workCwd`, implement the change, run
79
- `npm test` once in the worktree, then run the bounded acceptance self-eval
80
- loop ([`helpers/deliver-story.md`](helpers/deliver-story.md) Step 1a). Commit
81
- on `story-<id>` with `(refs #<storyId>)`.
82
-
83
- 4. **Diff backstop.** Before close, re-check the ACTUAL diff:
84
-
85
- ```bash
86
- node .agents/scripts/deliver-light.js --backstop --story <storyId>
87
- ```
88
-
89
- Exit `3` (`blocked: true`) means the landed diff exceeds the light ceilings
90
- (file count or a sensitive-path class). STOP, flip `agent::blocked`, and
91
- escalate to `/plan` — do not land.
92
-
93
- 5. **Close and land (same engine).** Exactly [`/deliver`](deliver.md)'s close:
94
-
95
- ```bash
96
- node .agents/scripts/single-story-close.js --story <storyId> --cwd <main-repo>
97
- ```
98
-
99
- Branch on the terminal envelope's `status` per
100
- [`helpers/deliver-digest.md`](helpers/deliver-digest.md) § 5 — every close
101
- gate runs byte-identical to the full path.
102
-
103
- ## Escalation is terminal {#escalation-is-terminal}
104
-
105
- Over-scope under `--yes` emits a schema-validated `story-deliver-terminal`
106
- envelope with **`status: "escalated"`**, `storyId: null`, and a `nextCommand`
107
- naming the `/plan` invocation that owns the work.
108
-
109
- **That envelope IS this session's terminal output.** Relay it and stop. There is
110
- no remaining step, no degraded fallback, and no smaller version of the work to
111
- attempt.
112
-
113
- **Invoking `/plan` in this same session is forbidden.** Hand the operator the
114
- `nextCommand`; `/plan` runs in a **fresh** session.
115
-
116
- This is not style — it is the empirical finding that motivated the envelope.
117
- A mandrel-bench 2.13.0 light-arm run read the escalation and continued anyway:
118
- it invoked `/plan` in-session and delivered. The in-session plan authored **one**
119
- Story against the scenario's 3–5 contract, where a fresh `/plan` session on the
120
- identical seed authored **four**. Planning inside a session already framed as
121
- small work under-decomposes, so walking past the escalation silently produced
122
- the very outcome the guard exists to prevent. The gate's decision was right both
123
- times; only the outcome's finality was missing.
124
-
125
- Nothing is left half-started: an escalated run creates **no receipt Story, no
126
- `story-<id>` branch, and no worktree** — the escalation path returns before
127
- every creation call site, and `escalation.created` records all three as `false`
128
- in a shape the schema pins, so a later run finds nothing to trip over.
129
-
130
- ## Constraints
131
-
132
- - **Land, block, or escalate — never a silent local build.** The close push is
133
- the only sanctioned landing; an `escalated` terminal is the only sanctioned
134
- ending that delivers nothing, and it ends the session
135
- (§ Escalation is terminal).
136
- - **No parallel engine.** `/deliver-light` invokes `single-story-init.js` and
137
- `single-story-close.js`; it never reimplements worktree, branch, PR, or merge
138
- mechanics.
139
- - **State only via `update-ticket-state.js`.** Drive every `agent::*`
140
- transition through the script; report state, not process.
141
-
142
- ## See also
143
-
144
- - [`/deliver`](deliver.md) — the multi-Story / planned delivery entry point.
145
- - [`helpers/deliver-story.md`](helpers/deliver-story.md) — the one Story
146
- delivery engine both entry points share.
147
- - [`helpers/deliver-digest.md`](helpers/deliver-digest.md) — engine invariants,
148
- gates, and the terminal-envelope contract.