mandrel 2.6.0 → 2.8.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 (78) hide show
  1. package/.agents/README.md +104 -330
  2. package/.agents/agents/auditor.md +135 -0
  3. package/.agents/agents/plan-critic.md +80 -0
  4. package/.agents/audit-checklists/dependencies.md +7 -0
  5. package/.agents/audit-checklists/documentation.md +1 -0
  6. package/.agents/docs/SDLC.md +69 -162
  7. package/.agents/docs/configuration.md +133 -499
  8. package/.agents/docs/quality-gates.md +59 -180
  9. package/.agents/instructions.md +170 -295
  10. package/.agents/rules/changelog-style.md +8 -66
  11. package/.agents/rules/ci-remediation.md +65 -124
  12. package/.agents/rules/gherkin-standards.md +10 -31
  13. package/.agents/rules/git-conventions-reference.md +28 -61
  14. package/.agents/rules/git-conventions.md +1 -1
  15. package/.agents/rules/orchestration-error-handling.md +5 -15
  16. package/.agents/rules/security-baseline.md +7 -13
  17. package/.agents/rules/shell-conventions.md +4 -13
  18. package/.agents/rules/test-seams.md +2 -2
  19. package/.agents/rules/testing-standards.md +7 -17
  20. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +7 -2
  21. package/.agents/scripts/lib/feedback-loop/graduator-core.js +144 -12
  22. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +11 -1
  23. package/.agents/scripts/lib/observability/runtime-friction.js +97 -36
  24. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +29 -5
  25. package/.agents/skills/core/api-and-interface-design/SKILL.md +23 -297
  26. package/.agents/skills/core/api-and-interface-design/reference.md +76 -0
  27. package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +20 -327
  28. package/.agents/skills/core/browser-testing-with-devtools/reference.md +74 -0
  29. package/.agents/skills/core/code-review-and-quality/reference.md +16 -398
  30. package/.agents/skills/core/debugging-and-error-recovery/reference.md +14 -281
  31. package/.agents/skills/core/documentation-and-adrs/reference.md +42 -338
  32. package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +28 -326
  33. package/.agents/skills/core/idea-refinement/SKILL.md +67 -193
  34. package/.agents/skills/core/security-and-hardening/SKILL.md +15 -31
  35. package/.agents/skills/core/security-and-hardening/reference.md +15 -273
  36. package/.agents/skills/skills.index.json +5 -5
  37. package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +16 -222
  38. package/.agents/skills/stack/qa/gherkin-authoring/reference.md +157 -0
  39. package/.agents/skills/stack/qa/playwright/SKILL.md +0 -29
  40. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +19 -23
  41. package/.agents/skills/stack/qa/qa-harness/SKILL.md +35 -53
  42. package/.agents/skills/stack/qa/vitest/SKILL.md +0 -29
  43. package/.agents/workflows/audit-accessibility.md +34 -108
  44. package/.agents/workflows/audit-architecture.md +35 -123
  45. package/.agents/workflows/audit-clean-code.md +19 -78
  46. package/.agents/workflows/audit-data-model.md +32 -100
  47. package/.agents/workflows/audit-dependencies.md +47 -111
  48. package/.agents/workflows/audit-devops.md +16 -83
  49. package/.agents/workflows/audit-documentation.md +46 -93
  50. package/.agents/workflows/audit-navigability.md +26 -80
  51. package/.agents/workflows/audit-performance.md +40 -106
  52. package/.agents/workflows/audit-privacy.md +17 -80
  53. package/.agents/workflows/audit-quality.md +35 -99
  54. package/.agents/workflows/audit-security.md +20 -78
  55. package/.agents/workflows/audit-seo.md +20 -98
  56. package/.agents/workflows/audit-sre.md +20 -88
  57. package/.agents/workflows/audit-to-stories.md +1 -8
  58. package/.agents/workflows/audit-ux-ui.md +17 -80
  59. package/.agents/workflows/deliver.md +54 -9
  60. package/.agents/workflows/git-cleanup.md +50 -275
  61. package/.agents/workflows/helpers/audit-lens-core.md +230 -0
  62. package/.agents/workflows/helpers/code-review.md +11 -23
  63. package/.agents/workflows/helpers/deliver-story-reference.md +114 -17
  64. package/.agents/workflows/helpers/deliver-story.md +26 -186
  65. package/.agents/workflows/helpers/qa-core.md +174 -0
  66. package/.agents/workflows/helpers/qa-run-scenario-reference.md +35 -0
  67. package/.agents/workflows/helpers/qa-run-scenario.md +11 -25
  68. package/.agents/workflows/helpers/worktree-lifecycle.md +6 -67
  69. package/.agents/workflows/mandrel-update.md +7 -13
  70. package/.agents/workflows/plan.md +17 -15
  71. package/.agents/workflows/qa-assist.md +140 -269
  72. package/.agents/workflows/qa-explore.md +125 -316
  73. package/.agents/workflows/qa-run.md +180 -380
  74. package/docs/CHANGELOG.md +18 -0
  75. package/package.json +1 -1
  76. package/.agents/workflows/helpers/audit-dual-path.md +0 -59
  77. package/.agents/workflows/helpers/audit-self-check.md +0 -70
  78. package/.agents/workflows/helpers/audit-severity-scale.md +0 -19
