agentic-orchestrator 0.1.6 → 0.1.8

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 (438) hide show
  1. package/.prettierignore +10 -0
  2. package/.prettierrc.json +24 -0
  3. package/CLAUDE.md +3 -2
  4. package/README.md +71 -48
  5. package/agentic/orchestrator/defaults/policy.defaults.yaml +1 -1
  6. package/agentic/orchestrator/prompts/planner.system.md +1 -0
  7. package/agentic/orchestrator/schemas/agents.schema.json +5 -22
  8. package/agentic/orchestrator/schemas/gates.schema.json +4 -19
  9. package/agentic/orchestrator/schemas/index.schema.json +3 -14
  10. package/agentic/orchestrator/schemas/multi-project.schema.json +2 -8
  11. package/agentic/orchestrator/schemas/plan.schema.json +6 -26
  12. package/agentic/orchestrator/schemas/policy.schema.json +19 -81
  13. package/agentic/orchestrator/schemas/policy.user.schema.json +1 -5
  14. package/agentic/orchestrator/schemas/qa_test_index.schema.json +5 -29
  15. package/agentic/orchestrator/schemas/state.schema.json +11 -61
  16. package/agentic/orchestrator/tools/catalog.json +33 -164
  17. package/agentic/orchestrator/tools/schemas/input/evidence.latest.input.schema.json +1 -3
  18. package/agentic/orchestrator/tools/schemas/input/feature.delete.input.schema.json +1 -5
  19. package/agentic/orchestrator/tools/schemas/input/feature.get_context.input.schema.json +1 -3
  20. package/agentic/orchestrator/tools/schemas/input/feature.init.input.schema.json +1 -4
  21. package/agentic/orchestrator/tools/schemas/input/feature.log_append.input.schema.json +1 -5
  22. package/agentic/orchestrator/tools/schemas/input/feature.ready_to_merge.input.schema.json +1 -6
  23. package/agentic/orchestrator/tools/schemas/input/feature.state_get.input.schema.json +1 -3
  24. package/agentic/orchestrator/tools/schemas/input/feature.state_patch.input.schema.json +1 -5
  25. package/agentic/orchestrator/tools/schemas/input/gates.run.input.schema.json +1 -5
  26. package/agentic/orchestrator/tools/schemas/input/locks.acquire.input.schema.json +1 -5
  27. package/agentic/orchestrator/tools/schemas/input/locks.release.input.schema.json +1 -5
  28. package/agentic/orchestrator/tools/schemas/input/performance.record_outcome.input.schema.json +10 -1
  29. package/agentic/orchestrator/tools/schemas/input/plan.get.input.schema.json +1 -3
  30. package/agentic/orchestrator/tools/schemas/input/plan.submit.input.schema.json +1 -5
  31. package/agentic/orchestrator/tools/schemas/input/plan.update.input.schema.json +1 -6
  32. package/agentic/orchestrator/tools/schemas/input/qa.test_index_get.input.schema.json +1 -3
  33. package/agentic/orchestrator/tools/schemas/input/qa.test_index_update.input.schema.json +1 -6
  34. package/agentic/orchestrator/tools/schemas/input/repo.apply_patch.input.schema.json +1 -5
  35. package/agentic/orchestrator/tools/schemas/input/repo.diff.input.schema.json +1 -3
  36. package/agentic/orchestrator/tools/schemas/input/repo.diff_bundle.input.schema.json +1 -3
  37. package/agentic/orchestrator/tools/schemas/input/repo.ensure_worktree.input.schema.json +1 -4
  38. package/agentic/orchestrator/tools/schemas/input/repo.read_file.input.schema.json +1 -4
  39. package/agentic/orchestrator/tools/schemas/input/repo.search.input.schema.json +1 -4
  40. package/agentic/orchestrator/tools/schemas/input/repo.status.input.schema.json +1 -3
  41. package/agentic/orchestrator/tools/schemas/input/report.feature_summary.input.schema.json +1 -3
  42. package/agentic/orchestrator/tools/schemas/output/collisions.scan.output.schema.json +1 -3
  43. package/agentic/orchestrator/tools/schemas/output/evidence.latest.output.schema.json +1 -4
  44. package/agentic/orchestrator/tools/schemas/output/feature.delete.output.schema.json +4 -20
  45. package/agentic/orchestrator/tools/schemas/output/feature.discover_specs.output.schema.json +2 -7
  46. package/agentic/orchestrator/tools/schemas/output/feature.get_context.output.schema.json +1 -8
  47. package/agentic/orchestrator/tools/schemas/output/feature.init.output.schema.json +1 -5
  48. package/agentic/orchestrator/tools/schemas/output/feature.log_append.output.schema.json +1 -5
  49. package/agentic/orchestrator/tools/schemas/output/feature.ready_to_merge.output.schema.json +1 -6
  50. package/agentic/orchestrator/tools/schemas/output/feature.state_get.output.schema.json +1 -4
  51. package/agentic/orchestrator/tools/schemas/output/feature.state_patch.output.schema.json +1 -5
  52. package/agentic/orchestrator/tools/schemas/output/gates.list.output.schema.json +2 -7
  53. package/agentic/orchestrator/tools/schemas/output/gates.run.output.schema.json +1 -8
  54. package/agentic/orchestrator/tools/schemas/output/locks.acquire.output.schema.json +1 -7
  55. package/agentic/orchestrator/tools/schemas/output/locks.release.output.schema.json +1 -5
  56. package/agentic/orchestrator/tools/schemas/output/performance.get_analytics.output.schema.json +22 -2
  57. package/agentic/orchestrator/tools/schemas/output/plan.get.output.schema.json +1 -4
  58. package/agentic/orchestrator/tools/schemas/output/plan.submit.output.schema.json +1 -5
  59. package/agentic/orchestrator/tools/schemas/output/plan.update.output.schema.json +1 -5
  60. package/agentic/orchestrator/tools/schemas/output/qa.test_index_get.output.schema.json +1 -5
  61. package/agentic/orchestrator/tools/schemas/output/qa.test_index_update.output.schema.json +1 -4
  62. package/agentic/orchestrator/tools/schemas/output/repo.apply_patch.output.schema.json +1 -6
  63. package/agentic/orchestrator/tools/schemas/output/repo.diff.output.schema.json +1 -4
  64. package/agentic/orchestrator/tools/schemas/output/repo.diff_bundle.output.schema.json +1 -7
  65. package/agentic/orchestrator/tools/schemas/output/repo.ensure_worktree.output.schema.json +1 -6
  66. package/agentic/orchestrator/tools/schemas/output/repo.read_file.output.schema.json +1 -5
  67. package/agentic/orchestrator/tools/schemas/output/repo.search.output.schema.json +1 -5
  68. package/agentic/orchestrator/tools/schemas/output/repo.status.output.schema.json +1 -5
  69. package/agentic/orchestrator/tools/schemas/output/report.dashboard.output.schema.json +1 -4
  70. package/apps/control-plane/scripts/validate-architecture-rules.mjs +16 -5
  71. package/apps/control-plane/scripts/validate-docker-mcp-contract.mjs +30 -8
  72. package/apps/control-plane/scripts/validate-mcp-contracts.ts +13 -7
  73. package/apps/control-plane/src/application/adapters/adapter-registry.ts +35 -15
  74. package/apps/control-plane/src/application/multi-project-loader.ts +27 -10
  75. package/apps/control-plane/src/application/services/activity-monitor-service.ts +26 -14
  76. package/apps/control-plane/src/application/services/collision-queue-service.ts +31 -17
  77. package/apps/control-plane/src/application/services/cost-tracking-service.ts +23 -16
  78. package/apps/control-plane/src/application/services/dependency-scheduler-service.ts +12 -4
  79. package/apps/control-plane/src/application/services/feature-deletion-service.ts +94 -58
  80. package/apps/control-plane/src/application/services/feature-lifecycle-service.ts +19 -13
  81. package/apps/control-plane/src/application/services/feature-state-service.ts +29 -19
  82. package/apps/control-plane/src/application/services/gate-interpolation-service.ts +7 -2
  83. package/apps/control-plane/src/application/services/gate-service.ts +64 -41
  84. package/apps/control-plane/src/application/services/instance-isolation-service.ts +1 -1
  85. package/apps/control-plane/src/application/services/issue-tracker-service.ts +49 -38
  86. package/apps/control-plane/src/application/services/lock-service.ts +75 -49
  87. package/apps/control-plane/src/application/services/merge-service.ts +91 -50
  88. package/apps/control-plane/src/application/services/notifier-service.ts +42 -20
  89. package/apps/control-plane/src/application/services/patch-service.ts +73 -44
  90. package/apps/control-plane/src/application/services/performance-analytics-service.ts +8 -6
  91. package/apps/control-plane/src/application/services/plan-service.ts +148 -89
  92. package/apps/control-plane/src/application/services/policy-loader-service.ts +10 -4
  93. package/apps/control-plane/src/application/services/pr-monitor-service.ts +33 -14
  94. package/apps/control-plane/src/application/services/qa-index-service.ts +20 -16
  95. package/apps/control-plane/src/application/services/reactions-service.ts +30 -15
  96. package/apps/control-plane/src/application/services/reporting-service.ts +16 -12
  97. package/apps/control-plane/src/application/services/run-lease-service.ts +138 -81
  98. package/apps/control-plane/src/application/tools/tool-metadata.ts +5 -5
  99. package/apps/control-plane/src/application/tools/tool-router.ts +6 -3
  100. package/apps/control-plane/src/cli/aop.ts +2 -2
  101. package/apps/control-plane/src/cli/attach-command-handler.ts +9 -9
  102. package/apps/control-plane/src/cli/cleanup-command-handler.ts +16 -11
  103. package/apps/control-plane/src/cli/cli-argument-parser.ts +6 -3
  104. package/apps/control-plane/src/cli/dashboard-command-handler.ts +28 -8
  105. package/apps/control-plane/src/cli/delete-command-handler.ts +7 -7
  106. package/apps/control-plane/src/cli/env-file.ts +115 -0
  107. package/apps/control-plane/src/cli/help-command-handler.ts +61 -32
  108. package/apps/control-plane/src/cli/init-command-handler.ts +182 -56
  109. package/apps/control-plane/src/cli/io.ts +7 -3
  110. package/apps/control-plane/src/cli/resume-command-handler.ts +21 -13
  111. package/apps/control-plane/src/cli/retry-command-handler.ts +12 -11
  112. package/apps/control-plane/src/cli/run-command-handler.ts +12 -8
  113. package/apps/control-plane/src/cli/send-command-handler.ts +6 -6
  114. package/apps/control-plane/src/cli/spec-ingestion-service.ts +14 -8
  115. package/apps/control-plane/src/cli/spec-input-resolver.ts +6 -1
  116. package/apps/control-plane/src/cli/spec-utils.ts +2 -2
  117. package/apps/control-plane/src/cli/status-command-handler.ts +13 -12
  118. package/apps/control-plane/src/cli/tooling.ts +3 -3
  119. package/apps/control-plane/src/cli/types.ts +1 -1
  120. package/apps/control-plane/src/core/collisions.ts +27 -10
  121. package/apps/control-plane/src/core/constants.ts +13 -7
  122. package/apps/control-plane/src/core/error-codes.ts +1 -1
  123. package/apps/control-plane/src/core/fs.ts +11 -5
  124. package/apps/control-plane/src/core/gates.ts +53 -27
  125. package/apps/control-plane/src/core/git.ts +18 -6
  126. package/apps/control-plane/src/core/kernel.ts +513 -227
  127. package/apps/control-plane/src/core/patch.ts +7 -3
  128. package/apps/control-plane/src/core/path-layout.ts +5 -1
  129. package/apps/control-plane/src/core/path-rules.ts +19 -5
  130. package/apps/control-plane/src/core/qa-index.ts +26 -12
  131. package/apps/control-plane/src/core/response.ts +9 -6
  132. package/apps/control-plane/src/core/schemas.ts +29 -10
  133. package/apps/control-plane/src/core/tool-caller.ts +1 -1
  134. package/apps/control-plane/src/core/workspace-hooks.ts +5 -5
  135. package/apps/control-plane/src/index.ts +3 -9
  136. package/apps/control-plane/src/interfaces/cli/bootstrap.ts +79 -35
  137. package/apps/control-plane/src/mcp/kernel-tool-executor.ts +7 -3
  138. package/apps/control-plane/src/mcp/mcp-server-adapter.ts +12 -10
  139. package/apps/control-plane/src/mcp/operation-ledger.ts +18 -8
  140. package/apps/control-plane/src/mcp/protocol-contract.ts +2 -2
  141. package/apps/control-plane/src/mcp/runtime-factory.ts +15 -6
  142. package/apps/control-plane/src/mcp/token-auth-verifier.ts +3 -2
  143. package/apps/control-plane/src/mcp/token-claims-validator.ts +11 -7
  144. package/apps/control-plane/src/mcp/tool-authorizer.ts +1 -3
  145. package/apps/control-plane/src/mcp/tool-client.ts +17 -5
  146. package/apps/control-plane/src/mcp/tool-contract-validator.ts +17 -8
  147. package/apps/control-plane/src/mcp/tool-registry-loader.ts +7 -3
  148. package/apps/control-plane/src/mcp/tool-runtime.ts +66 -39
  149. package/apps/control-plane/src/mcp/tools-markdown-generator.ts +6 -1
  150. package/apps/control-plane/src/providers/providers.ts +137 -54
  151. package/apps/control-plane/src/supervisor/build-wave-executor.ts +44 -25
  152. package/apps/control-plane/src/supervisor/planning-wave-executor.ts +46 -33
  153. package/apps/control-plane/src/supervisor/prompt-bundle-loader.ts +1 -1
  154. package/apps/control-plane/src/supervisor/qa-wave-executor.ts +38 -23
  155. package/apps/control-plane/src/supervisor/run-coordinator.ts +71 -36
  156. package/apps/control-plane/src/supervisor/runtime.ts +59 -35
  157. package/apps/control-plane/src/supervisor/session-orchestrator.ts +48 -31
  158. package/apps/control-plane/src/supervisor/types.ts +22 -7
  159. package/apps/control-plane/src/supervisor/worker-decision-loop.ts +30 -20
  160. package/apps/control-plane/test/activity-monitor.spec.ts +54 -30
  161. package/apps/control-plane/test/adapter-registry.spec.ts +5 -5
  162. package/apps/control-plane/test/aop.spec.ts +4 -4
  163. package/apps/control-plane/test/batch-operations.spec.ts +20 -18
  164. package/apps/control-plane/test/bootstrap-attach.spec.ts +52 -19
  165. package/apps/control-plane/test/bootstrap-edge-cases.spec.ts +58 -27
  166. package/apps/control-plane/test/bootstrap.spec.ts +72 -40
  167. package/apps/control-plane/test/cleanup-command.spec.ts +86 -32
  168. package/apps/control-plane/test/cli-helpers.spec.ts +119 -66
  169. package/apps/control-plane/test/cli.spec.ts +1 -1
  170. package/apps/control-plane/test/cli.unit.spec.ts +226 -167
  171. package/apps/control-plane/test/collision-queue.spec.ts +49 -40
  172. package/apps/control-plane/test/collisions.spec.ts +30 -30
  173. package/apps/control-plane/test/core-utils.spec.ts +29 -15
  174. package/apps/control-plane/test/cost-tracking.spec.ts +38 -22
  175. package/apps/control-plane/test/dashboard-api.integration.spec.ts +68 -36
  176. package/apps/control-plane/test/dashboard-client.spec.ts +18 -12
  177. package/apps/control-plane/test/dashboard-command.spec.ts +11 -7
  178. package/apps/control-plane/test/delete-command-handler.spec.ts +49 -41
  179. package/apps/control-plane/test/dependency-scheduler.spec.ts +47 -20
  180. package/apps/control-plane/test/epoch-tracking.spec.ts +9 -9
  181. package/apps/control-plane/test/feature-deletion-service.spec.ts +60 -52
  182. package/apps/control-plane/test/feature-lifecycle.spec.ts +36 -17
  183. package/apps/control-plane/test/gates.spec.ts +101 -81
  184. package/apps/control-plane/test/git-spawn-error.spec.ts +1 -1
  185. package/apps/control-plane/test/helpers.ts +10 -6
  186. package/apps/control-plane/test/incremental-gates.spec.ts +59 -20
  187. package/apps/control-plane/test/init-wizard.spec.ts +328 -68
  188. package/apps/control-plane/test/instance-isolation.spec.ts +43 -10
  189. package/apps/control-plane/test/issue-tracker.spec.ts +368 -128
  190. package/apps/control-plane/test/kernel-collision-replay.spec.ts +50 -29
  191. package/apps/control-plane/test/kernel.branches.spec.ts +64 -40
  192. package/apps/control-plane/test/kernel.coverage.spec.ts +85 -49
  193. package/apps/control-plane/test/kernel.coverage2.spec.ts +109 -65
  194. package/apps/control-plane/test/kernel.spec.ts +134 -51
  195. package/apps/control-plane/test/lock-service.spec.ts +92 -68
  196. package/apps/control-plane/test/mcp-helpers.spec.ts +53 -39
  197. package/apps/control-plane/test/mcp.spec.ts +231 -115
  198. package/apps/control-plane/test/merge-service.spec.ts +142 -94
  199. package/apps/control-plane/test/multi-project.spec.ts +28 -22
  200. package/apps/control-plane/test/notifier-service.spec.ts +136 -92
  201. package/apps/control-plane/test/parallel-gates.spec.ts +51 -35
  202. package/apps/control-plane/test/patch-service.spec.ts +128 -48
  203. package/apps/control-plane/test/performance-analytics.spec.ts +99 -63
  204. package/apps/control-plane/test/plan-service.spec.ts +50 -39
  205. package/apps/control-plane/test/planning-wave-executor.spec.ts +95 -71
  206. package/apps/control-plane/test/policy-loader-service.spec.ts +41 -19
  207. package/apps/control-plane/test/pr-monitor.spec.ts +113 -64
  208. package/apps/control-plane/test/providers.spec.ts +208 -104
  209. package/apps/control-plane/test/qa-index-service.spec.ts +31 -33
  210. package/apps/control-plane/test/qa-index.spec.ts +58 -61
  211. package/apps/control-plane/test/reactions.spec.ts +88 -45
  212. package/apps/control-plane/test/response.spec.ts +5 -5
  213. package/apps/control-plane/test/resume-command.spec.ts +121 -80
  214. package/apps/control-plane/test/run-coordinator.spec.ts +205 -136
  215. package/apps/control-plane/test/schema-date-time.spec.ts +49 -41
  216. package/apps/control-plane/test/service-retry-paths.spec.ts +77 -57
  217. package/apps/control-plane/test/services.spec.ts +147 -129
  218. package/apps/control-plane/test/session-management.spec.ts +136 -74
  219. package/apps/control-plane/test/spec-ingestion.spec.ts +23 -21
  220. package/apps/control-plane/test/spec-input-resolver.spec.ts +11 -10
  221. package/apps/control-plane/test/supervisor-collaborators.spec.ts +168 -121
  222. package/apps/control-plane/test/supervisor.calltool.spec.ts +21 -18
  223. package/apps/control-plane/test/supervisor.spec.ts +67 -43
  224. package/apps/control-plane/test/supervisor.unit.spec.ts +195 -126
  225. package/apps/control-plane/test/token-auth-verifier.spec.ts +29 -14
  226. package/apps/control-plane/test/tool-registry-loader.spec.ts +51 -27
  227. package/apps/control-plane/test/tool-runtime.spec.ts +63 -46
  228. package/apps/control-plane/test/worker-decision-loop.spec.ts +143 -122
  229. package/apps/control-plane/test/workspace-hooks.spec.ts +61 -23
  230. package/apps/control-plane/tsconfig.build.json +2 -7
  231. package/apps/control-plane/tsconfig.json +1 -5
  232. package/apps/control-plane/vitest.config.ts +7 -7
  233. package/config/agentic/orchestrator/adapters.yaml +3 -0
  234. package/config/agentic/orchestrator/agents.yaml +14 -0
  235. package/config/agentic/orchestrator/gates.yaml +28 -0
  236. package/config/agentic/orchestrator/policy.yaml +22 -0
  237. package/config/agentic/orchestrator/prompts/builder.system.md +1 -0
  238. package/config/agentic/orchestrator/prompts/planner.system.md +16 -0
  239. package/config/agentic/orchestrator/prompts/qa.system.md +1 -0
  240. package/dist/apps/control-plane/application/adapters/adapter-registry.js +12 -5
  241. package/dist/apps/control-plane/application/adapters/adapter-registry.js.map +1 -1
  242. package/dist/apps/control-plane/application/multi-project-loader.js +26 -9
  243. package/dist/apps/control-plane/application/multi-project-loader.js.map +1 -1
  244. package/dist/apps/control-plane/application/services/activity-monitor-service.js +7 -7
  245. package/dist/apps/control-plane/application/services/activity-monitor-service.js.map +1 -1
  246. package/dist/apps/control-plane/application/services/collision-queue-service.js +7 -7
  247. package/dist/apps/control-plane/application/services/collision-queue-service.js.map +1 -1
  248. package/dist/apps/control-plane/application/services/cost-tracking-service.js +6 -8
  249. package/dist/apps/control-plane/application/services/cost-tracking-service.js.map +1 -1
  250. package/dist/apps/control-plane/application/services/dependency-scheduler-service.js.map +1 -1
  251. package/dist/apps/control-plane/application/services/feature-deletion-service.js +37 -29
  252. package/dist/apps/control-plane/application/services/feature-deletion-service.js.map +1 -1
  253. package/dist/apps/control-plane/application/services/feature-lifecycle-service.js +10 -10
  254. package/dist/apps/control-plane/application/services/feature-lifecycle-service.js.map +1 -1
  255. package/dist/apps/control-plane/application/services/feature-state-service.js +11 -11
  256. package/dist/apps/control-plane/application/services/feature-state-service.js.map +1 -1
  257. package/dist/apps/control-plane/application/services/gate-interpolation-service.js +3 -1
  258. package/dist/apps/control-plane/application/services/gate-interpolation-service.js.map +1 -1
  259. package/dist/apps/control-plane/application/services/gate-service.js +26 -26
  260. package/dist/apps/control-plane/application/services/gate-service.js.map +1 -1
  261. package/dist/apps/control-plane/application/services/instance-isolation-service.js +1 -1
  262. package/dist/apps/control-plane/application/services/instance-isolation-service.js.map +1 -1
  263. package/dist/apps/control-plane/application/services/issue-tracker-service.js +25 -15
  264. package/dist/apps/control-plane/application/services/issue-tracker-service.js.map +1 -1
  265. package/dist/apps/control-plane/application/services/lock-service.js +32 -32
  266. package/dist/apps/control-plane/application/services/lock-service.js.map +1 -1
  267. package/dist/apps/control-plane/application/services/merge-service.js +41 -27
  268. package/dist/apps/control-plane/application/services/merge-service.js.map +1 -1
  269. package/dist/apps/control-plane/application/services/notifier-service.js +29 -15
  270. package/dist/apps/control-plane/application/services/notifier-service.js.map +1 -1
  271. package/dist/apps/control-plane/application/services/patch-service.js +21 -19
  272. package/dist/apps/control-plane/application/services/patch-service.js.map +1 -1
  273. package/dist/apps/control-plane/application/services/performance-analytics-service.js +4 -4
  274. package/dist/apps/control-plane/application/services/performance-analytics-service.js.map +1 -1
  275. package/dist/apps/control-plane/application/services/plan-service.js +33 -33
  276. package/dist/apps/control-plane/application/services/plan-service.js.map +1 -1
  277. package/dist/apps/control-plane/application/services/policy-loader-service.js.map +1 -1
  278. package/dist/apps/control-plane/application/services/pr-monitor-service.js +23 -11
  279. package/dist/apps/control-plane/application/services/pr-monitor-service.js.map +1 -1
  280. package/dist/apps/control-plane/application/services/qa-index-service.js +11 -11
  281. package/dist/apps/control-plane/application/services/qa-index-service.js.map +1 -1
  282. package/dist/apps/control-plane/application/services/reactions-service.js +13 -9
  283. package/dist/apps/control-plane/application/services/reactions-service.js.map +1 -1
  284. package/dist/apps/control-plane/application/services/reporting-service.js +11 -9
  285. package/dist/apps/control-plane/application/services/reporting-service.js.map +1 -1
  286. package/dist/apps/control-plane/application/services/run-lease-service.js +34 -33
  287. package/dist/apps/control-plane/application/services/run-lease-service.js.map +1 -1
  288. package/dist/apps/control-plane/application/tools/tool-metadata.js +2 -2
  289. package/dist/apps/control-plane/application/tools/tool-router.js.map +1 -1
  290. package/dist/apps/control-plane/cli/attach-command-handler.js +9 -9
  291. package/dist/apps/control-plane/cli/cleanup-command-handler.js +11 -9
  292. package/dist/apps/control-plane/cli/cleanup-command-handler.js.map +1 -1
  293. package/dist/apps/control-plane/cli/cli-argument-parser.js +4 -3
  294. package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
  295. package/dist/apps/control-plane/cli/dashboard-command-handler.js +23 -7
  296. package/dist/apps/control-plane/cli/dashboard-command-handler.js.map +1 -1
  297. package/dist/apps/control-plane/cli/delete-command-handler.js +7 -7
  298. package/dist/apps/control-plane/cli/env-file.d.ts +4 -0
  299. package/dist/apps/control-plane/cli/env-file.js +89 -0
  300. package/dist/apps/control-plane/cli/env-file.js.map +1 -0
  301. package/dist/apps/control-plane/cli/help-command-handler.js +58 -30
  302. package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
  303. package/dist/apps/control-plane/cli/init-command-handler.js +97 -37
  304. package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
  305. package/dist/apps/control-plane/cli/io.js +2 -2
  306. package/dist/apps/control-plane/cli/io.js.map +1 -1
  307. package/dist/apps/control-plane/cli/resume-command-handler.js +9 -9
  308. package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
  309. package/dist/apps/control-plane/cli/retry-command-handler.js +12 -11
  310. package/dist/apps/control-plane/cli/retry-command-handler.js.map +1 -1
  311. package/dist/apps/control-plane/cli/run-command-handler.js +12 -8
  312. package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
  313. package/dist/apps/control-plane/cli/send-command-handler.js +6 -6
  314. package/dist/apps/control-plane/cli/spec-ingestion-service.js +10 -8
  315. package/dist/apps/control-plane/cli/spec-ingestion-service.js.map +1 -1
  316. package/dist/apps/control-plane/cli/spec-input-resolver.js.map +1 -1
  317. package/dist/apps/control-plane/cli/spec-utils.js.map +1 -1
  318. package/dist/apps/control-plane/cli/status-command-handler.js +8 -8
  319. package/dist/apps/control-plane/cli/status-command-handler.js.map +1 -1
  320. package/dist/apps/control-plane/cli/tooling.js +1 -1
  321. package/dist/apps/control-plane/core/collisions.js +11 -8
  322. package/dist/apps/control-plane/core/collisions.js.map +1 -1
  323. package/dist/apps/control-plane/core/constants.js +13 -7
  324. package/dist/apps/control-plane/core/constants.js.map +1 -1
  325. package/dist/apps/control-plane/core/error-codes.js +1 -1
  326. package/dist/apps/control-plane/core/fs.js.map +1 -1
  327. package/dist/apps/control-plane/core/gates.d.ts +2 -2
  328. package/dist/apps/control-plane/core/gates.js +26 -19
  329. package/dist/apps/control-plane/core/gates.js.map +1 -1
  330. package/dist/apps/control-plane/core/git.js +3 -3
  331. package/dist/apps/control-plane/core/git.js.map +1 -1
  332. package/dist/apps/control-plane/core/kernel.d.ts +1 -0
  333. package/dist/apps/control-plane/core/kernel.js +134 -81
  334. package/dist/apps/control-plane/core/kernel.js.map +1 -1
  335. package/dist/apps/control-plane/core/patch.js +7 -3
  336. package/dist/apps/control-plane/core/patch.js.map +1 -1
  337. package/dist/apps/control-plane/core/path-layout.d.ts +1 -0
  338. package/dist/apps/control-plane/core/path-layout.js +4 -1
  339. package/dist/apps/control-plane/core/path-layout.js.map +1 -1
  340. package/dist/apps/control-plane/core/path-rules.js +3 -1
  341. package/dist/apps/control-plane/core/path-rules.js.map +1 -1
  342. package/dist/apps/control-plane/core/qa-index.js +5 -5
  343. package/dist/apps/control-plane/core/qa-index.js.map +1 -1
  344. package/dist/apps/control-plane/core/response.js +3 -3
  345. package/dist/apps/control-plane/core/response.js.map +1 -1
  346. package/dist/apps/control-plane/core/schemas.js +10 -6
  347. package/dist/apps/control-plane/core/schemas.js.map +1 -1
  348. package/dist/apps/control-plane/core/workspace-hooks.js +3 -3
  349. package/dist/apps/control-plane/index.d.ts +1 -1
  350. package/dist/apps/control-plane/index.js +1 -1
  351. package/dist/apps/control-plane/index.js.map +1 -1
  352. package/dist/apps/control-plane/interfaces/cli/bootstrap.js +40 -23
  353. package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
  354. package/dist/apps/control-plane/mcp/kernel-tool-executor.js +1 -1
  355. package/dist/apps/control-plane/mcp/kernel-tool-executor.js.map +1 -1
  356. package/dist/apps/control-plane/mcp/mcp-server-adapter.js +6 -7
  357. package/dist/apps/control-plane/mcp/mcp-server-adapter.js.map +1 -1
  358. package/dist/apps/control-plane/mcp/operation-ledger.js +5 -5
  359. package/dist/apps/control-plane/mcp/operation-ledger.js.map +1 -1
  360. package/dist/apps/control-plane/mcp/protocol-contract.js +2 -2
  361. package/dist/apps/control-plane/mcp/runtime-factory.js +2 -2
  362. package/dist/apps/control-plane/mcp/runtime-factory.js.map +1 -1
  363. package/dist/apps/control-plane/mcp/token-auth-verifier.js +1 -1
  364. package/dist/apps/control-plane/mcp/token-auth-verifier.js.map +1 -1
  365. package/dist/apps/control-plane/mcp/token-claims-validator.js +5 -5
  366. package/dist/apps/control-plane/mcp/token-claims-validator.js.map +1 -1
  367. package/dist/apps/control-plane/mcp/tool-authorizer.js +1 -3
  368. package/dist/apps/control-plane/mcp/tool-authorizer.js.map +1 -1
  369. package/dist/apps/control-plane/mcp/tool-client.js +2 -2
  370. package/dist/apps/control-plane/mcp/tool-client.js.map +1 -1
  371. package/dist/apps/control-plane/mcp/tool-contract-validator.js +3 -3
  372. package/dist/apps/control-plane/mcp/tool-contract-validator.js.map +1 -1
  373. package/dist/apps/control-plane/mcp/tool-registry-loader.js +1 -1
  374. package/dist/apps/control-plane/mcp/tool-registry-loader.js.map +1 -1
  375. package/dist/apps/control-plane/mcp/tool-runtime.js +17 -17
  376. package/dist/apps/control-plane/mcp/tool-runtime.js.map +1 -1
  377. package/dist/apps/control-plane/mcp/tools-markdown-generator.js +6 -1
  378. package/dist/apps/control-plane/mcp/tools-markdown-generator.js.map +1 -1
  379. package/dist/apps/control-plane/providers/providers.d.ts +3 -2
  380. package/dist/apps/control-plane/providers/providers.js +81 -39
  381. package/dist/apps/control-plane/providers/providers.js.map +1 -1
  382. package/dist/apps/control-plane/supervisor/build-wave-executor.js +12 -12
  383. package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
  384. package/dist/apps/control-plane/supervisor/planning-wave-executor.js +19 -16
  385. package/dist/apps/control-plane/supervisor/planning-wave-executor.js.map +1 -1
  386. package/dist/apps/control-plane/supervisor/prompt-bundle-loader.js +1 -1
  387. package/dist/apps/control-plane/supervisor/qa-wave-executor.js +13 -13
  388. package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
  389. package/dist/apps/control-plane/supervisor/run-coordinator.js +37 -20
  390. package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
  391. package/dist/apps/control-plane/supervisor/runtime.js +25 -21
  392. package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
  393. package/dist/apps/control-plane/supervisor/session-orchestrator.js +29 -23
  394. package/dist/apps/control-plane/supervisor/session-orchestrator.js.map +1 -1
  395. package/dist/apps/control-plane/supervisor/types.d.ts +3 -3
  396. package/dist/apps/control-plane/supervisor/types.js.map +1 -1
  397. package/dist/apps/control-plane/supervisor/worker-decision-loop.js +14 -16
  398. package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
  399. package/eslint.config.mjs +20 -20
  400. package/example-configurations/README.md +1 -1
  401. package/example-configurations/java/agents.yaml +3 -3
  402. package/example-configurations/java/policy.yaml +1 -1
  403. package/example-configurations/node/agents.yaml +3 -3
  404. package/example-configurations/node/policy.yaml +1 -1
  405. package/package.json +10 -5
  406. package/packages/web-dashboard/next.config.js +2 -2
  407. package/packages/web-dashboard/src/app/api/actions/route.ts +25 -9
  408. package/packages/web-dashboard/src/app/api/events/route.ts +20 -6
  409. package/packages/web-dashboard/src/app/api/features/[id]/checkout/route.ts +88 -37
  410. package/packages/web-dashboard/src/app/api/features/[id]/evidence/[artifact]/route.ts +8 -5
  411. package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +27 -9
  412. package/packages/web-dashboard/src/app/api/features/[id]/route.ts +5 -2
  413. package/packages/web-dashboard/src/app/api/projects/route.ts +5 -5
  414. package/packages/web-dashboard/src/app/globals.css +10 -2
  415. package/packages/web-dashboard/src/app/page.tsx +100 -37
  416. package/packages/web-dashboard/src/lib/aop-client.ts +68 -37
  417. package/packages/web-dashboard/src/lib/multi-project-config.ts +28 -7
  418. package/packages/web-dashboard/src/lib/orchestrator-tools.ts +59 -36
  419. package/packages/web-dashboard/tsconfig.json +3 -11
  420. package/scripts/nx-safe.mjs +10 -10
  421. package/spec-files/completed/agentic_orchestrator_cli_delete_command_spec.md +5 -0
  422. package/spec-files/completed/agentic_orchestrator_feature_gaps_closure_spec.md +189 -90
  423. package/spec-files/completed/agentic_orchestrator_init_policy_ux_simplification_spec.md +49 -16
  424. package/spec-files/completed/agentic_orchestrator_mcp_formalization_spec.md +24 -1
  425. package/spec-files/completed/agentic_orchestrator_single_global_orchestrator_spec.md +9 -0
  426. package/spec-files/completed/agentic_orchestrator_spec.md +171 -75
  427. package/spec-files/completed/agentic_orchestrator_validator_hardening_spec.md +25 -17
  428. package/spec-files/outstanding/agentic_orchestrator_artifact_database_publishing_spec.md +40 -5
  429. package/spec-files/outstanding/agentic_orchestrator_enterprise_governance_dashboard_spec.md +23 -12
  430. package/spec-files/outstanding/agentic_orchestrator_knowledge_canary_spec.md +16 -4
  431. package/spec-files/outstanding/agentic_orchestrator_observability_integrity_diagnostics_spec.md +42 -2
  432. package/spec-files/outstanding/agentic_orchestrator_performance_improvements_spec.md +209 -130
  433. package/spec-files/outstanding/agentic_orchestrator_planning_review_quality_spec.md +56 -3
  434. package/spec-files/outstanding/agentic_orchestrator_productization_commercial_spec.md +77 -10
  435. package/spec-files/outstanding/agentic_orchestrator_provider_auth_bootstrap_spec.md +384 -0
  436. package/spec-files/outstanding/agentic_orchestrator_quality_adoption_execution_spec.md +29 -14
  437. package/spec-files/progress.md +186 -175
  438. package/tsconfig.json +2 -8
