@yemi33/minions 0.1.2423 → 0.1.2425

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 (184) hide show
  1. package/bin/install-internal-minions.js +1209 -0
  2. package/bin/minions.js +75 -9
  3. package/dashboard/docs/typography.md +27 -12
  4. package/dashboard/js/command-center.js +13 -11
  5. package/dashboard/js/live-stream.js +1 -1
  6. package/dashboard/js/memory-search.js +388 -43
  7. package/dashboard/js/modal-qa.js +5 -5
  8. package/dashboard/js/qa.js +39 -26
  9. package/dashboard/js/refresh.js +37 -18
  10. package/dashboard/js/render-agents.js +14 -18
  11. package/dashboard/js/render-dispatch.js +14 -74
  12. package/dashboard/js/render-inbox.js +3 -3
  13. package/dashboard/js/render-meetings.js +8 -8
  14. package/dashboard/js/render-other.js +45 -20
  15. package/dashboard/js/render-pipelines.js +6 -6
  16. package/dashboard/js/render-plans.js +14 -14
  17. package/dashboard/js/render-prd.js +46 -46
  18. package/dashboard/js/render-prs.js +9 -65
  19. package/dashboard/js/render-schedules.js +5 -5
  20. package/dashboard/js/render-skills.js +6 -6
  21. package/dashboard/js/render-utils.js +4 -4
  22. package/dashboard/js/render-watches.js +4 -16
  23. package/dashboard/js/render-work-items.js +95 -107
  24. package/dashboard/js/settings.js +175 -74
  25. package/dashboard/layout.html +3 -2
  26. package/dashboard/pages/inbox.html +1 -1
  27. package/dashboard/pages/work.html +1 -1
  28. package/dashboard/shared/model-display.js +9 -0
  29. package/dashboard/shared/watches-source.js +43 -0
  30. package/dashboard/shared/welcome-popup.js +259 -0
  31. package/dashboard/slim/body.html +6 -6
  32. package/dashboard/slim/js/chat.js +4 -2
  33. package/dashboard/slim/js/history.js +10 -3
  34. package/dashboard/slim/js/modals-tiles.js +85 -16
  35. package/dashboard/slim/js/status.js +12 -16
  36. package/dashboard/slim/styles.css +24 -4
  37. package/dashboard/styles.css +62 -27
  38. package/dashboard-build.js +8 -2
  39. package/dashboard.js +3854 -2514
  40. package/docs/README.md +6 -4
  41. package/docs/api-errors.md +144 -0
  42. package/docs/auto-discovery.md +83 -61
  43. package/docs/capture-demos.js +173 -30
  44. package/docs/command-center.md +5 -1
  45. package/docs/completion-reports.md +127 -11
  46. package/docs/constants.md +15 -3
  47. package/docs/constellation-style-telemetry.md +2 -2
  48. package/docs/copilot-cli-schema.md +32 -22
  49. package/docs/cross-repo-plans.md +30 -30
  50. package/docs/demo/memory-system.html +1 -1
  51. package/docs/deprecated.json +132 -18
  52. package/docs/diagnostics-memory.md +8 -4
  53. package/docs/human-vs-automated.md +2 -2
  54. package/docs/internal-install.md +190 -0
  55. package/docs/kb-pr3223-cascade-archiving.md +16 -0
  56. package/docs/kb-pr696-merge-conflict-docs.md +23 -0
  57. package/docs/kb-sweep.md +2 -2
  58. package/docs/keep-processes.md +8 -1
  59. package/docs/live-checkout-mode.md +12 -7
  60. package/docs/managed-spawn.md +21 -3
  61. package/docs/named-agents.md +3 -2
  62. package/docs/plan-lifecycle.md +32 -32
  63. package/docs/pr-auto-fix-dispatch.md +3 -3
  64. package/docs/pr-review-fix-loop.md +6 -6
  65. package/docs/pr-screenshots/pr-899/worker-pool-worktrees-AFTER.png +0 -0
  66. package/docs/pr-screenshots/pr-899/worker-pool-worktrees-BEFORE.png +0 -0
  67. package/docs/pr-screenshots/pr-979/auto-fix-pane-AFTER.png +0 -0
  68. package/docs/pr-screenshots/pr-979/auto-fix-pane-BEFORE.png +0 -0
  69. package/docs/pr-screenshots/pr-985/pr-column-em-dash-AFTER.png +0 -0
  70. package/docs/pr-screenshots/pr-985/pr-column-em-dash-BEFORE.png +0 -0
  71. package/docs/qa-runbook-lifecycle.md +67 -51
  72. package/docs/qa-runbooks.md +2 -2
  73. package/docs/runtime-adapters.md +101 -50
  74. package/docs/security.md +28 -0
  75. package/docs/self-improvement.md +47 -13
  76. package/docs/skills.md +29 -0
  77. package/docs/slim-ux/concepts.md +2 -2
  78. package/docs/specs/agent-configurability.md +43 -41
  79. package/docs/specs/agent-rename.md +13 -13
  80. package/docs/team-memory.md +283 -14
  81. package/docs/tutorials/03-plan-driven-feature.md +3 -3
  82. package/docs/tutorials/04-runtimes-and-harness.md +18 -21
  83. package/docs/tutorials/08-operations-and-recovery.md +3 -2
  84. package/docs/tutorials/README.md +4 -3
  85. package/docs/visual-evidence-ci.md +103 -0
  86. package/docs/watches.md +35 -30
  87. package/docs/worktree-lifecycle.md +151 -13
  88. package/engine/acp-transport.js +1 -0
  89. package/engine/ado.js +80 -33
  90. package/engine/agent-api-validation.js +571 -0
  91. package/engine/agent-worker-pool.js +7 -6
  92. package/engine/api-contracts/agent-content.js +761 -0
  93. package/engine/api-contracts/cc-ops.js +219 -0
  94. package/engine/api-contracts/config-runtime.js +419 -0
  95. package/engine/api-contracts/core.js +138 -0
  96. package/engine/api-contracts/index.js +506 -0
  97. package/engine/api-contracts/orchestration.js +602 -0
  98. package/engine/api-contracts/pull-requests.js +323 -0
  99. package/engine/api-contracts/qa-process.js +764 -0
  100. package/engine/api-contracts/work-plan-prd.js +494 -0
  101. package/engine/api-validation.js +543 -0
  102. package/engine/cc-api-validation.js +586 -0
  103. package/engine/cc-worker-pool.js +9 -1
  104. package/engine/cleanup.js +393 -271
  105. package/engine/cli.js +65 -7
  106. package/engine/comment-classifier.js +70 -5
  107. package/engine/consolidation.js +123 -5
  108. package/engine/content-api-validation.js +606 -0
  109. package/engine/create-pr-worktree.js +22 -1
  110. package/engine/db/migrations/027-review-learning-lifecycle.js +162 -0
  111. package/engine/dispatch.js +33 -0
  112. package/engine/distribution.js +189 -0
  113. package/engine/execution-model.js +59 -0
  114. package/engine/features.js +12 -0
  115. package/engine/github.js +67 -25
  116. package/engine/harness-context.js +313 -0
  117. package/engine/inbox-store.js +1 -1
  118. package/engine/kb-sweep.js +161 -38
  119. package/engine/keep-process-sweep.js +43 -3
  120. package/engine/lifecycle.js +1066 -165
  121. package/engine/llm.js +4 -0
  122. package/engine/managed-spawn.js +463 -48
  123. package/engine/meeting.js +197 -34
  124. package/engine/memory-retrieval.js +280 -0
  125. package/engine/memory-store.js +821 -38
  126. package/engine/model-discovery.js +17 -3
  127. package/engine/pipeline.js +802 -14
  128. package/engine/plan-prd-validation.js +745 -0
  129. package/engine/playbook.js +206 -17
  130. package/engine/pooled-agent-process.js +6 -1
  131. package/engine/pr-action.js +1 -1
  132. package/engine/pr-issue-validation.js +653 -0
  133. package/engine/pr-resolve.js +75 -13
  134. package/engine/prd-store.js +39 -6
  135. package/engine/preflight.js +7 -2
  136. package/engine/process-utils.js +79 -31
  137. package/engine/projects.js +198 -12
  138. package/engine/promotion.js +371 -0
  139. package/engine/qa-from-prd.js +3 -0
  140. package/engine/qa-process-validation.js +572 -0
  141. package/engine/qa-runbooks.js +41 -37
  142. package/engine/qa-runners/maestro.js +11 -7
  143. package/engine/qa-runners/playwright.js +37 -14
  144. package/engine/qa-runners.js +9 -10
  145. package/engine/qa-runs.js +124 -11
  146. package/engine/qa-sessions.js +139 -40
  147. package/engine/quarantine-refs.js +81 -11
  148. package/engine/queries.js +163 -9
  149. package/engine/review-learning-backfill.js +482 -0
  150. package/engine/review-learning.js +1236 -0
  151. package/engine/runtimes/claude.js +60 -2
  152. package/engine/runtimes/codex.js +57 -16
  153. package/engine/runtimes/contract.js +21 -0
  154. package/engine/runtimes/copilot.js +51 -3
  155. package/engine/runtimes/index.js +1 -0
  156. package/engine/scheduler.js +201 -32
  157. package/engine/settings-validation.js +909 -0
  158. package/engine/shared.js +705 -208
  159. package/engine/spawn-agent.js +48 -21
  160. package/engine/steering-constraints.js +31 -0
  161. package/engine/steering-store.js +10 -2
  162. package/engine/steering.js +14 -2
  163. package/engine/timeout.js +404 -111
  164. package/engine/untrusted-fence.js +24 -10
  165. package/engine/watch-actions.js +7 -2
  166. package/engine/watches.js +353 -51
  167. package/engine/work-item-validation.js +561 -0
  168. package/engine/work-items-store.js +61 -1
  169. package/engine/worktree-gc.js +656 -37
  170. package/engine/worktree-preflight.js +154 -0
  171. package/engine.js +2068 -342
  172. package/package.json +1 -1
  173. package/playbooks/_pr-description-audit.md +88 -41
  174. package/playbooks/build-fix-complex.md +3 -3
  175. package/playbooks/docs.md +2 -2
  176. package/playbooks/fix.md +18 -18
  177. package/playbooks/implement.md +18 -18
  178. package/playbooks/qa-session-draft.md +10 -12
  179. package/playbooks/qa-session-execute.md +16 -12
  180. package/playbooks/qa-validate.md +8 -7
  181. package/playbooks/shared-rules.md +45 -0
  182. package/playbooks/test.md +4 -0
  183. package/prompts/cc-system.md +1 -1
  184. package/skills/check-self-authored-review-comment/SKILL.md +2 -2
