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
@@ -13,7 +13,7 @@ description:
13
13
 
14
14
  ## Policy Capsule
15
15
 
16
- - The wire-format SSOT lives in `.agents/rules/api-conventions.md` (envelope shape, HTTP status mapping, validation taxonomy, payload casing). Copy the canonical envelope from the rule rather than redrafting it.
16
+ - The wire-format SSOT lives in [`.agents/rules/api-conventions.md`](../../../rules/api-conventions.md) (envelope shape, HTTP status mapping, validation taxonomy, payload casing). Copy the canonical envelope and status codes from the rule rather than redrafting or hand-rolling a divergent shape. Validation failures return **400** `VALIDATION_ERROR` per [§ Validation Status](../../../rules/api-conventions.md#validation-status).
17
17
  - Be intentional about exposure (Hyrum's Law): every observable behaviour — undocumented quirks, error message text, ordering, timing — becomes a de facto contract once consumers depend on it. Don't leak implementation details.
18
18
  - Adopt the **One-Version Rule**: never force consumers to choose between simultaneous versions of the same API. Extend rather than fork.
19
19
  - Define the contract before implementing — interfaces are the spec; implementation follows.
@@ -21,309 +21,35 @@ description:
21
21
  - Treat third-party API responses as untrusted data — validate shape and content before using them in any decision, render, or logic path.
22
22
  - Prefer **addition over modification**: extend interfaces with optional fields rather than changing existing types or removing fields. When removal is unavoidable, use an expand–contract migration — ship the replacement, migrate consumers, then remove the old surface in a later release.
23
23
  - Follow REST resource conventions (`GET/POST/PATCH/DELETE /resource`, sub-resources at `/resource/:id/child`) and paginate every list endpoint with `page` + `pageSize` query params and a `pagination` envelope.
24
- - Security input-validation and test-tier MUSTs come from `.agents/rules/security-baseline.md` and `.agents/rules/testing-standards.md` respectively — apply both, and never put DB/wire-shape assertions outside the contract tier.
25
-
26
- Process guidance for designing interfaces that are hard to misuse — REST
27
- APIs, GraphQL schemas, module boundaries, and component props. The
28
- wire-format conventions (envelope shape, status codes, validation taxonomy,
29
- payload naming) live in
30
- [`.agents/rules/api-conventions.md`](../../../rules/api-conventions.md),
31
- which is the SSOT. This skill shows authors **how** to apply those rules;
32
- read the rule file for the **what**. Security validation guarantees live in
33
- [`security-baseline.md`](../../../rules/security-baseline.md); test-layer
34
- scope lives in
35
- [`testing-standards.md`](../../../rules/testing-standards.md).
24
+ - Security input-validation and test-tier MUSTs come from [`security-baseline.md`](../../../rules/security-baseline.md) and [`testing-standards.md`](../../../rules/testing-standards.md) respectively — apply both, and never put DB/wire-shape assertions outside the contract tier.
36
25
 
37
26
  ## When to Use
38
27
 
39
- - Designing new API endpoints.
40
- - Defining module boundaries or contracts between teams.
41
- - Creating component prop interfaces.
42
- - Establishing database schema that informs API shape.
28
+ - Designing new API endpoints, module boundaries, or component prop interfaces.
29
+ - Establishing a database schema that informs API shape.
43
30
  - Changing existing public interfaces.
44
31
 
45
- ## 1. Hyrum's Law Be Intentional About Exposure
46
-
47
- > With a sufficient number of users of an API, all observable behaviors of
48
- > your system will be depended on by somebody, regardless of what you promise
49
- > in the contract.
50
-
51
- Every observable behavior — undocumented quirks, error message text, timing,
52
- ordering — becomes a de facto contract once users depend on it. Implications:
53
-
54
- - **Be intentional about what you expose.** Every observable behavior is a
55
- potential commitment.
56
- - **Don't leak implementation details.** If users can observe it, they will
57
- depend on it.
58
- - **Plan for deprecation at design time.** Remove things users depend on via
59
- expand–contract: add the replacement, migrate consumers behind a deprecation
60
- window, then delete the old surface — never break a published contract in one
61
- step.
62
- - **Tests are not enough.** Even with perfect contract tests, "safe" changes
63
- can break real users who depend on undocumented behavior.
64
-
65
- ## 2. The One-Version Rule
66
-
67
- Avoid forcing consumers to choose between multiple versions of the same
68
- dependency or API. Diamond dependency problems arise when different consumers
69
- need different versions of the same thing. Design for a world where only one
70
- version exists at a time — extend rather than fork.
71
-
72
- ## 3. Contract First
73
-
74
- Define the interface before implementing it. The contract is the spec —
75
- implementation follows.
76
-
77
- ```typescript
78
- interface TaskAPI {
79
- // Creates a task and returns the created task with server-generated fields
80
- createTask(input: CreateTaskInput): Promise<Task>;
81
-
82
- // Returns paginated tasks matching filters
83
- listTasks(params: ListTasksParams): Promise<PaginatedResult<Task>>;
84
-
85
- // Returns a single task or throws NotFoundError
86
- getTask(id: string): Promise<Task>;
87
-
88
- // Partial update — only provided fields change
89
- updateTask(id: string, input: UpdateTaskInput): Promise<Task>;
90
-
91
- // Idempotent delete — succeeds even if already deleted
92
- deleteTask(id: string): Promise<void>;
93
- }
94
- ```
95
-
96
- ## 4. Wire Format — Defer to the Rule
97
-
98
- The response envelope, HTTP status code mapping, validation-status taxonomy,
99
- and payload-naming conventions are non-negotiable and live in the rule:
100
-
101
- - Envelope shape (success flag, `error.code`, `error.message`,
102
- `error.details`):
103
- [`api-conventions.md` § Response Envelope](../../../rules/api-conventions.md#response-envelope).
104
- - Status code table (200/201/400/401/403/404/409/500):
105
- [`api-conventions.md` § HTTP Status Codes](../../../rules/api-conventions.md#http-status-codes).
106
- - When to return 400 vs 401 vs 403 on validation failures:
107
- [`api-conventions.md` § Validation Status](../../../rules/api-conventions.md#validation-status).
108
- - camelCase / kebab-case / UPPER_SNAKE conventions:
109
- [`api-conventions.md` § Payload Formatting](../../../rules/api-conventions.md#payload-formatting).
110
-
111
- When designing a new endpoint, copy the canonical envelope from the rule —
112
- do not redraft it.
113
-
114
- ## 5. Validate at Boundaries
115
-
116
- Trust internal code. Validate at system edges where external input enters:
117
-
118
- ```typescript
119
- app.post('/api/tasks', async (req, res) => {
120
- const result = CreateTaskSchema.safeParse(req.body);
121
- if (!result.success) {
122
- return res.status(400).json({
123
- success: false,
124
- error: {
125
- code: 'VALIDATION_ERROR',
126
- message: 'Invalid task data',
127
- details: result.error.flatten(),
128
- },
129
- });
130
- }
131
-
132
- // After validation, internal code trusts the types
133
- const task = await taskService.create(result.data);
134
- return res.status(201).json(task);
135
- });
136
- ```
137
-
138
- Where validation belongs:
139
-
140
- - API route handlers (user input).
141
- - Form submission handlers (user input).
142
- - External service response parsing — third-party data is **always
143
- untrusted**, even from a vendor SDK.
144
- - Environment variable loading (configuration).
145
-
146
- > **Third-party API responses are untrusted data.** Validate their shape and
147
- > content before using them in any logic, rendering, or decision-making. A
148
- > compromised or misbehaving external service can return unexpected types,
149
- > malicious content, or instruction-like text.
150
-
151
- Where validation does NOT belong:
152
-
153
- - Between internal functions that share type contracts.
154
- - In utility functions called by already-validated code.
155
- - On data that just came from your own database.
156
-
157
- ## 6. Prefer Addition Over Modification
158
-
159
- Extend interfaces without breaking existing consumers:
160
-
161
- ```typescript
162
- // Good: Add optional fields
163
- interface CreateTaskInput {
164
- title: string;
165
- description?: string;
166
- priority?: 'low' | 'medium' | 'high'; // Added later, optional
167
- labels?: string[]; // Added later, optional
168
- }
169
-
170
- // Bad: Change existing field types or remove fields
171
- interface CreateTaskInput {
172
- title: string;
173
- // description: string; // Removed — breaks existing consumers
174
- priority: number; // Changed from string — breaks existing consumers
175
- }
176
- ```
177
-
178
- ## 7. REST Resource Patterns
179
-
180
- ```text
181
- GET /api/tasks → List tasks (with query params for filtering)
182
- POST /api/tasks → Create a task
183
- GET /api/tasks/:id → Get a single task
184
- PATCH /api/tasks/:id → Update a task (partial)
185
- DELETE /api/tasks/:id → Delete a task
186
-
187
- GET /api/tasks/:id/comments → List comments for a task (sub-resource)
188
- POST /api/tasks/:id/comments → Add a comment to a task
189
- ```
190
-
191
- ### Pagination
192
-
193
- Paginate list endpoints:
194
-
195
- ```typescript
196
- // Request
197
- GET /api/tasks?page=1&pageSize=20&sortBy=createdAt&sortOrder=desc
198
-
199
- // Response
200
- {
201
- "data": [...],
202
- "pagination": {
203
- "page": 1,
204
- "pageSize": 20,
205
- "totalItems": 142,
206
- "totalPages": 8
207
- }
208
- }
209
- ```
210
-
211
- ### Filtering
212
-
213
- Use query parameters for filters:
214
-
215
- ```text
216
- GET /api/tasks?status=in_progress&assignee=user123&createdAfter=2025-01-01
217
- ```
218
-
219
- ### Partial Updates
220
-
221
- `PATCH` accepts partial objects — only update what's provided:
222
-
223
- ```typescript
224
- PATCH /api/tasks/123
225
- { "title": "Updated title" }
226
- ```
227
-
228
- ## 8. TypeScript Interface Patterns
229
-
230
- ### Discriminated Unions for Variants
231
-
232
- ```typescript
233
- type TaskStatus =
234
- | { type: 'pending' }
235
- | { type: 'in_progress'; assignee: string; startedAt: Date }
236
- | { type: 'completed'; completedAt: Date; completedBy: string }
237
- | { type: 'cancelled'; reason: string; cancelledAt: Date };
238
-
239
- function getStatusLabel(status: TaskStatus): string {
240
- switch (status.type) {
241
- case 'pending':
242
- return 'Pending';
243
- case 'in_progress':
244
- return `In progress (${status.assignee})`;
245
- case 'completed':
246
- return `Done on ${status.completedAt}`;
247
- case 'cancelled':
248
- return `Cancelled: ${status.reason}`;
249
- }
250
- }
251
- ```
252
-
253
- ### Input/Output Separation
254
-
255
- ```typescript
256
- // Input: what the caller provides
257
- interface CreateTaskInput {
258
- title: string;
259
- description?: string;
260
- }
261
-
262
- // Output: what the system returns (includes server-generated fields)
263
- interface Task {
264
- id: string;
265
- title: string;
266
- description: string | null;
267
- createdAt: Date;
268
- updatedAt: Date;
269
- createdBy: string;
270
- }
271
- ```
272
-
273
- ### Branded Types for IDs
274
-
275
- ```typescript
276
- type TaskId = string & { readonly __brand: 'TaskId' };
277
- type UserId = string & { readonly __brand: 'UserId' };
278
-
279
- // Prevents accidentally passing a UserId where a TaskId is expected
280
- function getTask(id: TaskId): Promise<Task> { ... }
281
- ```
282
-
283
- ## 9. Common Rationalizations
284
-
285
- | Rationalization | Reality |
286
- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
287
- | "We'll document the API later" | The types ARE the documentation. Define them first. |
288
- | "We don't need pagination for now" | You will the moment someone has 100+ items. Add it from the start. |
289
- | "PATCH is complicated, let's just use PUT" | PUT requires the full object every time. PATCH is what clients actually want. |
290
- | "We'll version the API when we need to" | Breaking changes without versioning break consumers. Design for extension from the start. |
291
- | "Nobody uses that undocumented behavior" | Hyrum's Law: if it's observable, somebody depends on it. Treat every public behavior as a commitment. |
292
- | "We can just maintain two versions" | Multiple versions multiply maintenance cost and create diamond dependency problems. Prefer the One-Version Rule. |
293
- | "Internal APIs don't need contracts" | Internal consumers are still consumers. Contracts prevent coupling and enable parallel work. |
294
-
295
- ## 10. Red Flags
296
-
297
- - Endpoints that return different envelope shapes depending on conditions
298
- (the rule fixes the shape — see § 4).
299
- - Validation scattered throughout internal code instead of at boundaries.
300
- - Breaking changes to existing fields (type changes, removals).
301
- - List endpoints without pagination.
302
- - Verbs in REST URLs (`/api/createTask`, `/api/getUsers`).
303
- - Third-party API responses used without validation or sanitization.
32
+ ## Wire formatdefer to the rule
304
33
 
305
- ## 11. Authoring Checklist
34
+ The response envelope, HTTP status-code mapping, validation-status taxonomy,
35
+ and payload-naming conventions are non-negotiable and live in the rule. When
36
+ designing a new endpoint, **copy the canonical envelope from the rule** — do
37
+ not redraft it, and do not invent a project-specific validation status:
306
38
 
307
- Before opening a PR that adds or edits an API surface:
39
+ - Envelope shape: [`api-conventions.md` § Response Envelope](../../../rules/api-conventions.md#response-envelope).
40
+ - Status table (200/201/400/401/403/404/409/500): [`§ HTTP Status Codes`](../../../rules/api-conventions.md#http-status-codes).
41
+ - Validation status (**400** `VALIDATION_ERROR`): [`§ Validation Status`](../../../rules/api-conventions.md#validation-status).
42
+ - Casing conventions: [`§ Payload Formatting`](../../../rules/api-conventions.md#payload-formatting).
308
43
 
309
- - [ ] Every endpoint has typed input and output schemas.
310
- - [ ] Error responses follow the envelope in
311
- [`api-conventions.md` § Response Envelope](../../../rules/api-conventions.md#response-envelope).
312
- - [ ] Status codes match
313
- [`api-conventions.md` § HTTP Status Codes](../../../rules/api-conventions.md#http-status-codes).
314
- - [ ] Validation runs at the API boundary and returns the canonical
315
- `VALIDATION_ERROR` shape on failure.
316
- - [ ] List endpoints support pagination.
317
- - [ ] New fields are additive and optional (backward compatible).
318
- - [ ] Naming follows
319
- [`api-conventions.md` § Payload Formatting](../../../rules/api-conventions.md#payload-formatting).
320
- - [ ] API documentation or types are committed alongside the implementation.
44
+ ## Long-form reference read on demand
321
45
 
322
- ## 12. Cross-References
46
+ The elaboration behind the capsule — Hyrum's-Law implications, the
47
+ contract-first stance, and where boundary validation does and does not belong,
48
+ plus the pre-PR authoring checklist — lives in the on-demand sibling
49
+ [`reference.md`](reference.md). Generic REST-catalog and TypeScript-idiom
50
+ snippets are intentionally omitted (frontier-known; the rule owns the wire
51
+ format). Open a section only when the task engages it.
323
52
 
324
- - SSOT rules:
325
- [`.agents/rules/api-conventions.md`](../../../rules/api-conventions.md).
326
- - Security validation guarantees:
327
- [`security-baseline.md`](../../../rules/security-baseline.md).
328
- - Test-layer scope:
329
- [`testing-standards.md`](../../../rules/testing-standards.md).
53
+ - [Hyrum's Law and the One-Version Rule](reference.md#hyrums-law-and-the-one-version-rule)
54
+ - [Contract First and Boundary Validation](reference.md#contract-first-and-boundary-validation)
55
+ - [Authoring Checklist](reference.md#authoring-checklist)
@@ -0,0 +1,76 @@
1
+ # API & Interface Design — Reference (on-demand)
2
+
3
+ **Read this when** a task engages one of the sections below and the Policy
4
+ Capsule in [`SKILL.md`](SKILL.md) does not settle it on its own. The capsule
5
+ is the contract; this file is the reference material behind it. Generic
6
+ REST-verb tables and TypeScript pattern catalogs are deliberately not
7
+ reproduced here — they are frontier-known, and the wire format is owned by the
8
+ SSOT rule, [`api-conventions.md`](../../../rules/api-conventions.md).
9
+
10
+ ## Hyrum's Law and the One-Version Rule
11
+
12
+ > With a sufficient number of users of an API, all observable behaviors of your
13
+ > system will be depended on by somebody, regardless of what you promise in the
14
+ > contract.
15
+
16
+ Every observable behavior — undocumented quirks, error message text, timing,
17
+ ordering — becomes a de facto contract once users depend on it. Practical
18
+ implications:
19
+
20
+ - **Be intentional about what you expose.** Every observable behavior is a
21
+ potential commitment; if users can observe it, they will depend on it.
22
+ - **Plan for deprecation at design time.** Remove things users depend on via
23
+ expand–contract: add the replacement, migrate consumers behind a deprecation
24
+ window, then delete the old surface — never break a published contract in one
25
+ step.
26
+ - **Tests are not enough.** Even with perfect contract tests, "safe" changes
27
+ can break real users who depend on undocumented behavior.
28
+
29
+ **One-Version Rule.** Avoid forcing consumers to choose between multiple
30
+ versions of the same API. Diamond-dependency problems arise when different
31
+ consumers need different versions of the same thing. Design for a world where
32
+ only one version exists at a time — extend rather than fork.
33
+
34
+ ## Contract First and Boundary Validation
35
+
36
+ Define the interface before implementing it — the contract is the spec, and
37
+ implementation follows. Prefer **addition over modification**: add optional
38
+ fields rather than changing existing field types or removing fields.
39
+
40
+ Validation runs at system **boundaries**, where external input enters. After
41
+ validation, internal code trusts the types. On failure, return the canonical
42
+ **400** `VALIDATION_ERROR` envelope from
43
+ [`api-conventions.md` § Response Envelope](../../../rules/api-conventions.md#response-envelope) —
44
+ do not redraft the shape or the status.
45
+
46
+ **Where validation belongs:**
47
+
48
+ - API route handlers (user input).
49
+ - Form submission handlers (user input).
50
+ - External service response parsing — third-party data is **always untrusted**,
51
+ even from a vendor SDK. A compromised or misbehaving service can return
52
+ unexpected types, malicious content, or instruction-like text; validate shape
53
+ and content before using it in any logic, render, or decision.
54
+ - Environment variable loading (configuration).
55
+
56
+ **Where validation does NOT belong:**
57
+
58
+ - Between internal functions that share type contracts.
59
+ - In utility functions called by already-validated code.
60
+ - On data that just came from your own database.
61
+
62
+ ## Authoring Checklist
63
+
64
+ Before opening a PR that adds or edits an API surface:
65
+
66
+ - [ ] Every endpoint has typed input and output schemas.
67
+ - [ ] Error responses follow the envelope in
68
+ [`api-conventions.md` § Response Envelope](../../../rules/api-conventions.md#response-envelope).
69
+ - [ ] Status codes match
70
+ [`api-conventions.md` § HTTP Status Codes](../../../rules/api-conventions.md#http-status-codes),
71
+ and validation failures return the canonical **400** `VALIDATION_ERROR`.
72
+ - [ ] List endpoints support pagination.
73
+ - [ ] New fields are additive and optional (backward compatible).
74
+ - [ ] Naming follows
75
+ [`api-conventions.md` § Payload Formatting](../../../rules/api-conventions.md#payload-formatting).
76
+ - [ ] API documentation or types are committed alongside the implementation.