@@ -38,20 +38,20 @@ All new and modified code MUST follow the testing standards already established
38
38
 
39
39
  The following issues were identified in the v1.0 spec during architect review against the actual codebase. Each issue is assigned a severity and cross-references the task where it is resolved.
40
40
 
41
- | # | Severity | Issue | Resolution |
42
- |---|----------|-------|------------|
43
- | A-1 | **CRITICAL** | **`latest.json` does not exist.** Finding I-5 and PER-T-005/006 claim `gates.ts:430` writes a `latest.json` sentinel. The actual code at line 429–430 writes `latest-${mode}.json` (e.g., `latest-fast.json`). PER-T-005's fix of reading `path.join(evidenceDir, 'latest.json')` would always return null, silently breaking `featureGetContext` for all agent roles. PER-T-006's pruning filter `f !== 'latest.json'` would delete all mode-specific sentinels. | PER-T-005 now writes a canonical `latest.json` in `gates.ts` alongside the per-mode sentinel; PER-T-006 pruning filter excludes `latest-*.json` patterns. |
44
- | A-2 | **CRITICAL** | **PER-T-003 is a write-ordering behavioral change.** The v1.0 fix eliminates the sequential `for` loop (lines 41–52) and moves `workerDecisionRunner.execute()` into the parallel `executing` map. `workerDecisionRunner.execute()` for the builder role can call PATCH_APPLY, LOCK_ACQUIRE, and PLAN_UPDATE — all writes to shared state. Making these concurrent violates §0.2. | PER-T-003 is redesigned as a **context-capture Map pattern**: the sequential loop is preserved; context is stored in a Map and reused by the parallel executing map, eliminating the duplicate fetch without changing write ordering. |
45
- | A-3 | **CRITICAL** | **PER-T-003 reused pre-decision context for repair loop.** After `workerDecisionRunner.execute()` applies patches (changing working-tree state) and potentially acquires or releases locks (mutating `state.md`), the captured pre-decision context is stale. The repair loop needs fresh state to give agents accurate `locks.held` data. | PER-T-003 redesign fetches repair context as a fresh call after gate failure, which is the minimal re-fetch (one call per failure, not one per retry). |
46
- | A-4 | **HIGH** | **Coverage thresholds wrong.** §0.1 specified Lines ≥70%, Branches ≥70%, Functions ≥85%. CLAUDE.md mandates 90% on all metrics. Implementing to v1.0 thresholds would pass spec-level gates but fail CI. | §0.1 corrected to 90% everywhere. |
47
- | A-5 | **HIGH** | **`normalizeSet` extraction incomplete.** PER-T-013 identified 4 files but the codebase has 7 copies: `reporting-service.ts`, `merge-service.ts`, `feature-lifecycle-service.ts`, `feature-deletion-service.ts`, `kernel.ts`, `lock-service.ts`, `plan-service.ts`. Leaving 3 copies behind is worse than a partial refactor because it creates a false sense of completeness. | PER-T-013 scope expanded to all 7 files. |
48
- | A-6 | **HIGH** | **§0.2 constraint conflict with PER-T-008.** §0.2 stated "Input/output schemas for all 33 MCP tools remain unchanged." PER-T-008 adds an optional `role` parameter to `feature.get_context`. These directly contradict each other; §4 item 6 tried to paper over this by calling it "backward-compatible." | §0.2 amended to "no breaking changes" with explicit allowance for backward-compatible optional input additions. |
49
- | A-7 | **HIGH** | **Output schema implicit shape change in PER-T-008.** When `role=builder`, `qa_test_index` in the response payload becomes `{summary}` instead of the full object. The tool's output JSON schema doesn't account for this. Validators would fail at runtime when trying to validate the projected payload against the existing schema. | PER-T-008 adds a note that the existing output schema validates the `full` projection only; partial projections bypass output schema validation and return raw AOP objects. |
50
- | A-8 | **MEDIUM** | **`QaIndexRecord` type undefined.** PER-T-009 uses `QaIndexRecord` as a type in `projectQaIndex` but this type does not exist in the codebase. No import path is given. | PER-T-009 defines a local `QaIndexSnapshot` interface inline and derives the projection from `AnyRecord`. |
51
- | A-9 | **MEDIUM** | **Projection table vs implementation inconsistency.** PER-T-008 table shows QA role gets `summary + failed + pending` from `qa_test_index`, but PER-T-009 code returns `{ passed: _omitted, ...rest }` — all fields except `passed`, including `running`, `flaky`, etc. The table and code must agree. | PER-T-009 implementation updated to return only `{ summary, failed, pending }` for QA role, matching the table. |
52
- | A-10 | **MEDIUM** | **`schema_version` guard requires manual discipline.** PER-T-011 relies on developers remembering to bump `CURRENT_INDEX_SCHEMA_VERSION` when `normalizeIndexShape` changes shape. If forgotten, stale indices never migrate and the performance optimization yields incorrect behavior. | PER-T-011 adds a mandatory developer protocol note with a co-located integration test that detects shape drift. |
53
- | A-11 | **MEDIUM** | **PER-T-007 leaves planning context fetches sequential.** After pre-filtering with `FEATURE_STATE_GET`, the full context fetches for `planningFeatureIds` remain sequential in a `for` loop. Parallelizing these fetches extends the savings from PER-T-001's parallel-reads principle. | PER-T-007 updated to use `Promise.all` for the planning context fetches; `runPostQaReconciliation` pre-filter is fully specified with concrete code. |
54
- | A-12 | **LOW** | **`gate-service.spec.ts` does not exist.** PER-T-005 says "add cases to `gate-service.spec.ts` (create if not existing)" — should be explicit. | PER-T-005 updated to say "create `gate-service.spec.ts`." |
41
+ | # | Severity | Issue | Resolution |
42
+ | ---- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
+ | A-1 | **CRITICAL** | **`latest.json` does not exist.** Finding I-5 and PER-T-005/006 claim `gates.ts:430` writes a `latest.json` sentinel. The actual code at line 429–430 writes `latest-${mode}.json` (e.g., `latest-fast.json`). PER-T-005's fix of reading `path.join(evidenceDir, 'latest.json')` would always return null, silently breaking `featureGetContext` for all agent roles. PER-T-006's pruning filter `f !== 'latest.json'` would delete all mode-specific sentinels. | PER-T-005 now writes a canonical `latest.json` in `gates.ts` alongside the per-mode sentinel; PER-T-006 pruning filter excludes `latest-*.json` patterns. |
44
+ | A-2 | **CRITICAL** | **PER-T-003 is a write-ordering behavioral change.** The v1.0 fix eliminates the sequential `for` loop (lines 41–52) and moves `workerDecisionRunner.execute()` into the parallel `executing` map. `workerDecisionRunner.execute()` for the builder role can call PATCH_APPLY, LOCK_ACQUIRE, and PLAN_UPDATE — all writes to shared state. Making these concurrent violates §0.2. | PER-T-003 is redesigned as a **context-capture Map pattern**: the sequential loop is preserved; context is stored in a Map and reused by the parallel executing map, eliminating the duplicate fetch without changing write ordering. |
45
+ | A-3 | **CRITICAL** | **PER-T-003 reused pre-decision context for repair loop.** After `workerDecisionRunner.execute()` applies patches (changing working-tree state) and potentially acquires or releases locks (mutating `state.md`), the captured pre-decision context is stale. The repair loop needs fresh state to give agents accurate `locks.held` data. | PER-T-003 redesign fetches repair context as a fresh call after gate failure, which is the minimal re-fetch (one call per failure, not one per retry). |
46
+ | A-4 | **HIGH** | **Coverage thresholds wrong.** §0.1 specified Lines ≥70%, Branches ≥70%, Functions ≥85%. CLAUDE.md mandates 90% on all metrics. Implementing to v1.0 thresholds would pass spec-level gates but fail CI. | §0.1 corrected to 90% everywhere. |
47
+ | A-5 | **HIGH** | **`normalizeSet` extraction incomplete.** PER-T-013 identified 4 files but the codebase has 7 copies: `reporting-service.ts`, `merge-service.ts`, `feature-lifecycle-service.ts`, `feature-deletion-service.ts`, `kernel.ts`, `lock-service.ts`, `plan-service.ts`. Leaving 3 copies behind is worse than a partial refactor because it creates a false sense of completeness. | PER-T-013 scope expanded to all 7 files. |
48
+ | A-6 | **HIGH** | **§0.2 constraint conflict with PER-T-008.** §0.2 stated "Input/output schemas for all 33 MCP tools remain unchanged." PER-T-008 adds an optional `role` parameter to `feature.get_context`. These directly contradict each other; §4 item 6 tried to paper over this by calling it "backward-compatible." | §0.2 amended to "no breaking changes" with explicit allowance for backward-compatible optional input additions. |
49
+ | A-7 | **HIGH** | **Output schema implicit shape change in PER-T-008.** When `role=builder`, `qa_test_index` in the response payload becomes `{summary}` instead of the full object. The tool's output JSON schema doesn't account for this. Validators would fail at runtime when trying to validate the projected payload against the existing schema. | PER-T-008 adds a note that the existing output schema validates the `full` projection only; partial projections bypass output schema validation and return raw AOP objects. |
50
+ | A-8 | **MEDIUM** | **`QaIndexRecord` type undefined.** PER-T-009 uses `QaIndexRecord` as a type in `projectQaIndex` but this type does not exist in the codebase. No import path is given. | PER-T-009 defines a local `QaIndexSnapshot` interface inline and derives the projection from `AnyRecord`. |
51
+ | A-9 | **MEDIUM** | **Projection table vs implementation inconsistency.** PER-T-008 table shows QA role gets `summary + failed + pending` from `qa_test_index`, but PER-T-009 code returns `{ passed: _omitted, ...rest }` — all fields except `passed`, including `running`, `flaky`, etc. The table and code must agree. | PER-T-009 implementation updated to return only `{ summary, failed, pending }` for QA role, matching the table. |
52
+ | A-10 | **MEDIUM** | **`schema_version` guard requires manual discipline.** PER-T-011 relies on developers remembering to bump `CURRENT_INDEX_SCHEMA_VERSION` when `normalizeIndexShape` changes shape. If forgotten, stale indices never migrate and the performance optimization yields incorrect behavior. | PER-T-011 adds a mandatory developer protocol note with a co-located integration test that detects shape drift. |
53
+ | A-11 | **MEDIUM** | **PER-T-007 leaves planning context fetches sequential.** After pre-filtering with `FEATURE_STATE_GET`, the full context fetches for `planningFeatureIds` remain sequential in a `for` loop. Parallelizing these fetches extends the savings from PER-T-001's parallel-reads principle. | PER-T-007 updated to use `Promise.all` for the planning context fetches; `runPostQaReconciliation` pre-filter is fully specified with concrete code. |
54
+ | A-12 | **LOW** | **`gate-service.spec.ts` does not exist.** PER-T-005 says "add cases to `gate-service.spec.ts` (create if not existing)" — should be explicit. | PER-T-005 updated to say "create `gate-service.spec.ts`." |
55
55
 
