mandrel 1.92.0 → 1.94.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 (144) hide show
  1. package/.agents/agents/acceptance-critic.md +129 -0
  2. package/.agents/agents/retro.md +42 -0
  3. package/.agents/agents/story-worker.md +162 -0
  4. package/.agents/docs/configuration.md +7 -1
  5. package/.agents/docs/execution-reference.md +27 -2
  6. package/.agents/instructions.md +43 -33
  7. package/.agents/personas/engineer.md +26 -112
  8. package/.agents/personas/security-engineer.md +1 -2
  9. package/.agents/rules/git-conventions-reference.md +225 -0
  10. package/.agents/rules/git-conventions.md +25 -200
  11. package/.agents/rules/security-baseline.md +5 -0
  12. package/.agents/rules/testing-standards.md +106 -13
  13. package/.agents/schemas/agentrc.schema.json +31 -1
  14. package/.agents/schemas/lifecycle/slice.end.schema.json +21 -0
  15. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +20 -0
  16. package/.agents/schemas/lifecycle/slice.start.schema.json +17 -0
  17. package/.agents/scripts/acceptance-eval.js +62 -18
  18. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  19. package/.agents/scripts/bookkeeping-reconcile.js +117 -0
  20. package/.agents/scripts/check-context-budget.js +62 -5
  21. package/.agents/scripts/diagnose-friction.js +0 -6
  22. package/.agents/scripts/epic-deliver-prepare.js +272 -10
  23. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
  24. package/.agents/scripts/lib/close-validation/gates.js +159 -21
  25. package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
  26. package/.agents/scripts/lib/config/delivery-routing.js +87 -0
  27. package/.agents/scripts/lib/config/explain.js +2 -0
  28. package/.agents/scripts/lib/config-resolver.js +1 -1
  29. package/.agents/scripts/lib/config-settings-schema-delivery.js +37 -3
  30. package/.agents/scripts/lib/config-settings-schema-quality.js +9 -0
  31. package/.agents/scripts/lib/doc-tiers.js +37 -2
  32. package/.agents/scripts/lib/observability/active-story-env.js +111 -2
  33. package/.agents/scripts/lib/observability/hook-heartbeat.js +219 -0
  34. package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
  35. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
  36. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
  37. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +270 -0
  38. package/.agents/scripts/lib/orchestration/ceremony-routing.js +141 -0
  39. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +3 -124
  40. package/.agents/scripts/lib/orchestration/deliver-route.js +173 -0
  41. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +1 -1
  42. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +233 -0
  43. package/.agents/scripts/lib/orchestration/file-assumptions.js +68 -7
  44. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +270 -0
  45. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +83 -2
  46. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +6 -0
  47. package/.agents/scripts/lib/orchestration/plan-context.js +189 -3
  48. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
  49. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +99 -0
  50. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +38 -1
  51. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +16 -1
  52. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
  53. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +1 -0
  54. package/.agents/scripts/lib/orchestration/ticket-validator.js +19 -2
  55. package/.agents/scripts/lib/provider-factory.js +1 -1
  56. package/.agents/scripts/lib/templates/decomposer-prompts.js +1 -1
  57. package/.agents/scripts/plan-context.js +28 -10
  58. package/.agents/scripts/post-structured-comment.js +38 -0
  59. package/.agents/scripts/slice-phase.js +361 -0
  60. package/.agents/scripts/sync-claude-agents.js +165 -0
  61. package/.agents/scripts/update-ticket-state.js +31 -0
  62. package/.agents/scripts/wave-tick.js +138 -9
  63. package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
  64. package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
  65. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
  66. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +5 -5
  67. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +8 -8
  68. package/.agents/skills/core/epic-plan-premortem/SKILL.md +4 -4
  69. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +26 -56
  70. package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
  71. package/.agents/skills/core/idea-refinement/SKILL.md +2 -8
  72. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
  73. package/.agents/skills/skills.index.json +11 -381
  74. package/.agents/workflows/deliver.md +47 -4
  75. package/.agents/workflows/helpers/acceptance-self-eval.md +38 -13
  76. package/.agents/workflows/helpers/deliver-epic-reference.md +18 -5
  77. package/.agents/workflows/helpers/deliver-epic-single.md +331 -0
  78. package/.agents/workflows/helpers/deliver-epic.md +51 -8
  79. package/.agents/workflows/helpers/deliver-stories.md +15 -5
  80. package/.agents/workflows/helpers/epic-deliver-story.md +12 -3
  81. package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
  82. package/.agents/workflows/helpers/plan-epic-reference.md +19 -8
  83. package/.agents/workflows/helpers/plan-epic.md +95 -27
  84. package/.agents/workflows/helpers/scope-triage-gate.md +9 -0
  85. package/.agents/workflows/mandrel-update.md +1 -1
  86. package/.agents/workflows/plan.md +16 -4
  87. package/docs/CHANGELOG.md +23 -0
  88. package/lib/cli/registry.js +95 -0
  89. package/package.json +4 -2
  90. package/.agents/personas/engineer-mobile.md +0 -120
  91. package/.agents/personas/engineer-web.md +0 -111
  92. package/.agents/personas/product.md +0 -94
  93. package/.agents/personas/refactorer.md +0 -113
  94. package/.agents/personas/sre.md +0 -86
  95. package/.agents/personas/ux-designer.md +0 -95
  96. package/.agents/scripts/epic-plan-decompose.js +0 -54
  97. package/.agents/scripts/epic-plan-spec.js +0 -64
  98. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
  99. package/.agents/scripts/plan-critics.js +0 -227
  100. package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
  101. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
  102. package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
  103. package/.agents/skills/core/code-simplification/SKILL.md +0 -389
  104. package/.agents/skills/core/context-engineering/SKILL.md +0 -309
  105. package/.agents/skills/core/context-engineering/examples.md +0 -58
  106. package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
  107. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
  108. package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
  109. package/.agents/skills/core/idea-refinement/examples.md +0 -437
  110. package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
  111. package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
  112. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
  113. package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
  114. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
  115. package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
  116. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
  117. package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
  118. package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
  119. package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
  120. package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
  121. package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
  122. package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
  123. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
  124. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
  125. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
  126. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
  127. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
  128. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
  129. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
  130. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
  131. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
  132. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
  133. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
  134. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
  135. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
  136. package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
  137. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
  138. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
  139. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
  140. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
  141. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
  142. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
  143. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
  144. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
