mandrel 2.7.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +104 -330
- package/.agents/agents/auditor.md +135 -0
- package/.agents/agents/plan-critic.md +80 -0
- package/.agents/audit-checklists/dependencies.md +7 -0
- package/.agents/audit-checklists/documentation.md +1 -0
- package/.agents/docs/SDLC.md +69 -162
- package/.agents/docs/configuration.md +159 -499
- package/.agents/docs/quality-gates.md +59 -180
- package/.agents/instructions.md +170 -295
- package/.agents/rules/changelog-style.md +8 -66
- package/.agents/rules/ci-remediation.md +65 -124
- package/.agents/rules/gherkin-standards.md +10 -31
- package/.agents/rules/git-conventions-reference.md +28 -61
- package/.agents/rules/git-conventions.md +1 -1
- package/.agents/rules/orchestration-error-handling.md +5 -15
- package/.agents/rules/security-baseline.md +7 -13
- package/.agents/rules/shell-conventions.md +4 -13
- package/.agents/rules/test-seams.md +2 -2
- package/.agents/rules/testing-standards.md +7 -17
- package/.agents/schemas/agentrc.schema.json +21 -0
- package/.agents/scripts/audit-to-stories.js +51 -0
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +120 -55
- package/.agents/scripts/lib/config-settings-schema.js +32 -0
- package/.agents/scripts/lib/findings/semantic-issue-search.js +43 -5
- package/.agents/scripts/lib/observability/terse-result.js +114 -0
- package/.agents/scripts/lib/orchestration/complexity-gate.js +207 -0
- package/.agents/scripts/lib/orchestration/plan-context.js +3 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +221 -8
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +55 -14
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +9 -3
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +4 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +13 -40
- package/.agents/scripts/lib/story-body/body-format-lints.js +215 -0
- package/.agents/scripts/lib/story-body/story-body.js +18 -2
- package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -0
- package/.agents/scripts/providers/github/issues.js +54 -7
- package/.agents/scripts/providers/github/search-budget.js +124 -0
- package/.agents/scripts/providers/github/search-query.js +71 -0
- package/.agents/scripts/single-story-confirm-merge.js +14 -5
- package/.agents/scripts/single-story-init.js +19 -3
- package/.agents/scripts/sync-branch-from-base.js +9 -3
- package/.agents/skills/core/api-and-interface-design/SKILL.md +23 -297
- package/.agents/skills/core/api-and-interface-design/reference.md +76 -0
- package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +20 -327
- package/.agents/skills/core/browser-testing-with-devtools/reference.md +74 -0
- package/.agents/skills/core/code-review-and-quality/reference.md +16 -398
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +14 -281
- package/.agents/skills/core/documentation-and-adrs/reference.md +42 -338
- package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +28 -326
- package/.agents/skills/core/idea-refinement/SKILL.md +67 -193
- package/.agents/skills/core/security-and-hardening/SKILL.md +15 -31
- package/.agents/skills/core/security-and-hardening/reference.md +15 -273
- package/.agents/skills/skills.index.json +5 -5
- package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +16 -222
- package/.agents/skills/stack/qa/gherkin-authoring/reference.md +157 -0
- package/.agents/skills/stack/qa/playwright/SKILL.md +0 -29
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +19 -23
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +35 -53
- package/.agents/skills/stack/qa/vitest/SKILL.md +0 -29
- package/.agents/workflows/audit-accessibility.md +34 -108
- package/.agents/workflows/audit-architecture.md +35 -123
- package/.agents/workflows/audit-clean-code.md +19 -78
- package/.agents/workflows/audit-data-model.md +32 -100
- package/.agents/workflows/audit-dependencies.md +47 -111
- package/.agents/workflows/audit-devops.md +16 -83
- package/.agents/workflows/audit-documentation.md +46 -93
- package/.agents/workflows/audit-navigability.md +26 -80
- package/.agents/workflows/audit-performance.md +40 -106
- package/.agents/workflows/audit-privacy.md +17 -80
- package/.agents/workflows/audit-quality.md +35 -99
- package/.agents/workflows/audit-security.md +20 -78
- package/.agents/workflows/audit-seo.md +20 -98
- package/.agents/workflows/audit-sre.md +20 -88
- package/.agents/workflows/audit-to-stories.md +1 -8
- package/.agents/workflows/audit-ux-ui.md +17 -80
- package/.agents/workflows/deliver.md +54 -9
- package/.agents/workflows/git-cleanup.md +50 -275
- package/.agents/workflows/helpers/audit-lens-core.md +230 -0
- package/.agents/workflows/helpers/code-review.md +11 -23
- package/.agents/workflows/helpers/deliver-story-reference.md +114 -17
- package/.agents/workflows/helpers/deliver-story.md +36 -186
- package/.agents/workflows/helpers/qa-core.md +174 -0
- package/.agents/workflows/helpers/qa-run-scenario-reference.md +35 -0
- package/.agents/workflows/helpers/qa-run-scenario.md +11 -25
- package/.agents/workflows/helpers/worktree-lifecycle.md +6 -67
- package/.agents/workflows/mandrel-update.md +7 -13
- package/.agents/workflows/plan.md +44 -17
- package/.agents/workflows/qa-assist.md +140 -269
- package/.agents/workflows/qa-explore.md +125 -316
- package/.agents/workflows/qa-run.md +180 -380
- package/docs/CHANGELOG.md +30 -0
- package/package.json +1 -1
- package/.agents/workflows/helpers/audit-dual-path.md +0 -59
- package/.agents/workflows/helpers/audit-self-check.md +0 -70
- 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
|
|
9
|
-
|
|
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 —
|
|
132
|
+
## Worked Example — On-Contract
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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)
|
|
5
|
-
([`deliver.md`](../workflows/deliver.md))
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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`
|
|
33
|
-
|
|
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,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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 —
|
|
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
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
operator
|
|
87
|
-
|
|
88
|
-
- **
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
(`
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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 cover — triaging 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.
|
|
128
|
-
|
|
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
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
4
|
-
|
|
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
|
|
7
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
34
|
-
|
|
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
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
|
|
@@ -327,6 +327,27 @@
|
|
|
327
327
|
"codebaseSnapshot": {
|
|
328
328
|
"$ref": "#/$defs/codebaseSnapshot"
|
|
329
329
|
},
|
|
330
|
+
"complexityGate": {
|
|
331
|
+
"type": "object",
|
|
332
|
+
"description": "Plan-time ceremony-lite complexity gate. Routes trivial single-artifact seeds onto a collapsed plan/deliver path; conservative (full on any doubt). Never relaxes the Story-ticket / PR-to-main / repo-gates / security-baseline non-negotiables.",
|
|
333
|
+
"properties": {
|
|
334
|
+
"enabled": {
|
|
335
|
+
"type": "boolean",
|
|
336
|
+
"description": "Master switch. When false, every seed takes the full plan/deliver ceremony. Default true."
|
|
337
|
+
},
|
|
338
|
+
"maxSeedWords": {
|
|
339
|
+
"type": "integer",
|
|
340
|
+
"minimum": 0,
|
|
341
|
+
"description": "Seed prose word ceiling for the lite path. A seed above this many words is not trivial and takes the full path. Default 60."
|
|
342
|
+
},
|
|
343
|
+
"maxArtifacts": {
|
|
344
|
+
"type": "integer",
|
|
345
|
+
"minimum": 0,
|
|
346
|
+
"description": "Enumerated-artifact ceiling for the lite path. A seed enumerating more than this many candidate artifacts is multi-capability and takes the full path. Default 1."
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
"additionalProperties": false
|
|
350
|
+
},
|
|
330
351
|
"failOnSharedEditors": {
|
|
331
352
|
"type": "boolean",
|
|
332
353
|
"description": "When true, upgrade shared-editor conflict findings to hard errors (default false — advisory soft findings only)."
|