56
56
  ---
57
57
 
@@ -143,6 +143,7 @@ The dashboard loop reads `state.md` and the cost JSON file for each feature one
143
143
  On every `featureGetContext` call, `evidenceLatest` lists the entire evidence directory, calls `fs.stat()` on every `.json` file to read mtimes, sorts by mtime, then reads the newest file.
144
144
 
145
145
  `gates.ts:429–430` already writes a per-mode sentinel file on every gate run:
146
+
146
147
  ```typescript
147
148
  const latestPath = path.join(evidenceDirectory, `latest-${mode}.json`);
148
149
  await fs.writeFile(latestPath, `${JSON.stringify(evidence, null, 2)}\n`, 'utf8');
@@ -228,12 +229,12 @@ Every gate run appends a new timestamped JSON file to `.aop/features/<id>/eviden
228
229
 
229
230
  The context bundle returned to every agent role includes the complete QA test index (all test records, including passed), the full gate evidence JSON (verbose stdout/stderr), and the complete state frontmatter (all historical lock, gate, and PR metadata). A feature with 200 tests and 50 gate retry cycles produces a bundle exceeding 80–100 KB — roughly 20,000–25,000 tokens per agent invocation.
230
231
 
231
- | Field | Problem |
232
- |-------|---------|
233
- | `qa_test_index` | All test records including passed — agents only need `summary` + `failed` + `pending` |
234
- | `latest_evidence` | Full verbose gate output — agents need overall result + top failing steps |
235
- | `state.front_matter` | All historical locks/gates/PR metadata — agents need current status + held locks |
236
- | `plan` | Full plan when builder/QA roles only need current-phase tasks |
232
+ | Field | Problem |
233
+ | -------------------- | ------------------------------------------------------------------------------------- |
234
+ | `qa_test_index` | All test records including passed — agents only need `summary` + `failed` + `pending` |
235
+ | `latest_evidence` | Full verbose gate output — agents need overall result + top failing steps |
236
+ | `state.front_matter` | All historical locks/gates/PR metadata — agents need current status + held locks |
237
+ | `plan` | Full plan when builder/QA roles only need current-phase tasks |
237
238
 