@@ -0,0 +1,494 @@
1
+ 'use strict';
2
+
3
+ const AUDITED_NEGATIVE_TESTS = Object.freeze([{
4
+ strategy: 'isolated-http-invalid-input-state-snapshot',
5
+ expectedStatus: '400-or-409',
6
+ audit: 'audited',
7
+ }]);
8
+
9
+ module.exports = {
10
+ owner: 'work-plan-prd',
11
+ routes: [
12
+ 'GET /api/work-items',
13
+ 'GET /api/prd',
14
+ 'GET /api/archived-prds',
15
+ 'GET /api/verify-guides',
16
+ 'POST /api/work-items',
17
+ 'POST /api/work-items/update',
18
+ 'POST /api/work-items/retry',
19
+ 'POST /api/work-items/delete',
20
+ 'POST /api/work-items/cancel',
21
+ 'POST /api/work-items/archive',
22
+ 'GET /api/work-items/archive',
23
+ 'POST /api/work-items/reopen',
24
+ 'POST /api/work-items/feedback',
25
+ 'GET /api/work-items/<id>',
26
+ 'POST /api/plan',
27
+ 'GET /api/plans',
28
+ 'POST /api/plans/trigger-verify',
29
+ 'POST /api/plans/approve',
30
+ 'POST /api/plans/pause',
31
+ 'POST /api/plans/execute',
32
+ 'POST /api/plans/reject',
33
+ 'POST /api/plans/regenerate',
34
+ 'POST /api/plans/delete',
35
+ 'POST /api/plans/archive',
36
+ 'POST /api/plans/unarchive',
37
+ 'POST /api/plans/revise',
38
+ 'POST /api/plans/discuss',
39
+ 'GET /api/plans/archive/<file>',
40
+ 'GET /api/plans/<file>',
41
+ 'POST /api/prd-items',
42
+ 'POST /api/prd-items/update',
43
+ 'POST /api/prd-items/remove',
44
+ 'POST /api/plans/create',
45
+ ],
46
+ overrides: {
47
+ // Read-side list endpoints that actively reject any query string via
48
+ // planPrdValidation.validateNoQuery — declared explicitly so they stay
49
+ // certified as audited rather than defaulting to pending-audit.
50
+ 'GET /api/prd': {
51
+ query: { policy: 'none', rationale: 'Handler rejects any query string (planPrdValidation.validateNoQuery).' },
52
+ },
53
+ 'GET /api/archived-prds': {
54
+ query: { policy: 'none', rationale: 'Handler rejects any query string (planPrdValidation.validateNoQuery).' },
55
+ },
56
+ 'GET /api/verify-guides': {
57
+ query: { policy: 'none', rationale: 'Handler rejects any query string (planPrdValidation.validateNoQuery).' },
58
+ },
59
+ 'GET /api/plans': {
60
+ query: { policy: 'none', rationale: 'Handler rejects any query string (planPrdValidation.validateNoQuery).' },
61
+ },
62
+ 'POST /api/work-items': {
63
+ audit: 'audited',
64
+ body: {
65
+ policy: 'required',
66
+ fields: [
67
+ { name: 'title', type: 'string', required: true },
68
+ { name: 'type', type: 'string', required: false, allowedValuesSource: 'shared.WORK_TYPE' },
69
+ { name: 'description', type: 'string', required: false },
70
+ { name: 'priority', type: 'string', required: false, allowedValuesSource: 'shared.WORK_ITEM_PRIORITY_VALUES' },
71
+ { name: 'project', type: 'string', required: false, allowedValuesSource: 'config.projects[].name' },
72
+ { name: 'agent', type: 'string', required: false, allowedValuesSource: 'config.agents keys' },
73
+ { name: 'agents', type: 'string|array<string>', required: false, allowedValuesSource: 'config.agents keys' },
74
+ { name: 'scope', type: 'string', required: false, allowedValues: ['fan-out'] },
75
+ { name: 'references', type: 'array<object>', required: false },
76
+ { name: 'acceptanceCriteria', type: 'array|string', required: false },
77
+ { name: 'depends_on', type: 'array<string>', required: false },
78
+ { name: 'skipPr', type: 'boolean', required: false },
79
+ { name: 'oneShot', type: 'boolean', required: false },
80
+ { name: 'agentLock', type: 'boolean', required: false },
81
+ { name: 'hardAgent', type: 'boolean', required: false },
82
+ { name: 'meta', type: 'object', required: false },
83
+ { name: 'meta.pr_followup', type: 'object', required: false },
84
+ { name: 'meta.workdir', type: 'string', required: false },
85
+ { name: 'planFile', type: 'string', required: false },
86
+ { name: 'branch', type: 'string', required: false },
87
+ { name: 'branchStrategy', type: 'string', required: false },
88
+ { name: 'featureBranch', type: 'string', required: false },
89
+ { name: 'targetPr', type: 'string|integer', required: false },
90
+ { name: 'pr_id', type: 'string|integer', required: false },
91
+ { name: 'prUrl', type: 'string|integer', required: false },
92
+ { name: 'prNumber', type: 'integer|string', required: false },
93
+ ],
94
+ },
95
+ headers: {
96
+ policy: 'optional',
97
+ fields: [
98
+ { name: 'X-Minions-Agent', type: 'string', required: false },
99
+ { name: 'X-Minions-Origin-Wi', type: 'string', required: false },
100
+ ],
101
+ },
102
+ aliases: [
103
+ { name: 'agents', canonical: 'agent routing hints', location: 'body', type: 'string|array' },
104
+ { name: 'acceptanceCriteria', canonical: 'acceptanceCriteria[]', location: 'body', type: 'string|array' },
105
+ { name: 'hardAgent', canonical: 'agentLock', location: 'body', type: 'boolean' },
106
+ ],
107
+ constraints: [
108
+ { rule: 'worktree-requiring types require a configured project unless exactly one project exists' },
109
+ { rule: 'plan-to-prd requires planFile' },
110
+ { rule: 'follow-up dedup rejects before PR auto-enrollment' },
111
+ { rule: 'all validation completes before PR stamping, enrollment, branch derivation, dedup, SQL mutation, or cache invalidation' },
112
+ ],
113
+ negativeTests: AUDITED_NEGATIVE_TESTS,
114
+ },
115
+ 'POST /api/work-items/update': {
116
+ audit: 'audited',
117
+ body: {
118
+ policy: 'required',
119
+ fields: [
120
+ { name: 'id', type: 'identifier', required: true },
121
+ { name: 'source', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
122
+ { name: 'title', type: 'string', required: false },
123
+ { name: 'description', type: 'string', required: false },
124
+ { name: 'type', type: 'string', required: false, allowedValuesSource: 'shared.WORK_TYPE' },
125
+ { name: 'priority', type: 'string', required: false, allowedValuesSource: 'shared.WORK_ITEM_PRIORITY_VALUES' },
126
+ { name: 'agent', type: 'string|null', required: false, allowedValuesSource: 'config.agents keys' },
127
+ { name: 'project', type: 'string|null', required: false, allowedValuesSource: 'central + config.projects[].name' },
128
+ { name: 'references', type: 'array<object>', required: false },
129
+ { name: 'acceptanceCriteria', type: 'array|string', required: false },
130
+ { name: 'depends_on', type: 'array<string>', required: false },
131
+ { name: 'workdir', type: 'string|null', required: false },
132
+ { name: 'meta', type: 'object', required: false },
133
+ ],
134
+ },
135
+ aliases: [
136
+ { name: 'acceptanceCriteria', canonical: 'acceptanceCriteria[]', location: 'body', type: 'string|array' },
137
+ { name: 'workdir', canonical: 'meta.workdir', location: 'body', type: 'string|null' },
138
+ ],
139
+ constraints: [
140
+ { rule: 'only pending or failed work items are editable' },
141
+ { rule: 'every supplied update field is validated before SQL mutation' },
142
+ { rule: 'cross-scope moves and field updates commit in one SQL transaction' },
143
+ ],
144
+ negativeTests: AUDITED_NEGATIVE_TESTS,
145
+ },
146
+ 'POST /api/work-items/retry': {
147
+ audit: 'audited',
148
+ body: {
149
+ policy: 'required',
150
+ fields: [
151
+ { name: 'id', type: 'identifier', required: true },
152
+ { name: 'source', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
153
+ { name: 'prdFile', type: 'basename', required: false },
154
+ { name: 'force', type: 'boolean', required: false },
155
+ ],
156
+ },
157
+ constraints: [
158
+ { rule: 'only failed or dispatched items retry; force:true additionally permits completed items' },
159
+ { rule: 'source is required when the id exists in multiple scopes' },
160
+ { rule: 'PRD rematerialization applies the same project requirement as create' },
161
+ ],
162
+ negativeTests: AUDITED_NEGATIVE_TESTS,
163
+ },
164
+ 'POST /api/work-items/delete': {
165
+ audit: 'audited',
166
+ body: {
167
+ policy: 'required',
168
+ fields: [
169
+ { name: 'id', type: 'identifier', required: true },
170
+ { name: 'source', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
171
+ ],
172
+ },
173
+ negativeTests: AUDITED_NEGATIVE_TESTS,
174
+ },
175
+ 'POST /api/work-items/cancel': {
176
+ audit: 'audited',
177
+ body: {
178
+ policy: 'required',
179
+ fields: [
180
+ { name: 'id', type: 'identifier', required: true },
181
+ { name: 'source', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
182
+ { name: 'reason', type: 'string', required: false },
183
+ ],
184
+ },
185
+ constraints: [
186
+ { rule: 'completed and already-cancelled items cannot be cancelled' },
187
+ ],
188
+ negativeTests: AUDITED_NEGATIVE_TESTS,
189
+ },
190
+ 'POST /api/work-items/archive': {
191
+ audit: 'audited',
192
+ body: {
193
+ policy: 'required',
194
+ fields: [
195
+ { name: 'id', type: 'identifier', required: true },
196
+ { name: 'source', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
197
+ ],
198
+ },
199
+ constraints: [
200
+ { rule: 'only completed or failed items can be archived' },
201
+ ],
202
+ negativeTests: AUDITED_NEGATIVE_TESTS,
203
+ },
204
+ 'POST /api/work-items/reopen': {
205
+ audit: 'audited',
206
+ body: {
207
+ policy: 'required',
208
+ fields: [
209
+ { name: 'id', type: 'identifier', required: true },
210
+ { name: 'project', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
211
+ { name: 'source', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
212
+ { name: 'description', type: 'string', required: false },
213
+ ],
214
+ },
215
+ aliases: [
216
+ { name: 'source', canonical: 'project', location: 'body', type: 'string' },
217
+ ],
218
+ constraints: [
219
+ { rule: 'project and source must match when both are supplied' },
220
+ { rule: 'only done or failed items can be reopened' },
221
+ ],
222
+ negativeTests: AUDITED_NEGATIVE_TESTS,
223
+ },
224
+ 'POST /api/work-items/feedback': {
225
+ audit: 'audited',
226
+ body: {
227
+ policy: 'required',
228
+ fields: [
229
+ { name: 'id', type: 'identifier', required: true },
230
+ { name: 'source', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
231
+ { name: 'rating', type: 'string', required: true, allowedValues: ['up', 'down'] },
232
+ { name: 'comment', type: 'string', required: false },
233
+ ],
234
+ },
235
+ constraints: [
236
+ { rule: 'feedback is accepted only for completed items' },
237
+ { rule: 'source is required when the id exists in multiple scopes' },
238
+ ],
239
+ negativeTests: AUDITED_NEGATIVE_TESTS,
240
+ },
241
+ 'GET /api/work-items/<id>': {
242
+ audit: 'audited',
243
+ query: {
244
+ policy: 'optional',
245
+ fields: [
246
+ { name: 'source', type: 'string', required: false, allowedValuesSource: 'central + config.projects[].name' },
247
+ ],
248
+ },
249
+ },
250
+ 'GET /api/work-items': {
251
+ // Polled list endpoint: reads no query/body — returns the full slimmed
252
+ // work-item collection. Affirmed input-less so it is audited rather than
253
+ // defaulting to pending-audit by omission (review PR #966).
254
+ noInput: true,
255
+ },
256
+ 'GET /api/work-items/archive': {
257
+ // Archived-item listing: reads no query/body. Affirmed input-less.
258
+ noInput: true,
259
+ },
260
+ 'POST /api/plan': {
261
+ audit: 'audited',
262
+ body: {
263
+ policy: 'required',
264
+ fields: [
265
+ { name: 'title', type: 'string', required: true },
266
+ { name: 'description', type: 'string', required: false },
267
+ { name: 'priority', type: 'string', required: false, allowedValuesSource: 'shared.WORK_ITEM_PRIORITY_VALUES' },
268
+ { name: 'project', type: 'string|array', required: false, allowedValuesSource: 'config.projects[].name' },
269
+ { name: 'agent', type: 'string', required: false, allowedValuesSource: 'config.agents keys' },
270
+ { name: 'branchStrategy', type: 'string', required: false, allowedValues: ['parallel', 'shared-branch'] },
271
+ ],
272
+ },
273
+ aliases: [
274
+ { name: 'branch_strategy', canonical: 'branchStrategy', location: 'body' },
275
+ ],
276
+ constraints: [
277
+ 'project arrays contain only configured project strings and are canonicalized through shared.resolveProjectSource',
278
+ 'branch_strategy and branchStrategy must match when both are supplied',
279
+ ],
280
+ },
281
+ 'POST /api/plans/trigger-verify': {
282
+ audit: 'audited',
283
+ body: {
284
+ policy: 'required',
285
+ fields: [{ name: 'file', type: 'string', required: true, pattern: 'safe .json basename' }],
286
+ },
287
+ constraints: ['PRD must exist, be live, and have shared.PLAN_STATUS.COMPLETED'],
288
+ },
289
+ 'POST /api/plans/approve': {
290
+ audit: 'audited',
291
+ body: {
292
+ policy: 'required',
293
+ fields: [
294
+ { name: 'file', type: 'string', required: true, pattern: 'safe .json basename' },
295
+ { name: 'approvedBy', type: 'string', required: false },
296
+ { name: 'forceRegen', type: 'boolean', required: false },
297
+ { name: 'skipRegen', type: 'boolean', required: false },
298
+ ],
299
+ },
300
+ constraints: [
301
+ 'forceRegen and skipRegen are mutually exclusive',
302
+ 'revision-requested, rejected, and archived PRDs cannot be approved',
303
+ ],
304
+ },
305
+ 'POST /api/plans/pause': {
306
+ audit: 'audited',
307
+ body: {
308
+ policy: 'required',
309
+ fields: [{ name: 'file', type: 'string', required: true, pattern: 'safe .json basename' }],
310
+ },
311
+ constraints: ['PRD status must be active or approved'],
312
+ },
313
+ 'POST /api/plans/execute': {
314
+ audit: 'audited',
315
+ body: {
316
+ policy: 'required',
317
+ fields: [
318
+ { name: 'file', type: 'string', required: true, pattern: 'safe .md basename' },
319
+ { name: 'project', type: 'string', required: false, allowedValuesSource: 'config.projects[].name' },
320
+ { name: 'feedback', type: 'string', required: false },
321
+ ],
322
+ },
323
+ constraints: [
324
+ 'plan must be live, not archived',
325
+ 'Project/Projects/targetProjects declarations must be valid and mutually consistent',
326
+ ],
327
+ },
328
+ 'POST /api/plans/reject': {
329
+ audit: 'audited',
330
+ body: {
331
+ policy: 'required',
332
+ fields: [
333
+ { name: 'file', type: 'string', required: true, pattern: 'safe .json basename' },
334
+ { name: 'rejectedBy', type: 'string', required: false },
335
+ { name: 'reason', type: 'string', required: false },
336
+ ],
337
+ },
338
+ constraints: ['completed, rejected, and archived PRDs cannot be rejected'],
339
+ },
340
+ 'POST /api/plans/regenerate': {
341
+ audit: 'audited',
342
+ body: {
343
+ policy: 'required',
344
+ fields: [{ name: 'source', type: 'string', required: true, pattern: 'safe .json basename' }],
345
+ },
346
+ constraints: ['source PRD must be live and in a resumable lifecycle state'],
347
+ },
348
+ 'POST /api/plans/delete': {
349
+ audit: 'audited',
350
+ body: {
351
+ policy: 'required',
352
+ fields: [{ name: 'file', type: 'string', required: true, pattern: 'safe .md or .json basename' }],
353
+ },
354
+ constraints: ['explicit delete is the only operation that may permanently remove an archived PRD'],
355
+ },
356
+ 'POST /api/plans/archive': {
357
+ audit: 'audited',
358
+ body: {
359
+ policy: 'required',
360
+ fields: [{ name: 'file', type: 'string', required: true, pattern: 'safe .md or .json basename' }],
361
+ },
362
+ constraints: [
363
+ 'artifact must be live and not already archived',
364
+ 'SQL PRD changes are compensated if the linked Markdown move fails',
365
+ ],
366
+ },
367
+ 'POST /api/plans/unarchive': {
368
+ audit: 'audited',
369
+ body: {
370
+ policy: 'required',
371
+ fields: [{ name: 'file', type: 'string', required: true, pattern: 'safe .md or .json basename' }],
372
+ },
373
+ constraints: [
374
+ 'artifact must be archived',
375
+ 'PRD state is compensated if the linked Markdown restore fails',
376
+ ],
377
+ },
378
+ 'POST /api/plans/revise': {
379
+ audit: 'audited',
380
+ body: {
381
+ policy: 'required',
382
+ fields: [
383
+ { name: 'file', type: 'string', required: true, pattern: 'safe .json basename' },
384
+ { name: 'feedback', type: 'string', required: true },
385
+ { name: 'requestedBy', type: 'string', required: false },
386
+ ],
387
+ },
388
+ constraints: ['feedback must contain non-whitespace text and PRD status must allow revision'],
389
+ },
390
+ 'POST /api/plans/discuss': {
391
+ audit: 'audited',
392
+ body: {
393
+ policy: 'required',
394
+ fields: [{ name: 'file', type: 'string', required: true, pattern: 'safe .json basename' }],
395
+ },
396
+ constraints: ['PRD status must be awaiting-approval or revision-requested'],
397
+ },
398
+ 'GET /api/plans/archive/<file>': {
399
+ audit: 'audited',
400
+ path: {
401
+ policy: 'required',
402
+ fields: [{ name: 'file', type: 'string', required: true, pattern: 'safe .md or .json basename' }],
403
+ },
404
+ negativeTests: [{
405
+ strategy: 'reject-traversal-encoded-traversal-and-wrong-extension',
406
+ expectedStatus: '400',
407
+ audit: 'audited',
408
+ }],
409
+ },
410
+ 'GET /api/plans/<file>': {
411
+ audit: 'audited',
412
+ path: {
413
+ policy: 'required',
414
+ fields: [{ name: 'file', type: 'string', required: true, pattern: 'safe .md or .json basename' }],
415
+ },
416
+ negativeTests: [{
417
+ strategy: 'reject-traversal-encoded-traversal-and-wrong-extension',
418
+ expectedStatus: '400',
419
+ audit: 'audited',
420
+ }],
421
+ },
422
+ 'POST /api/prd-items': {
423
+ audit: 'audited',
424
+ body: {
425
+ policy: 'required',
426
+ fields: [
427
+ { name: 'source', type: 'string', required: false, pattern: 'safe .json basename' },
428
+ { name: 'id', type: 'string', required: false, pattern: 'safe item identifier' },
429
+ { name: 'name', type: 'string', required: true },
430
+ { name: 'description', type: 'string', required: false },
431
+ { name: 'priority', type: 'string', required: false, allowedValuesSource: 'shared.WORK_ITEM_PRIORITY_VALUES' },
432
+ { name: 'estimated_complexity', type: 'string', required: false, allowedValues: ['small', 'medium', 'large'] },
433
+ { name: 'type', type: 'string', required: false, allowedValuesSource: 'shared.VALID_WORK_TYPES' },
434
+ { name: 'status', type: 'string', required: false, allowedValuesSource: 'shared.PRD_ITEM_STATUS' },
435
+ { name: 'project', type: 'string', required: false, allowedValuesSource: 'config.projects[].name' },
436
+ { name: 'itemProject', type: 'string', required: false, allowedValuesSource: 'config.projects[].name' },
437
+ ],
438
+ },
439
+ aliases: [
440
+ { name: 'item_project', canonical: 'itemProject', location: 'body' },
441
+ { name: 'workType', canonical: 'type', location: 'body' },
442
+ { name: 'work_type', canonical: 'type', location: 'body' },
443
+ ],
444
+ },
445
+ 'POST /api/prd-items/update': {
446
+ audit: 'audited',
447
+ body: {
448
+ policy: 'required',
449
+ fields: [
450
+ { name: 'source', type: 'string', required: true, pattern: 'safe .json basename' },
451
+ { name: 'itemId', type: 'string', required: true, pattern: 'safe item identifier' },
452
+ { name: 'name', type: 'string', required: false },
453
+ { name: 'description', type: 'string', required: false },
454
+ { name: 'priority', type: 'string', required: false, allowedValuesSource: 'shared.WORK_ITEM_PRIORITY_VALUES' },
455
+ { name: 'estimated_complexity', type: 'string', required: false, allowedValues: ['small', 'medium', 'large'] },
456
+ { name: 'type', type: 'string', required: false, allowedValuesSource: 'shared.VALID_WORK_TYPES' },
457
+ { name: 'status', type: 'string', required: false, allowedValuesSource: 'shared.PRD_ITEM_STATUS' },
458
+ { name: 'project', type: 'string', required: false, allowedValuesSource: 'config.projects[].name' },
459
+ ],
460
+ },
461
+ aliases: [
462
+ { name: 'workType', canonical: 'type', location: 'body' },
463
+ { name: 'work_type', canonical: 'type', location: 'body' },
464
+ ],
465
+ constraints: ['archived and rejected PRDs cannot be edited'],
466
+ },
467
+ 'POST /api/prd-items/remove': {
468
+ audit: 'audited',
469
+ body: {
470
+ policy: 'required',
471
+ fields: [
472
+ { name: 'source', type: 'string', required: true, pattern: 'safe .json basename' },
473
+ { name: 'itemId', type: 'string', required: true, pattern: 'safe item identifier' },
474
+ ],
475
+ },
476
+ constraints: ['archived and rejected PRDs cannot have items removed'],
477
+ },
478
+ 'POST /api/plans/create': {
479
+ audit: 'audited',
480
+ body: {
481
+ policy: 'required',
482
+ fields: [
483
+ { name: 'title', type: 'string', required: true },
484
+ { name: 'content', type: 'string', required: true },
485
+ { name: 'project', type: 'string|array', required: false, allowedValuesSource: 'config.projects[].name' },
486
+ { name: 'meetingId', type: 'string', required: false, pattern: 'safe identifier' },
487
+ ],
488
+ },
489
+ constraints: [
490
+ 'embedded Project/Projects/targetProjects declarations must be valid and agree with project',
491
+ ],
492
+ },
493
+ },
494
+ };