onto-mcp 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/.onto/processes/reconstruct/actionable-ontology-seed-recomposition-design.md +447 -0
  2. package/.onto/processes/reconstruct/foundry-style-ontology-seed-contract.md +934 -0
  3. package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +303 -725
  4. package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +1645 -0
  5. package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +26 -22
  6. package/.onto/processes/reconstruct/source-profile-contract.md +49 -23
  7. package/.onto/processes/reconstruct/source-profiles/code.md +6 -3
  8. package/.onto/processes/reconstruct/source-profiles/database.md +5 -2
  9. package/.onto/processes/reconstruct/source-profiles/document.md +5 -2
  10. package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +5 -4
  11. package/.onto/processes/review/review-execution-ux-contract.md +40 -0
  12. package/.onto/processes/shared/pipeline-execution-ledger-contract.md +26 -10
  13. package/.onto/processes/shared/target-material-kind-contract.md +29 -16
  14. package/AGENTS.md +6 -4
  15. package/README.md +135 -76
  16. package/dist/cli.js +8 -8
  17. package/dist/core-api/reconstruct-api.js +117 -31
  18. package/dist/core-api/review-api.js +47 -0
  19. package/dist/core-runtime/cli/codex-review-unit-executor.js +39 -2
  20. package/dist/core-runtime/cli/complete-review-session.js +2 -2
  21. package/dist/core-runtime/cli/mock-review-unit-executor.js +1 -1
  22. package/dist/core-runtime/cli/review-invoke.js +9 -9
  23. package/dist/core-runtime/cli/run-review-prompt-execution.js +39 -5
  24. package/dist/core-runtime/cli/spawn-watcher.js +266 -47
  25. package/dist/core-runtime/cli/start-review-session.js +3 -3
  26. package/dist/core-runtime/llm/llm-caller.js +11 -0
  27. package/dist/core-runtime/llm/llm-tool-loop.js +2 -0
  28. package/dist/core-runtime/observability/runtime-stream-observation.js +118 -0
  29. package/dist/core-runtime/onboard/cli-host.js +149 -0
  30. package/dist/core-runtime/onboard/host-target.js +22 -0
  31. package/dist/core-runtime/onboard/json-config-host.js +122 -0
  32. package/dist/core-runtime/onboard/path-scan.js +26 -0
  33. package/dist/core-runtime/onboard/prompt.js +51 -0
  34. package/dist/core-runtime/onboard/register.js +207 -0
  35. package/dist/core-runtime/onboard/types.js +27 -0
  36. package/dist/core-runtime/reconstruct/actionable-seed-validation.js +1777 -0
  37. package/dist/core-runtime/reconstruct/artifact-types.js +10 -4
  38. package/dist/core-runtime/reconstruct/contract-registry.js +623 -0
  39. package/dist/core-runtime/reconstruct/domain-id.js +10 -0
  40. package/dist/core-runtime/reconstruct/governing-snapshot.js +716 -0
  41. package/dist/core-runtime/reconstruct/material-profile-validation.js +191 -0
  42. package/dist/core-runtime/reconstruct/materialize-preparation.js +49 -11
  43. package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +269 -79
  44. package/dist/core-runtime/reconstruct/post-seed-validation.js +1194 -51
  45. package/dist/core-runtime/reconstruct/record.js +104 -20
  46. package/dist/core-runtime/reconstruct/run.js +2107 -413
  47. package/dist/core-runtime/reconstruct/seed-claim-projections.js +268 -0
  48. package/dist/core-runtime/reconstruct/source-profiles.js +93 -4
  49. package/dist/core-runtime/reconstruct/terminal-validation.js +807 -0
  50. package/dist/core-runtime/review/review-invocation-runner.js +4 -4
  51. package/dist/mcp/server.js +110 -38
  52. package/dist/mcp/tool-schemas.js +20 -6
  53. package/package.json +8 -17
  54. package/scripts/onto-review-watch.sh +486 -0
  55. package/scripts/onto-runtime-watch.sh +122 -0
  56. package/scripts/postinstall-hint.js +22 -0
  57. package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +0 -387
  58. package/dist/core-runtime/cli/bootstrap-review-binding.js +0 -186
  59. package/dist/core-runtime/cli/codex-nested-dispatch.test.js +0 -390
  60. package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +0 -335
  61. package/dist/core-runtime/cli/coordinator-helpers.js +0 -583
  62. package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +0 -167
  63. package/dist/core-runtime/cli/coordinator-state-machine.js +0 -794
  64. package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +0 -615
  65. package/dist/core-runtime/cli/e2e-start-review-session.test.js +0 -312
  66. package/dist/core-runtime/cli/health.js +0 -44
  67. package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +0 -567
  68. package/dist/core-runtime/cli/materialize-review-execution-preparation.js +0 -104
  69. package/dist/core-runtime/cli/migrate-session-roots.js +0 -118
  70. package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +0 -106
  71. package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +0 -268
  72. package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +0 -136
  73. package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +0 -201
  74. package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +0 -192
  75. package/dist/core-runtime/cli/session-root-guard.js +0 -168
  76. package/dist/core-runtime/cli/spawn-watcher.test.js +0 -457
  77. package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +0 -79
  78. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +0 -412
  79. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +0 -351
  80. package/dist/core-runtime/cli/topology-executor-mapping.js +0 -139
  81. package/dist/core-runtime/cli/topology-executor-mapping.test.js +0 -173
  82. package/dist/core-runtime/cli/write-review-interpretation.js +0 -81
  83. package/dist/core-runtime/config/onto-config-cli.js +0 -278
  84. package/dist/core-runtime/config/onto-config-key-path.js +0 -288
  85. package/dist/core-runtime/config/onto-config-key-path.test.js +0 -195
  86. package/dist/core-runtime/config/onto-config-preview.js +0 -108
  87. package/dist/core-runtime/config/onto-config-preview.test.js +0 -132
  88. package/dist/core-runtime/discovery/config-chain.js +0 -118
  89. package/dist/core-runtime/discovery/config-chain.test.js +0 -103
  90. package/dist/core-runtime/discovery/config-profile.js +0 -199
  91. package/dist/core-runtime/discovery/config-profile.test.js +0 -233
  92. package/dist/core-runtime/discovery/host-detection.test.js +0 -186
  93. package/dist/core-runtime/discovery/installation-paths.test.js +0 -65
  94. package/dist/core-runtime/discovery/lens-registry.test.js +0 -81
  95. package/dist/core-runtime/discovery/path-normalization.test.js +0 -22
  96. package/dist/core-runtime/discovery/plugin-path.js +0 -72
  97. package/dist/core-runtime/discovery/plugin-path.test.js +0 -95
  98. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +0 -344
  99. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +0 -915
  100. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +0 -564
  101. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +0 -708
  102. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +0 -165
  103. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +0 -227
  104. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +0 -59
  105. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +0 -205
  106. package/dist/core-runtime/evolve/adapters/methodology/adapter.js +0 -16
  107. package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +0 -9
  108. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +0 -298
  109. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +0 -70
  110. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +0 -46
  111. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +0 -73
  112. package/dist/core-runtime/evolve/adapters/registry.js +0 -47
  113. package/dist/core-runtime/evolve/adapters/registry.test.js +0 -67
  114. package/dist/core-runtime/evolve/cli.js +0 -256
  115. package/dist/core-runtime/evolve/commands/align.js +0 -194
  116. package/dist/core-runtime/evolve/commands/align.test.js +0 -82
  117. package/dist/core-runtime/evolve/commands/apply.js +0 -161
  118. package/dist/core-runtime/evolve/commands/apply.test.js +0 -138
  119. package/dist/core-runtime/evolve/commands/close.js +0 -39
  120. package/dist/core-runtime/evolve/commands/close.test.js +0 -99
  121. package/dist/core-runtime/evolve/commands/defer.js +0 -40
  122. package/dist/core-runtime/evolve/commands/defer.test.js +0 -134
  123. package/dist/core-runtime/evolve/commands/draft.js +0 -323
  124. package/dist/core-runtime/evolve/commands/draft.test.js +0 -178
  125. package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +0 -208
  126. package/dist/core-runtime/evolve/commands/error-messages.js +0 -125
  127. package/dist/core-runtime/evolve/commands/error-messages.test.js +0 -167
  128. package/dist/core-runtime/evolve/commands/propose-align.js +0 -222
  129. package/dist/core-runtime/evolve/commands/propose-align.test.js +0 -136
  130. package/dist/core-runtime/evolve/commands/reconstruct.js +0 -330
  131. package/dist/core-runtime/evolve/commands/reconstruct.test.js +0 -278
  132. package/dist/core-runtime/evolve/commands/shared.js +0 -22
  133. package/dist/core-runtime/evolve/commands/stale-check.js +0 -103
  134. package/dist/core-runtime/evolve/commands/stale-check.test.js +0 -84
  135. package/dist/core-runtime/evolve/commands/start.js +0 -887
  136. package/dist/core-runtime/evolve/commands/start.test.js +0 -396
  137. package/dist/core-runtime/evolve/config/project-config.js +0 -99
  138. package/dist/core-runtime/evolve/config/project-config.test.js +0 -170
  139. package/dist/core-runtime/evolve/renderers/align-packet.js +0 -280
  140. package/dist/core-runtime/evolve/renderers/align-packet.test.js +0 -332
  141. package/dist/core-runtime/evolve/renderers/draft-packet.js +0 -303
  142. package/dist/core-runtime/evolve/renderers/draft-packet.test.js +0 -377
  143. package/dist/core-runtime/evolve/renderers/format.js +0 -5
  144. package/dist/core-runtime/evolve/renderers/scope-md.js +0 -237
  145. package/dist/core-runtime/evolve/renderers/scope-md.test.js +0 -306
  146. package/dist/core-runtime/govern/cli.js +0 -369
  147. package/dist/core-runtime/govern/cli.test.js +0 -314
  148. package/dist/core-runtime/govern/drift-engine.js +0 -103
  149. package/dist/core-runtime/govern/drift-engine.test.js +0 -319
  150. package/dist/core-runtime/govern/promote-principle.js +0 -206
  151. package/dist/core-runtime/govern/promote-principle.test.js +0 -368
  152. package/dist/core-runtime/govern/queue.js +0 -81
  153. package/dist/core-runtime/govern/types.js +0 -16
  154. package/dist/core-runtime/install/cli.js +0 -530
  155. package/dist/core-runtime/install/detect.js +0 -128
  156. package/dist/core-runtime/install/detect.test.js +0 -155
  157. package/dist/core-runtime/install/gitignore-update.js +0 -74
  158. package/dist/core-runtime/install/gitignore-update.test.js +0 -64
  159. package/dist/core-runtime/install/install-integration.test.js +0 -373
  160. package/dist/core-runtime/install/prompts.js +0 -389
  161. package/dist/core-runtime/install/prompts.test.js +0 -293
  162. package/dist/core-runtime/install/types.js +0 -26
  163. package/dist/core-runtime/install/validation.js +0 -295
  164. package/dist/core-runtime/install/validation.test.js +0 -313
  165. package/dist/core-runtime/install/writer.js +0 -254
  166. package/dist/core-runtime/install/writer.test.js +0 -218
  167. package/dist/core-runtime/learning/extractor.js +0 -461
  168. package/dist/core-runtime/learning/feedback.js +0 -179
  169. package/dist/core-runtime/learning/health-report.js +0 -165
  170. package/dist/core-runtime/learning/health-report.test.js +0 -169
  171. package/dist/core-runtime/learning/loader.js +0 -388
  172. package/dist/core-runtime/learning/loader.test.js +0 -102
  173. package/dist/core-runtime/learning/promote/apply-state.js +0 -240
  174. package/dist/core-runtime/learning/promote/audit-obligation.js +0 -195
  175. package/dist/core-runtime/learning/promote/collector.js +0 -432
  176. package/dist/core-runtime/learning/promote/degraded-state.js +0 -125
  177. package/dist/core-runtime/learning/promote/domain-doc-proposer.js +0 -166
  178. package/dist/core-runtime/learning/promote/e2e-promote.test.js +0 -6385
  179. package/dist/core-runtime/learning/promote/health-snapshot.js +0 -150
  180. package/dist/core-runtime/learning/promote/insight-reclassifier.js +0 -544
  181. package/dist/core-runtime/learning/promote/judgment-auditor.js +0 -517
  182. package/dist/core-runtime/learning/promote/panel-reviewer.js +0 -1158
  183. package/dist/core-runtime/learning/promote/promote-executor.js +0 -1675
  184. package/dist/core-runtime/learning/promote/promoter.js +0 -307
  185. package/dist/core-runtime/learning/promote/retirement.js +0 -122
  186. package/dist/core-runtime/learning/promote/types.js +0 -23
  187. package/dist/core-runtime/learning/prompt-sections.js +0 -51
  188. package/dist/core-runtime/learning/shared/artifact-registry-init.js +0 -45
  189. package/dist/core-runtime/learning/shared/artifact-registry.js +0 -254
  190. package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +0 -73
  191. package/dist/core-runtime/learning/shared/audit-state.js +0 -99
  192. package/dist/core-runtime/learning/shared/duplicate-check.js +0 -28
  193. package/dist/core-runtime/learning/shared/llm-caller.js +0 -831
  194. package/dist/core-runtime/learning/shared/llm-caller.test.js +0 -601
  195. package/dist/core-runtime/learning/shared/llm-tool-loop.js +0 -393
  196. package/dist/core-runtime/learning/shared/mode.js +0 -25
  197. package/dist/core-runtime/learning/shared/paths.js +0 -84
  198. package/dist/core-runtime/learning/shared/paths.test.js +0 -79
  199. package/dist/core-runtime/learning/shared/patterns.js +0 -37
  200. package/dist/core-runtime/learning/shared/recoverability.js +0 -355
  201. package/dist/core-runtime/learning/shared/recovery-context.js +0 -374
  202. package/dist/core-runtime/learning/shared/scope.js +0 -1
  203. package/dist/core-runtime/learning/shared/semantic-classifier.js +0 -94
  204. package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +0 -42
  205. package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +0 -37
  206. package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +0 -39
  207. package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +0 -41
  208. package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +0 -38
  209. package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +0 -43
  210. package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +0 -113
  211. package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +0 -36
  212. package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +0 -48
  213. package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +0 -43
  214. package/dist/core-runtime/learning/shared/specs/spec-helpers.js +0 -64
  215. package/dist/core-runtime/learning/usage-tracker.js +0 -190
  216. package/dist/core-runtime/learning/usage-tracker.test.js +0 -176
  217. package/dist/core-runtime/onboard/detect-review-axes.js +0 -122
  218. package/dist/core-runtime/onboard/detect-review-axes.test.js +0 -127
  219. package/dist/core-runtime/onboard/write-review-block.js +0 -188
  220. package/dist/core-runtime/onboard/write-review-block.test.js +0 -240
  221. package/dist/core-runtime/readers/brownfield-builder.js +0 -150
  222. package/dist/core-runtime/readers/brownfield-builder.test.js +0 -136
  223. package/dist/core-runtime/readers/code-chunk-collector.js +0 -53
  224. package/dist/core-runtime/readers/code-chunk-collector.test.js +0 -136
  225. package/dist/core-runtime/readers/file-utils.js +0 -240
  226. package/dist/core-runtime/readers/file-utils.test.js +0 -146
  227. package/dist/core-runtime/readers/lexicon-citation-check.js +0 -93
  228. package/dist/core-runtime/readers/lexicon-citation-check.test.js +0 -77
  229. package/dist/core-runtime/readers/mcp-figma.js +0 -30
  230. package/dist/core-runtime/readers/mcp-figma.test.js +0 -82
  231. package/dist/core-runtime/readers/mcp-generic.js +0 -31
  232. package/dist/core-runtime/readers/mcp-generic.test.js +0 -76
  233. package/dist/core-runtime/readers/ontology-index.js +0 -148
  234. package/dist/core-runtime/readers/ontology-index.test.js +0 -245
  235. package/dist/core-runtime/readers/ontology-query.js +0 -168
  236. package/dist/core-runtime/readers/ontology-query.test.js +0 -311
  237. package/dist/core-runtime/readers/ontology-resolve.js +0 -48
  238. package/dist/core-runtime/readers/ontology-resolve.test.js +0 -48
  239. package/dist/core-runtime/readers/patterns/index.js +0 -7
  240. package/dist/core-runtime/readers/review-log.js +0 -213
  241. package/dist/core-runtime/readers/review-log.test.js +0 -313
  242. package/dist/core-runtime/readers/scan-local.js +0 -102
  243. package/dist/core-runtime/readers/scan-local.test.js +0 -102
  244. package/dist/core-runtime/readers/scan-tarball.js +0 -121
  245. package/dist/core-runtime/readers/scan-tarball.test.js +0 -283
  246. package/dist/core-runtime/readers/scan-vault.js +0 -34
  247. package/dist/core-runtime/readers/scan-vault.test.js +0 -81
  248. package/dist/core-runtime/readers/types.js +0 -42
  249. package/dist/core-runtime/readers/types.test.js +0 -94
  250. package/dist/core-runtime/readers/viewpoint-collectors.js +0 -229
  251. package/dist/core-runtime/reconstruct/seed-candidate-validation.js +0 -385
  252. package/dist/core-runtime/review/citation-audit.test.js +0 -165
  253. package/dist/core-runtime/review/execution-plan-resolver.js +0 -247
  254. package/dist/core-runtime/review/execution-plan-resolver.test.js +0 -243
  255. package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +0 -246
  256. package/dist/core-runtime/review/execution-topology-resolver.js +0 -401
  257. package/dist/core-runtime/review/execution-topology-resolver.test.js +0 -315
  258. package/dist/core-runtime/review/inline-context-embedder.test.js +0 -154
  259. package/dist/core-runtime/review/legacy-mode-policy.js +0 -88
  260. package/dist/core-runtime/review/materializers-effort-persist.test.js +0 -79
  261. package/dist/core-runtime/review/ontology-path-classifier.js +0 -179
  262. package/dist/core-runtime/review/ontology-path-classifier.test.js +0 -216
  263. package/dist/core-runtime/review/packet-boundary-policy.test.js +0 -107
  264. package/dist/core-runtime/review/participating-lens-paths.test.js +0 -73
  265. package/dist/core-runtime/review/review-config-legacy-translate.js +0 -244
  266. package/dist/core-runtime/review/review-config-legacy-translate.test.js +0 -161
  267. package/dist/core-runtime/review/review-config-validator.js +0 -289
  268. package/dist/core-runtime/review/review-config-validator.test.js +0 -236
  269. package/dist/core-runtime/review/shape-pipeline-audit.test.js +0 -311
  270. package/dist/core-runtime/review/shape-to-topology-id.js +0 -117
  271. package/dist/core-runtime/review/shape-to-topology-id.test.js +0 -132
  272. package/dist/core-runtime/review/topology-shape-derivation.js +0 -155
  273. package/dist/core-runtime/review/topology-shape-derivation.test.js +0 -195
  274. package/dist/core-runtime/scope-runtime/constants.js +0 -12
  275. package/dist/core-runtime/scope-runtime/constraint-pool.js +0 -166
  276. package/dist/core-runtime/scope-runtime/constraint-pool.test.js +0 -674
  277. package/dist/core-runtime/scope-runtime/domain-validation-log.js +0 -135
  278. package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +0 -156
  279. package/dist/core-runtime/scope-runtime/eval-persistence.js +0 -65
  280. package/dist/core-runtime/scope-runtime/eval-persistence.test.js +0 -84
  281. package/dist/core-runtime/scope-runtime/event-pipeline.js +0 -64
  282. package/dist/core-runtime/scope-runtime/event-pipeline.test.js +0 -450
  283. package/dist/core-runtime/scope-runtime/event-store.js +0 -39
  284. package/dist/core-runtime/scope-runtime/event-store.test.js +0 -95
  285. package/dist/core-runtime/scope-runtime/gate-guard.js +0 -348
  286. package/dist/core-runtime/scope-runtime/gate-guard.test.js +0 -1047
  287. package/dist/core-runtime/scope-runtime/hash.js +0 -4
  288. package/dist/core-runtime/scope-runtime/hash.test.js +0 -33
  289. package/dist/core-runtime/scope-runtime/id.js +0 -4
  290. package/dist/core-runtime/scope-runtime/id.test.js +0 -17
  291. package/dist/core-runtime/scope-runtime/reducer.js +0 -297
  292. package/dist/core-runtime/scope-runtime/reducer.test.js +0 -759
  293. package/dist/core-runtime/scope-runtime/scope-manager.js +0 -161
  294. package/dist/core-runtime/scope-runtime/state-machine.js +0 -309
  295. package/dist/core-runtime/scope-runtime/state-machine.test.js +0 -704
  296. package/dist/core-runtime/scope-runtime/types.js +0 -116
  297. package/dist/core-runtime/scope-runtime/types.test.js +0 -69
  298. package/dist/core-runtime/translate/render-for-user.js +0 -169
  299. package/dist/core-runtime/translate/render-for-user.test.js +0 -122
  300. package/dist/providers/capability-contract.js +0 -1