238
239
  ---
239
240
 
@@ -263,24 +264,24 @@ See Finding I-8. The structural fix (hoist above the loop) also ensures prompts
263
264
 
264
265
  ### 2.4 Complete Findings Table
265
266
 
266
- | ID | File | Lines | Severity | Category | Task |
267
- |----|------|-------|----------|----------|------|
268
- | I-1 | `feature-lifecycle-service.ts` | 142–146 | HIGH | I/O | PER-T-001 |
269
- | I-2 | `build-wave-executor.ts` | 42, 95 | HIGH | I/O | PER-T-003 |
270
- | I-3 | `build-wave-executor.ts`, `qa-wave-executor.ts` | 30–38, 54–62 | HIGH | I/O | PER-T-002 |
271
- | I-4 | `reporting-service.ts` | 81–108 | MEDIUM | I/O | PER-T-004 |
272
- | I-5 | `gate-service.ts` | 236–256 | MEDIUM | I/O | PER-T-005 |
273
- | I-6 | `kernel.ts` | 758 | MEDIUM | CPU | PER-T-011 |
274
- | I-7 | `reporting-service.ts` | 40–68 | MEDIUM | CPU/I/O | Deferred |
275
- | I-8 | `qa-wave-executor.ts` | 196 | LOW | I/O | PER-T-014 |
276
- | M-1 | 7 service/core files | various | LOW | Memory | PER-T-013 |
277
- | M-2 | `planning-wave-executor.ts` | 298 | LOW | Memory | PER-T-012 |
278
- | M-3 | `run-coordinator.ts` | 61–62, 272 | MEDIUM | Memory | PER-T-010 |
279
- | M-4 | `core/gates.ts` | 427–430 | HIGH | Disk | PER-T-006 |
280
- | C-1 | `feature-lifecycle-service.ts` | 132–158 | HIGH | Context | PER-T-008, PER-T-009 |
281
- | C-2 | `planning-wave-executor.ts` | 125–133 | MEDIUM | Context | PER-T-007 |
282
- | C-3 | `planning-wave-executor.ts` | 313 | LOW | Context | Deferred |
283
- | C-4 | `qa-wave-executor.ts`, `prompt-bundle-loader.ts` | 196, 15–52 | LOW | Context | PER-T-014 |
267
+ | ID | File | Lines | Severity | Category | Task |
268
+ | --- | ------------------------------------------------ | ------------ | -------- | -------- | -------------------- |
269
+ | I-1 | `feature-lifecycle-service.ts` | 142–146 | HIGH | I/O | PER-T-001 |
270
+ | I-2 | `build-wave-executor.ts` | 42, 95 | HIGH | I/O | PER-T-003 |
271
+ | I-3 | `build-wave-executor.ts`, `qa-wave-executor.ts` | 30–38, 54–62 | HIGH | I/O | PER-T-002 |
272
+ | I-4 | `reporting-service.ts` | 81–108 | MEDIUM | I/O | PER-T-004 |
273
+ | I-5 | `gate-service.ts` | 236–256 | MEDIUM | I/O | PER-T-005 |
274
+ | I-6 | `kernel.ts` | 758 | MEDIUM | CPU | PER-T-011 |
275
+ | I-7 | `reporting-service.ts` | 40–68 | MEDIUM | CPU/I/O | Deferred |
276
+ | I-8 | `qa-wave-executor.ts` | 196 | LOW | I/O | PER-T-014 |
277
+ | M-1 | 7 service/core files | various | LOW | Memory | PER-T-013 |
278
+ | M-2 | `planning-wave-executor.ts` | 298 | LOW | Memory | PER-T-012 |
279
+ | M-3 | `run-coordinator.ts` | 61–62, 272 | MEDIUM | Memory | PER-T-010 |
280
+ | M-4 | `core/gates.ts` | 427–430 | HIGH | Disk | PER-T-006 |
281
+ | C-1 | `feature-lifecycle-service.ts` | 132–158 | HIGH | Context | PER-T-008, PER-T-009 |
282
+ | C-2 | `planning-wave-executor.ts` | 125–133 | MEDIUM | Context | PER-T-007 |
283
+ | C-3 | `planning-wave-executor.ts` | 313 | LOW | Context | Deferred |
284
+ | C-4 | `qa-wave-executor.ts`, `prompt-bundle-loader.ts` | 196, 15–52 | LOW | Context | PER-T-014 |
284
285
 