@@ -1,227 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * plan-critics.js — deterministic dispatch gate for the conditional
5
- * author-step critics of the collapsed /plan flow (Epic #4474 PR6,
6
- * design §4).
7
- *
8
- * Runs between authoring and gate #2, entirely git-local (zero GitHub
9
- * calls): reads the authored artifacts, evaluates the risk/size dispatch
10
- * conditions for the consolidation (8.3) and pre-mortem (8.5) critics via
11
- * `lib/orchestration/plan-critic-conditions.js`, and emits one JSON
12
- * verdict on stdout. The workflow dispatches a fresh-context sub-agent
13
- * ONLY for critics with `dispatch: true`; every skip decision is appended
14
- * to the plan-metrics ledger (`kind: "critic-skip"`, with reasons) so
15
- * under-firing is auditable — the persist validators remain unchanged
16
- * hard gates regardless of what this gate decides.
17
- *
18
- * Conditions (design §4 / §6 PR6):
19
- * - Consolidation: the existing deterministic precondition
20
- * (`evaluateConsolidationPrecondition`) says dispatch AND (the draft
21
- * has > 5 stories OR a confirmed divergence from the Tech Spec's
22
- * Delivery Slicing table). Skipped outright in the single-delivery
23
- * shape (no tickets exist to consolidate).
24
- * - Pre-mortem: risk verdict overall level is high, OR ticket count is
25
- * at least half `maxTickets`, OR any `planning.riskHeuristics` phrase
26
- * matches the plan text (case-insensitive substring over tech spec +
27
- * tickets + risk summary).
28
- *
29
- * Modes:
30
- * --epic <id> Artifact paths default to the per-Epic temp tree
31
- * (`temp/epic-<id>/techspec.md`, `risk-verdict.json`,
32
- * `tickets.json`); skip records land on the
33
- * per-Epic plan-metrics ledger.
34
- * explicit paths Ideation mode: pass --tech-spec/--risk-verdict
35
- * (and --tickets when fan-out) explicitly; skip
36
- * records land on the standalone ledger stream.
37
- *
38
- * Output (stdout-pure JSON):
39
- * { epicId, consolidation: { critic, dispatch, reasons },
40
- * premortem: { critic, dispatch, reasons } }
41
- *
42
- * Exit codes: 0 — verdict emitted (dispatch decisions are data, not
43
- * failures); 1 — fatal error (unreadable/invalid artifacts, bad args).
44
- */
45
-
46
- // Fail-fast if the framework's runtime deps are not installed — must be the
47
- // first import so the check runs before any third-party-importing sibling
48
- // module is evaluated (Story #3432).
49
- import './lib/runtime-deps/ensure-installed.js';
50
- import { readFile } from 'node:fs/promises';
51
- import { parseArgs } from 'node:util';
52
-
53
- import { runAsCli } from './lib/cli-utils.js';
54
- import { epicArtifactPath } from './lib/config/temp-paths.js';
55
- import {
56
- getLimits,
57
- resolveConfig,
58
- validateOrchestrationConfig,
59
- } from './lib/config-resolver.js';
60
- import { routeAllOutputToStderr } from './lib/Logger.js';
61
- import { loadRiskVerdict } from './lib/orchestration/epic-plan-spec/phases/risk-verdict.js';
62
- import {
63
- evaluateConsolidationDispatch,
64
- evaluatePremortemDispatch,
65
- } from './lib/orchestration/plan-critic-conditions.js';
66
- import {
67
- appendCriticSkip,
68
- recordPlanInvocation,
69
- } from './lib/orchestration/plan-metrics.js';
70
-
71
- const USAGE =
72
- 'Usage: plan-critics.js (--epic <EpicId> | --tech-spec <file> ' +
73
- '--risk-verdict <file> [--tickets <file>]) [--pretty]';
74
-
75
- /**
76
- * Resolve the planning risk heuristics list from the canonical config
77
- * block (same resolution `plan-context.js` and the decompose context use).
78
- *
79
- * @param {object} config
80
- * @returns {string[]}
81
- */
82
- function resolveRiskHeuristics(config = {}) {
83
- if (Array.isArray(config.planning?.riskHeuristics)) {
84
- return config.planning.riskHeuristics;
85
- }
86
- return config.agentSettings?.planning?.riskHeuristics || [];
87
- }
88
-
89
- async function readOptional(filePath, { required }) {
90
- try {
91
- return await readFile(filePath, 'utf8');
92
- } catch (err) {
93
- if (!required && err?.code === 'ENOENT') return null;
94
- throw new Error(`Cannot read ${filePath}: ${err.message}`);
95
- }
96
- }
97
-
98
- async function main() {
99
- const { values } = parseArgs({
100
- options: {
101
- epic: { type: 'string' },
102
- 'tech-spec': { type: 'string' },
103
- 'risk-verdict': { type: 'string' },
104
- tickets: { type: 'string' },
105
- pretty: { type: 'boolean', default: false },
106
- },
107
- strict: true,
108
- });
109
-
110
- let epicId = null;
111
- if (values.epic !== undefined) {
112
- epicId = Number.parseInt(values.epic, 10);
113
- if (!Number.isInteger(epicId)) {
114
- throw new Error(
115
- `--epic must be a numeric issue id (got "${values.epic}").\n${USAGE}`,
116
- );
117
- }
118
- }
119
-
120
- // stdout is reserved for the JSON verdict — flip every Logger sink to
121
- // stderr before any pipeline code runs (same guarantee plan-context.js
122
- // gives its envelope).
123
- routeAllOutputToStderr();
124
-
125
- let config;
126
- try {
127
- config = resolveConfig();
128
- validateOrchestrationConfig(config);
129
- } catch (err) {
130
- throw new Error(`Config schema validation failed:\n${err.message}`);
131
- }
132
-
133
- const fallback = (basename) =>
134
- epicId === null ? undefined : epicArtifactPath(epicId, basename, config);
135
- const techSpecPath = values['tech-spec'] ?? fallback('techspec.md');
136
- const riskVerdictPath =
137
- values['risk-verdict'] ?? fallback('risk-verdict.json');
138
- const ticketsPath = values.tickets ?? fallback('tickets.json');
139
- if (!techSpecPath || !riskVerdictPath) {
140
- throw new Error(
141
- `Missing artifact path(s): without --epic, explicit --tech-spec and --risk-verdict are required.\n${USAGE}`,
142
- );
143
- }
144
-
145
- const verdict = await recordPlanInvocation(
146
- { cli: 'plan-critics', mode: 'evaluate', epicId, config },
147
- async () => {
148
- const techSpecContent = await readOptional(techSpecPath, {
149
- required: true,
150
- });
151
- const riskVerdict = loadRiskVerdict(riskVerdictPath);
152
- // Tickets are shape-dependent: a single-delivery plan authors none.
153
- // Required only when passed explicitly.
154
- const ticketsRaw = ticketsPath
155
- ? await readOptional(ticketsPath, {
156
- required: values.tickets !== undefined,
157
- })
158
- : null;
159
- let tickets = null;
160
- if (ticketsRaw !== null) {
161
- try {
162
- tickets = JSON.parse(ticketsRaw);
163
- } catch (err) {
164
- throw new Error(
165
- `Failed to parse tickets file "${ticketsPath}" as JSON: ${err.message}`,
166
- );
167
- }
168
- if (!Array.isArray(tickets)) {
169
- throw new Error(
170
- `Tickets file "${ticketsPath}" must contain a JSON array.`,
171
- );
172
- }
173
- }
174
-
175
- const consolidation =
176
- tickets === null
177
- ? {
178
- critic: 'consolidation',
179
- dispatch: false,
180
- reasons: [
181
- 'single-delivery shape — no draft tickets exist to consolidate.',
182
- ],
183
- }
184
- : evaluateConsolidationDispatch({
185
- draftStories: tickets,
186
- specText: techSpecContent,
187
- });
188
-
189
- const premortem = evaluatePremortemDispatch({
190
- riskVerdict,
191
- ticketCount: tickets?.length ?? 0,
192
- maxTickets: getLimits(config).maxTickets,
193
- riskHeuristics: resolveRiskHeuristics(config),
194
- planText: [
195
- techSpecContent,
196
- ticketsRaw ?? '',
197
- riskVerdict.summary ?? '',
198
- ].join('\n'),
199
- });
200
-
201
- // Skip-audit trail (#4474 PR6): every non-dispatch is a ledger
202
- // record. Best-effort — a failed append never fails the gate.
203
- for (const decision of [consolidation, premortem]) {
204
- if (!decision.dispatch) {
205
- await appendCriticSkip(
206
- {
207
- critic: decision.critic,
208
- reasons: decision.reasons,
209
- cli: 'plan-critics',
210
- epicId,
211
- },
212
- config,
213
- );
214
- }
215
- }
216
-
217
- return { epicId, consolidation, premortem };
218
- },
219
- );
220
-
221
- const json = values.pretty
222
- ? JSON.stringify(verdict, null, 2)
223
- : JSON.stringify(verdict);
224
- process.stdout.write(`${json}\n`);
225
- }
226
-
227
- runAsCli(import.meta.url, main, { source: 'plan-critics' });
@@ -1,181 +0,0 @@
1
- ---
2
- name: baseline-refresh
3
- description: >-
4
- Author a refresh commit for any of the unified-baseline snapshots (CRAP,
5
- maintainability, dead-exports, lighthouse). Use whenever an intentional
6
- code change resets a baseline key (rename, deliberate complexity bump,
7
- perf regression with operator sign-off) and the close-validation chain
8
- needs the refreshed snapshot to land on the same Story branch as the
9
- triggering edit.
10
- allowed_tools:
11
- - Read
12
- - Write
13
- - Bash
14
- ---
15
-
16
- # baseline-refresh
17
-
18
- ## Policy Capsule
19
-
20
- - Refresh only when the change is **deliberate** (rename, approved complexity bump, signed-off perf delta, intentional API surface change). Never refresh to paper over an unintentional regression — fix the regression instead.
21
- - Run the kind-specific update command (`npm run crap:update` / `maintainability:update` / `dead-exports:update` / `lighthouse:update`) on the **Story branch**, not on `main`.
22
- - Verify the resulting diff is scoped to the relevant `baselines/<kind>.json` (plus cosmetic `package-lock.json` churn only). If unrelated files appear, STOP — the refresh is contaminated.
23
- - Stage baseline files **explicitly** (`git add baselines/<kind>.json`). Never `git add -A` in a refresh commit.
24
- - Commit-subject contract: a **Conventional-Commits** subject of the form `chore(baselines): refresh <kind> snapshot for <reason>` — never an ad-hoc leading token like `baseline-refresh:` (commitlint and the planner validator reject it).
25
- - The commit body is **mandatory** and non-empty: explain what changed, why the new floor is correct, and link the Story/Epic that triggered the refresh.
26
- - Add the machine-readable trailer `baseline-refresh: true` (one per line, `Key: value` git-trailer style) to the body whenever observability classification matters.
27
- - Include `Epic: #<epic-id>` as a body trailer.
28
- - Never pass `--no-verify`. The `commit-msg` hook (commitlint) MUST run and pass.
29
- - After the refresh lands, re-run `node .agents/scripts/check-baselines.js` to confirm the gate passes against the new snapshot; if it still fails, a sibling kind drifted — refresh that kind too.
30
-
31
- ## Role
32
-
33
- Senior engineer authoring a deliberate, observable refresh of one of the
34
- unified baseline snapshots that the close-validation chain enforces
35
- (`baselines/crap.json`, `baselines/maintainability.json`,
36
- `baselines/dead-exports.json`, `baselines/lighthouse.json`).
37
-
38
- A refresh is **not** a regression entry — it tells the ratchet that the
39
- new baseline key is intentional, so the gate compares future runs against
40
- the refreshed snapshot rather than the prior one.
41
-
42
- ## When to use
43
-
44
- - A file rename or move detached an MI/CRAP key from its prior baseline.
45
- - A method rename inside a file produced a phantom new key + phantom
46
- deleted key under escomplex's `<file>::<methodName>` keying.
47
- - An operator-approved complexity bump or perf delta needs to be
48
- enshrined as the new floor.
49
- - A dead-export gate flagged a deliberate API surface change that has
50
- been signed off.
51
-
52
- If the underlying change is an **unintentional** regression, do not refresh
53
- — remediate the regression first.
54
-
55
- ## Commit-subject contract (authoritative)
56
-
57
- Refresh commits MUST use a **Conventional-Commits subject** and MUST NOT
58
- use a legacy ad-hoc prefix as the leading token. The canonical shape is:
59
-
60
- ```text
61
- chore(baselines): refresh <kind> snapshot for <reason>
62
-
63
- <non-empty body explaining the refresh — what changed, why the new
64
- baseline is the correct floor, and any operator sign-off reference>
65
-
66
- baseline-refresh: true
67
- Epic: #<epic-id>
68
- ```
69
-
70
- ### Why a Conventional-Commits subject
71
-
72
- 1. The local `commit-msg` hook (`.husky/commit-msg` → `commitlint`) rejects
73
- any subject whose leading token is not one of
74
- `feat|fix|chore|refactor|perf|docs|style|test|build|ci|revert`. Legacy
75
- ad-hoc leading tokens fail this hook. `--no-verify` is forbidden by
76
- [`.agents/rules/git-conventions.md`](../../../rules/git-conventions.md),
77
- so the subject must conform.
78
- 2. `release-please` consumes Conventional-Commits subjects on `main` to
79
- generate `docs/CHANGELOG.md` and bump `package.json`. A
80
- non-conventional subject parses as "no changelog entry" and the
81
- refresh disappears from the release record.
82
- 3. `chore(baselines):` keeps the refresh out of the user-facing changelog
83
- (which is correct — a baseline refresh is internal hygiene, not a
84
- feature or fix) while still being machine-parseable.
85
-
86
- ### Body trailer for machine-readable classification
87
-
88
- When telemetry, the friction analyzer, or the baseline-refresh-rate
89
- observability surface needs to detect a refresh commit, add the trailer
90
- `baseline-refresh: true` to the commit **body** (one trailer per line,
91
- following the `Key: value` git-trailer convention). The trailer is the
92
- canonical machine-readable marker. Subject-level leading tokens are not
93
- — and must not be — used for this purpose.
94
-
95
- The trailer form is also what
96
- [`.agents/scripts/lib/observability/baseline-refresh-rate.js`](../../../scripts/lib/observability/baseline-refresh-rate.js)
97
- should classify against going forward; until that classifier is updated,
98
- the historical subject-prefix detection remains in place as a
99
- backwards-compatibility fallback but is not the prescribed shape for new
100
- commits.
101
-
102
- ## Procedure
103
-
104
- ### Step 1 — Run the matching update command
105
-
106
- Each baseline kind has a dedicated update script:
107
-
108
- | Kind | Update command |
109
- | --------------- | ------------------------------- |
110
- | CRAP | `npm run crap:update` |
111
- | Maintainability | `npm run maintainability:update`|
112
- | Dead-exports | `npm run dead-exports:update` |
113
- | Lighthouse | `npm run lighthouse:update` |
114
-
115
- Run the command on the Story branch that triggered the refresh — the
116
- worktree's HEAD must already be the Story branch, not `main`.
117
-
118
- ### Step 2 — Verify the diff is scoped to the baseline file
119
-
120
- `git status` should show only the relevant `baselines/<kind>.json` (or
121
- sibling per-kind files) and possibly `package-lock.json` cosmetic churn.
122
- If unrelated files appear in the diff, **STOP** — the update script
123
- picked up an unintentional regression and the refresh is contaminated.
124
-
125
- ### Step 3 — Author the commit
126
-
127
- Stage the baseline file(s) explicitly (do not `git add -A`), then commit
128
- with the Conventional-Commits subject + body trailer:
129
-
130
- ```bash
131
- git add baselines/<kind>.json
132
- git commit -m "$(cat <<'EOF'
133
- chore(baselines): refresh <kind> snapshot for <reason>
134
-
135
- <body explaining what changed, why the new floor is correct, and
136
- linking the upstream Story/Epic that triggered the refresh.>
137
-
138
- baseline-refresh: true
139
- Epic: #<epic-id>
140
- EOF
141
- )"
142
- ```
143
-
144
- Do NOT pass `--no-verify`. The `commit-msg` hook (commitlint) MUST run
145
- and MUST pass.
146
-
147
- ### Step 4 — Re-run the gate
148
-
149
- After the refresh commit lands on the Story branch, re-run
150
- `node .agents/scripts/check-baselines.js` to confirm the gate now passes
151
- against the refreshed snapshot. If it still fails, the refresh was
152
- incomplete (a sibling kind also drifted) — repeat from Step 1 for the
153
- remaining kind.
154
-
155
- ## Constraints
156
-
157
- - **Never** use a legacy ad-hoc token as the leading Conventional-Commits
158
- type in the commit subject. The allowed leading types are
159
- `feat|fix|chore|refactor|perf|docs|style|test|build|ci|revert` — this
160
- is enforced by commitlint locally and by the planning-time validator
161
- (`ticket-validator.js` → `validateAcceptanceSubjectPrefix`) at
162
- decompose time.
163
- - **Always** include a non-empty body. Empty-body refreshes are
164
- unreviewable and hide the operator decision behind a one-line subject.
165
- - **Always** include the `baseline-refresh: true` trailer when telemetry
166
- / observability classification matters. The trailer is the
167
- machine-readable marker going forward.
168
- - **Always** stage the baseline file(s) explicitly. A refresh commit
169
- whose diff also touches unrelated files is a contaminated refresh and
170
- the gate's "this floor is correct" semantics no longer hold.
171
- - **Never** refresh to paper over an unintentional regression. Refresh
172
- is "this is the new correct floor"; if the change isn't a deliberate
173
- one, fix the regression instead.
174
-
175
- ## Rationale anchor
176
-
177
- Epic #2501 retired the legacy `baseline-refresh` ad-hoc leading-token
178
- prescription in favor of the Conventional-Commits subject +
179
- `baseline-refresh: true` body-trailer shape documented above. See that
180
- Epic for the full migration history and the friction signals that
181
- motivated the change.
@@ -1,274 +0,0 @@
1
- ---
2
- name: ci-cd-and-automation
3
- description:
4
- Automates CI/CD pipeline setup. Use when setting up or modifying build and
5
- deployment pipelines. Use when you need to automate quality gates, configure
6
- test runners in CI, or establish deployment strategies.
7
- ---
8
-
9
- # CI/CD and Automation
10
-
11
- ## Policy Capsule
12
-
13
- - Every PR passes the same quality-gate pipeline before merge: **lint → typecheck → unit tests → build → integration tests → optional E2E → security audit → bundle-size**. Gates are ordered shift-left so cheap checks fail first.
14
- - **No gate may be skipped.** Failing lint means fix lint, not disable the rule. Failing a test means fix the code, not delete or `.skip` the test.
15
- - **Faster is safer.** Prefer many small, frequent releases over big-bang merges; one deploy of three changes is debuggable, one deploy of thirty is not.
16
- - Cache aggressively (npm cache, build cache) and split lint / typecheck / test into parallel jobs to keep PR feedback under ~10 minutes.
17
- - Use GitHub Secrets (or platform equivalent) for every credential — even in CI-only test databases. Never hardcode credentials in workflow YAML.
18
- - Wire preview deployments for every PR so reviewers can exercise the change in a production-like environment before merge.
19
- - Feed CI failure output verbatim back to the agent loop with the specific error and the directive to verify locally before re-pushing.
20
- - Treat the security audit (`npm audit` or equivalent) as gating: critical and high vulnerabilities reachable in production code MUST be remediated before merge.
21
- - Enforce a bundle-size budget in CI; a budget breach blocks the change just like a failing test.
22
-
23
- ## Overview
24
-
25
- Automate quality gates so that no change reaches production without passing
26
- tests, lint, type checking, and build. CI/CD is the enforcement mechanism for
27
- every other skill — it catches what humans and agents miss, and it does so
28
- consistently on every single change.
29
-
30
- **Shift Left:** Catch problems as early in the pipeline as possible. A bug
31
- caught in linting costs minutes; the same bug caught in production costs hours.
32
- Move checks upstream — static analysis before tests, tests before staging,
33
- staging before production.
34
-
35
- **Faster is Safer:** Smaller batches and more frequent releases reduce risk, not
36
- increase it. A deployment with 3 changes is easier to debug than one with 30.
37
- Frequent releases build confidence in the release process itself.
38
-
39
- ## When to Use
40
-
41
- - Setting up a new project's CI pipeline
42
- - Adding or modifying automated checks
43
- - Configuring deployment pipelines
44
- - When a change should trigger automated verification
45
- - Debugging CI failures
46
-
47
- ## The Quality Gate Pipeline
48
-
49
- Every change goes through these gates before merge:
50
-
51
- ```text
52
- Pull Request Opened
53
-
54
-
55
- ┌─────────────────┐
56
- │ LINT CHECK │ eslint, prettier
57
- │ ↓ pass │
58
- │ TYPE CHECK │ tsc --noEmit
59
- │ ↓ pass │
60
- │ UNIT TESTS │ jest/vitest
61
- │ ↓ pass │
62
- │ BUILD │ npm run build
63
- │ ↓ pass │
64
- │ INTEGRATION │ API/DB tests
65
- │ ↓ pass │
66
- │ E2E (optional) │ Playwright/Cypress
67
- │ ↓ pass │
68
- │ SECURITY AUDIT │ npm audit
69
- │ ↓ pass │
70
- │ BUNDLE SIZE │ bundlesize check
71
- └─────────────────┘
72
-
73
-
74
- Ready for review
75
- ```
76
-
77
- **No gate can be skipped.** If lint fails, fix lint — don't disable the rule. If
78
- a test fails, fix the code — don't skip the test.
79
-
80
- **Introducing a new gate that asserts on pre-existing state** (doc-drift,
81
- lint-vocabulary, dependency-cycle, missing-test-coverage) has its own
82
- hazard: the gate lands red because of latent findings nobody authored,
83
- and every downstream PR is blocked until someone hotfixes the integration
84
- branch. Before wiring such a gate into `requiredChecks`, read
85
- [`core/introducing-a-baseline-gate`](../introducing-a-baseline-gate/SKILL.md) —
86
- it covers the two landing shapes (advisory-first or
87
- populate-the-baseline) that keep the gate green at merge.
88
-
89
- ## CI Configuration (GitHub Actions)
90
-
91
- A representative pipeline for a Node project runs lint → type check → unit
92
- tests → build → security audit on every PR and push to `main`. Add
93
- integration jobs that spin up service containers (e.g. Postgres) and an E2E
94
- job that installs Playwright and uploads the report on failure.
95
-
96
- > See [`examples.md`](./examples.md) for full GitHub Actions YAML covering:
97
- >
98
- > - Basic CI pipeline (lint, types, tests, build, audit)
99
- > - Integration tests with a Postgres service container + Prisma migrations
100
- > - Playwright E2E with report artifacts
101
- > - Caching and parallelism (split lint/typecheck/test into separate jobs)
102
- >
103
- > Use GitHub Secrets for credentials — even in CI-only test databases — to
104
- > avoid normalizing hardcoded values that could leak into other contexts.
105
-
106
- ## Feeding CI Failures Back to Agents
107
-
108
- The power of CI with AI agents is the feedback loop. When CI fails:
109
-
110
- ```text
111
- CI fails
112
-
113
-
114
- Copy the failure output
115
-
116
-
117
- Feed it to the agent:
118
- "The CI pipeline failed with this error:
119
- [paste specific error]
120
- Fix the issue and verify locally before pushing again."
121
-
122
-
123
- Agent fixes → pushes → CI runs again
124
- ```
125
-
126
- **Key patterns:**
127
-
128
- ```text
129
- Lint failure → Agent runs `npm run lint --fix` and commits
130
- Type error → Agent reads the error location and fixes the type
131
- Test failure → Agent follows debugging-and-error-recovery skill
132
- Build error → Agent checks config and dependencies
133
- ```
134
-
135
- ## Deployment Strategies
136
-
137
- ### Preview Deployments
138
-
139
- Every PR gets a preview deployment for manual testing — most platforms (Vercel,
140
- Netlify, Cloudflare Pages) ship a one-step action you wire into the PR
141
- workflow. See [`examples.md`](./examples.md) for a representative Vercel
142
- preview-deploy job.
143
-
144
- ### Feature Flags
145
-
146
- Feature flags decouple deployment from release. Deploy incomplete or risky
147
- features behind flags so you can:
148
-
149
- - **Ship code without enabling it.** Merge to main early, enable when ready.
150
- - **Roll back without redeploying.** Disable the flag instead of reverting code.
151
- - **Canary new features.** Enable for 1% of users, then 10%, then 100%.
152
- - **Run A/B tests.** Compare behavior with and without the feature.
153
-
154
- **Flag lifecycle:** Create → Enable for testing → Canary → Full rollout →
155
- Remove the flag and dead code. Flags that live forever become technical debt —
156
- set a cleanup date when you create them. See [`examples.md`](./examples.md)
157
- for a minimal flag-check pattern.
158
-
159
- ### Staged Rollouts
160
-
161
- ```text
162
- PR merged to main
163
-
164
-
165
- Staging deployment (auto)
166
- │ Manual verification
167
-
168
- Production deployment (manual trigger or auto after staging)
169
-
170
-
171
- Monitor for errors (15-minute window)
172
-
173
- ├── Errors detected → Rollback
174
- └── Clean → Done
175
- ```
176
-
177
- ### Rollback Plan
178
-
179
- Every deployment should be reversible. Wire a `workflow_dispatch` job that
180
- takes a target version as input and re-deploys it; see
181
- [`examples.md`](./examples.md) for a representative manual-rollback workflow.
182
-
183
- ## Environment Management
184
-
185
- ```text
186
- .env.example → Committed (template for developers)
187
- .env → NOT committed (local development)
188
- .env.test → Committed (test environment, no real secrets)
189
- CI secrets → Stored in GitHub Secrets / vault
190
- Production secrets → Stored in deployment platform / vault
191
- ```
192
-
193
- CI should never have production secrets. Use separate secrets for CI testing.
194
-
195
- ## Automation Beyond CI
196
-
197
- ### Dependabot / Renovate
198
-
199
- Schedule dependency updates so they show up as PRs you can triage in batches
200
- rather than chasing security advisories ad hoc. A minimal `dependabot.yml` is
201
- in [`examples.md`](./examples.md); Renovate's config covers the same shape
202
- with more knobs.
203
-
204
- ### Build Cop Role
205
-
206
- Designate someone responsible for keeping CI green. When the build breaks, the
207
- Build Cop's job is to fix or revert — not the person whose change caused the
208
- break. This prevents broken builds from accumulating while everyone assumes
209
- someone else will fix it.
210
-
211
- ### PR Checks
212
-
213
- - **Required reviews:** At least 1 approval before merge
214
- - **Required status checks:** CI must pass before merge
215
- - **Branch protection:** No force-pushes to main
216
- - **Auto-merge:** If all checks pass and approved, merge automatically
217
-
218
- ## CI Optimization
219
-
220
- When the pipeline exceeds 10 minutes, apply these strategies in order of impact:
221
-
222
- ```text
223
- Slow CI pipeline?
224
- ├── Cache dependencies
225
- │ └── Use actions/cache or setup-node cache option for node_modules
226
- ├── Run jobs in parallel
227
- │ └── Split lint, typecheck, test, build into separate parallel jobs
228
- ├── Only run what changed
229
- │ └── Use path filters to skip unrelated jobs (e.g., skip e2e for docs-only PRs)
230
- ├── Use matrix builds
231
- │ └── Shard test suites across multiple runners
232
- ├── Optimize the test suite
233
- │ └── Remove slow tests from the critical path, run them on a schedule instead
234
- └── Use larger runners
235
- └── GitHub-hosted larger runners or self-hosted for CPU-heavy builds
236
- ```
237
-
238
- ### Example: Caching and Parallelism
239
-
240
- Split lint, typecheck, and test into separate jobs that each restore the npm
241
- cache via `actions/setup-node`'s `cache: 'npm'` option. See
242
- [`examples.md`](./examples.md) for a parallel three-job layout.
243
-
244
- ## Common Rationalizations
245
-
246
- | Rationalization | Reality |
247
- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
248
- | "CI is too slow" | Optimize the pipeline (see CI Optimization below), don't skip it. A 5-minute pipeline prevents hours of debugging. |
249
- | "This change is trivial, skip CI" | Trivial changes break builds. CI is fast for trivial changes anyway. |
250
- | "The test is flaky, just re-run" | Flaky tests mask real bugs and waste everyone's time. Fix the flakiness. |
251
- | "We'll add CI later" | Projects without CI accumulate broken states. Set it up on day one. |
252
- | "Manual testing is enough" | Manual testing doesn't scale and isn't repeatable. Automate what you can. |
253
-
254
- ## Red Flags
255
-
256
- - No CI pipeline in the project
257
- - CI failures ignored or silenced
258
- - Tests disabled in CI to make the pipeline pass
259
- - Production deploys without staging verification
260
- - No rollback mechanism
261
- - Secrets stored in code or CI config files (not secrets manager)
262
- - Long CI times with no optimization effort
263
-
264
- ## Verification
265
-
266
- After setting up or modifying CI:
267
-
268
- - [ ] All quality gates are present (lint, types, tests, build, audit)
269
- - [ ] Pipeline runs on every PR and push to main
270
- - [ ] Failures block merge (branch protection configured)
271
- - [ ] CI results feed back into the development loop
272
- - [ ] Secrets are stored in the secrets manager, not in code
273
- - [ ] Deployment has a rollback mechanism
274
- - [ ] Pipeline runs in under 10 minutes for the test suite