@@ -5,8 +5,8 @@ This rule governs the shape of per-release entries in the project CHANGELOG
5
5
  release entry is authored or edited — most commonly inside Story #N's
6
6
  docs sweep before `/deliver` opens the release PR.
7
7
 
8
- The contract is **guidance-tier** in v1: no automated gate fails a close when
9
- an entry drifts off-template. It still binds every author.
8
+ The contract is **guidance-tier**: no automated gate fails a close when an
9
+ entry drifts off-template. It still binds every author.
10
10
 
11
11
  ## Goal
12
12
 
@@ -129,71 +129,13 @@ release into grouped sub-sections over padding the bullet list. Before
129
129
  accepting a long entry, ask: which bullets are user-visible, and which
130
130
  are internal detail that migrated in from the Epic body?
131
131
 
132
- ## Worked Example — Before/After
132
+ ## Worked Example — On-Contract
133
133
 
134
- The "before" reflects the style that drove the Epic #553 retro action item:
135
- multi-section entries where each bullet leaked internal function names,
136
- file paths, and implementation mechanics. The "after" applies the contract
137
- above.
138
-
139
- ### Before (off-contract, ~48 lines)
140
-
141
- ```markdown
142
- ## [5.8.7] - 2026-04-15
143
-
144
- ### Robust story→epic merge at story close
145
-
146
- Parallel wave execution kept producing conflicts — Stories branched
147
- early in a wave landed after peers had merged. `finalizeMerge` now:
148
-
149
- 1. **Pre-merge rebase in the story worktree** onto
150
- `origin/<epicBranch>`, shrinking the conflict surface to the
151
- Story's real delta. Failed rebase is aborted and merge still
152
- proceeds.
153
- 2. **Conflict triage via `mergeFeatureBranch`** — same threshold-based
154
- triage used at integration time (major ≥3 files or ≥20 markers =
155
- abort; minor = auto-resolve by accepting Story's version with audit
156
- log).
157
-
158
- ### Per-worktree node_modules collapsed into shared store
159
-
160
- Per-worktree `npm install` duplicated dependencies across every story
161
- tree and blew out disk on parallel waves. `ensure()` now links each
162
- worktree's `node_modules` to a primed donor tree (junction on Windows)
163
- and `reap()` removes the link before `git worktree remove`.
164
- Auto-detected: if the configured strategy is `symlink`, the link
165
- applies.
166
-
167
- ### Deliver tail auto-invokes pre-merge gates
168
-
169
- `/deliver` auto-invokes the code-review module (Phase 4) and
170
- the retro runner (Phase 5) inline instead of halting to ask the
171
- operator to run them separately. `--skip-code-review` available as
172
- an override.
173
-
174
- ### Epic Health ticket closed alongside PRD/Tech Spec
175
-
176
- Step 8's closure sweep now matches any ticket carrying `type::health`
177
- or a title starting with `📉 Epic Health:`, in addition to
178
- `context::prd` / `context::tech-spec`.
179
-
180
- ### Stale-lock sweep for shared `.git/` dir
181
-
182
- `WorktreeManager.sweepStaleLocks({ maxAgeMs = 30_000 })` removes
183
- well-known lock files (`index.lock`, `HEAD.lock`, `packed-refs.lock`,
184
- `config.lock`, `shallow.lock`) whose mtime exceeds the threshold.
185
- Fresh locks belonging to in-flight ops are skipped. Runs at
186
- `/deliver` start, before worktree GC.
187
- ```
188
-
189
- Contract violations: five separate `###` sub-sections where one theme
190
- would do; internal function names (`finalizeMerge`, `mergeFeatureBranch`,
191
- `ensure()`, `reap()`, `WorktreeManager.sweepStaleLocks`); implementation
192
- mechanics (`BFS walker` equivalent, exact argument shapes, internal step
193
- numbering like "Step 1.4", "Step 8"); lock-file name list leaks
194
- implementation detail that operators cannot act on.
195
-
196
- ### After (on-contract, ~18 lines)
134
+ Off-contract entries the style that drove the Epic #553 retro action item
135
+ pack several `###` sub-sections into one release and leak internal function
136
+ names (`finalizeMerge`, `mergeFeatureBranch`, `ensure()`, `reap()`),
137
+ implementation mechanics, internal step numbering, and lock-file name lists
138
+ operators cannot act on. The on-contract version collapses all of that:
197
139
 