285
286
  ---
286
287
 
@@ -299,29 +300,33 @@ See Finding I-8. The structural fix (hoist above the loop) also ensures prompts
299
300
  **Lines:** 142–146
300
301
 
301
302
  **Before:**
303
+
302
304
  ```typescript
303
- const state = await this.port.featureStateGet(featureId);
304
- const plan = await this.port.planGet(featureId);
305
- const qaIndex = await this.port.qaTestIndexGet(featureId);
305
+ const state = await this.port.featureStateGet(featureId);
306
+ const plan = await this.port.planGet(featureId);
307
+ const qaIndex = await this.port.qaTestIndexGet(featureId);
306
308
  const evidence = await this.port.evidenceLatest(featureId);
307
309
  const specText = await fs.readFile(this.port.specPath(featureId), 'utf8').catch(() => '');
308
310
  ```
309
311
 
310
312
  **After:**
313
+
311
314
  ```typescript
312
315
  const [state, plan, qaIndex, evidence, specText] = await Promise.all([
313
316
  this.port.featureStateGet(featureId),
314
317
  this.port.planGet(featureId),
315
318
  this.port.qaTestIndexGet(featureId),
316
319
  this.port.evidenceLatest(featureId),
317
- fs.readFile(this.port.specPath(featureId), 'utf8').catch(() => '')
320
+ fs.readFile(this.port.specPath(featureId), 'utf8').catch(() => ''),
318
321
  ]);
319
322
  ```
320
323
 
321
324
  **Tests to write:** `apps/control-plane/test/feature-lifecycle-service.spec.ts`
325
+
322
326
  - `GIVEN_featureGetContext_WHEN_called_THEN_all_reads_are_parallel` — assert each port method is called exactly once and all are called before any result is consumed.
323
327
 
324
328
  **Acceptance criteria:**
329
+
325
330
  1. `featureGetContext` returns identical output before and after.
326
331
  2. All five port method spies are called; the individual calls are non-ordered.
327
332
  3. A single I/O error in any one read propagates as a rejected promise (existing behavior).
