onto-mcp 0.3.2 → 0.4.1

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 +149 -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 +174 -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 +214 -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,615 +0,0 @@
1
- /**
2
- * Codex multi-agent fixes — E2E test suite.
3
- *
4
- * Run: `npx vitest run src/core-runtime/cli/e2e-codex-multi-agent-fixes.test.ts`
5
- *
6
- * Covers:
7
- * B. OntoConfig codex namespace (config-chain.ts)
8
- * C. appendExecutorModelArgs codex fallback (review-invoke.ts)
9
- * D. Synthesize retry (run-review-prompt-execution.ts)
10
- * E. Coordinator agent prompt — Write tool removed (coordinator-state-machine.ts)
11
- * F. process.md ToolSearch instruction
12
- *
13
- * Isolation strategy:
14
- * Each test builds minimal tmpdir fixtures. Tests that exercise the
15
- * prompt execution runner build a full session directory with a mock
16
- * execution-plan.yaml and mock prompt packets.
17
- *
18
- * Format history:
19
- * Converted from a tsx-run custom minimal test runner to vitest in
20
- * 2026-04-18 (handoff §2 Priority 2 Phase C). Fixture update included:
21
- * B-1~B-6 now declare `execution_topology_priority` so atomic profile
22
- * adoption (PR #96 + PR #113) does not reject the partial-profile
23
- * fixtures that predated sketch v3.
24
- */
25
- import { describe, it, afterAll } from "vitest";
26
- import fs from "node:fs";
27
- import os from "node:os";
28
- import path from "node:path";
29
- import { resolveConfigChain } from "../discovery/config-chain.js";
30
- // ---------------------------------------------------------------------------
31
- // Test helpers
32
- // ---------------------------------------------------------------------------
33
- function assert(condition, message) {
34
- if (!condition)
35
- throw new Error(message);
36
- }
37
- function assertEqual(actual, expected, message) {
38
- if (actual !== expected) {
39
- throw new Error(`${message} — expected ${JSON.stringify(expected)} got ${JSON.stringify(actual)}`);
40
- }
41
- }
42
- function assertIncludes(text, needle, message) {
43
- if (!text.includes(needle)) {
44
- throw new Error(`${message} — text does not include ${JSON.stringify(needle)}`);
45
- }
46
- }
47
- function assertNotIncludes(text, needle, message) {
48
- if (text.includes(needle)) {
49
- throw new Error(`${message} — text unexpectedly includes ${JSON.stringify(needle)}`);
50
- }
51
- }
52
- // ---------------------------------------------------------------------------
53
- // Fixture helpers
54
- // ---------------------------------------------------------------------------
55
- function makeTmpDir(prefix) {
56
- return fs.mkdtempSync(path.join(os.tmpdir(), `onto-e2e-cmaf-${prefix}-`));
57
- }
58
- function writeYaml(filePath, data) {
59
- // Minimal YAML serializer sufficient for test fixtures
60
- const lines = [];
61
- function renderValue(value, indent) {
62
- const pad = " ".repeat(indent);
63
- if (value === null || value === undefined) {
64
- lines.push("null");
65
- return;
66
- }
67
- if (typeof value === "string") {
68
- // Use quoted form for safety
69
- lines.push(`"${value.replace(/"/g, '\\"')}"`);
70
- return;
71
- }
72
- if (typeof value === "number" || typeof value === "boolean") {
73
- lines.push(String(value));
74
- return;
75
- }
76
- if (Array.isArray(value)) {
77
- if (value.length === 0) {
78
- lines.push("[]");
79
- return;
80
- }
81
- lines.push("");
82
- for (const item of value) {
83
- const lineStart = `${pad}- `;
84
- if (typeof item === "object" && item !== null && !Array.isArray(item)) {
85
- const entries = Object.entries(item);
86
- let first = true;
87
- for (const [k, v] of entries) {
88
- if (first) {
89
- lines.push(`${lineStart}${k}: `);
90
- first = false;
91
- }
92
- else {
93
- lines.push(`${pad} ${k}: `);
94
- }
95
- renderValue(v, indent + 4);
96
- }
97
- }
98
- else {
99
- lines.push(lineStart);
100
- renderValue(item, indent + 2);
101
- }
102
- }
103
- return;
104
- }
105
- if (typeof value === "object") {
106
- const entries = Object.entries(value);
107
- if (entries.length === 0) {
108
- lines.push("{}");
109
- return;
110
- }
111
- lines.push("");
112
- for (const [k, v] of entries) {
113
- lines.push(`${pad}${k}: `);
114
- renderValue(v, indent + 2);
115
- }
116
- return;
117
- }
118
- lines.push(String(value));
119
- }
120
- for (const [key, value] of Object.entries(data)) {
121
- lines.push(`${key}: `);
122
- renderValue(value, 2);
123
- }
124
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
125
- fs.writeFileSync(filePath, lines.join("").replace(/: \n/g, ":\n").replace(/: (\S)/g, ": $1") + "\n", "utf8");
126
- }
127
- /** Cleanup directory, ignoring errors. */
128
- function rmDir(dir) {
129
- try {
130
- fs.rmSync(dir, { recursive: true, force: true });
131
- }
132
- catch { /* ignore */ }
133
- }
134
- const cleanupDirs = [];
135
- function trackCleanup(dir) {
136
- cleanupDirs.push(dir);
137
- return dir;
138
- }
139
- // ---------------------------------------------------------------------------
140
- // B. OntoConfig codex namespace (config-chain.ts)
141
- // ---------------------------------------------------------------------------
142
- describe("B. config-chain codex namespace", () => {
143
- // Fixture note (P9.4, 2026-04-21): each config.yml declares a `review:`
144
- // axis block so the project side claims profile ownership. Post-P9.4
145
- // this is no longer a hard requirement — a project with only profile
146
- // fields (no review block) would also adopt, and a project with only
147
- // a review block (no profile fields) also adopts via the ownership
148
- // claim — but keeping the review block in fixtures exercises the
149
- // canonical user-facing shape. The specific axis values don't affect
150
- // what these tests assert: they verify that the orthogonal/profile
151
- // merge correctly surfaces the `codex:` namespace and top-level
152
- // `model` / `reasoning_effort` values.
153
- //
154
- // History: pre-P9.2 the completeness signal was
155
- // `execution_topology_priority`. Pre-P9.4 the signal was the `review:`
156
- // axis block via `validateProfileCompleteness` (retired along with
157
- // `buildBothIncompleteError` in P9.4). P9.5 additionally retired
158
- // `legacy-field-deprecation.ts` — legacy provider fields in YAML are
159
- // now silently dropped during type narrowing; these tests still
160
- // declare `review:` blocks for realism, not for correctness.
161
- it("B-1: codex namespace parsed from project config", async () => {
162
- const homeDir = trackCleanup(makeTmpDir("b1h"));
163
- const projDir = trackCleanup(makeTmpDir("b1p"));
164
- fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
165
- fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex:\n model: gpt-5.4\n effort: xhigh\n", "utf8");
166
- const config = await resolveConfigChain(homeDir, projDir);
167
- assertEqual(config.codex?.model, "gpt-5.4", "codex.model parsed");
168
- assertEqual(config.codex?.effort, "xhigh", "codex.effort parsed");
169
- });
170
- it("B-2: project codex namespace overrides home", async () => {
171
- const homeDir = trackCleanup(makeTmpDir("b2h"));
172
- const projDir = trackCleanup(makeTmpDir("b2p"));
173
- fs.mkdirSync(path.join(homeDir, ".onto"), { recursive: true });
174
- fs.writeFileSync(path.join(homeDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex:\n model: gpt-5.3\n effort: high\n", "utf8");
175
- fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
176
- fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex:\n model: gpt-5.4\n effort: xhigh\n", "utf8");
177
- const config = await resolveConfigChain(homeDir, projDir);
178
- assertEqual(config.codex?.model, "gpt-5.4", "project codex.model wins");
179
- assertEqual(config.codex?.effort, "xhigh", "project codex.effort wins");
180
- });
181
- it("B-3: top-level model coexists with codex namespace", async () => {
182
- const homeDir = trackCleanup(makeTmpDir("b3h"));
183
- const projDir = trackCleanup(makeTmpDir("b3p"));
184
- fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
185
- fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\nmodel: claude-sonnet-4-20250514\nreasoning_effort: medium\ncodex:\n model: gpt-5.4\n effort: xhigh\n", "utf8");
186
- const config = await resolveConfigChain(homeDir, projDir);
187
- assertEqual(config.model, "claude-sonnet-4-20250514", "top-level model");
188
- assertEqual(config.reasoning_effort, "medium", "top-level reasoning_effort");
189
- assertEqual(config.codex?.model, "gpt-5.4", "codex.model");
190
- assertEqual(config.codex?.effort, "xhigh", "codex.effort");
191
- });
192
- it("B-4: missing codex namespace → undefined", async () => {
193
- const homeDir = trackCleanup(makeTmpDir("b4h"));
194
- const projDir = trackCleanup(makeTmpDir("b4p"));
195
- fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
196
- fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\nmodel: claude-sonnet-4-20250514\n", "utf8");
197
- const config = await resolveConfigChain(homeDir, projDir);
198
- assertEqual(config.codex, undefined, "codex absent → undefined");
199
- });
200
- it("B-5: empty codex namespace → empty object", async () => {
201
- const homeDir = trackCleanup(makeTmpDir("b5h"));
202
- const projDir = trackCleanup(makeTmpDir("b5p"));
203
- fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
204
- fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex: {}\n", "utf8");
205
- const config = await resolveConfigChain(homeDir, projDir);
206
- assert(config.codex !== undefined, "codex namespace exists");
207
- assertEqual(config.codex?.model, undefined, "codex.model undefined");
208
- assertEqual(config.codex?.effort, undefined, "codex.effort undefined");
209
- });
210
- it("B-6: home codex used when project has no config", async () => {
211
- const homeDir = trackCleanup(makeTmpDir("b6h"));
212
- const projDir = trackCleanup(makeTmpDir("b6p"));
213
- fs.mkdirSync(path.join(homeDir, ".onto"), { recursive: true });
214
- fs.writeFileSync(path.join(homeDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex:\n model: gpt-5.3\n effort: high\n", "utf8");
215
- // No .onto/config.yml in project
216
- const config = await resolveConfigChain(homeDir, projDir);
217
- assertEqual(config.codex?.model, "gpt-5.3", "home codex.model used");
218
- assertEqual(config.codex?.effort, "high", "home codex.effort used");
219
- });
220
- });
221
- // ---------------------------------------------------------------------------
222
- // C. appendExecutorModelArgs codex fallback (review-invoke.ts)
223
- //
224
- // We can't import the private function directly, so we test it indirectly
225
- // through the CLI argv interface by checking the resolved executor config.
226
- // Strategy: invoke reviewPrepareOnly with --codex and mock executor, then
227
- // inspect the execution-plan + the runner result to verify model/effort.
228
- //
229
- // For isolated unit testing, we duplicate the function's logic and verify.
230
- // ---------------------------------------------------------------------------
231
- import { readSingleOptionValueFromArgv } from "../review/review-artifact-utils.js";
232
- describe("C. codex config fallback", () => {
233
- function resolveModel(argv, config) {
234
- const fromArgv = readSingleOptionValueFromArgv(argv, "model");
235
- return ((typeof fromArgv === "string" && fromArgv.length > 0 ? fromArgv : undefined) ??
236
- config?.model ??
237
- config?.codex?.model);
238
- }
239
- function resolveEffort(argv, config) {
240
- const fromArgv = readSingleOptionValueFromArgv(argv, "reasoning-effort");
241
- return ((typeof fromArgv === "string" && fromArgv.length > 0 ? fromArgv : undefined) ??
242
- config?.reasoning_effort ??
243
- config?.codex?.effort);
244
- }
245
- it("C-1: CLI flag wins over everything (model)", () => {
246
- const config = {
247
- model: "claude-sonnet-4-20250514",
248
- codex: { model: "gpt-5.3" },
249
- };
250
- const result = resolveModel(["--model", "gpt-5.4"], config);
251
- assertEqual(result, "gpt-5.4", "CLI flag wins");
252
- });
253
- it("C-2: top-level config wins over codex namespace", () => {
254
- const config = {
255
- model: "claude-sonnet-4-20250514",
256
- codex: { model: "gpt-5.4" },
257
- };
258
- const result = resolveModel([], config);
259
- assertEqual(result, "claude-sonnet-4-20250514", "top-level wins");
260
- });
261
- it("C-3: codex namespace used when top-level absent (model)", () => {
262
- const config = {
263
- codex: { model: "gpt-5.4" },
264
- };
265
- const result = resolveModel([], config);
266
- assertEqual(result, "gpt-5.4", "codex.model fallback");
267
- });
268
- it("C-4: codex effort used when reasoning_effort absent", () => {
269
- const config = {
270
- codex: { effort: "xhigh" },
271
- };
272
- const result = resolveEffort([], config);
273
- assertEqual(result, "xhigh", "codex.effort fallback");
274
- });
275
- it("C-5: top-level reasoning_effort wins over codex effort", () => {
276
- const config = {
277
- reasoning_effort: "medium",
278
- codex: { effort: "xhigh" },
279
- };
280
- const result = resolveEffort([], config);
281
- assertEqual(result, "medium", "top-level effort wins");
282
- });
283
- it("C-6: CLI reasoning-effort wins over all", () => {
284
- const config = {
285
- reasoning_effort: "medium",
286
- codex: { effort: "xhigh" },
287
- };
288
- const result = resolveEffort(["--reasoning-effort", "low"], config);
289
- assertEqual(result, "low", "CLI flag wins");
290
- });
291
- it("C-7: all absent → undefined", () => {
292
- const config = {};
293
- assertEqual(resolveModel([], config), undefined, "model undefined");
294
- assertEqual(resolveEffort([], config), undefined, "effort undefined");
295
- });
296
- it("C-8: undefined config → undefined", () => {
297
- assertEqual(resolveModel([], undefined), undefined, "model no config");
298
- assertEqual(resolveEffort([], undefined), undefined, "effort no config");
299
- });
300
- });
301
- // ---------------------------------------------------------------------------
302
- // D. Synthesize retry (run-review-prompt-execution.ts)
303
- //
304
- // Strategy: build a minimal session, use always-succeed executor for lenses,
305
- // and flaky/always-fail executor for synthesize to test the new retry logic.
306
- // D-4/D-5 pre-write lens outputs to bypass the lens retry loop (10 retries
307
- // with 8s backoff = too slow for E2E tests).
308
- // ---------------------------------------------------------------------------
309
- import { executeReviewPromptExecution } from "./run-review-prompt-execution.js";
310
- import { writeYamlDocument } from "../review/review-artifact-utils.js";
311
- describe("D. Synthesize retry", () => {
312
- const projectRoot = process.cwd();
313
- const BOUNDARY_DECISION = {
314
- requested_policy: "denied",
315
- effective_policy: "denied",
316
- guarantee_level: "prompt_declared_only",
317
- notes: [],
318
- };
319
- async function buildMinimalSession(prefix) {
320
- const sessionRoot = trackCleanup(makeTmpDir(prefix));
321
- const packetRoot = path.join(sessionRoot, "prompt-packets");
322
- const round1Root = path.join(sessionRoot, "round1");
323
- fs.mkdirSync(packetRoot, { recursive: true });
324
- fs.mkdirSync(round1Root, { recursive: true });
325
- for (const lensId of ["logic", "pragmatics"]) {
326
- fs.writeFileSync(path.join(packetRoot, `${lensId}.prompt.md`), `# ${lensId} prompt packet\nTest.\n`, "utf8");
327
- }
328
- fs.writeFileSync(path.join(packetRoot, "synthesize.prompt.md"), "# Synthesize\nCombine.\n", "utf8");
329
- const synthesizeOutputPath = path.join(sessionRoot, "synthesis-output.md");
330
- await writeYamlDocument(path.join(sessionRoot, "execution-plan.yaml"), {
331
- session_id: `e2e-${prefix}`,
332
- session_root: sessionRoot,
333
- execution_realization: "subagent",
334
- host_runtime: "codex",
335
- review_mode: "core-axis",
336
- interpretation_artifact_path: path.join(sessionRoot, "interpretation.yaml"),
337
- binding_output_path: path.join(sessionRoot, "binding.yaml"),
338
- session_metadata_path: path.join(sessionRoot, "session-metadata.yaml"),
339
- execution_preparation_root: path.join(sessionRoot, "execution-preparation"),
340
- round1_root: round1Root,
341
- lens_execution_seats: [],
342
- prompt_packets_root: packetRoot,
343
- lens_prompt_packet_seats: [
344
- {
345
- lens_id: "logic",
346
- packet_path: path.join(packetRoot, "logic.prompt.md"),
347
- output_path: path.join(round1Root, "logic.md"),
348
- },
349
- {
350
- lens_id: "pragmatics",
351
- packet_path: path.join(packetRoot, "pragmatics.prompt.md"),
352
- output_path: path.join(round1Root, "pragmatics.md"),
353
- },
354
- ],
355
- synthesize_prompt_packet_path: path.join(packetRoot, "synthesize.prompt.md"),
356
- synthesis_output_path: synthesizeOutputPath,
357
- deliberation_output_path: path.join(sessionRoot, "deliberation.md"),
358
- execution_result_path: path.join(sessionRoot, "execution-result.yaml"),
359
- error_log_path: path.join(sessionRoot, "error-log.md"),
360
- final_output_path: path.join(sessionRoot, "final-output.md"),
361
- review_record_path: path.join(sessionRoot, "review-record.yaml"),
362
- boundary_policy: { web_research: "denied", repo_exploration: "denied", recursive_reference_expansion: "denied", source_mutation: "denied" },
363
- boundary_presentation: { web_research: "denied", repo_exploration: "denied", recursive_reference_expansion: "denied", source_mutation: "denied" },
364
- boundary_enforcement_profile: { web_research: "prompt_declared_only", repo_exploration: "prompt_declared_only", recursive_reference_expansion: "prompt_declared_only", source_mutation: "prompt_declared_only" },
365
- effective_boundary_state: {
366
- web_research: BOUNDARY_DECISION,
367
- repo_exploration: BOUNDARY_DECISION,
368
- recursive_reference_expansion: BOUNDARY_DECISION,
369
- source_mutation: BOUNDARY_DECISION,
370
- filesystem_scope: { requested_allowed_roots: [projectRoot], effective_allowed_roots: [projectRoot], guarantee_level: "prompt_declared_only", notes: [] },
371
- },
372
- });
373
- return { sessionRoot, synthesizeOutputPath };
374
- }
375
- /** Always-succeed executor script (for lenses). */
376
- function createSucceedScript(dir) {
377
- const scriptPath = path.join(dir, "succeed-executor.mjs");
378
- fs.writeFileSync(scriptPath, `
379
- import fs from "node:fs";
380
- import path from "node:path";
381
- const args = process.argv.slice(2);
382
- const unitId = args[args.indexOf("--unit-id") + 1];
383
- const unitKind = args[args.indexOf("--unit-kind") + 1];
384
- const outputPath = args[args.indexOf("--output-path") + 1];
385
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
386
- const output = unitKind === "synthesize"
387
- ? "---\\ndeliberation_status: not_needed\\n---\\n# Synthesize\\nResult.\\n"
388
- : "# " + unitId + "\\nLens result.\\n";
389
- fs.writeFileSync(outputPath, output, "utf8");
390
- `, "utf8");
391
- return scriptPath;
392
- }
393
- /** Flaky synthesize executor: tracks attempts via counter file. */
394
- function createSynthFlakyScript(dir, mode) {
395
- const scriptPath = path.join(dir, "synth-flaky.mjs");
396
- const counterPath = path.join(dir, "synth-counter.txt");
397
- fs.writeFileSync(scriptPath, `
398
- import fs from "node:fs";
399
- import path from "node:path";
400
- const args = process.argv.slice(2);
401
- const unitKind = args[args.indexOf("--unit-kind") + 1];
402
- const unitId = args[args.indexOf("--unit-id") + 1];
403
- const outputPath = args[args.indexOf("--output-path") + 1];
404
- const counterPath = ${JSON.stringify(counterPath)};
405
- const mode = ${JSON.stringify(mode)};
406
- if (unitKind === "synthesize") {
407
- let count = 0;
408
- try { count = parseInt(fs.readFileSync(counterPath, "utf8").trim(), 10); } catch {}
409
- count++;
410
- fs.writeFileSync(counterPath, String(count), "utf8");
411
- if (mode === "always-fail" || (mode === "fail-then-succeed" && count === 1)) {
412
- process.stderr.write("Simulated synthesize failure (attempt " + count + ")\\n");
413
- process.exit(1);
414
- }
415
- }
416
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
417
- const output = unitKind === "synthesize"
418
- ? "---\\ndeliberation_status: not_needed\\n---\\n# Synthesize\\nResult.\\n"
419
- : "# " + unitId + "\\nLens.\\n";
420
- fs.writeFileSync(outputPath, output, "utf8");
421
- `, "utf8");
422
- return { scriptPath, counterPath };
423
- }
424
- // ── D-1: synthesize succeeds on first attempt ──
425
- it("D-1: synthesize succeeds on first attempt", async () => {
426
- const { sessionRoot } = await buildMinimalSession("d1");
427
- const execDir = trackCleanup(makeTmpDir("d1-exec"));
428
- const succeedScript = createSucceedScript(execDir);
429
- const result = await executeReviewPromptExecution({
430
- projectRoot,
431
- sessionRoot,
432
- defaultExecutorConfig: { bin: "node", args: [succeedScript] },
433
- });
434
- assertEqual(result.synthesis_executed, true, "synthesis executed");
435
- assert(!result.halt_reason, "no halt");
436
- assertEqual(result.executed_lens_count, 2, "2 lenses");
437
- });
438
- // ── D-2: synthesize fails first, succeeds on retry ──
439
- it("D-2: synthesize fails then succeeds on retry", async () => {
440
- const { sessionRoot } = await buildMinimalSession("d2");
441
- const execDir = trackCleanup(makeTmpDir("d2-exec"));
442
- const succeedScript = createSucceedScript(execDir);
443
- const synthDir = path.join(execDir, "synth");
444
- fs.mkdirSync(synthDir, { recursive: true });
445
- const { scriptPath: synthScript, counterPath } = createSynthFlakyScript(synthDir, "fail-then-succeed");
446
- const result = await executeReviewPromptExecution({
447
- projectRoot,
448
- sessionRoot,
449
- defaultExecutorConfig: { bin: "node", args: [succeedScript] },
450
- synthesizeExecutorConfig: { bin: "node", args: [synthScript] },
451
- });
452
- assertEqual(result.synthesis_executed, true, "synthesis after retry");
453
- assert(!result.halt_reason, "no halt");
454
- const attempts = parseInt(fs.readFileSync(counterPath, "utf8").trim(), 10);
455
- assertEqual(attempts, 2, "2 attempts (1 fail + 1 success)");
456
- const errorLog = fs.readFileSync(path.join(sessionRoot, "error-log.md"), "utf8");
457
- assertIncludes(errorLog, "synthesize retry", "retry logged");
458
- });
459
- // ── D-3: synthesize fails both attempts → halt ──
460
- it("D-3: synthesize fails both attempts → halted", async () => {
461
- const { sessionRoot } = await buildMinimalSession("d3");
462
- const execDir = trackCleanup(makeTmpDir("d3-exec"));
463
- const succeedScript = createSucceedScript(execDir);
464
- const synthDir = path.join(execDir, "synth");
465
- fs.mkdirSync(synthDir, { recursive: true });
466
- const { scriptPath: synthScript, counterPath } = createSynthFlakyScript(synthDir, "always-fail");
467
- const result = await executeReviewPromptExecution({
468
- projectRoot,
469
- sessionRoot,
470
- defaultExecutorConfig: { bin: "node", args: [succeedScript] },
471
- synthesizeExecutorConfig: { bin: "node", args: [synthScript] },
472
- });
473
- assertEqual(result.synthesis_executed, false, "synthesis failed");
474
- assert(typeof result.halt_reason === "string" && result.halt_reason.length > 0, "halt_reason present");
475
- assertIncludes(result.halt_reason, "Synthesize execution failed", "halt reason");
476
- const attempts = parseInt(fs.readFileSync(counterPath, "utf8").trim(), 10);
477
- assertEqual(attempts, 2, "2 attempts before halt");
478
- });
479
- // ── D-4: execution-result artifact written on synthesize halt ──
480
- it("D-4: execution-result artifact written on synth halt", async () => {
481
- const { sessionRoot } = await buildMinimalSession("d4");
482
- const execDir = trackCleanup(makeTmpDir("d4-exec"));
483
- const succeedScript = createSucceedScript(execDir);
484
- const synthDir = path.join(execDir, "synth");
485
- fs.mkdirSync(synthDir, { recursive: true });
486
- const { scriptPath: synthScript } = createSynthFlakyScript(synthDir, "always-fail");
487
- await executeReviewPromptExecution({
488
- projectRoot,
489
- sessionRoot,
490
- defaultExecutorConfig: { bin: "node", args: [succeedScript] },
491
- synthesizeExecutorConfig: { bin: "node", args: [synthScript] },
492
- });
493
- const resultPath = path.join(sessionRoot, "execution-result.yaml");
494
- assert(fs.existsSync(resultPath), "execution-result.yaml created");
495
- const resultText = fs.readFileSync(resultPath, "utf8");
496
- assertIncludes(resultText, "halted_partial", "status is halted_partial");
497
- assertIncludes(resultText, "Synthesize execution failed", "halt_reason in artifact");
498
- });
499
- // ── D-5: successful retry still produces correct execution-result ──
500
- it("D-5: successful retry produces correct execution-result", async () => {
501
- const { sessionRoot } = await buildMinimalSession("d5");
502
- const execDir = trackCleanup(makeTmpDir("d5-exec"));
503
- const succeedScript = createSucceedScript(execDir);
504
- const synthDir = path.join(execDir, "synth");
505
- fs.mkdirSync(synthDir, { recursive: true });
506
- const { scriptPath: synthScript } = createSynthFlakyScript(synthDir, "fail-then-succeed");
507
- const result = await executeReviewPromptExecution({
508
- projectRoot,
509
- sessionRoot,
510
- defaultExecutorConfig: { bin: "node", args: [succeedScript] },
511
- synthesizeExecutorConfig: { bin: "node", args: [synthScript] },
512
- });
513
- assertEqual(result.synthesis_executed, true, "synthesis executed");
514
- const resultPath = path.join(sessionRoot, "execution-result.yaml");
515
- assert(fs.existsSync(resultPath), "execution-result.yaml created");
516
- const resultText = fs.readFileSync(resultPath, "utf8");
517
- assertIncludes(resultText, "completed", "status is completed");
518
- assertNotIncludes(resultText, "halted_partial", "not halted");
519
- });
520
- });
521
- // ---------------------------------------------------------------------------
522
- // E. Coordinator agent prompt — Write tool removed
523
- // ---------------------------------------------------------------------------
524
- describe("E. Coordinator agent prompt", () => {
525
- // Read the coordinator source to verify prompt template
526
- const coordinatorSource = fs.readFileSync(path.join(process.cwd(), "src/core-runtime/cli/coordinator-state-machine.ts"), "utf8");
527
- it("E-1: prompt does NOT contain 'using the Write tool'", () => {
528
- // Extract the AGENT_PROMPT_TEMPLATE string
529
- const templateMatch = coordinatorSource.match(/const AGENT_PROMPT_TEMPLATE = `([\s\S]*?)`;/);
530
- assert(templateMatch !== null, "AGENT_PROMPT_TEMPLATE found in source");
531
- const template = templateMatch?.[1] ?? "";
532
- assertNotIncludes(template, "using the Write tool", "prompt should not mention Write tool (Codex incompatible)");
533
- });
534
- it("E-2: prompt still instructs writing to output path", () => {
535
- const templateMatch = coordinatorSource.match(/const AGENT_PROMPT_TEMPLATE = `([\s\S]*?)`;/);
536
- const template = templateMatch?.[1] ?? "";
537
- assertIncludes(template, "write the complete output to {output_path}", "output path write instruction preserved");
538
- });
539
- it("E-3: prompt contains all required rule keywords", () => {
540
- const templateMatch = coordinatorSource.match(/const AGENT_PROMPT_TEMPLATE = `([\s\S]*?)`;/);
541
- const template = templateMatch?.[1] ?? "";
542
- const requiredPhrases = [
543
- "prompt packet",
544
- "Boundary Policy",
545
- "Effective Boundary State",
546
- "hard constraints",
547
- "Do not modify repository files",
548
- "insufficient access or insufficient evidence",
549
- ];
550
- for (const phrase of requiredPhrases) {
551
- assertIncludes(template, phrase, `required phrase: "${phrase}"`);
552
- }
553
- });
554
- it("E-4: buildAgentPrompt replaces all placeholders", () => {
555
- // Import and call the actual function
556
- // Since buildAgentPrompt is not exported, verify via template regex
557
- const templateMatch = coordinatorSource.match(/const AGENT_PROMPT_TEMPLATE = `([\s\S]*?)`;/);
558
- const template = templateMatch?.[1] ?? "";
559
- // All placeholders should be {unit_id}, {unit_kind}, {packet_path}, {output_path}
560
- const placeholders = template.match(/\{[a-z_]+\}/g) ?? [];
561
- const uniquePlaceholders = [...new Set(placeholders)];
562
- const expected = new Set(["{unit_id}", "{unit_kind}", "{packet_path}", "{output_path}"]);
563
- for (const placeholder of uniquePlaceholders) {
564
- assert(expected.has(placeholder), `unexpected placeholder: ${placeholder}`);
565
- }
566
- for (const exp of expected) {
567
- assert(uniquePlaceholders.includes(exp), `missing expected placeholder: ${exp}`);
568
- }
569
- });
570
- });
571
- // ---------------------------------------------------------------------------
572
- // F. process.md ToolSearch instruction
573
- // ---------------------------------------------------------------------------
574
- describe("F. process.md ToolSearch", () => {
575
- const processContent = fs.readFileSync(path.join(process.cwd(), "process.md"), "utf8");
576
- it("F-1: ToolSearch instruction exists before Team Creation", () => {
577
- const toolSearchPos = processContent.indexOf('ToolSearch("select:TeamCreate,SendMessage,TeamDelete")');
578
- const teamCreationPos = processContent.indexOf("#### Team Creation");
579
- assert(toolSearchPos !== -1, "ToolSearch instruction found");
580
- assert(teamCreationPos !== -1, "Team Creation section found");
581
- assert(toolSearchPos < teamCreationPos, "ToolSearch appears before Team Creation");
582
- });
583
- it("F-2: ToolSearch section marked as mandatory", () => {
584
- assertIncludes(processContent, "Tool Availability Check (mandatory", "section marked mandatory");
585
- });
586
- it("F-3: deferred tools explanation present", () => {
587
- assertIncludes(processContent, "deferred tools", "deferred tools concept explained");
588
- });
589
- it("F-4: fallback instruction on ToolSearch failure", () => {
590
- // Find the ToolSearch section
591
- const sectionStart = processContent.indexOf("#### Tool Availability Check");
592
- const sectionEnd = processContent.indexOf("#### Team Creation");
593
- const section = processContent.slice(sectionStart, sectionEnd);
594
- assertIncludes(section, "Fallback Rules", "fallback instruction on ToolSearch failure");
595
- });
596
- it("F-5: once-per-session note present", () => {
597
- assertIncludes(processContent, "once per conversation session", "once-per-session guidance");
598
- });
599
- it("F-6: ToolSearch targets all three team tools", () => {
600
- const toolSearchLine = processContent.match(/ToolSearch\("select:([^"]+)"\)/);
601
- assert(toolSearchLine !== null, "ToolSearch call found");
602
- const tools = (toolSearchLine?.[1] ?? "").split(",");
603
- assert(tools.includes("TeamCreate"), "TeamCreate in ToolSearch");
604
- assert(tools.includes("SendMessage"), "SendMessage in ToolSearch");
605
- assert(tools.includes("TeamDelete"), "TeamDelete in ToolSearch");
606
- });
607
- });
608
- // ---------------------------------------------------------------------------
609
- // Cleanup
610
- // ---------------------------------------------------------------------------
611
- afterAll(() => {
612
- for (const dir of cleanupDirs) {
613
- rmDir(dir);
614
- }
615
- });