198
140
  ```markdown
199
141
  ## [5.8.7] - 2026-04-15
@@ -1,127 +1,68 @@
1
1
  # CI Failure Triage & Remediation
2
2
 
3
3
  This rule applies when a delivery path is watching a pull request's CI checks
4
- and a required check is red (or repeatedly slow) the `/deliver` router
5
- ([`deliver.md`](../workflows/deliver.md)) runs each Story through the
6
- single-Story Step 4 CI watch + fix loop
7
- ([`deliver-story.md`](../workflows/helpers/deliver-story.md)), which hands off
8
- to it. It is the single triage brain that mechanism defers to:
9
- the watcher (`pr-watch-with-update.js`) surfaces the failing check, the run
10
- link, and the failure signature; this rule decides what to do next.
11
-
12
- The animating principle: **a red check is a defect until proven otherwise, and
13
- the fix is always to remove the defect — never to hide it.** There is no
14
- rerun-the-failed-job path and no quarantine path in this rule, by design.
15
- Reruns and quarantines mask defects; a flaky test that passes on the second
16
- attempt is still a bug that will fail a future run for a real user or a future
17
- delivery. Root-cause it or file it never re-roll the dice.
18
-
19
- ## The triage decision tree
20
-
21
- When a required check goes red, walk this tree top to bottom. Do **not** skip
22
- to "fix" before you have classified the failure an unclassified fix is a
23
- guess.
24
-
25
- ### 1. Pull the evidence
26
-
27
- Fetch the failing job log and record the failure signature (the failing check
28
- name, the run id / run link, and the first distinctive error line). The
29
- watcher already writes this to `temp/story-<id>-ci-digest.{json,md}` — start
30
- from that digest.
31
-
32
- ### 2. Classify the failure
33
-
34
- - **Deterministic (real) failure** — the check fails the same way every time,
35
- and the failure is caused by the diff under review (a lint violation, a
36
- broken test, a coverage regression, a baseline drift the diff genuinely
37
- caused). Go to Real failures](#real-failures--route-to-the-per-check-fix-table).
38
- - **Infra / transient failure** a runner died, a network fetch timed out, a
39
- dependency registry 5xx'd, a step hit a platform-conditional path. Go to
40
- Infra, transient, and flaky failures](#infra-transient-and-flaky-failures-are-root-cause-defects).
41
- - **Flaky failure** — the check fails intermittently: green on one run, red on
42
- the next, with **no diff change** between them (order-dependent tests,
43
- timing/race assertions, shared-state bleed, wall-clock or timezone
44
- assumptions). Go to
45
- Infra, transient, and flaky failures](#infra-transient-and-flaky-failures-are-root-cause-defects).
46
-
47
- ## Real failures route to the per-check fix table
48
-
49
- A deterministic failure caused by the diff is remediated at source. Use the
50
- existing per-check fix table — do **not** duplicate it here:
51
-
52
- - **Story Step 4**:
53
- [`deliver-story-reference.md` § Step 4 CI watch + fix recovery](../workflows/helpers/deliver-story-reference.md#step-4--ci-watch--fix-recovery).
54
-
55
- In short: lint/format `npm run lint` + biome apply; maintainability/crap
56
- baseline drift re-run the ratcheted script and fix at source (refresh a
57
- baseline only when the diff demonstrably can't be covered); test failure →
58
- reproduce with `npm test`, fix source or test; coverage threshold → add tests.
59
- Commit the fix on the delivery branch (`story-<storyId>`), push, and re-run the
60
- watcher. Auto-merge stays armed across retries.
61
-
62
- ## Infra, transient, and flaky failures ARE root-cause defects
63
-
64
- Treat every infra/transient failure **and** every flaky failure as a
65
- root-cause defect. The remediation sequence is the same for both — you do not
66
- get to wave it off because "CI was flaky."
67
-
68
- 1. **Reproduce.** Run the failing check locally (or in a clean environment as
69
- close to CI as you can get). Re-run it enough times to observe the
70
- intermittency for a flaky failure. If you cannot reproduce it at all after a
71
- genuine attempt, that itself is a finding — record it in the issue you file
72
- in step 4.
73
- 2. **Check whether it also fails on `main`.** Run the same check against an
74
- unmodified `main` checkout. If it fails on `main`
75
- too, the defect is **pre-existing** — it is not caused by the diff under
76
- review, and the fix belongs in a separate change, not silently folded into
77
- this delivery.
78
- 3. **Bisect environment vs. code.** Determine whether the failure is driven by
79
- the environment (runner OS, Node version, concurrency, a platform-
80
- conditional branch, an external service) or by the code (an
81
- order-dependent test, a race, a shared-state assumption). This tells you
82
- where the fix has to land.
83
- 4. **Then either fix in-scope OR file the defect.**
84
- - **Fix in-scope** when the root cause is within this delivery's footprint
85
- and the fix is a cohesive part of the change under review (e.g. a race in
86
- a test the diff touches, a timezone assumption in code the Story owns).
87
- Commit it on the delivery branch, push, and re-run the watcher.
88
- - **File a `meta::framework-gap` issue** when the root cause is outside this
89
- delivery's scope — a pre-existing flaky test, a runner/infra weakness, a
90
- framework-level environment gap. Open the issue with the
91
- `meta::framework-gap` label (see
92
- [`git-conventions.md` § `meta::framework-gap`](git-conventions.md)),
93
- and include **the run link and the failure signature** (failing check,
94
- run id, first distinctive error line) captured in step 1 so a later
95
- `/plan` Phase 0 sweep can act on it. Then remediate this delivery only if
96
- the pre-existing defect is genuinely blocking it; otherwise proceed once
97
- the defect is filed and the check is not caused by your diff.
98
-
99
- **There is no shortcut.** You may **not** re-run the failed job to "see if it
100
- goes green," and you may **not** quarantine, skip, or `.only`/`.skip` a flaky
101
- test to get a green bar. Both mask the defect and are prohibited by this rule.
102
-
103
- ## Escalation criteria
104
-
105
- Escalate — flip the ticket to `agent::blocked`, post a `friction` comment, and
106
- hand back to the operator — under **any** of the following. These extend the
107
- existing three-strikes halt rule; they do not replace it.
108
-
109
- - **Three strikes (existing).** Three consecutive remediation iterations on the
110
- same failure class without convergence. Stop; the diagnosis is likely wrong
111
- (see [`instructions.md` § 1.I Anti-Thrashing](../instructions.md)).
112
- - **Wall-clock timebox.** Regardless of iteration count, if you have spent more
113
- than **30 minutes of active remediation** on a single CI failure without a
114
- green bar in sight, stop and escalate. A long grind on one red check is
115
- itself a signal that the failure exceeds a single delivery turn's judgment.
116
- - **Clearly-environmental → escalate immediately (fast path).** When the
117
- failure is unambiguously environmental and outside your control — a runner
118
- provisioning failure, a persistent registry/network outage, a
119
- branch-protection or CI-configuration misconfiguration, an expired
120
- credential — do **not** burn iterations trying to code around it. File the
121
- `meta::framework-gap` issue (with run link + signature) and escalate on the
122
- first encounter. This fast path exists so an operator-side or infra-side
123
- problem reaches the operator immediately instead of consuming the turn.
124
-
125
- When you escalate, name the failing check, the run link, the failure
126
- signature, the classification you reached, and what you tried — never fall
127
- silent.
4
+ and a required check is red (or repeatedly slow). The Story Step 4 CI watch +
5
+ fix loop ([`deliver-story.md`](../workflows/helpers/deliver-story.md)) hands off
6
+ to it: the watcher (`pr-watch-with-update.js`) surfaces the failing check, the
7
+ run link, and the failure signature; this rule decides what to do next.
8
+
9
+ ## Goal
10
+
11
+ **A red check is a defect until proven otherwise, and the fix is always to
12
+ remove the defect never to hide it.** A red required check is resolved in
13
+ exactly one of two ways, and no others:
14
+
15
+ 1. **Remove the root cause on the branch.** Pull the failing job log and record
16
+ the failure signature (failing check, run id / run link, first distinctive
17
+ error line the watcher writes this to
18
+ `temp/story-<id>-ci-digest.{json,md}`). Reproduce the failure, confirm it is
19
+ caused by the diff under review — **verify the same check against an
20
+ unmodified `main` checkout**; if it also fails on `main` the defect is
21
+ pre-existing and belongs in a separate change then fix it at source,
22
+ commit on `story-<storyId>`, push, and re-run the watcher. Auto-merge stays
23
+ armed across retries. Route deterministic per-check failures (lint/format,
24
+ maintainability/CRAP baseline drift, test failure, coverage threshold)
25
+ through the fix table in
26
+ [`deliver-story-reference.md` § Step 4](../workflows/helpers/deliver-story-reference.md#step-4--ci-watch--fix-recovery);
27
+ refresh a baseline only when the diff demonstrably can't be covered.
28
+ 2. **File a `meta::framework-gap` issue** when the root cause is outside this
29
+ delivery's scope a pre-existing flaky test, a runner/infra weakness, a
30
+ framework-level environment gap. Open the issue with the `meta::framework-gap`
31
+ label (see [`git-conventions.md`](git-conventions.md)) carrying **the run
32
+ link and the failure signature** so a later `/plan` Phase 0 sweep can act on
33
+ it. Remediate this delivery only if the pre-existing defect is genuinely
34
+ blocking it.
35
+
36
+ Infra, transient, and flaky failures are root-cause defects too a flaky test
37
+ that passes on a rerun is still a bug that will fail a future run. They route
38
+ through the same two options; bisect environment (runner OS, Node version,
39
+ concurrency, a platform-conditional branch, an external service) vs. code (an
40
+ order-dependent test, a race, a shared-state assumption) to decide which.
41
+
42
+ ## Verifier
43
+
44
+ The check is resolved only when it is **green with zero reruns of the failed
45
+ job**, and the diff carries **no `.skip` / `.only`, no quarantine, and no
46
+ deleted or loosened assertion** introduced to reach green. You may **not**
47
+ re-run a failed job to "see if it goes green," and you may **not** skip,
48
+ `.only`, or quarantine a flaky test to get a green bar. Both mask the defect
49
+ and are prohibited by this rule.
50
+
51
+ ## Escalation
52
+
53
+ Flip the ticket to `agent::blocked`, post a `friction` comment (naming the
54
+ failing check, the run link, the failure signature, the classification you
55
+ reached, and what you tried **never fall silent**), and hand back to the
56
+ operator under **any** of:
57
+
58
+ - **Three strikes.** Three consecutive remediation iterations on the same
59
+ failure class without convergence the diagnosis is likely wrong (see
60
+ [`instructions.md` § 1.I Anti-Thrashing](../instructions.md)).
61
+ - **Wall-clock timebox.** More than **30 minutes** of active remediation on a
62
+ single CI failure without a green bar in sight.
63
+ - **Clearly-environmental → escalate immediately.** An unambiguously
64
+ environmental failure outside your control (runner provisioning, a persistent
65
+ registry/network outage, a branch-protection or CI misconfiguration, an
66
+ expired credential) file the `meta::framework-gap` issue (with run link +
67
+ signature) and escalate on the first encounter rather than burning iterations
68
+ trying to code around it.
@@ -29,10 +29,8 @@ scenarios. Use the canonical set below; do not invent ad-hoc tags.
29
29
  the tag (the "de-skip" edit). Unlike `@flaky`, `@skip` marks planned
30
30
  not-yet-implemented behavior, never a stability problem.
31
31
 
32
- Retired: the `@epic-<id>-ac-N` namespaced AC tag. Its consumer
33
- (`acceptance-spec-reconciler.js`) was deleted in the v2 Epic removal, so
34
- the tag is inert — do not apply it to new scenarios. The `mandrel update`
35
- migration strips surviving instances from consumer feature files.
32
+ Retired: the `@epic-<id>-ac-N` AC tag is inert — do not apply it to new
33
+ scenarios; `mandrel update` strips surviving instances from consumer files.
36
34
 
37
35
  Rules:
38
36
 
@@ -127,30 +125,11 @@ implementation detail.
127
125
 
128
126
  ## Step Reuse — Grep Before You Write
129
127
 
130
- Before authoring a new step, search the existing step-definition library for
131
- an equivalent phrase. New steps are a cost: they fragment the vocabulary and
132
- multiply step-definition maintenance.
133
-
134
- Workflow:
135
-
136
- 1. Identify the verb phrase you want to write (e.g. "the user signs in as").
137
- 2. Grep the step-definition directory for the verb stem:
138
-
139
- ```bash
140
- rg -n "signs? in" tests/steps
141
- ```
142
-
143
- 3. If a matching step exists, reuse it verbatim — adjust your scenario
144
- phrasing to fit the existing step, not the reverse.
145
- 4. If a near-match exists, extend the existing step (add a parameter, widen
146
- the regex) rather than forking a new one. Update every call site in the
147
- same PR.
148
- 5. Only when no reasonable match exists, add a new step definition.
149
- Co-locate it with related steps and follow the library's naming
150
- convention.
151
- 6. Never copy-paste a step implementation to support a paraphrased scenario.
152
- Rephrase the scenario instead.
153
-
154
- Deprecations: when a step is superseded, mark the old definition deprecated
155
- in code and migrate all call sites in the same PR. Do not leave two
156
- near-identical steps live.
128
+ Before authoring a new step, grep the step-definition library for the verb
129
+ stem and **reuse an existing step verbatim** (adjust your scenario to fit it),
130
+ or **extend a near-match** (add a parameter, widen the regex, updating every
131
+ call site in the same PR) — new steps fragment the vocabulary and multiply
132
+ maintenance. Add a new definition only when no reasonable match exists, and
133
+ never copy-paste a step implementation to support a paraphrased scenario.
134
+ When a step is superseded, mark it deprecated and migrate every call site in
135
+ the same PR; do not leave two near-identical steps live.
@@ -31,17 +31,6 @@ therefore:
31
31
  by side for a release window. If a shape changes, the old shape is
32
32
  deleted in the same PR.
33
33
 
34
- The codifying decision is **Epic #2646** (the "Hard-Cutover Cleanup Epic"),
35
- which deleted the existing compatibility shim layer across
36
- `config-resolver.js`, `lib/config/*.js`, `lib/baselines/`,
37
- `wave-session.js`, `IExecutionAdapter` / `ManualDispatchAdapter`, lifecycle
38
- emit shims, and duplicate progress/comment writers in one pass. The
39
- per-finding closing references (audit Findings #10, #11, #13, #17) live in
40
- the merged PRs and the Epic #2646 history; the Part 1 — Model-Evolution
41
- Audit analysis this section grew out of is preserved at
42
- `docs/roadmap.md` @ tag `mandrel-v1.94.0` (see the Historical-anchors
43
- table in the live [`docs/roadmap.md`](../../docs/roadmap.md)).
44
-
45
34
  Practical guidance when authoring a contract change:
46
35
 
47
36
  - If you are tempted to add a "legacy shape" branch in a parser or
@@ -74,63 +63,41 @@ signature is worth naming:
74
63
  (`--no-errors-on-unmatched` or equivalent) before escalating via
75
64
  `agent::blocked`.
76
65
 
77
- ## Local checkout hygiene — full mechanics
66
+ ## Local checkout hygiene — outcome contract
78
67
 
79
68
  **Invariant (stated in the core): the delivering flow owns tidying the local
80
69
  checkout — reaping its own merged refs and fast-forwarding the base branch.
81
- `/git-cleanup` is a recovery tool, not a routine chore.** The mechanics behind
82
- that invariant:
83
-
84
- Every flow that lands work — `/deliver` and `/git-deliver` — is responsible
85
- for leaving the local checkout tidy without
86
- operator intervention:
87
-
88
- - **Fast-forwarding the base branch is owned by the flow.** `/deliver`
89
- fast-forwards `main` itself in its cleanup phase (via
90
- `git-cleanup.js --fast-forward-main --execute --yes`). No workflow ends by
91
- telling the operator to "run `/git-cleanup` afterwards to catch up".
92
- - **Reaping merged local refs is owned by the flow's next boot.** `/plan` and
93
- `/git-deliver` open with a **protected boot sweep**
94
- (`boot-sweep.js`) that fast-forwards `main`, prunes stale remote-tracking
95
- refs, and reaps every local branch whose PR is already merged skipping any
96
- candidate with unpushed work, a dirty worktree, or a still-open parent
97
- ticket. A branch a flow leaves behind (e.g. a `/git-deliver` feature branch
98
- whose PR merges out of band) is therefore reaped automatically at the next
99
- workflow boot, not left for the operator to sweep by hand. `boot-sweep.js`
100
- defaults its `--include` glob to `story-*`a bare invocation only sweeps
101
- Story branches; `/plan` and `/git-deliver` widen the scope to their own
102
- branch namespaces (`epic/*`, `feat/*`, `fix/*`, `chore/*`, `docs/*`,
103
- `refactor/*`) by passing `--include` explicitly at their boot call site.
104
- A branch the planner detects only via the weaker content-equivalence
105
- signal (`detectedBy: 'content-merged'`, Story #4395's
106
- `git merge-tree --write-tree` probe — content already landed in the base
107
- branch by another route, such as a squash-merged Epic PR, with no merged
108
- PR or git ancestry of its own) is **never** reaped by the boot sweep: it
109
- is report-only, surfaced under `contentMerged` in the result envelope and
110
- a routing hint in the summary line (Story #4396), so the operator can
111
- send it to `/git-cleanup` for a confirmed, eyeballed reap.
112
- - **`/git-cleanup` is recovery, not routine.** Run it by hand only to recover
113
- an unusual state the automated hygiene does not cover — triaging stashes,
114
- reaping across non-standard branch namespaces, or `--remote` pruning after a
115
- force-push diverged a tip. It is **not** the expected way to keep `main`
116
- current or to clear merged branches after a normal delivery; the delivering
117
- flows already own that. If you find yourself reaching for `/git-cleanup`
118
- after every routine `/deliver` or `/git-deliver` run, that is a signal the
119
- owning flow's hygiene step regressed — fix the flow, do not codify the manual
120
- sweep.
121
-
122
- ### Shared-checkout contention (Stories #4460, #4424, #4545)
70
+ `/git-cleanup` is a recovery tool, not a routine chore.** The outcome every
71
+ delivering flow (`/deliver`, `/git-deliver`) guarantees, with the mechanics
72
+ owned by `boot-sweep.js` / `git-cleanup.js`:
73
+
74
+ - **`main` is fast-forwarded** by the flow itself in its cleanup phase, so the
75
+ next init seeds from a current base. No workflow ends by telling the operator
76
+ to run `/git-cleanup` to catch up.
77
+ - **Merged local refs are reaped** at the next workflow boot's protected sweep
78
+ (`boot-sweep.js`) every local branch whose PR is already merged, skipping
79
+ any candidate with unpushed work, a dirty worktree, or a still-open parent
80
+ ticket. `/plan` and `/git-deliver` widen the sweep's `--include` scope beyond
81
+ the default `story-*` to their own branch namespaces at their boot call site.
82
+ - **Content-merged branches are report-only.** A branch detected only via the
83
+ weaker content-equivalence signal (`detectedBy: 'content-merged'` content
84
+ already landed in the base by another route, with no merged PR or git
85
+ ancestry of its own) is **never** reaped by the boot sweep; it is surfaced
86
+ under `contentMerged` for the operator to send to `/git-cleanup` for a
87
+ confirmed, eyeballed reap.
88
+ - **`/git-cleanup` is recovery, not routine.** Run it by hand only for a state
89
+ the automated hygiene does not covertriaging stashes, reaping across
90
+ non-standard namespaces, or `--remote` pruning after a force-push. Reaching
91
+ for it after every routine delivery signals the owning flow's hygiene step
92
+ regressed fix the flow, do not codify the manual sweep.
93
+
94
+ ### Shared-checkout contention
123
95
 
124
96
  **One delivery per checkout is the model.** v2 has no Epic integration branch
125
97
  and no merge phase that parks the shared checkout on someone else's branch:
126
98
  each Story works in its own worktree (`.worktrees/story-<id>/`) and lands by
127
- pushing `story-<id>` and opening a PR. The Epic-era collision this section used
128
- to describe — `story-close.js` running `git checkout <epic-branch>` in the
129
- shared main checkout under a per-Epic `epic-*.merge.lock` — is gone with the
130
- machinery that caused it (Story #4545 deleted the last of that prose; the six
131
- modules it named had already been removed in the v2.0.0 cutover).
132
-
133
- Two guards remain, and they cover different hazards:
99
+ pushing `story-<id>` and opening a PR. Two guards remain, and they cover
100
+ different hazards:
134
101
 
135
102
  - **Per-Story lease** (`lib/orchestration/single-story-lease-guard.js`). The
136
103
  standalone path has no Epic-scoped dispatch manifest to serialize two
@@ -20,7 +20,7 @@ Every Story lands on a dedicated **Story branch** named `story-<storyId>`
20
20
  (e.g., `story-104`), seeded from `project.baseBranch` (`main` by default).
21
21
  The runtime owns branch creation via `single-story-init.js`; agents commit
22
22
  on that branch only. Close opens a PR against `main` (squash + required
23
- checks). There is **no** `epic/<id>` integration branch and no `--no-ff`
23
+ checks). There is no `epic/<id>` integration branch and no `--no-ff`
24
24
  wave merge.
25
25
 
26
26
  > **Commit subjects.** Stories have no child tickets. Commits land on
@@ -9,21 +9,11 @@ orchestrators themselves.
9
9
  ## Throw, Never Fatal
10
10
 
11
11
  Orchestration scripts MUST surface unrecoverable failures with
12
- `throw new Error(<message>)` rather than `Logger.fatal(<message>)`.
13
-
14
- ### Why
15
-
16
- The `runAsCli` boundary catches the throw and maps it to `process.exit(1)`,
17
- preserving the operator-visible message verbatim while staying robust under
18
- a mocked `process.exit` (in tests or when the harness stubs it). By contrast,
19
- `Logger.fatal` falls through silently when `process.exit` is stubbed, which
20
- lets execution continue past the intended hard-stop and masks failures.
21
-
22
- ### Precedent
23
-
24
- Story #959 converted every `Logger.fatal` call inside the story-close
25
- orchestrator surface to `throw` and established this rule for future
26
- orchestration work.
12
+ `throw new Error(<message>)` rather than `Logger.fatal(<message>)`. The
13
+ `runAsCli` boundary catches the throw and maps it to `process.exit(1)`,
14
+ preserving the message verbatim and staying robust under a mocked
15
+ `process.exit`; `Logger.fatal` falls through silently when `process.exit` is
16
+ stubbed, letting execution continue past the intended hard-stop.
27
17
 
28
18
  ### Where it applies
29
19
 
@@ -1,13 +1,10 @@
1
1
  # Application Security Baseline
2
2
 
3
- Non-negotiable security MUSTs that apply to every piece of code generated. This
4
- rule is the SSOT for security taxonomy and constraints; the companion skill
3
+ Non-negotiable security MUSTs (the SSOT for security taxonomy and constraints)
4
+ that apply to every piece of code generated; the companion skill
5
5
  [`core/security-and-hardening`](../skills/core/security-and-hardening/SKILL.md)
6
- shows **how** to apply these MUSTs with code patterns, examples, and process
7
- guidance. Conflicts resolve per the central ordering in
8
- [`.agents/instructions.md` § 1.K](../instructions.md) — this rule sits above
9
- the skill, and its security MUSTs are **inviolable**: no persona, skill, or
10
- local override may relax them. The skill is updated to match.
6
+ shows **how** to apply them. These MUSTs are inviolable per
7
+ [`.agents/instructions.md` § 1.K](../instructions.md).
11
8
 
12
9
  ## Input Validation
13
10
 
@@ -87,11 +84,8 @@ local override may relax them. The skill is updated to match.
87
84
 
88
85
  ## Forbidden Practices
89
86
 
87
+ The MUSTs above are the contract; two rationalizations recur often enough to
88
+ name explicitly (both violate a MUST above):
89
+
90
90
  - Committing secrets to version control.
91
- - Logging passwords, tokens, or full credit-card numbers.
92
- - Trusting client-side validation as a security boundary.
93
91
  - Disabling security headers for convenience.
94
- - Using `eval()` or `innerHTML` with user-provided data.
95
- - Storing auth tokens in client-accessible storage.
96
- - Exposing stack traces or internal error details to users.
97
- - Hardcoding fallback secrets ("default" API keys, debug bypasses) in source.
@@ -45,19 +45,10 @@ Other PowerShell-isms agents must respect:
45
45
 
46
46
  ## Searching the Workspace
47
47
 
48
- When searching for strings, patterns, or files, prioritize speed and avoid
49
- pipeline bottlenecks or full-file reads. Use this decision tree:
50
-
51
- 1. **Host grep tool first.** If the harness exposes a dedicated grep tool
52
- (e.g. Claude Code's `Grep` tool, ripgrep wrappers), use it. These
53
- normalize quoting, respect `.gitignore`, and stream results.
54
- 2. **`git grep`** when the workspace is a git repo and no host tool is
55
- available. Pass `-l` to list only filenames when paths are sufficient.
56
- 3. **`rg` (ripgrep)** when installed and outside a git repo, or when you
57
- need features `git grep` lacks (multiline, type filters).
58
- 4. **Avoid full-file reads** for searches. Reading whole files into memory
59
- to scan for a pattern wastes context and is slower than a streaming
60
- grep.
48
+ Prefer, in order: the host's dedicated grep tool (ripgrep-backed normalizes
49
+ quoting, respects `.gitignore`, streams results), then `git grep` in a git
50
+ repo (`-l` for filenames only), then `rg` outside a git repo or when you need
51
+ multiline / type filters. Do not read whole files to scan for a pattern.
61
52
 
62
53
  ### PowerShell-specific anti-patterns
63
54
 
@@ -30,8 +30,8 @@ export function ensureSomething(ctx, { fsImpl = fs, spawnImpl = defaultSpawnSync
30
30
 
31
31
  ### Canonical In-Repo Reference
32
32
 
33
- `baseline-snapshot.js` (`forkMainToEpic` at line 135 / `commitSnapshotsToEpicBranch`
34
- at line 259) is the established baseline for this pattern in this codebase.
33
+ `.agents/scripts/lib/bootstrap/project-bootstrap.js` (its exported step
34
+ functions) is the established in-repo baseline for this pattern.
35
35
 
36
36
  ## Rules
37
37
 
@@ -101,23 +101,13 @@ semantics, including:
101
101
  - Header values that carry protocol semantics (`Location`, `ETag`,
102
102
  `Retry-After`)
103
103
 
104
- When a reviewer finds one of the above in a `.feature` file, the required
105
- remediation is to delete it from the scenario and add (or extend) a
106
- contract test that covers the assertion. The scenario should assert the
107
- **user-visible outcome** only ("the invoice appears in the outbox"), not
108
- the wire shape that produced it.
109
-
110
- This rule is enforced bidirectionally: the companion prohibition on
111
- `.feature` authoring lives in
112
- [`gherkin-standards.md § Forbidden Patterns`](./gherkin-standards.md#forbidden-patterns),
113
- which forbids raw SQL, HTTP status codes, DOM selectors, URLs, and JSON
114
- payloads inside scenarios. That list and this section are two sides of the
115
- same constraint: shape and state belong in contract tests; business
116
- outcomes belong in acceptance scenarios.
117
-
118
- This is the pyramid's load-bearing constraint. It is why the contract
119
- tier exists as a distinct layer, and why acceptance scenarios stay
120
- readable, stable, and free of implementation churn.
104
+ When one of the above appears in a `.feature` file, delete it from the
105
+ scenario and add (or extend) a contract test that covers it; the scenario
106
+ asserts the **user-visible outcome** only ("the invoice appears in the
107
+ outbox"). The companion prohibition on `.feature` authoring lives in
108
+ [`gherkin-standards.md § Forbidden Patterns`](./gherkin-standards.md#forbidden-patterns)
109
+ — the two are the same constraint from both sides, and it is the pyramid's
110
+ load-bearing one.
121
111
 
122
112
  ## Test Structure (Arrange, Act, Assert)
123
113
 
@@ -97,7 +97,9 @@ function metaSourceLabel(source) {
97
97
  * ({@link buildContentMarker}) at the Story #4415 cutover, but still
98
98
  * probed for so follow-ups filed before the cutover are recognized and
99
99
  * not re-filed. An HTML comment so it survives markdown rendering without
100
- * leaking into the visible body, but stays indexable via `gh search`.
100
+ * leaking into the visible body; the idempotency probe strips the comment
101
+ * delimiters before querying `gh search` (the raw `<!-- … -->` form never
102
+ * matches the index — Story #4657).
101
103
  *
102
104
  * @param {number} epicId
103
105
  * @param {number} index — zero-based finding ordinal within the Epic.
@@ -112,7 +114,10 @@ export function buildIdempotencyMarker(epicId, index) {
112
114
  * follow-up bodies. Derived from the finding's `lens|path|summary` triple
113
115
  * so the marker is stable across sibling insert/remove/reorder churn in
114
116
  * the source `audit-results` comment (Story #4415). An HTML comment so it
115
- * survives markdown rendering but stays indexable via `gh search`.
117
+ * survives markdown rendering without leaking into the visible body; the
118
+ * idempotency probe strips the comment delimiters before querying
119
+ * `gh search` (the raw `<!-- … -->` form never matches the index —
120
+ * Story #4657).
116
121
  *
117
122
  * @param {number} epicId
118
123
  * @param {{ lens?: string, path?: string, summary?: string }} finding