@@ -332,16 +337,22 @@ const [state, plan, qaIndex, evidence, specText] = await Promise.all([
332
337
 
333
338
  **Fixes:** Finding I-3
334
339
  **Files:**
340
+
335
341
  - `apps/control-plane/src/supervisor/build-wave-executor.ts` (lines 30–38)
336
342
  - `apps/control-plane/src/supervisor/qa-wave-executor.ts` (lines 54–62)
337
343
 
338
344
  **Before (BuildWaveExecutor):**
345
+
339
346
  ```typescript
340
347
  const batch: string[] = [];
341
348
  for (const featureId of featureIds) {
342
- const state = await this.toolCaller.callTool<FeatureStatePayload>('builder', TOOLS.FEATURE_STATE_GET, {
343
- feature_id: featureId
344
- });
349
+ const state = await this.toolCaller.callTool<FeatureStatePayload>(
350
+ 'builder',
351
+ TOOLS.FEATURE_STATE_GET,
352
+ {
353
+ feature_id: featureId,
354
+ },
355
+ );
345
356
  if (state.data.front_matter.status === STATUS.BUILDING) {
346
357
  batch.push(featureId);
347
358
  }
@@ -349,13 +360,14 @@ for (const featureId of featureIds) {
349
360
  ```
350
361
 
351
362
  **After (BuildWaveExecutor):**
363
+
352
364
  ```typescript
353
365
  const states = await Promise.all(
354
366
  featureIds.map((featureId) =>
355
367
  this.toolCaller.callTool<FeatureStatePayload>('builder', TOOLS.FEATURE_STATE_GET, {
356
- feature_id: featureId
357
- })
358
- )
368
+ feature_id: featureId,
369
+ }),
370
+ ),
359
371
  );
360
372
  const batch = featureIds.filter((_, i) => states[i].data.front_matter.status === STATUS.BUILDING);
361
373
  ```
@@ -363,10 +375,12 @@ const batch = featureIds.filter((_, i) => states[i].data.front_matter.status ===
363
375
  Apply the same transformation to `QaWaveExecutor` substituting role `'qa'` and status `STATUS.QA`.
364
376
 
365
377
  **Tests to write:** `apps/control-plane/test/batch-operations.spec.ts` (existing — add cases)
378
+
366
379
  - `GIVEN_BuildWaveExecutor_run_WHEN_multiple_features_THEN_state_reads_are_parallel`
367
380
  - `GIVEN_QaWaveExecutor_run_WHEN_multiple_features_THEN_state_reads_are_parallel`
368
381
 
369
382
  **Acceptance criteria:**
383
+
370
384
  1. Identical `batch` array produced before and after (same filter logic, same contents).
371
385
  2. All `FEATURE_STATE_GET` calls are issued concurrently (spy call ordering is non-sequential).
372
386
  3. `selected` slice behavior (`batch.slice(0, maxParallelGateRuns)`) is unchanged.
@@ -382,6 +396,7 @@ Apply the same transformation to `QaWaveExecutor` substituting role `'qa'` and s
382
396
  **Design rationale:** The sequential `for` loop at lines 41–52 MUST remain sequential (§0.2) because `workerDecisionRunner.execute()` can call write-producing tools (PATCH_APPLY, LOCK_ACQUIRE). The duplicate fetch at line 95 is eliminated by capturing each feature's context in a Map during the sequential phase, then looking it up in the parallel phase for the repair loop. The repair-loop context is still re-fetched once per feature on gate failure (not once per retry as it was before) to capture any state changes from the initial decision. This reduces the duplicate from O(retries) to O(1) on the failure path.
383
397
 
384
398
  **Before:**
399
+
385
400
  ```typescript
386
401
  // Sequential loop (lines 41–52): initial worker decision
387
402
  for (const featureId of selected) {
@@ -409,27 +424,32 @@ const executing = selected.map(async (featureId) => {
409
424
  ```
410
425
 
411
426
  **After:**
427
+
412
428
  ```typescript
413
429
  // Phase 1: Sequential — initial worker decisions (write ordering preserved)
414
430
  const preDecisionContextByFeature = new Map<string, unknown>();
415
431
  for (const featureId of selected) {
416
432
  const context = await this.toolCaller.callTool('builder', TOOLS.FEATURE_GET_CONTEXT, {
417
- feature_id: featureId
433
+ feature_id: featureId,
418
434
  });
419
435
  preDecisionContextByFeature.set(featureId, context.data);
420
436
  await this.workerDecisionRunner.execute({
421
437
  role: 'builder',
422
438
  featureId,
423
439
  contextBundle: context.data,
424
- instructions: '...'
440
+ instructions: '...',
425
441
  });
426
442
  }
427
443
 
428
444
  // Phase 2: Parallel — gate runs and repair
429
445
  const executing = selected.map(async (featureId) => {
430
- const stateForRetry = await this.toolCaller.callTool<FeatureStatePayload>('builder', TOOLS.FEATURE_STATE_GET, {
431
- feature_id: featureId
432
- });
446
+ const stateForRetry = await this.toolCaller.callTool<FeatureStatePayload>(
447
+ 'builder',
448
+ TOOLS.FEATURE_STATE_GET,
449
+ {
450
+ feature_id: featureId,
451
+ },
452
+ );
433
453
  const initialRetryCount = stateForRetry.data.front_matter.gate_retry_count ?? 0;
434
454
 
435
455
  // ... gate run (unchanged) ...
@@ -440,7 +460,7 @@ const executing = selected.map(async (featureId) => {
440
460
  // This is one fetch per failing feature — eliminates the per-retry fetch
441
461
  // that occurred in the v1.0 repair loop.
442
462
  const repairContext = await this.toolCaller.callTool('builder', TOOLS.FEATURE_GET_CONTEXT, {
443
- feature_id: featureId
463
+ feature_id: featureId,
444
464
  });
445
465
  let retryCount = initialRetryCount;
446
466
  while (this.reactionsService.shouldRetry(featureId, retryCount)) {
@@ -449,7 +469,7 @@ const executing = selected.map(async (featureId) => {
449
469
  role: 'builder',
450
470
  featureId,
451
471
  contextBundle: repairContext.data,
452
- instructions: repairPrompt
472
+ instructions: repairPrompt,
453
473
  });
454
474
  // ... gate re-run, retryCount increment ...
455
475
  }
@@ -461,11 +481,13 @@ await Promise.allSettled(executing);
461
481
  **Rationale for still re-fetching on gate failure:** After `workerDecisionRunner.execute()` in Phase 1, the feature may have acquired locks or had patches applied, mutating `state.md`. The repair loop needs `locks.held` to be accurate to avoid incorrect lock-conflict decisions. The re-fetch is gated on `gateOverall === GATE_RESULT.FAIL` — on the fast-path (gate passes), no additional context fetch occurs at all.
462
482
 
463
483
  **Tests to write:** `apps/control-plane/test/batch-operations.spec.ts`
484
+
464
485
  - `GIVEN_BuildWaveExecutor_gate_passes_WHEN_run_THEN_FEATURE_GET_CONTEXT_called_exactly_once_per_feature`
465
486
  - `GIVEN_BuildWaveExecutor_gate_fails_WHEN_run_THEN_FEATURE_GET_CONTEXT_called_twice_per_failing_feature`
466
487
  - `GIVEN_BuildWaveExecutor_multiple_retries_WHEN_gate_fails_THEN_repair_context_not_re_fetched_per_retry`
467
488
 
468
489
  **Acceptance criteria:**
490
+
469
491
  1. When gate passes, `FEATURE_GET_CONTEXT` is called exactly once per feature per `run()` invocation.
470
492
  2. When gate fails, `FEATURE_GET_CONTEXT` is called exactly twice per failing feature: once in Phase 1 (pre-decision), once in Phase 2 (repair context) — never per retry.
471
493
  3. Sequential write ordering of `workerDecisionRunner.execute()` across features is preserved.
@@ -480,6 +502,7 @@ await Promise.allSettled(executing);
480
502
  **Lines:** 81–108
481
503
 
482
504
  **Before:**
505
+
483
506
  ```typescript
484
507
  const features = [];
485
508
  for (const featureId of featureIds) {
@@ -494,6 +517,7 @@ for (const featureId of featureIds) {
494
517
  ```
495
518
 
496
519
  **After:**
520
+
497
521
  ```typescript
498
522
  const features = (
499
523
  await Promise.all(
@@ -504,16 +528,20 @@ const features = (
504
528
  }
505
529
  const [state, costData] = await Promise.all([
506
530
  this.port.readState(featureId),
507
- readJson<{ estimated_cost_usd: number; tokens_used: number }>(this.port.featureCostPath(featureId), null)
531
+ readJson<{ estimated_cost_usd: number; tokens_used: number }>(
532
+ this.port.featureCostPath(featureId),
533
+ null,
534
+ ),
508
535
  ]);
509
536
  return {
510
537
  feature_id: featureId,
511
538
  status: state.frontMatter.status,
512
- branch: typeof state.frontMatter.worktree_branch === 'string'
513
- ? state.frontMatter.worktree_branch
514
- : typeof state.frontMatter.branch === 'string'
515
- ? state.frontMatter.branch
516
- : null,
539
+ branch:
540
+ typeof state.frontMatter.worktree_branch === 'string'
541
+ ? state.frontMatter.worktree_branch
542
+ : typeof state.frontMatter.branch === 'string'
543
+ ? state.frontMatter.branch
544
+ : null,
517
545
  locks: readHeldLocks(state.frontMatter),
518
546
  gate_profile: state.frontMatter.gate_profile,
519
547
  gates: state.frontMatter.gates,
@@ -524,18 +552,20 @@ const features = (
524
552
  activity_detected_via: state.frontMatter.activity_detected_via,
525
553
  cost: costData
526
554
  ? { estimated_cost_usd: costData.estimated_cost_usd, tokens_used: costData.tokens_used }
527
- : null
555
+ : null,
528
556
  };
529
- })
557
+ }),
530
558
  )
531
559
  ).filter((entry): entry is NonNullable<typeof entry> => entry !== null);
532
560
  ```
533
561
 
534
562
  **Tests to write:** `apps/control-plane/test/services.spec.ts` (existing) — add cases:
563
+
535
564
  - `GIVEN_reportDashboard_WHEN_multiple_features_exist_THEN_reads_are_parallel`
536
565
  - `GIVEN_reportDashboard_WHEN_state_file_missing_THEN_feature_is_omitted`
537
566
 
538
567
  **Acceptance criteria:**
568
+
539
569
  1. Returned `features` array contains identical entries in the same order as before.
540
570
  2. Features without a state file are omitted from output (unchanged behavior).
541
571
  3. `readState` and `readJson` (cost) are called in parallel per feature.
@@ -552,10 +582,12 @@ const features = (
552
582
 
553
583
  **Fixes:** Finding I-5
554
584
  **Files:**
585
+
555
586
  - `apps/control-plane/src/core/gates.ts` (add canonical sentinel write)
556
587
  - `apps/control-plane/src/application/services/gate-service.ts` (read sentinel directly)
557
588
 
558
589
  **Context:** `gates.ts:427–430` currently writes two files per gate run:
590
+
559
591
  - `gate-${mode}-${Date.now()}.json` — the timestamped archive record
560
592
  - `latest-${mode}.json` — a per-mode sentinel (e.g., `latest-fast.json`, `latest-full.json`)
561
593
 
@@ -564,6 +596,7 @@ const features = (
564
596
  **Fix:** Add a third write in `gates.ts` — a canonical `latest.json` — updated after every gate run regardless of mode. This is the single O(1) read target for `evidenceLatest`.
565
597
 
566
598
  **Change to `gates.ts`** (after line 430):
599
+
567
600
  ```typescript
568
601
  // Existing:
569
602
  const evidencePath = path.join(evidenceDirectory, `gate-${mode}-${Date.now()}.json`);
@@ -577,6 +610,7 @@ await fs.writeFile(latestPath, `${JSON.stringify(evidence, null, 2)}\n`, 'utf8')
577
610
  ```
578
611
 
579
612
  **Change to `gate-service.ts` `evidenceLatest`** — replace O(N) scan:
613
+
580
614
  ```typescript
581
615
  // Before (O(N) stat scan):
582
616
  const files = (await fs.readdir(evidenceDir))
@@ -594,12 +628,13 @@ return {
594
628
  data: {
595
629
  feature_id: featureId,
596
630
  latest,
597
- path: normalizeRepoPathForState(repoRoot, latestPath)
598
- }
631
+ path: normalizeRepoPathForState(repoRoot, latestPath),
632
+ },
599
633
  };
600
634
  ```
601
635
 
602
636
  **Tests to write:** Create `apps/control-plane/test/gate-service.spec.ts`
637
+
603
638
  - `GIVEN_evidenceLatest_WHEN_latest_json_exists_THEN_returns_its_contents`
604
639
  - `GIVEN_evidenceLatest_WHEN_no_evidence_dir_exists_THEN_returns_null`
605
640
  - `GIVEN_evidenceLatest_WHEN_latest_json_missing_THEN_returns_null`
@@ -607,6 +642,7 @@ return {
607
642
  - `GIVEN_gates_run_WHEN_gate_completes_THEN_latest_json_matches_per_mode_sentinel`
608
643
 
609
644
  **Acceptance criteria:**
645
+
610
646
  1. `evidenceLatest` reads only `latest.json`; no `readdir` or `stat` calls.
611
647
  2. Return shape `{ data: { feature_id, latest, path? } }` is identical to the existing interface.
612
648
  3. `gates.ts` writes `latest.json` after every gate run; its content equals the evidence object.
@@ -619,20 +655,23 @@ return {
619
655
 
620
656
  **Fixes:** Finding M-4
621
657
  **Files:**
658
+
622
659
  - `agentic/orchestrator/policy.yaml` — add `evidence_retention_count` field
623
660
  - `agentic/orchestrator/defaults/policy.defaults.yaml` — add default value
624
661
  - `agentic/orchestrator/schemas/policy.schema.json` — add field to `cleanup` object
625
662
  - `apps/control-plane/src/core/gates.ts` — prune after writing new evidence file
626
663
 
627
664
  **Policy change (`policy.yaml`):**
665
+
628
666
  ```yaml
629
667
  cleanup:
630
668
  grace_period_seconds: 300
631
669
  auto_after_merge: true
632
- evidence_retention_count: 10 # NEW: keep the N most recent timestamped evidence files per feature
670
+ evidence_retention_count: 10 # NEW: keep the N most recent timestamped evidence files per feature
633
671
  ```
634
672
 
635
673
  **Schema change (`schemas/policy.schema.json`):** Add to the `cleanup` object properties:
674
+
636
675
  ```json
637
676
  "evidence_retention_count": {
638
677
  "type": "integer",
@@ -644,6 +683,7 @@ cleanup:
644
683
  ```
645
684
 
646
685
  **Implementation in `gates.ts`** — after writing all three evidence files, add pruning:
686
+
647
687
  ```typescript
648
688
  await pruneEvidenceFiles(evidenceDir, retentionCount);
649
689
 
@@ -666,12 +706,14 @@ async function pruneEvidenceFiles(dir: string, keep: number): Promise<void> {
666
706
  The `retentionCount` value is read from the policy snapshot, defaulting to `10` if absent.
667
707
 
668
708
  **Tests to write:** `apps/control-plane/test/incremental-gates.spec.ts` (existing) — add cases:
709
+
669
710
  - `GIVEN_pruneEvidenceFiles_WHEN_archived_count_exceeds_retention_THEN_oldest_are_deleted`
670
711
  - `GIVEN_pruneEvidenceFiles_WHEN_archived_count_within_retention_THEN_nothing_deleted`
671
712
  - `GIVEN_pruneEvidenceFiles_WHEN_latest_json_present_THEN_it_is_never_pruned`
672
713
  - `GIVEN_pruneEvidenceFiles_WHEN_latest_mode_sentinels_present_THEN_they_are_never_pruned`
673
714
 
674
715
  **Acceptance criteria:**
716
+
675
717
  1. After every gate run, the evidence directory contains at most `evidence_retention_count` timestamped `gate-*.json` files.
676
718
  2. `latest.json` is never deleted by pruning.
677
719
  3. `latest-${mode}.json` sentinel files (e.g., `latest-fast.json`) are never deleted by pruning.
@@ -694,6 +736,7 @@ The `retentionCount` value is read from the policy snapshot, defaulting to `10`
694
736
  **Lines:** 124–153 (`run`) and 156–228 (`runPostQaReconciliation`)
695
737
 
696
738
  **Before (`run`):**
739
+
697
740
  ```typescript
698
741
  async run(featureIds: string[]): Promise<void> {
699
742
  for (const featureId of featureIds) {
@@ -710,6 +753,7 @@ async run(featureIds: string[]): Promise<void> {
710
753
  ```
711
754
 
712
755
  **After (`run`):**
756
+
713
757
  ```typescript
714
758
  async run(featureIds: string[]): Promise<void> {
715
759
  // Phase 1: Batch-fetch lightweight state in parallel to identify planning features
@@ -745,6 +789,7 @@ async run(featureIds: string[]): Promise<void> {
745
789
  ```
746
790
 
747
791
  **Before (`runPostQaReconciliation`):**
792
+
748
793
  ```typescript
749
794
  async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<void> {
750
795
  for (const featureId of featureIds) {
@@ -762,6 +807,7 @@ async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<
762
807
  ```
763
808
 
764
809
  **After (`runPostQaReconciliation`):**
810
+
765
811
  ```typescript
766
812
  async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<void> {
767
813
  // Phase 1: Batch-fetch state in parallel to identify post-QA features
@@ -798,6 +844,7 @@ async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<
798
844
  ```
799
845
 
800
846
  **Tests to write:** `apps/control-plane/test/planning-wave-executor.spec.ts` (existing — add cases)
847
+
801
848
  - `GIVEN_run_WHEN_features_not_in_planning_status_THEN_FEATURE_GET_CONTEXT_not_called`
802
849
  - `GIVEN_run_WHEN_features_in_planning_THEN_FEATURE_GET_CONTEXT_called_only_for_those`
803
850
  - `GIVEN_run_WHEN_multiple_planning_features_THEN_context_fetches_are_parallel`
@@ -805,6 +852,7 @@ async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<
805
852
  - `GIVEN_runPostQaReconciliation_WHEN_post_qa_features_exist_THEN_context_fetches_are_parallel`
806
853
 
807
854
  **Acceptance criteria:**
855
+
808
856
  1. `FEATURE_GET_CONTEXT` is never called for features not in `PLANNING` or `BLOCKED` status (in `run`).
809
857
  2. `FEATURE_GET_CONTEXT` is never called for features not in a post-QA status (in `runPostQaReconciliation`).
810
858
  3. `FEATURE_STATE_GET` batch calls are issued in parallel.
@@ -817,6 +865,7 @@ async runPostQaReconciliation(featureIds: string[], iteration: number): Promise<
817
865
 
818
866
  **Fixes:** Finding C-1
819
867
  **Files:**
868
+
820
869
  - `apps/control-plane/src/application/services/feature-lifecycle-service.ts`
821
870
  - `agentic/orchestrator/tools/schemas/input/feature.get_context.input.schema.json` (add optional `role` field)
822
871
 
@@ -838,14 +887,14 @@ Add an optional `role` parameter to the existing `feature.get_context` input sch
838
887
 
839
888
  **Context projections by role:**
840
889
 
841
- | Field | `full` | `planner` | `builder` | `qa` |
842
- |-------|--------|-----------|-----------|------|
843
- | `feature_id` | ✓ | ✓ | ✓ | ✓ |
844
- | `spec` | full | full | trimmed to 8 KB | trimmed to 4 KB |
845
- | `state.front_matter` | full | full | `{ status, branch, locks.held, gates, gate_profile }` | `{ status, branch, gates, gate_profile }` |
846
- | `plan` | full | full | `{ tasks (current phase only), acceptance_criteria }` | `{ acceptance_criteria, risk }` |
847
- | `qa_test_index` | full | `{ summary }` | `{ summary }` | `{ summary, failed, pending }` (no `passed`) |
848
- | `latest_evidence` | full | `{ overall, profile }` | `{ overall, profile, failed_steps[0..4] }` | `{ overall, profile, failed_steps[0..9], coverage }` |
890
+ | Field | `full` | `planner` | `builder` | `qa` |
891
+ | -------------------- | ------ | ---------------------- | ----------------------------------------------------- | ---------------------------------------------------- |
892
+ | `feature_id` | ✓ | ✓ | ✓ | ✓ |
893
+ | `spec` | full | full | trimmed to 8 KB | trimmed to 4 KB |
894
+ | `state.front_matter` | full | full | `{ status, branch, locks.held, gates, gate_profile }` | `{ status, branch, gates, gate_profile }` |
895
+ | `plan` | full | full | `{ tasks (current phase only), acceptance_criteria }` | `{ acceptance_criteria, risk }` |
896
+ | `qa_test_index` | full | `{ summary }` | `{ summary }` | `{ summary, failed, pending }` (no `passed`) |
897
+ | `latest_evidence` | full | `{ overall, profile }` | `{ overall, profile, failed_steps[0..4] }` | `{ overall, profile, failed_steps[0..9], coverage }` |
849
898
 
850
899
  **Implementation in `FeatureLifecycleService`:**
851
900
 
@@ -886,15 +935,17 @@ const specBudgetByRole: Record<string, number> = {
886
935
  ```
887
936
 
888
937
  Wave executors pass their role when calling context:
938
+
889
939
  ```typescript
890
940
  // BuildWaveExecutor
891
941
  const context = await this.toolCaller.callTool('builder', TOOLS.FEATURE_GET_CONTEXT, {
892
942
  feature_id: featureId,
893
- role: 'builder' // NEW
943
+ role: 'builder', // NEW
894
944
  });
895
945
  ```
896
946
 
897
947
  **Tests to write:** `apps/control-plane/test/feature-lifecycle-service.spec.ts`
948
+
898
949
  - `GIVEN_featureGetContext_with_role_builder_WHEN_called_THEN_qa_index_is_summary_only`
899
950
  - `GIVEN_featureGetContext_with_role_qa_WHEN_called_THEN_passed_tests_are_omitted`
900
951
  - `GIVEN_featureGetContext_with_role_planner_WHEN_called_THEN_state_is_projected`
@@ -902,6 +953,7 @@ const context = await this.toolCaller.callTool('builder', TOOLS.FEATURE_GET_CONT
902
953
  - `GIVEN_featureGetContext_no_role_WHEN_called_THEN_bundle_is_unchanged` (backward compat)
903
954
 
904
955
  **Acceptance criteria:**
956
+
905
957
  1. `role: 'full'` (and omitting `role`) returns the existing complete bundle — no regression for callers that do not pass a role.
906
958
  2. `role: 'builder'` returns `{ summary }` only for `qa_test_index`; `latest_evidence` includes at most 5 `failed_steps`.
907
959
  3. `role: 'qa'` returns `{ summary, failed, pending }` for `qa_test_index` (no `passed`); `latest_evidence` includes at most 10 `failed_steps` plus `coverage`.
@@ -930,7 +982,7 @@ interface QaIndexSnapshot {
930
982
 
931
983
  export function projectQaIndex(
932
984
  qaIndex: QaIndexSnapshot,
933
- role: 'full' | 'planner' | 'builder' | 'qa'
985
+ role: 'full' | 'planner' | 'builder' | 'qa',
934
986
  ): Partial<QaIndexSnapshot> {
935
987
  if (role === 'full') return qaIndex;
936
988
  if (role === 'planner' || role === 'builder') return { summary: qaIndex.summary };
@@ -938,13 +990,13 @@ export function projectQaIndex(
938
990
  return {
939
991
  summary: qaIndex.summary,
940
992
  failed: qaIndex.failed,
941
- pending: qaIndex.pending
993
+ pending: qaIndex.pending,
942
994
  };
943
995
  }
944
996
 
945
997
  export function projectEvidence(
946
998
  evidence: AnyRecord | null,
947
- role: 'full' | 'planner' | 'builder' | 'qa'
999
+ role: 'full' | 'planner' | 'builder' | 'qa',
948
1000
  ): AnyRecord | null {
949
1001
  if (!evidence || role === 'full') return evidence;
950
1002
  if (role === 'planner') return { overall: evidence.overall, profile: evidence.profile };
@@ -956,16 +1008,20 @@ export function projectEvidence(
956
1008
  overall: evidence.overall,
957
1009
  profile: evidence.profile,
958
1010
  failed_steps: failedSteps,
959
- ...(role === 'qa' ? { coverage: evidence.coverage } : {})
1011
+ ...(role === 'qa' ? { coverage: evidence.coverage } : {}),
960
1012
  };
961
1013
  }
962
1014
 
963
- export function projectState(stateData: AnyRecord, role: 'full' | 'planner' | 'builder' | 'qa'): AnyRecord {
1015
+ export function projectState(
1016
+ stateData: AnyRecord,
1017
+ role: 'full' | 'planner' | 'builder' | 'qa',
1018
+ ): AnyRecord {
964
1019
  if (role === 'full' || role === 'planner') return stateData;
965
1020
  const fm = stateData.front_matter ?? {};
966
- const includedFields: (keyof typeof fm)[] = role === 'builder'
967
- ? ['status', 'branch', 'worktree_branch', 'locks', 'gates', 'gate_profile']
968
- : ['status', 'branch', 'worktree_branch', 'gates', 'gate_profile'];
1021
+ const includedFields: (keyof typeof fm)[] =
1022
+ role === 'builder'
1023
+ ? ['status', 'branch', 'worktree_branch', 'locks', 'gates', 'gate_profile']
1024
+ : ['status', 'branch', 'worktree_branch', 'gates', 'gate_profile'];
969
1025
  const projected: AnyRecord = {};
970
1026
  for (const field of includedFields) {
971
1027
  if (field in fm) projected[field] = fm[field];
@@ -980,6 +1036,7 @@ export function trimSpec(spec: string, budgetBytes: number): string {
980
1036
  ```
981
1037
 
982
1038
  **Tests to write:** `apps/control-plane/test/feature-lifecycle-service.spec.ts`
1039
+
983
1040
  - `GIVEN_projectQaIndex_role_qa_WHEN_index_has_passed_tests_THEN_passed_is_omitted`
984
1041
  - `GIVEN_projectQaIndex_role_qa_WHEN_index_has_running_field_THEN_running_is_omitted`
985
1042
  - `GIVEN_projectQaIndex_role_full_WHEN_called_THEN_index_is_unchanged`
@@ -1008,24 +1065,26 @@ export function trimSpec(spec: string, budgetBytes: number): string {
1008
1065
  When `closeFeatureCluster(featureId)` is called for a terminal-status feature, the corresponding `statusCache` entry is never deleted. Over a long run processing hundreds of features, the Map accumulates dead entries indefinitely.
1009
1066
 
1010
1067
  **Before:**
1068
+
1011
1069
  ```typescript
1012
1070
  for (const featureId of sortedCurrent) {
1013
1071
  const status = await this.readFeatureStatus(featureId);
1014
1072
  if (status && RunCoordinator.TERMINAL_STATUSES.has(status)) {
1015
1073
  await this.sessionOrchestrator.closeFeatureCluster(featureId);
1016
- continue; // cache entry remains
1074
+ continue; // cache entry remains
1017
1075
  }
1018
1076
  survivingActiveFeatureIds.push(featureId);
1019
1077
  }
1020
1078
  ```
1021
1079
 
1022
1080
  **After:**
1081
+
1023
1082
  ```typescript
1024
1083
  for (const featureId of sortedCurrent) {
1025
1084
  const status = await this.readFeatureStatus(featureId);
1026
1085
  if (status && RunCoordinator.TERMINAL_STATUSES.has(status)) {
1027
1086
  await this.sessionOrchestrator.closeFeatureCluster(featureId);
1028
- this.statusCache.delete(featureId); // NEW: evict dead entry
1087
+ this.statusCache.delete(featureId); // NEW: evict dead entry
1029
1088
  continue;
1030
1089
  }
1031
1090
  survivingActiveFeatureIds.push(featureId);
@@ -1035,10 +1094,12 @@ for (const featureId of sortedCurrent) {
1035
1094
  Apply the same eviction in the queue-drain loop (lines 193–207) where features popped from `this.state.queue` are found to already be terminal.
1036
1095
 
1037
1096
  **Tests to write:** `apps/control-plane/test/run-coordinator.spec.ts` (existing — add case)
1097
+
1038
1098
  - `GIVEN_rebalanceActiveFeatures_WHEN_feature_reaches_terminal_status_THEN_statusCache_entry_is_evicted`
1039
1099
  - `GIVEN_rebalanceActiveFeatures_WHEN_queue_feature_is_terminal_THEN_statusCache_entry_is_evicted`
1040
1100
 
1041
1101
  **Acceptance criteria:**
1102
+
1042
1103
  1. After `closeFeatureCluster` is called for a terminal feature, `statusCache.has(featureId)` returns `false`.
1043
1104
  2. `notifyStatusTransitions` is unaffected — it reads `statusCache` only for currently active features.
1044
1105
  3. No change to orchestration loop behavior or status transition notification logic.
@@ -1049,12 +1110,14 @@ Apply the same eviction in the queue-drain loop (lines 193–207) where features
1049
1110
 
1050
1111
  **Fixes:** Finding I-6
1051
1112
  **Files:**
1113
+
1052
1114
  - `apps/control-plane/src/core/kernel.ts` (lines 755–763)
1053
1115
  - `agentic/orchestrator/schemas/index.schema.json` (add optional `schema_version` field)
1054
1116
 
1055
1117
  `readIndex` serializes the entire index (20–50 KB) twice on every call just to detect whether schema migration is needed — a cold-path concern paid on every hot-path read.
1056
1118
 
1057
1119
  **Current behavior:**
1120
+
1058
1121
  ```typescript
1059
1122
  const changed = JSON.stringify(existing ?? null) !== JSON.stringify(normalized);
1060
1123
  if (changed) {
@@ -1090,12 +1153,14 @@ async readIndex(): Promise<AnyRecord> {
1090
1153
  **Shape-drift detection test:** Add a test that calls `normalizeIndexShape` with the current `CURRENT_INDEX_SCHEMA_VERSION` and asserts that the output's `schema_version` equals it. If a developer changes `normalizeIndexShape` without bumping the constant, the test will still pass — but if they also change what `normalizeIndexShape` produces (e.g., new field), the test ensures the constant is documented in context. Add a comment in the test: `// If this test fails, increment CURRENT_INDEX_SCHEMA_VERSION in kernel.ts`.
1091
1154
 
1092
1155
  **Tests to write:** `apps/control-plane/test/kernel.spec.ts` (existing — add cases)
1156
+
1093
1157
  - `GIVEN_readIndex_WHEN_schema_version_matches_THEN_normalizeIndexShape_not_called`
1094
1158
  - `GIVEN_readIndex_WHEN_schema_version_absent_THEN_migration_runs_and_writes_file`
1095
1159
  - `GIVEN_readIndex_WHEN_index_is_null_THEN_migration_runs`
1096
1160
  - `GIVEN_normalizeIndexShape_WHEN_called_THEN_schema_version_equals_current_constant` (shape-drift guard)
1097
1161
 
1098
1162
  **Acceptance criteria:**
1163
+
1099
1164
  1. When the on-disk index has the current `schema_version`, `normalizeIndexShape` is not called and no write occurs.
1100
1165
  2. When the field is absent (legacy index), normalization and re-write happen exactly once.
1101
1166
  3. The `schema_version` field is included in `index.schema.json` as an optional integer and validates correctly.
@@ -1113,6 +1178,7 @@ async readIndex(): Promise<AnyRecord> {
1113
1178
  `structuredClone` serializes the entire plan object graph for a mutation that only touches five top-level fields. Since those fields are scalars or wholly replaced arrays, a shallow spread is sufficient and does not risk mutating the original.
1114
1179
 
1115
1180
  **Before:**
1181
+
1116
1182
  ```typescript
1117
1183
  private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: ReconciliationDecision): AnyRecord {
1118
1184
  const nextPlan = structuredClone(plan);
@@ -1129,6 +1195,7 @@ private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: Reconci
1129
1195
  ```
1130
1196
 
1131
1197
  **After:**
1198
+
1132
1199
  ```typescript
1133
1200
  private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: ReconciliationDecision): AnyRecord {
1134
1201
  return {
@@ -1146,10 +1213,12 @@ private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: Reconci
1146
1213
  ```
1147
1214
 
1148
1215
  **Tests to write:** `apps/control-plane/test/planning-wave-executor.spec.ts` (existing — add cases)
1216
+
1149
1217
  - `GIVEN_buildUpdatedPlan_WHEN_called_THEN_original_plan_is_not_mutated`
1150
1218
  - `GIVEN_buildUpdatedPlan_WHEN_called_THEN_only_mutated_fields_change`
1151
1219
 
1152
1220
  **Acceptance criteria:**
1221
+
1153
1222
  1. Returned plan object has all fields from the original plan plus the five updated fields.
1154
1223
  2. The original `plan` argument is not mutated.
1155
1224
  3. `structuredClone` is not called.
@@ -1161,6 +1230,7 @@ private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: Reconci
1161
1230
 
1162
1231
  **Fixes:** Finding M-1
1163
1232
  **Files:**
1233
+
1164
1234
  - **Create:** `apps/control-plane/src/core/utils.ts`
1165
1235
  - **Refactor** (replace local definition, add import):
1166
1236
  - `apps/control-plane/src/core/kernel.ts`
@@ -1174,6 +1244,7 @@ private buildUpdatedPlan(plan: AnyRecord, planVersion: number, decision: Reconci
1174
1244
  **Note:** The v1.0 spec missed `kernel.ts`, `lock-service.ts`, and `plan-service.ts`. All 7 files must be updated in this task for the extraction to be complete.
1175
1245
 
1176
1246
  Add to `apps/control-plane/src/core/utils.ts`:
1247
+
1177
1248
  ```typescript
1178
1249
  /** Deduplicate and sort a string array. Stable across key order. */
1179
1250
  export function normalizeSet(array: string[]): string[] {
@@ -1182,21 +1253,25 @@ export function normalizeSet(array: string[]): string[] {
1182
1253
  ```
1183
1254
 
1184
1255
  In each of the seven files, remove the local definition and add:
1256
+
1185
1257
  ```typescript
1186
- import { normalizeSet } from '../../core/utils.js'; // adjust relative path per file
1258
+ import { normalizeSet } from '../../core/utils.js'; // adjust relative path per file
1187
1259
  ```
1188
1260
 
1189
1261
  For `kernel.ts` the import is:
1262
+
1190
1263
  ```typescript
1191
1264
  import { normalizeSet } from './utils.js';
1192
1265
  ```
1193
1266
 
1194
1267
  **Tests to write:** `apps/control-plane/test/core-utils.spec.ts` (existing — add cases)
1268
+
1195
1269
  - `GIVEN_normalizeSet_WHEN_array_has_duplicates_THEN_deduplicates`
1196
1270
  - `GIVEN_normalizeSet_WHEN_array_is_unsorted_THEN_sorts_lexicographically`
1197
1271
  - `GIVEN_normalizeSet_WHEN_empty_array_THEN_returns_empty`
1198
1272
 
1199
1273
  **Acceptance criteria:**
1274
+
1200
1275
  1. All seven files import from `core/utils.js`; no local `normalizeSet` definitions remain anywhere in the codebase.
1201
1276
  2. Behavior is identical to the seven previous implementations (same Set deduplication, same `localeCompare` sort).
1202
1277
  3. No existing tests fail.
@@ -1213,18 +1288,20 @@ import { normalizeSet } from './utils.js';
1213
1288
  `loadRolePrompts()` is called once per feature inside the QA batch loop. The `PromptBundleLoader` cache makes subsequent calls cheap, but the placement is structurally fragile — cache invalidation silently causes per-feature file I/O.
1214
1289
 
1215
1290
  **Before:**
1291
+
1216
1292
  ```typescript
1217
1293
  for (const featureId of batch.slice(0, maxParallelGateRuns)) {
1218
1294
  // ... gate run logic ...
1219
- const prompts = await this.promptProvider.loadRolePrompts(); // INSIDE LOOP
1295
+ const prompts = await this.promptProvider.loadRolePrompts(); // INSIDE LOOP
1220
1296
  const newQa = await this.provider.createSession('qa', featureId, prompts.qa);
1221
1297
  // ...
1222
1298
  }
1223
1299
  ```
1224
1300
 
1225
1301
  **After:**
1302
+
1226
1303
  ```typescript
1227
- const prompts = await this.promptProvider.loadRolePrompts(); // OUTSIDE LOOP
1304
+ const prompts = await this.promptProvider.loadRolePrompts(); // OUTSIDE LOOP
1228
1305
 
1229
1306
  for (const featureId of batch.slice(0, maxParallelGateRuns)) {
1230
1307
  // ... gate run logic ...
@@ -1234,9 +1311,11 @@ for (const featureId of batch.slice(0, maxParallelGateRuns)) {
1234
1311
  ```
1235
1312
 
1236
1313
  **Tests to write:** `apps/control-plane/test/session-management.spec.ts` (existing — add case)
1314
+
1237
1315
  - `GIVEN_QaWaveExecutor_run_WHEN_multiple_features_in_batch_THEN_loadRolePrompts_called_once`
1238
1316
 
1239
1317
  **Acceptance criteria:**
1318
+
1240
1319
  1. `loadRolePrompts` is called exactly once per `run()` invocation regardless of batch size.
1241
1320
  2. The same `prompts` object is used for all session creations in the batch.
1242
1321
  3. QA session rotation behavior is unchanged.
@@ -1257,37 +1336,37 @@ for (const featureId of batch.slice(0, maxParallelGateRuns)) {
1257
1336
 
1258
1337
  ## 5. Risks and Mitigations
1259
1338
 
1260
- | Risk | Mitigation |
1261
- |------|-----------|
1262
- | `Promise.all` parallelism exposes hidden race conditions in test mocks | Add ordering assertions in tests; use `vi.fn()` with explicit mock return sequences |
1263
- | Context projection silently drops fields agents depend on | Gated behind `role: 'full'` default; add integration test asserting full bundle is unchanged |
1264
- | `schema_version` constant not bumped when shape changes | Developer protocol comment co-located in `kernel.ts`; shape-drift detection test in `kernel.spec.ts` |
1265
- | `structuredClone` removal causes mutation if spread is too shallow | The five mutated fields are scalars or wholly replaced arrays; mutation-guard test confirms |
1266
- | Evidence pruning deletes a file being read concurrently | Pruning occurs after the gate write completes; `fs.unlink` uses `.catch(() => undefined)` |
1267
- | `normalizeSet` extraction breaks an unknown caller | Signature is identical; all seven files updated atomically in this task; `npm run typecheck` catches any missed callers |
1268
- | Repair context re-fetch in PER-T-003 is still an extra call | This is by design: one fetch per failing feature vs one fetch per retry in v1.0; net improvement |
1269
- | `latest.json` write in `gates.ts` fails mid-run | `latest.json` is non-critical metadata; `latest-${mode}.json` sentinel is still written first; `evidenceLatest` falls back to `null` gracefully |
1339
+ | Risk | Mitigation |
1340
+ | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
1341
+ | `Promise.all` parallelism exposes hidden race conditions in test mocks | Add ordering assertions in tests; use `vi.fn()` with explicit mock return sequences |
1342
+ | Context projection silently drops fields agents depend on | Gated behind `role: 'full'` default; add integration test asserting full bundle is unchanged |
1343
+ | `schema_version` constant not bumped when shape changes | Developer protocol comment co-located in `kernel.ts`; shape-drift detection test in `kernel.spec.ts` |
1344
+ | `structuredClone` removal causes mutation if spread is too shallow | The five mutated fields are scalars or wholly replaced arrays; mutation-guard test confirms |
1345
+ | Evidence pruning deletes a file being read concurrently | Pruning occurs after the gate write completes; `fs.unlink` uses `.catch(() => undefined)` |
1346
+ | `normalizeSet` extraction breaks an unknown caller | Signature is identical; all seven files updated atomically in this task; `npm run typecheck` catches any missed callers |
1347
+ | Repair context re-fetch in PER-T-003 is still an extra call | This is by design: one fetch per failing feature vs one fetch per retry in v1.0; net improvement |
1348
+ | `latest.json` write in `gates.ts` fails mid-run | `latest.json` is non-critical metadata; `latest-${mode}.json` sentinel is still written first; `evidenceLatest` falls back to `null` gracefully |
1270
1349
 
1271
1350
  ---
1272
1351
 
1273
1352
  ## 6. Task Backlog
1274
1353
 
1275
- | ID | Milestone | File(s) | Description |
1276
- |----|-----------|---------|-------------|
1277
- | PER-T-001 | PER-M1 | `feature-lifecycle-service.ts` | Parallelize 5 sequential reads in `featureGetContext` |
1278
- | PER-T-002 | PER-M1 | `build-wave-executor.ts`, `qa-wave-executor.ts` | Parallelize status-filter loops |
1279
- | PER-T-003 | PER-M1 | `build-wave-executor.ts` | Context-capture Map pattern; eliminate per-retry duplicate fetch |
1280
- | PER-T-004 | PER-M1 | `reporting-service.ts` | Parallelize `reportDashboard` state+cost reads |
1281
- | PER-T-005 | PER-M2 | `gate-service.ts`, `gates.ts` | Write canonical `latest.json`; read it directly in `evidenceLatest` |
1282
- | PER-T-006 | PER-M2 | `policy.yaml`, `policy.defaults.yaml`, `policy.schema.json`, `gates.ts` | Add `evidence_retention_count` and pruning logic |
1283
- | PER-T-007 | PER-M3 | `planning-wave-executor.ts` | Pre-filter non-planning features; parallelize context fetches |
1284
- | PER-T-008 | PER-M3 | `feature-lifecycle-service.ts`, input schemas | Role-specific context projections |
1285
- | PER-T-009 | PER-M3 | `feature-lifecycle-service.ts` | Extract and test projection helpers |
1286
- | PER-T-010 | PER-M4 | `run-coordinator.ts` | Evict `statusCache` on feature termination |
1287
- | PER-T-011 | PER-M4 | `kernel.ts`, `schemas/index.schema.json` | Replace `JSON.stringify` diff with `schema_version` guard |
1288
- | PER-T-012 | PER-M4 | `planning-wave-executor.ts` | Replace `structuredClone(plan)` with spread |
1289
- | PER-T-013 | PER-M4 | `core/utils.ts` + 7 files | Deduplicate `normalizeSet` into shared utility |
1290
- | PER-T-014 | PER-M4 | `qa-wave-executor.ts` | Move `loadRolePrompts` outside per-feature loop |
1354
+ | ID | Milestone | File(s) | Description |
1355
+ | --------- | --------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------- |
1356
+ | PER-T-001 | PER-M1 | `feature-lifecycle-service.ts` | Parallelize 5 sequential reads in `featureGetContext` |
1357
+ | PER-T-002 | PER-M1 | `build-wave-executor.ts`, `qa-wave-executor.ts` | Parallelize status-filter loops |
1358
+ | PER-T-003 | PER-M1 | `build-wave-executor.ts` | Context-capture Map pattern; eliminate per-retry duplicate fetch |
1359
+ | PER-T-004 | PER-M1 | `reporting-service.ts` | Parallelize `reportDashboard` state+cost reads |
1360
+ | PER-T-005 | PER-M2 | `gate-service.ts`, `gates.ts` | Write canonical `latest.json`; read it directly in `evidenceLatest` |
1361
+ | PER-T-006 | PER-M2 | `policy.yaml`, `policy.defaults.yaml`, `policy.schema.json`, `gates.ts` | Add `evidence_retention_count` and pruning logic |
1362
+ | PER-T-007 | PER-M3 | `planning-wave-executor.ts` | Pre-filter non-planning features; parallelize context fetches |
1363
+ | PER-T-008 | PER-M3 | `feature-lifecycle-service.ts`, input schemas | Role-specific context projections |
1364
+ | PER-T-009 | PER-M3 | `feature-lifecycle-service.ts` | Extract and test projection helpers |
1365
+ | PER-T-010 | PER-M4 | `run-coordinator.ts` | Evict `statusCache` on feature termination |
1366
+ | PER-T-011 | PER-M4 | `kernel.ts`, `schemas/index.schema.json` | Replace `JSON.stringify` diff with `schema_version` guard |
1367
+ | PER-T-012 | PER-M4 | `planning-wave-executor.ts` | Replace `structuredClone(plan)` with spread |
1368
+ | PER-T-013 | PER-M4 | `core/utils.ts` + 7 files | Deduplicate `normalizeSet` into shared utility |
1369
+ | PER-T-014 | PER-M4 | `qa-wave-executor.ts` | Move `loadRolePrompts` outside per-feature loop |
1291
1370
 
1292
1371
  ---
1293
1372
 
@@ -1350,19 +1429,19 @@ The following 28 ordered steps represent the complete implementation sequence. S
1350
1429
 
1351
1430
  ## 9. Spec Gap Tracker
1352
1431
 
1353
- | Task | Status | Notes |
1354
- |------|--------|-------|
1355
- | PER-T-001: Parallelize 5 reads in `featureGetContext` | ⬜ Pending | |
1356
- | PER-T-002: Parallelize status-filter loops | ⬜ Pending | |
1357
- | PER-T-003: Context-capture Map pattern | ⬜ Pending | Redesigned from v1.0 |
1358
- | PER-T-004: Parallelize `reportDashboard` reads | ⬜ Pending | |
1359
- | PER-T-005: Write + read `latest.json` sentinel | ⬜ Pending | v1.0 had wrong filename |
1360
- | PER-T-006: Evidence retention policy | ⬜ Pending | Pruning filter updated for `latest-*.json` |
1361
- | PER-T-007: Pre-filter + parallel context in `PlanningWaveExecutor` | ⬜ Pending | `runPostQaReconciliation` fully specified |
1362
- | PER-T-008: Role-specific context projections | ⬜ Pending | Output schema note added |
1363
- | PER-T-009: Extract projection helpers | ⬜ Pending | `QaIndexSnapshot` type defined |
1364
- | PER-T-010: Evict `statusCache` on termination | ⬜ Pending | |
1365
- | PER-T-011: `schema_version` guard in `readIndex` | ⬜ Pending | Version-bump protocol added |
1366
- | PER-T-012: Replace `structuredClone` with spread | ⬜ Pending | |
1367
- | PER-T-013: Extract `normalizeSet` (7 files) | ⬜ Pending | Expanded from 4 to 7 files |
1368
- | PER-T-014: Move `loadRolePrompts` out of loop | ⬜ Pending | |
1432
+ | Task | Status | Notes |
1433
+ | ------------------------------------------------------------------ | ---------- | ------------------------------------------ |
1434
+ | PER-T-001: Parallelize 5 reads in `featureGetContext` | ⬜ Pending | |
1435
+ | PER-T-002: Parallelize status-filter loops | ⬜ Pending | |
1436
+ | PER-T-003: Context-capture Map pattern | ⬜ Pending | Redesigned from v1.0 |
1437
+ | PER-T-004: Parallelize `reportDashboard` reads | ⬜ Pending | |
1438
+ | PER-T-005: Write + read `latest.json` sentinel | ⬜ Pending | v1.0 had wrong filename |
1439
+ | PER-T-006: Evidence retention policy | ⬜ Pending | Pruning filter updated for `latest-*.json` |
1440
+ | PER-T-007: Pre-filter + parallel context in `PlanningWaveExecutor` | ⬜ Pending | `runPostQaReconciliation` fully specified |
1441
+ | PER-T-008: Role-specific context projections | ⬜ Pending | Output schema note added |
1442
+ | PER-T-009: Extract projection helpers | ⬜ Pending | `QaIndexSnapshot` type defined |
1443
+ | PER-T-010: Evict `statusCache` on termination | ⬜ Pending | |
1444
+ | PER-T-011: `schema_version` guard in `readIndex` | ⬜ Pending | Version-bump protocol added |
1445
+ | PER-T-012: Replace `structuredClone` with spread | ⬜ Pending | |
1446
+ | PER-T-013: Extract `normalizeSet` (7 files) | ⬜ Pending | Expanded from 4 to 7 files |
1447
+ | PER-T-014: Move `loadRolePrompts` out of loop | ⬜ Pending | |