@@ -1,161 +0,0 @@
1
- /**
2
- * /apply command orchestration.
3
- *
4
- * State-dependent behavior:
5
- * - compiled → apply.started (start applying delta-set)
6
- * - compiled → apply.completed (delta-set applied successfully)
7
- * - compiled → apply.decision_gap_found (edge case found during apply → constraints_resolved)
8
- * - applied → validation.started (begin validation)
9
- * - applied → validation.completed (validate() + record result)
10
- *
11
- * Apply and validation are agent-driven.
12
- * This module provides the event recording orchestration.
13
- */
14
- import { readEvents } from "../../scope-runtime/event-store.js";
15
- import { reduce } from "../../scope-runtime/reducer.js";
16
- import { appendScopeEvent } from "../../scope-runtime/event-pipeline.js";
17
- import { wrapGateError } from "./error-messages.js";
18
- import { refreshScopeMd } from "./shared.js";
19
- import { validate } from "../adapters/code-product/validators/validate.js";
20
- import { loadProjectConfig } from "../config/project-config.js";
21
- // ─── Main ───
22
- export function executeApply(paths, action, options) {
23
- switch (action.type) {
24
- case "start_apply":
25
- return handleStartApply(paths, action, options?.projectRoot);
26
- case "complete_apply":
27
- return handleCompleteApply(paths, action);
28
- case "report_gap":
29
- return handleReportGap(paths, action);
30
- case "start_validation":
31
- return handleStartValidation(paths, action);
32
- case "complete_validation":
33
- return handleCompleteValidation(paths, action);
34
- }
35
- }
36
- // ─── Action Handlers ───
37
- // Note: apply.started is a self-transition (compiled → compiled).
38
- // If the process is interrupted before complete_apply, this event can be
39
- // re-recorded on resume without state corruption. Duplicate self-transitions are acceptable.
40
- function handleStartApply(paths, action, projectRoot) {
41
- const config = projectRoot ? loadProjectConfig(projectRoot) : { default_sources: [] };
42
- const result = appendScopeEvent(paths, {
43
- type: "apply.started",
44
- actor: "agent",
45
- payload: { build_spec_hash: action.buildSpecHash },
46
- }, { apply_enabled: config.apply_enabled });
47
- if (!result.success)
48
- return { success: false, reason: wrapGateError(result.reason) };
49
- refreshScopeMd(paths, result.state);
50
- return {
51
- success: true,
52
- nextState: result.next_state,
53
- message: "Apply가 시작되었습니다. delta-set의 변경 사항을 적용하세요.",
54
- };
55
- }
56
- function handleCompleteApply(paths, action) {
57
- const result = appendScopeEvent(paths, {
58
- type: "apply.completed",
59
- actor: "agent",
60
- payload: { result: action.result },
61
- });
62
- if (!result.success)
63
- return { success: false, reason: wrapGateError(result.reason) };
64
- refreshScopeMd(paths, result.state);
65
- return {
66
- success: true,
67
- nextState: result.next_state,
68
- message: "구현이 완료되었습니다. validation을 시작하세요.",
69
- };
70
- }
71
- function handleReportGap(paths, action) {
72
- // 1. constraint.discovered 먼저 기록 (참조 무결성)
73
- const discoverResult = appendScopeEvent(paths, {
74
- type: "constraint.discovered",
75
- actor: "system",
76
- payload: action.constraintPayload,
77
- });
78
- if (!discoverResult.success)
79
- return { success: false, reason: wrapGateError(discoverResult.reason) };
80
- // 2. apply.decision_gap_found 기록 → constraints_resolved로 역전이
81
- const gapResult = appendScopeEvent(paths, {
82
- type: "apply.decision_gap_found",
83
- actor: "agent",
84
- payload: action.gapPayload,
85
- });
86
- if (!gapResult.success)
87
- return { success: false, reason: wrapGateError(gapResult.reason) };
88
- refreshScopeMd(paths, gapResult.state);
89
- return {
90
- success: true,
91
- nextState: gapResult.next_state,
92
- message: `Gap이 발견되었습니다 (${action.gapPayload.new_constraint_id}). Draft에서 재결정 후 재compile이 필요합니다.`,
93
- };
94
- }
95
- // Note: validation.started is a self-transition (applied → applied).
96
- // Same resilience pattern as apply.started above.
97
- function handleStartValidation(paths, action) {
98
- const result = appendScopeEvent(paths, {
99
- type: "validation.started",
100
- actor: "agent",
101
- payload: { validation_plan_hash: action.validationPlanHash },
102
- });
103
- if (!result.success)
104
- return { success: false, reason: wrapGateError(result.reason) };
105
- refreshScopeMd(paths, result.state);
106
- return {
107
- success: true,
108
- nextState: result.next_state,
109
- message: "Validation이 시작되었습니다. 각 VAL 항목을 검증하세요.",
110
- };
111
- }
112
- function handleCompleteValidation(paths, action) {
113
- // 1. validate() 순수 함수 호출
114
- const state = reduce(readEvents(paths.events));
115
- const validateOutput = validate({
116
- state,
117
- plan: action.plan,
118
- results: action.results,
119
- actualPlanHash: action.actualPlanHash,
120
- });
121
- if (!validateOutput.success) {
122
- return { success: false, reason: wrapGateError(validateOutput.reason) };
123
- }
124
- // 2. validation.completed 이벤트 기록
125
- const result = appendScopeEvent(paths, {
126
- type: "validation.completed",
127
- actor: "agent",
128
- payload: {
129
- result: validateOutput.result,
130
- pass_count: validateOutput.pass_count,
131
- fail_count: validateOutput.fail_count,
132
- items: validateOutput.items,
133
- },
134
- });
135
- if (!result.success)
136
- return { success: false, reason: wrapGateError(result.reason) };
137
- refreshScopeMd(paths, result.state);
138
- if (validateOutput.result === "pass") {
139
- return {
140
- success: true,
141
- nextState: result.next_state,
142
- message: "모든 검증이 통과했습니다. 결과를 확인하시고, 종료하려면 '완료'라고 말씀해 주세요.",
143
- data: {
144
- result: validateOutput.result,
145
- pass_count: validateOutput.pass_count,
146
- fail_count: validateOutput.fail_count,
147
- },
148
- };
149
- }
150
- return {
151
- success: true,
152
- nextState: result.next_state,
153
- message: `검증 실패: ${validateOutput.fail_count}건. 해당 constraint에 대해 재결정이 필요합니다.`,
154
- data: {
155
- result: validateOutput.result,
156
- pass_count: validateOutput.pass_count,
157
- fail_count: validateOutput.fail_count,
158
- },
159
- };
160
- }
161
- // refreshScopeMd is imported from ./shared.ts (UF-CONCISENESS-SCOPE-MD consolidated)
@@ -1,138 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { tmpdir } from "node:os";
5
- import { executeApply } from "./apply.js";
6
- import { createScope } from "../../scope-runtime/scope-manager.js";
7
- import { appendScopeEvent } from "../../scope-runtime/event-pipeline.js";
8
- import { readEvents } from "../../scope-runtime/event-store.js";
9
- import { reduce } from "../../scope-runtime/reducer.js";
10
- let tmpDir;
11
- beforeEach(() => { tmpDir = mkdtempSync(join(tmpdir(), "sprint-apply-")); });
12
- afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });
13
- /** Set up scope through compiled state */
14
- function setupCompiled() {
15
- writeFileSync(join(tmpDir, ".sprint-kit.yaml"), "apply_enabled: true\ndefault_sources: []\n", "utf-8");
16
- const paths = createScope(tmpDir, "SC-APPLY-001");
17
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "Test", description: "d", entry_mode: "experience" } });
18
- appendScopeEvent(paths, { type: "grounding.started", actor: "system", payload: { sources: [{ type: "add-dir", path_or_url: "/test" }] } });
19
- appendScopeEvent(paths, { type: "grounding.completed", actor: "system", payload: { snapshot_revision: 1, source_hashes: { "add-dir:/test": "h1" }, perspective_summary: { experience: 1, code: 1, policy: 1 } } });
20
- appendScopeEvent(paths, { type: "align.proposed", actor: "system", payload: { packet_path: "build/align-packet.md", packet_hash: "h", snapshot_revision: 1 } });
21
- appendScopeEvent(paths, { type: "align.locked", actor: "user", payload: { locked_direction: "test", locked_scope_boundaries: { in: ["a"], out: ["b"] }, locked_in_out: true } });
22
- appendScopeEvent(paths, { type: "surface.generated", actor: "system", payload: { surface_type: "experience", surface_path: "surface/preview/", content_hash: "sf1", based_on_snapshot: 1 } });
23
- appendScopeEvent(paths, { type: "surface.confirmed", actor: "user", payload: { final_surface_path: "surface/preview/", final_content_hash: "sf1", total_revisions: 0 } });
24
- appendScopeEvent(paths, { type: "constraint.discovered", actor: "system", payload: { constraint_id: "CST-001", perspective: "code", summary: "test constraint", severity: "required", discovery_stage: "draft_phase2", decision_owner: "product_owner", impact_if_ignored: "fails", source_refs: [{ source: "test.ts", detail: "d" }] } });
25
- appendScopeEvent(paths, { type: "constraint.decision_recorded", actor: "user", payload: { constraint_id: "CST-001", decision: "inject", selected_option: "fix", decision_owner: "product_owner", rationale: "필수" } });
26
- appendScopeEvent(paths, { type: "target.locked", actor: "system", payload: { surface_hash: "sf1", constraint_decisions: [{ constraint_id: "CST-001", decision: "inject" }] } });
27
- appendScopeEvent(paths, { type: "compile.started", actor: "system", payload: { snapshot_revision: 1, surface_hash: "sf1" } });
28
- appendScopeEvent(paths, { type: "compile.completed", actor: "system", payload: { build_spec_path: "build/build-spec.md", build_spec_hash: "bs1", brownfield_detail_path: "build/brownfield-detail.md", brownfield_detail_hash: "bf1", delta_set_path: "build/delta-set.json", delta_set_hash: "ds1", validation_plan_path: "build/validation-plan.md", validation_plan_hash: "vp1" } });
29
- appendScopeEvent(paths, { type: "pre_apply.review_completed", actor: "agent", payload: { verdict: "pass", findings: [] } });
30
- appendScopeEvent(paths, { type: "prd.review_completed", actor: "agent", payload: { verdict: "pass", perspectives: ["prd_logic", "prd_structure", "prd_dependency", "prd_semantics", "prd_pragmatics", "prd_evolution", "prd_coverage", "prd_conciseness"], findings: [] } });
31
- return paths;
32
- }
33
- /** Set up scope through applied state */
34
- function setupApplied() {
35
- const paths = setupCompiled();
36
- appendScopeEvent(paths, { type: "apply.started", actor: "agent", payload: { build_spec_hash: "bs1" } }, { apply_enabled: true });
37
- appendScopeEvent(paths, { type: "apply.completed", actor: "agent", payload: { result: "success" } });
38
- return paths;
39
- }
40
- describe("executeApply", () => {
41
- it("start_apply → compiled (self transition)", () => {
42
- const paths = setupCompiled();
43
- const result = executeApply(paths, { type: "start_apply", buildSpecHash: "bs1" }, { projectRoot: tmpDir });
44
- expect(result.success).toBe(true);
45
- if (!result.success)
46
- return;
47
- expect(result.nextState).toBe("compiled");
48
- const state = reduce(readEvents(paths.events));
49
- expect(state.current_state).toBe("compiled");
50
- });
51
- it("complete_apply → applied", () => {
52
- const paths = setupCompiled();
53
- executeApply(paths, { type: "start_apply", buildSpecHash: "bs1" });
54
- const result = executeApply(paths, { type: "complete_apply", result: "success" });
55
- expect(result.success).toBe(true);
56
- if (!result.success)
57
- return;
58
- expect(result.nextState).toBe("applied");
59
- const state = reduce(readEvents(paths.events));
60
- expect(state.current_state).toBe("applied");
61
- });
62
- it("full happy path: start → complete → validate → pass", () => {
63
- const paths = setupCompiled();
64
- // start_apply
65
- const startResult = executeApply(paths, { type: "start_apply", buildSpecHash: "bs1" }, { projectRoot: tmpDir });
66
- expect(startResult.success).toBe(true);
67
- // complete_apply
68
- const completeResult = executeApply(paths, { type: "complete_apply", result: "success" });
69
- expect(completeResult.success).toBe(true);
70
- // start_validation
71
- const valStartResult = executeApply(paths, { type: "start_validation", validationPlanHash: "vp1" });
72
- expect(valStartResult.success).toBe(true);
73
- // complete_validation (pass)
74
- const valCompleteResult = executeApply(paths, {
75
- type: "complete_validation",
76
- plan: [{ val_id: "VAL-001", related_cst: "CST-001", decision_type: "inject", target: "test.ts", method: "manual", pass_criteria: "works", fail_action: "fix" }],
77
- results: [{ val_id: "VAL-001", related_cst: "CST-001", result: "pass", detail: "확인 완료" }],
78
- actualPlanHash: "vp1",
79
- });
80
- expect(valCompleteResult.success).toBe(true);
81
- if (!valCompleteResult.success)
82
- return;
83
- expect(valCompleteResult.nextState).toBe("validated");
84
- const state = reduce(readEvents(paths.events));
85
- expect(state.current_state).toBe("validated");
86
- });
87
- it("report_gap → constraints_resolved (backward transition)", () => {
88
- const paths = setupCompiled();
89
- executeApply(paths, { type: "start_apply", buildSpecHash: "bs1" });
90
- const result = executeApply(paths, {
91
- type: "report_gap",
92
- constraintPayload: {
93
- constraint_id: "CST-002",
94
- perspective: "code",
95
- summary: "edge case 발견",
96
- severity: "required",
97
- discovery_stage: "apply",
98
- decision_owner: "product_owner",
99
- impact_if_ignored: "data loss",
100
- source_refs: [{ source: "handler.ts", detail: "line 42" }],
101
- },
102
- gapPayload: {
103
- new_constraint_id: "CST-002",
104
- description: "미결정 edge case 발견",
105
- },
106
- });
107
- expect(result.success).toBe(true);
108
- if (!result.success)
109
- return;
110
- expect(result.nextState).toBe("constraints_resolved");
111
- const state = reduce(readEvents(paths.events));
112
- expect(state.current_state).toBe("constraints_resolved");
113
- });
114
- it("validation fail → constraints_resolved", () => {
115
- const paths = setupApplied();
116
- // start_validation
117
- executeApply(paths, { type: "start_validation", validationPlanHash: "vp1" });
118
- // complete_validation (fail)
119
- const result = executeApply(paths, {
120
- type: "complete_validation",
121
- plan: [{ val_id: "VAL-001", related_cst: "CST-001", decision_type: "inject", target: "test.ts", method: "manual", pass_criteria: "works", fail_action: "fix" }],
122
- results: [{ val_id: "VAL-001", related_cst: "CST-001", result: "fail", detail: "구현 누락" }],
123
- actualPlanHash: "vp1",
124
- });
125
- expect(result.success).toBe(true);
126
- if (!result.success)
127
- return;
128
- expect(result.nextState).toBe("constraints_resolved");
129
- expect(result.data?.result).toBe("fail");
130
- const state = reduce(readEvents(paths.events));
131
- expect(state.current_state).toBe("constraints_resolved");
132
- });
133
- it("start_apply fails when not in compiled state", () => {
134
- const paths = setupApplied(); // already applied
135
- const result = executeApply(paths, { type: "start_apply", buildSpecHash: "bs1" }, { projectRoot: tmpDir });
136
- expect(result.success).toBe(false);
137
- });
138
- });
@@ -1,39 +0,0 @@
1
- /**
2
- * /close command orchestration.
3
- *
4
- * Closes a validated scope:
5
- * - validated → scope.closed → closed
6
- *
7
- * Only allowed when current state is "validated".
8
- */
9
- import { readEvents } from "../../scope-runtime/event-store.js";
10
- import { reduce } from "../../scope-runtime/reducer.js";
11
- import { appendScopeEvent } from "../../scope-runtime/event-pipeline.js";
12
- import { wrapGateError } from "./error-messages.js";
13
- import { refreshScopeMd } from "./shared.js";
14
- // ─── Main ───
15
- export function executeClose(paths) {
16
- const events = readEvents(paths.events);
17
- const state = reduce(events);
18
- if (state.current_state !== "validated") {
19
- return {
20
- success: false,
21
- reason: `현재 상태가 ${state.current_state}입니다. /close는 validated 상태에서만 실행할 수 있습니다.`,
22
- };
23
- }
24
- const result = appendScopeEvent(paths, {
25
- type: "scope.closed",
26
- actor: "user",
27
- payload: {},
28
- });
29
- if (!result.success)
30
- return { success: false, reason: wrapGateError(result.reason) };
31
- refreshScopeMd(paths, result.state);
32
- return {
33
- success: true,
34
- nextState: "closed",
35
- message: "Scope가 종료되었습니다.",
36
- };
37
- }
38
- // refreshScopeMd is imported from ./shared.ts (UF-CONCISENESS-SCOPE-MD consolidated)
39
- // executeDefer lives in ./defer.ts so deferral has its own runtime adapter surface.
@@ -1,99 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { mkdtempSync, rmSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { tmpdir } from "node:os";
5
- import { executeClose } from "./close.js";
6
- import { createScope } from "../../scope-runtime/scope-manager.js";
7
- import { appendScopeEvent } from "../../scope-runtime/event-pipeline.js";
8
- import { readEvents } from "../../scope-runtime/event-store.js";
9
- import { reduce } from "../../scope-runtime/reducer.js";
10
- let tmpDir;
11
- beforeEach(() => { tmpDir = mkdtempSync(join(tmpdir(), "sprint-close-")); });
12
- afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });
13
- /** Set up scope through validated state */
14
- function setupValidated() {
15
- const paths = createScope(tmpDir, "SC-CLOSE-001");
16
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "Test", description: "d", entry_mode: "experience" } });
17
- appendScopeEvent(paths, { type: "grounding.started", actor: "system", payload: { sources: [{ type: "add-dir", path_or_url: "/test" }] } });
18
- appendScopeEvent(paths, { type: "grounding.completed", actor: "system", payload: { snapshot_revision: 1, source_hashes: { "add-dir:/test": "h1" }, perspective_summary: { experience: 1, code: 1, policy: 1 } } });
19
- appendScopeEvent(paths, { type: "align.proposed", actor: "system", payload: { packet_path: "build/align-packet.md", packet_hash: "h", snapshot_revision: 1 } });
20
- appendScopeEvent(paths, { type: "align.locked", actor: "user", payload: { locked_direction: "test", locked_scope_boundaries: { in: ["a"], out: ["b"] }, locked_in_out: true } });
21
- appendScopeEvent(paths, { type: "surface.generated", actor: "system", payload: { surface_type: "experience", surface_path: "surface/preview/", content_hash: "sf1", based_on_snapshot: 1 } });
22
- appendScopeEvent(paths, { type: "surface.confirmed", actor: "user", payload: { final_surface_path: "surface/preview/", final_content_hash: "sf1", total_revisions: 0 } });
23
- appendScopeEvent(paths, { type: "constraint.discovered", actor: "system", payload: { constraint_id: "CST-001", perspective: "code", summary: "test constraint", severity: "required", discovery_stage: "draft_phase2", decision_owner: "product_owner", impact_if_ignored: "fails", source_refs: [{ source: "test.ts", detail: "d" }] } });
24
- appendScopeEvent(paths, { type: "constraint.decision_recorded", actor: "user", payload: { constraint_id: "CST-001", decision: "inject", selected_option: "fix", decision_owner: "product_owner", rationale: "필수" } });
25
- appendScopeEvent(paths, { type: "target.locked", actor: "system", payload: { surface_hash: "sf1", constraint_decisions: [{ constraint_id: "CST-001", decision: "inject" }] } });
26
- appendScopeEvent(paths, { type: "compile.started", actor: "system", payload: { snapshot_revision: 1, surface_hash: "sf1" } });
27
- appendScopeEvent(paths, { type: "compile.completed", actor: "system", payload: { build_spec_path: "build/build-spec.md", build_spec_hash: "bs1", brownfield_detail_path: "build/brownfield-detail.md", brownfield_detail_hash: "bf1", delta_set_path: "build/delta-set.json", delta_set_hash: "ds1", validation_plan_path: "build/validation-plan.md", validation_plan_hash: "vp1" } });
28
- appendScopeEvent(paths, { type: "apply.started", actor: "agent", payload: { build_spec_hash: "bs1" } });
29
- appendScopeEvent(paths, { type: "apply.completed", actor: "agent", payload: { result: "success" } });
30
- appendScopeEvent(paths, { type: "validation.started", actor: "agent", payload: { validation_plan_hash: "vp1" } });
31
- appendScopeEvent(paths, { type: "validation.completed", actor: "agent", payload: { result: "pass", pass_count: 1, fail_count: 0, items: [{ val_id: "VAL-001", related_cst: "CST-001", result: "pass", detail: "확인 완료" }] } });
32
- return paths;
33
- }
34
- describe("executeClose", () => {
35
- it("validated → closed", () => {
36
- const paths = setupValidated();
37
- const state = reduce(readEvents(paths.events));
38
- expect(state.current_state).toBe("validated");
39
- const result = executeClose(paths);
40
- expect(result.success).toBe(true);
41
- if (!result.success)
42
- return;
43
- expect(result.nextState).toBe("closed");
44
- const updatedState = reduce(readEvents(paths.events));
45
- expect(updatedState.current_state).toBe("closed");
46
- });
47
- it("fails when not in validated state (draft)", () => {
48
- const paths = createScope(tmpDir, "SC-CLOSE-002");
49
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "T", description: "d", entry_mode: "experience" } });
50
- const result = executeClose(paths);
51
- expect(result.success).toBe(false);
52
- if (result.success)
53
- return;
54
- expect(result.reason).toContain("validated");
55
- });
56
- it("fails when in compiled state", () => {
57
- const paths = createScope(tmpDir, "SC-CLOSE-003");
58
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "Test", description: "d", entry_mode: "experience" } });
59
- appendScopeEvent(paths, { type: "grounding.started", actor: "system", payload: { sources: [{ type: "add-dir", path_or_url: "/test" }] } });
60
- appendScopeEvent(paths, { type: "grounding.completed", actor: "system", payload: { snapshot_revision: 1, source_hashes: { "add-dir:/test": "h1" }, perspective_summary: { experience: 1, code: 1, policy: 1 } } });
61
- appendScopeEvent(paths, { type: "align.proposed", actor: "system", payload: { packet_path: "build/align-packet.md", packet_hash: "h", snapshot_revision: 1 } });
62
- appendScopeEvent(paths, { type: "align.locked", actor: "user", payload: { locked_direction: "test", locked_scope_boundaries: { in: ["a"], out: ["b"] }, locked_in_out: true } });
63
- appendScopeEvent(paths, { type: "surface.generated", actor: "system", payload: { surface_type: "experience", surface_path: "surface/preview/", content_hash: "sf1", based_on_snapshot: 1 } });
64
- appendScopeEvent(paths, { type: "surface.confirmed", actor: "user", payload: { final_surface_path: "surface/preview/", final_content_hash: "sf1", total_revisions: 0 } });
65
- appendScopeEvent(paths, { type: "constraint.discovered", actor: "system", payload: { constraint_id: "CST-001", perspective: "code", summary: "c", severity: "required", discovery_stage: "draft_phase2", decision_owner: "product_owner", impact_if_ignored: "f", source_refs: [{ source: "t", detail: "d" }] } });
66
- appendScopeEvent(paths, { type: "constraint.decision_recorded", actor: "user", payload: { constraint_id: "CST-001", decision: "inject", selected_option: "fix", decision_owner: "product_owner", rationale: "r" } });
67
- appendScopeEvent(paths, { type: "target.locked", actor: "system", payload: { surface_hash: "sf1", constraint_decisions: [{ constraint_id: "CST-001", decision: "inject" }] } });
68
- appendScopeEvent(paths, { type: "compile.started", actor: "system", payload: { snapshot_revision: 1, surface_hash: "sf1" } });
69
- appendScopeEvent(paths, { type: "compile.completed", actor: "system", payload: { build_spec_path: "build/build-spec.md", build_spec_hash: "bs1", brownfield_detail_path: "build/brownfield-detail.md", brownfield_detail_hash: "bf1", delta_set_path: "build/delta-set.json", delta_set_hash: "ds1", validation_plan_path: "build/validation-plan.md", validation_plan_hash: "vp1" } });
70
- const result = executeClose(paths);
71
- expect(result.success).toBe(false);
72
- if (result.success)
73
- return;
74
- expect(result.reason).toContain("validated");
75
- });
76
- it("fails when in applied state", () => {
77
- const paths = createScope(tmpDir, "SC-CLOSE-004");
78
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "Test", description: "d", entry_mode: "experience" } });
79
- appendScopeEvent(paths, { type: "grounding.started", actor: "system", payload: { sources: [{ type: "add-dir", path_or_url: "/test" }] } });
80
- appendScopeEvent(paths, { type: "grounding.completed", actor: "system", payload: { snapshot_revision: 1, source_hashes: { "add-dir:/test": "h1" }, perspective_summary: { experience: 1, code: 1, policy: 1 } } });
81
- appendScopeEvent(paths, { type: "align.proposed", actor: "system", payload: { packet_path: "build/align-packet.md", packet_hash: "h", snapshot_revision: 1 } });
82
- appendScopeEvent(paths, { type: "align.locked", actor: "user", payload: { locked_direction: "test", locked_scope_boundaries: { in: ["a"], out: ["b"] }, locked_in_out: true } });
83
- appendScopeEvent(paths, { type: "surface.generated", actor: "system", payload: { surface_type: "experience", surface_path: "surface/preview/", content_hash: "sf1", based_on_snapshot: 1 } });
84
- appendScopeEvent(paths, { type: "surface.confirmed", actor: "user", payload: { final_surface_path: "surface/preview/", final_content_hash: "sf1", total_revisions: 0 } });
85
- appendScopeEvent(paths, { type: "constraint.discovered", actor: "system", payload: { constraint_id: "CST-001", perspective: "code", summary: "c", severity: "required", discovery_stage: "draft_phase2", decision_owner: "product_owner", impact_if_ignored: "f", source_refs: [{ source: "t", detail: "d" }] } });
86
- appendScopeEvent(paths, { type: "constraint.decision_recorded", actor: "user", payload: { constraint_id: "CST-001", decision: "inject", selected_option: "fix", decision_owner: "product_owner", rationale: "r" } });
87
- appendScopeEvent(paths, { type: "target.locked", actor: "system", payload: { surface_hash: "sf1", constraint_decisions: [{ constraint_id: "CST-001", decision: "inject" }] } });
88
- appendScopeEvent(paths, { type: "compile.started", actor: "system", payload: { snapshot_revision: 1, surface_hash: "sf1" } });
89
- appendScopeEvent(paths, { type: "compile.completed", actor: "system", payload: { build_spec_path: "build/build-spec.md", build_spec_hash: "bs1", brownfield_detail_path: "build/brownfield-detail.md", brownfield_detail_hash: "bf1", delta_set_path: "build/delta-set.json", delta_set_hash: "ds1", validation_plan_path: "build/validation-plan.md", validation_plan_hash: "vp1" } });
90
- appendScopeEvent(paths, { type: "apply.started", actor: "agent", payload: { build_spec_hash: "bs1" } });
91
- appendScopeEvent(paths, { type: "apply.completed", actor: "agent", payload: { result: "success" } });
92
- const result = executeClose(paths);
93
- expect(result.success).toBe(false);
94
- if (result.success)
95
- return;
96
- expect(result.reason).toContain("validated");
97
- });
98
- });
99
- // executeDefer tests have moved to ./defer.test.ts
@@ -1,40 +0,0 @@
1
- /**
2
- * /defer command orchestration.
3
- *
4
- * Defers a non-terminal scope with a reason and a resume condition:
5
- * any non-terminal state → scope.deferred → deferred
6
- *
7
- * Rejected when the scope is already in a terminal state (closed, deferred,
8
- * rejected). Separated from close.ts so that deferral has its own runtime
9
- * surface (BL-061: executeDefer existed but was not reachable from the evolve runtime adapter).
10
- */
11
- import { readEvents } from "../../scope-runtime/event-store.js";
12
- import { reduce } from "../../scope-runtime/reducer.js";
13
- import { appendScopeEvent } from "../../scope-runtime/event-pipeline.js";
14
- import { wrapGateError } from "./error-messages.js";
15
- import { refreshScopeMd } from "./shared.js";
16
- // ─── Main ───
17
- export function executeDefer(paths, reason, resumeCondition) {
18
- const events = readEvents(paths.events);
19
- const state = reduce(events);
20
- const terminalStates = ["closed", "deferred", "rejected"];
21
- if (terminalStates.includes(state.current_state)) {
22
- return {
23
- success: false,
24
- reason: `현재 상태가 ${state.current_state}입니다. 이미 종료된 scope는 보류할 수 없습니다.`,
25
- };
26
- }
27
- const result = appendScopeEvent(paths, {
28
- type: "scope.deferred",
29
- actor: "user",
30
- payload: { reason, resume_condition: resumeCondition },
31
- });
32
- if (!result.success)
33
- return { success: false, reason: wrapGateError(result.reason) };
34
- refreshScopeMd(paths, result.state);
35
- return {
36
- success: true,
37
- nextState: "deferred",
38
- message: "Scope가 보류되었습니다.",
39
- };
40
- }
@@ -1,134 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
- import { mkdtempSync, rmSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { tmpdir } from "node:os";
5
- import { executeDefer } from "./defer.js";
6
- import { executeClose } from "./close.js";
7
- import { createScope } from "../../scope-runtime/scope-manager.js";
8
- import { appendScopeEvent } from "../../scope-runtime/event-pipeline.js";
9
- import { readEvents } from "../../scope-runtime/event-store.js";
10
- import { reduce } from "../../scope-runtime/reducer.js";
11
- import { handleEvolveCli } from "../cli.js";
12
- let tmpDir;
13
- beforeEach(() => { tmpDir = mkdtempSync(join(tmpdir(), "sprint-defer-")); });
14
- afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });
15
- /** Set up a scope through validated state so terminal-state tests can close it. */
16
- function setupValidated(scopeId) {
17
- const paths = createScope(tmpDir, scopeId);
18
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "Test", description: "d", entry_mode: "experience" } });
19
- appendScopeEvent(paths, { type: "grounding.started", actor: "system", payload: { sources: [{ type: "add-dir", path_or_url: "/test" }] } });
20
- appendScopeEvent(paths, { type: "grounding.completed", actor: "system", payload: { snapshot_revision: 1, source_hashes: { "add-dir:/test": "h1" }, perspective_summary: { experience: 1, code: 1, policy: 1 } } });
21
- appendScopeEvent(paths, { type: "align.proposed", actor: "system", payload: { packet_path: "build/align-packet.md", packet_hash: "h", snapshot_revision: 1 } });
22
- appendScopeEvent(paths, { type: "align.locked", actor: "user", payload: { locked_direction: "test", locked_scope_boundaries: { in: ["a"], out: ["b"] }, locked_in_out: true } });
23
- appendScopeEvent(paths, { type: "surface.generated", actor: "system", payload: { surface_type: "experience", surface_path: "surface/preview/", content_hash: "sf1", based_on_snapshot: 1 } });
24
- appendScopeEvent(paths, { type: "surface.confirmed", actor: "user", payload: { final_surface_path: "surface/preview/", final_content_hash: "sf1", total_revisions: 0 } });
25
- appendScopeEvent(paths, { type: "constraint.discovered", actor: "system", payload: { constraint_id: "CST-001", perspective: "code", summary: "c", severity: "required", discovery_stage: "draft_phase2", decision_owner: "product_owner", impact_if_ignored: "f", source_refs: [{ source: "t", detail: "d" }] } });
26
- appendScopeEvent(paths, { type: "constraint.decision_recorded", actor: "user", payload: { constraint_id: "CST-001", decision: "inject", selected_option: "fix", decision_owner: "product_owner", rationale: "r" } });
27
- appendScopeEvent(paths, { type: "target.locked", actor: "system", payload: { surface_hash: "sf1", constraint_decisions: [{ constraint_id: "CST-001", decision: "inject" }] } });
28
- appendScopeEvent(paths, { type: "compile.started", actor: "system", payload: { snapshot_revision: 1, surface_hash: "sf1" } });
29
- appendScopeEvent(paths, { type: "compile.completed", actor: "system", payload: { build_spec_path: "build/build-spec.md", build_spec_hash: "bs1", brownfield_detail_path: "build/brownfield-detail.md", brownfield_detail_hash: "bf1", delta_set_path: "build/delta-set.json", delta_set_hash: "ds1", validation_plan_path: "build/validation-plan.md", validation_plan_hash: "vp1" } });
30
- appendScopeEvent(paths, { type: "apply.started", actor: "agent", payload: { build_spec_hash: "bs1" } });
31
- appendScopeEvent(paths, { type: "apply.completed", actor: "agent", payload: { result: "success" } });
32
- appendScopeEvent(paths, { type: "validation.started", actor: "agent", payload: { validation_plan_hash: "vp1" } });
33
- appendScopeEvent(paths, { type: "validation.completed", actor: "agent", payload: { result: "pass", pass_count: 1, fail_count: 0, items: [{ val_id: "VAL-001", related_cst: "CST-001", result: "pass", detail: "확인 완료" }] } });
34
- return paths;
35
- }
36
- describe("executeDefer", () => {
37
- it("defers from any non-terminal state", () => {
38
- const paths = createScope(tmpDir, "SC-DEFER-001");
39
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "T", description: "d", entry_mode: "experience" } });
40
- const result = executeDefer(paths, "방향 재정립 필요", "다음 분기 재개");
41
- expect(result.success).toBe(true);
42
- if (!result.success)
43
- return;
44
- expect(result.nextState).toBe("deferred");
45
- const state = reduce(readEvents(paths.events));
46
- expect(state.current_state).toBe("deferred");
47
- });
48
- it("fails from terminal state (closed)", () => {
49
- const paths = setupValidated("SC-DEFER-002");
50
- executeClose(paths); // → closed
51
- const result = executeDefer(paths, "test", "test");
52
- expect(result.success).toBe(false);
53
- if (result.success)
54
- return;
55
- expect(result.reason).toContain("closed");
56
- });
57
- it("fails when already deferred", () => {
58
- const paths = createScope(tmpDir, "SC-DEFER-003");
59
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "T", description: "d", entry_mode: "experience" } });
60
- executeDefer(paths, "first", "cond");
61
- const result = executeDefer(paths, "second", "cond");
62
- expect(result.success).toBe(false);
63
- if (result.success)
64
- return;
65
- expect(result.reason).toContain("deferred");
66
- });
67
- });
68
- describe("onto evolve defer — CLI surface", () => {
69
- let logs;
70
- let errors;
71
- let logSpy;
72
- let errorSpy;
73
- beforeEach(() => {
74
- logs = [];
75
- errors = [];
76
- logSpy = vi.spyOn(console, "log").mockImplementation((msg) => {
77
- logs.push(String(msg));
78
- });
79
- errorSpy = vi.spyOn(console, "error").mockImplementation((msg) => {
80
- errors.push(String(msg));
81
- });
82
- });
83
- afterEach(() => {
84
- logSpy.mockRestore();
85
- errorSpy.mockRestore();
86
- });
87
- it("routes defer subcommand to executeDefer and succeeds", async () => {
88
- const scopesDir = join(tmpDir, "scopes");
89
- const paths = createScope(scopesDir, "SC-CLI-DEFER-001");
90
- appendScopeEvent(paths, { type: "scope.created", actor: "user", payload: { title: "T", description: "d", entry_mode: "experience" } });
91
- const code = await handleEvolveCli(tmpDir, [
92
- "defer",
93
- "--scope-id", "SC-CLI-DEFER-001",
94
- "--scopes-dir", scopesDir,
95
- "--reason", "방향 재정립",
96
- "--resume-condition", "다음 분기",
97
- ]);
98
- expect(code).toBe(0);
99
- const state = reduce(readEvents(paths.events));
100
- expect(state.current_state).toBe("deferred");
101
- const output = logs.join("\n");
102
- expect(output).toContain("\"success\": true");
103
- expect(output).toContain("\"nextState\": \"deferred\"");
104
- });
105
- it("rejects defer when --reason missing", async () => {
106
- const scopesDir = join(tmpDir, "scopes");
107
- createScope(scopesDir, "SC-CLI-DEFER-002");
108
- const code = await handleEvolveCli(tmpDir, [
109
- "defer",
110
- "--scope-id", "SC-CLI-DEFER-002",
111
- "--scopes-dir", scopesDir,
112
- "--resume-condition", "cond",
113
- ]);
114
- expect(code).toBe(1);
115
- expect(errors.some(e => e.includes("--reason") && e.includes("--resume-condition"))).toBe(true);
116
- });
117
- it("rejects defer when --scope-id missing", async () => {
118
- const code = await handleEvolveCli(tmpDir, [
119
- "defer",
120
- "--reason", "r",
121
- "--resume-condition", "c",
122
- ]);
123
- expect(code).toBe(1);
124
- expect(errors.some(e => e.includes("--scope-id"))).toBe(true);
125
- });
126
- it("lists defer in --help output", async () => {
127
- const code = await handleEvolveCli(tmpDir, ["--help"]);
128
- expect(code).toBe(0);
129
- const output = logs.join("\n");
130
- expect(output).toContain("defer --scope-id");
131
- expect(output).toContain("--reason");
132
- expect(output).toContain("--resume-condition");
133
- });
134
- });