onto-mcp 0.3.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 (447) hide show
  1. package/.onto/authority/core-lens-registry.yaml +134 -0
  2. package/.onto/authority/core-lexicon.yaml +1562 -0
  3. package/.onto/authority/diagnostic-codes.yaml +94 -0
  4. package/.onto/domains/accounting/competency_qs.md +384 -0
  5. package/.onto/domains/accounting/concepts.md +186 -0
  6. package/.onto/domains/accounting/conciseness_rules.md +160 -0
  7. package/.onto/domains/accounting/dependency_rules.md +239 -0
  8. package/.onto/domains/accounting/domain_scope.md +213 -0
  9. package/.onto/domains/accounting/extension_cases.md +416 -0
  10. package/.onto/domains/accounting/logic_rules.md +226 -0
  11. package/.onto/domains/accounting/structure_spec.md +298 -0
  12. package/.onto/domains/accounting-kr/competency_qs.md +562 -0
  13. package/.onto/domains/accounting-kr/concepts.md +187 -0
  14. package/.onto/domains/accounting-kr/conciseness_rules.md +125 -0
  15. package/.onto/domains/accounting-kr/dependency_rules.md +93 -0
  16. package/.onto/domains/accounting-kr/domain_scope.md +140 -0
  17. package/.onto/domains/accounting-kr/extension_cases.md +343 -0
  18. package/.onto/domains/accounting-kr/logic_rules.md +160 -0
  19. package/.onto/domains/accounting-kr/structure_spec.md +85 -0
  20. package/.onto/domains/business/competency_qs.md +263 -0
  21. package/.onto/domains/business/concepts.md +200 -0
  22. package/.onto/domains/business/conciseness_rules.md +135 -0
  23. package/.onto/domains/business/dependency_rules.md +113 -0
  24. package/.onto/domains/business/domain_scope.md +240 -0
  25. package/.onto/domains/business/extension_cases.md +249 -0
  26. package/.onto/domains/business/logic_rules.md +134 -0
  27. package/.onto/domains/business/structure_spec.md +114 -0
  28. package/.onto/domains/finance/competency_qs.md +362 -0
  29. package/.onto/domains/finance/concepts.md +194 -0
  30. package/.onto/domains/finance/conciseness_rules.md +155 -0
  31. package/.onto/domains/finance/dependency_rules.md +171 -0
  32. package/.onto/domains/finance/domain_scope.md +215 -0
  33. package/.onto/domains/finance/extension_cases.md +350 -0
  34. package/.onto/domains/finance/logic_rules.md +191 -0
  35. package/.onto/domains/finance/structure_spec.md +182 -0
  36. package/.onto/domains/llm-native-development/competency_qs.md +430 -0
  37. package/.onto/domains/llm-native-development/concepts.md +242 -0
  38. package/.onto/domains/llm-native-development/conciseness_rules.md +163 -0
  39. package/.onto/domains/llm-native-development/dependency_rules.md +216 -0
  40. package/.onto/domains/llm-native-development/domain_scope.md +197 -0
  41. package/.onto/domains/llm-native-development/extension_cases.md +474 -0
  42. package/.onto/domains/llm-native-development/logic_rules.md +123 -0
  43. package/.onto/domains/llm-native-development/prompt_interface.md +49 -0
  44. package/.onto/domains/llm-native-development/structure_spec.md +245 -0
  45. package/.onto/domains/market-intelligence/competency_qs.md +274 -0
  46. package/.onto/domains/market-intelligence/concepts.md +233 -0
  47. package/.onto/domains/market-intelligence/conciseness_rules.md +165 -0
  48. package/.onto/domains/market-intelligence/dependency_rules.md +197 -0
  49. package/.onto/domains/market-intelligence/domain_scope.md +231 -0
  50. package/.onto/domains/market-intelligence/extension_cases.md +425 -0
  51. package/.onto/domains/market-intelligence/logic_rules.md +247 -0
  52. package/.onto/domains/market-intelligence/structure_spec.md +209 -0
  53. package/.onto/domains/ontology/competency_qs.md +394 -0
  54. package/.onto/domains/ontology/concepts.md +172 -0
  55. package/.onto/domains/ontology/conciseness_rules.md +134 -0
  56. package/.onto/domains/ontology/dependency_rules.md +125 -0
  57. package/.onto/domains/ontology/domain_scope.md +114 -0
  58. package/.onto/domains/ontology/extension_cases.md +501 -0
  59. package/.onto/domains/ontology/logic_rules.md +114 -0
  60. package/.onto/domains/ontology/problem_framing_profile.md +67 -0
  61. package/.onto/domains/ontology/structure_spec.md +115 -0
  62. package/.onto/domains/palantir-foundry/RESEARCH_NOTES.md +911 -0
  63. package/.onto/domains/palantir-foundry/competency_qs.md +191 -0
  64. package/.onto/domains/palantir-foundry/competitive_comparison.md +329 -0
  65. package/.onto/domains/palantir-foundry/concepts.md +197 -0
  66. package/.onto/domains/palantir-foundry/conciseness_rules.md +245 -0
  67. package/.onto/domains/palantir-foundry/dependency_rules.md +135 -0
  68. package/.onto/domains/palantir-foundry/domain_scope.md +395 -0
  69. package/.onto/domains/palantir-foundry/extension_cases.md +210 -0
  70. package/.onto/domains/palantir-foundry/logic_rules.md +172 -0
  71. package/.onto/domains/palantir-foundry/structure_spec.md +291 -0
  72. package/.onto/domains/software-engineering/competency_qs.md +538 -0
  73. package/.onto/domains/software-engineering/concepts.md +238 -0
  74. package/.onto/domains/software-engineering/conciseness_rules.md +167 -0
  75. package/.onto/domains/software-engineering/dependency_rules.md +216 -0
  76. package/.onto/domains/software-engineering/domain_scope.md +183 -0
  77. package/.onto/domains/software-engineering/extension_cases.md +551 -0
  78. package/.onto/domains/software-engineering/logic_rules.md +240 -0
  79. package/.onto/domains/software-engineering/problem_framing_profile.md +68 -0
  80. package/.onto/domains/software-engineering/structure_spec.md +185 -0
  81. package/.onto/domains/ui-design/competency_qs.md +567 -0
  82. package/.onto/domains/ui-design/concepts.md +194 -0
  83. package/.onto/domains/ui-design/conciseness_rules.md +190 -0
  84. package/.onto/domains/ui-design/dependency_rules.md +323 -0
  85. package/.onto/domains/ui-design/domain_scope.md +340 -0
  86. package/.onto/domains/ui-design/extension_cases.md +563 -0
  87. package/.onto/domains/ui-design/logic_rules.md +349 -0
  88. package/.onto/domains/ui-design/structure_spec.md +252 -0
  89. package/.onto/domains/visual-design/competency_qs.md +472 -0
  90. package/.onto/domains/visual-design/concepts.md +147 -0
  91. package/.onto/domains/visual-design/conciseness_rules.md +186 -0
  92. package/.onto/domains/visual-design/dependency_rules.md +282 -0
  93. package/.onto/domains/visual-design/domain_scope.md +290 -0
  94. package/.onto/domains/visual-design/extension_cases.md +480 -0
  95. package/.onto/domains/visual-design/logic_rules.md +232 -0
  96. package/.onto/domains/visual-design/structure_spec.md +213 -0
  97. package/.onto/principles/llm-native-development-guideline.md +401 -0
  98. package/.onto/principles/llm-runtime-interface-principles.md +665 -0
  99. package/.onto/principles/non-specialist-communication-guideline.md +74 -0
  100. package/.onto/principles/ontology-as-code-guideline.md +243 -0
  101. package/.onto/principles/ontology-as-code-naming-charter.md +130 -0
  102. package/.onto/principles/product-locality-principle.md +129 -0
  103. package/.onto/principles/productization-charter.md +569 -0
  104. package/.onto/processes/evolve/material-kind-adapter-contract.md +113 -0
  105. package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +366 -0
  106. package/.onto/processes/reconstruct/source-profile-contract.md +107 -0
  107. package/.onto/processes/reconstruct/source-profiles/code.md +72 -0
  108. package/.onto/processes/reconstruct/source-profiles/database.md +74 -0
  109. package/.onto/processes/reconstruct/source-profiles/document.md +71 -0
  110. package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +79 -0
  111. package/.onto/processes/review/binding-contract.md +270 -0
  112. package/.onto/processes/review/execution-preparation-artifacts.md +281 -0
  113. package/.onto/processes/review/interpretation-contract.md +245 -0
  114. package/.onto/processes/review/issue-stance-deliberation-contract.md +761 -0
  115. package/.onto/processes/review/lens-prompt-contract.md +402 -0
  116. package/.onto/processes/review/lens-registry.md +127 -0
  117. package/.onto/processes/review/pre-dispatch-contracts.md +428 -0
  118. package/.onto/processes/review/productized-live-path.md +398 -0
  119. package/.onto/processes/review/prompt-execution-runner-contract.md +187 -0
  120. package/.onto/processes/review/record-contract.md +427 -0
  121. package/.onto/processes/review/record-field-mapping.md +337 -0
  122. package/.onto/processes/review/review-context-manifest-contract.md +356 -0
  123. package/.onto/processes/review/review-execution-ux-contract.md +809 -0
  124. package/.onto/processes/review/review-target-profile-contract.md +259 -0
  125. package/.onto/processes/review/shared-phenomenon-contract.md +129 -0
  126. package/.onto/processes/review/synthesize-prompt-contract.md +343 -0
  127. package/.onto/processes/shared/target-material-kind-contract.md +198 -0
  128. package/.onto/roles/axiology.md +81 -0
  129. package/.onto/roles/conciseness.md +36 -0
  130. package/.onto/roles/coverage.md +34 -0
  131. package/.onto/roles/dependency.md +37 -0
  132. package/.onto/roles/evolution.md +35 -0
  133. package/.onto/roles/logic.md +104 -0
  134. package/.onto/roles/pragmatics.md +32 -0
  135. package/.onto/roles/semantics.md +36 -0
  136. package/.onto/roles/structure.md +33 -0
  137. package/.onto/roles/synthesize.md +92 -0
  138. package/AGENTS.md +240 -0
  139. package/CLAUDE.md +39 -0
  140. package/README.md +287 -0
  141. package/bin/onto +92 -0
  142. package/dist/cli.js +101 -0
  143. package/dist/core-api/reconstruct-api.js +222 -0
  144. package/dist/core-api/review-api.js +1271 -0
  145. package/dist/core-runtime/cli/assemble-review-record.js +431 -0
  146. package/dist/core-runtime/cli/bootstrap-review-binding.js +186 -0
  147. package/dist/core-runtime/cli/codex-nested-dispatch.js +226 -0
  148. package/dist/core-runtime/cli/codex-nested-dispatch.test.js +390 -0
  149. package/dist/core-runtime/cli/codex-nested-teamlead-executor.js +464 -0
  150. package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +335 -0
  151. package/dist/core-runtime/cli/codex-review-unit-executor.js +228 -0
  152. package/dist/core-runtime/cli/complete-review-session.js +64 -0
  153. package/dist/core-runtime/cli/complexity-assessment.js +153 -0
  154. package/dist/core-runtime/cli/coordinator-helpers.js +583 -0
  155. package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +167 -0
  156. package/dist/core-runtime/cli/coordinator-state-machine.js +794 -0
  157. package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +615 -0
  158. package/dist/core-runtime/cli/e2e-start-review-session.test.js +312 -0
  159. package/dist/core-runtime/cli/health.js +44 -0
  160. package/dist/core-runtime/cli/inline-http-review-unit-executor.js +656 -0
  161. package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +567 -0
  162. package/dist/core-runtime/cli/materialize-review-execution-preparation.js +104 -0
  163. package/dist/core-runtime/cli/materialize-review-prompt-packets.js +952 -0
  164. package/dist/core-runtime/cli/migrate-session-roots.js +118 -0
  165. package/dist/core-runtime/cli/mock-review-unit-executor.js +285 -0
  166. package/dist/core-runtime/cli/onto-tools.js +369 -0
  167. package/dist/core-runtime/cli/prepare-review-session.js +272 -0
  168. package/dist/core-runtime/cli/render-review-final-output.js +350 -0
  169. package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +106 -0
  170. package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +268 -0
  171. package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +136 -0
  172. package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +201 -0
  173. package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +192 -0
  174. package/dist/core-runtime/cli/review-invoke.js +2030 -0
  175. package/dist/core-runtime/cli/run-review-prompt-execution.js +2152 -0
  176. package/dist/core-runtime/cli/session-root-guard.js +168 -0
  177. package/dist/core-runtime/cli/spawn-watcher.js +173 -0
  178. package/dist/core-runtime/cli/spawn-watcher.test.js +457 -0
  179. package/dist/core-runtime/cli/start-review-session.js +68 -0
  180. package/dist/core-runtime/cli/strip-wrapping-code-fence.js +56 -0
  181. package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +79 -0
  182. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +412 -0
  183. package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +351 -0
  184. package/dist/core-runtime/cli/topology-executor-mapping.js +139 -0
  185. package/dist/core-runtime/cli/topology-executor-mapping.test.js +173 -0
  186. package/dist/core-runtime/cli/write-review-interpretation.js +81 -0
  187. package/dist/core-runtime/config/onto-config-cli.js +278 -0
  188. package/dist/core-runtime/config/onto-config-key-path.js +288 -0
  189. package/dist/core-runtime/config/onto-config-key-path.test.js +195 -0
  190. package/dist/core-runtime/config/onto-config-preview.js +108 -0
  191. package/dist/core-runtime/config/onto-config-preview.test.js +132 -0
  192. package/dist/core-runtime/discovery/config-chain.js +118 -0
  193. package/dist/core-runtime/discovery/config-chain.test.js +103 -0
  194. package/dist/core-runtime/discovery/config-profile.js +199 -0
  195. package/dist/core-runtime/discovery/config-profile.test.js +233 -0
  196. package/dist/core-runtime/discovery/host-detection.js +33 -0
  197. package/dist/core-runtime/discovery/host-detection.test.js +186 -0
  198. package/dist/core-runtime/discovery/installation-paths.js +21 -0
  199. package/dist/core-runtime/discovery/installation-paths.test.js +65 -0
  200. package/dist/core-runtime/discovery/lens-registry.js +60 -0
  201. package/dist/core-runtime/discovery/lens-registry.test.js +81 -0
  202. package/dist/core-runtime/discovery/onto-home.js +71 -0
  203. package/dist/core-runtime/discovery/path-normalization.js +28 -0
  204. package/dist/core-runtime/discovery/path-normalization.test.js +22 -0
  205. package/dist/core-runtime/discovery/plugin-path.js +72 -0
  206. package/dist/core-runtime/discovery/plugin-path.test.js +95 -0
  207. package/dist/core-runtime/discovery/project-root.js +47 -0
  208. package/dist/core-runtime/discovery/settings-chain.js +353 -0
  209. package/dist/core-runtime/discovery/walk-up.js +17 -0
  210. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +344 -0
  211. package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +915 -0
  212. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +564 -0
  213. package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +708 -0
  214. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +165 -0
  215. package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +227 -0
  216. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +59 -0
  217. package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +205 -0
  218. package/dist/core-runtime/evolve/adapters/methodology/adapter.js +16 -0
  219. package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +9 -0
  220. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +298 -0
  221. package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +70 -0
  222. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +46 -0
  223. package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +73 -0
  224. package/dist/core-runtime/evolve/adapters/registry.js +47 -0
  225. package/dist/core-runtime/evolve/adapters/registry.test.js +67 -0
  226. package/dist/core-runtime/evolve/cli.js +256 -0
  227. package/dist/core-runtime/evolve/commands/align.js +194 -0
  228. package/dist/core-runtime/evolve/commands/align.test.js +82 -0
  229. package/dist/core-runtime/evolve/commands/apply.js +161 -0
  230. package/dist/core-runtime/evolve/commands/apply.test.js +138 -0
  231. package/dist/core-runtime/evolve/commands/close.js +39 -0
  232. package/dist/core-runtime/evolve/commands/close.test.js +99 -0
  233. package/dist/core-runtime/evolve/commands/defer.js +40 -0
  234. package/dist/core-runtime/evolve/commands/defer.test.js +134 -0
  235. package/dist/core-runtime/evolve/commands/draft.js +323 -0
  236. package/dist/core-runtime/evolve/commands/draft.test.js +178 -0
  237. package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +208 -0
  238. package/dist/core-runtime/evolve/commands/error-messages.js +125 -0
  239. package/dist/core-runtime/evolve/commands/error-messages.test.js +167 -0
  240. package/dist/core-runtime/evolve/commands/propose-align.js +222 -0
  241. package/dist/core-runtime/evolve/commands/propose-align.test.js +136 -0
  242. package/dist/core-runtime/evolve/commands/reconstruct.js +330 -0
  243. package/dist/core-runtime/evolve/commands/reconstruct.test.js +278 -0
  244. package/dist/core-runtime/evolve/commands/shared.js +22 -0
  245. package/dist/core-runtime/evolve/commands/stale-check.js +103 -0
  246. package/dist/core-runtime/evolve/commands/stale-check.test.js +84 -0
  247. package/dist/core-runtime/evolve/commands/start.js +887 -0
  248. package/dist/core-runtime/evolve/commands/start.test.js +396 -0
  249. package/dist/core-runtime/evolve/config/project-config.js +99 -0
  250. package/dist/core-runtime/evolve/config/project-config.test.js +170 -0
  251. package/dist/core-runtime/evolve/renderers/align-packet.js +280 -0
  252. package/dist/core-runtime/evolve/renderers/align-packet.test.js +332 -0
  253. package/dist/core-runtime/evolve/renderers/draft-packet.js +303 -0
  254. package/dist/core-runtime/evolve/renderers/draft-packet.test.js +377 -0
  255. package/dist/core-runtime/evolve/renderers/format.js +5 -0
  256. package/dist/core-runtime/evolve/renderers/scope-md.js +237 -0
  257. package/dist/core-runtime/evolve/renderers/scope-md.test.js +306 -0
  258. package/dist/core-runtime/govern/cli.js +369 -0
  259. package/dist/core-runtime/govern/cli.test.js +314 -0
  260. package/dist/core-runtime/govern/drift-engine.js +103 -0
  261. package/dist/core-runtime/govern/drift-engine.test.js +319 -0
  262. package/dist/core-runtime/govern/promote-principle.js +206 -0
  263. package/dist/core-runtime/govern/promote-principle.test.js +368 -0
  264. package/dist/core-runtime/govern/queue.js +81 -0
  265. package/dist/core-runtime/govern/types.js +16 -0
  266. package/dist/core-runtime/install/cli.js +530 -0
  267. package/dist/core-runtime/install/detect.js +128 -0
  268. package/dist/core-runtime/install/detect.test.js +155 -0
  269. package/dist/core-runtime/install/gitignore-update.js +74 -0
  270. package/dist/core-runtime/install/gitignore-update.test.js +64 -0
  271. package/dist/core-runtime/install/install-integration.test.js +373 -0
  272. package/dist/core-runtime/install/prompts.js +389 -0
  273. package/dist/core-runtime/install/prompts.test.js +293 -0
  274. package/dist/core-runtime/install/types.js +26 -0
  275. package/dist/core-runtime/install/validation.js +295 -0
  276. package/dist/core-runtime/install/validation.test.js +313 -0
  277. package/dist/core-runtime/install/writer.js +254 -0
  278. package/dist/core-runtime/install/writer.test.js +218 -0
  279. package/dist/core-runtime/learning/extractor.js +461 -0
  280. package/dist/core-runtime/learning/feedback.js +179 -0
  281. package/dist/core-runtime/learning/health-report.js +165 -0
  282. package/dist/core-runtime/learning/health-report.test.js +169 -0
  283. package/dist/core-runtime/learning/loader.js +388 -0
  284. package/dist/core-runtime/learning/loader.test.js +102 -0
  285. package/dist/core-runtime/learning/promote/apply-state.js +240 -0
  286. package/dist/core-runtime/learning/promote/audit-obligation.js +195 -0
  287. package/dist/core-runtime/learning/promote/collector.js +432 -0
  288. package/dist/core-runtime/learning/promote/degraded-state.js +125 -0
  289. package/dist/core-runtime/learning/promote/domain-doc-proposer.js +166 -0
  290. package/dist/core-runtime/learning/promote/e2e-promote.test.js +6385 -0
  291. package/dist/core-runtime/learning/promote/health-snapshot.js +150 -0
  292. package/dist/core-runtime/learning/promote/insight-reclassifier.js +544 -0
  293. package/dist/core-runtime/learning/promote/judgment-auditor.js +517 -0
  294. package/dist/core-runtime/learning/promote/panel-reviewer.js +1158 -0
  295. package/dist/core-runtime/learning/promote/promote-executor.js +1675 -0
  296. package/dist/core-runtime/learning/promote/promoter.js +307 -0
  297. package/dist/core-runtime/learning/promote/retirement.js +122 -0
  298. package/dist/core-runtime/learning/promote/types.js +23 -0
  299. package/dist/core-runtime/learning/prompt-sections.js +51 -0
  300. package/dist/core-runtime/learning/shared/artifact-registry-init.js +45 -0
  301. package/dist/core-runtime/learning/shared/artifact-registry.js +254 -0
  302. package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +73 -0
  303. package/dist/core-runtime/learning/shared/audit-state.js +99 -0
  304. package/dist/core-runtime/learning/shared/duplicate-check.js +28 -0
  305. package/dist/core-runtime/learning/shared/llm-caller.js +831 -0
  306. package/dist/core-runtime/learning/shared/llm-caller.test.js +601 -0
  307. package/dist/core-runtime/learning/shared/llm-tool-loop.js +393 -0
  308. package/dist/core-runtime/learning/shared/mode.js +25 -0
  309. package/dist/core-runtime/learning/shared/paths.js +84 -0
  310. package/dist/core-runtime/learning/shared/paths.test.js +79 -0
  311. package/dist/core-runtime/learning/shared/patterns.js +37 -0
  312. package/dist/core-runtime/learning/shared/recoverability.js +355 -0
  313. package/dist/core-runtime/learning/shared/recovery-context.js +374 -0
  314. package/dist/core-runtime/learning/shared/scope.js +1 -0
  315. package/dist/core-runtime/learning/shared/semantic-classifier.js +94 -0
  316. package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +42 -0
  317. package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +37 -0
  318. package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +39 -0
  319. package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +41 -0
  320. package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +38 -0
  321. package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +43 -0
  322. package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +113 -0
  323. package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +36 -0
  324. package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +48 -0
  325. package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +43 -0
  326. package/dist/core-runtime/learning/shared/specs/spec-helpers.js +64 -0
  327. package/dist/core-runtime/learning/usage-tracker.js +190 -0
  328. package/dist/core-runtime/learning/usage-tracker.test.js +176 -0
  329. package/dist/core-runtime/llm/llm-caller.js +649 -0
  330. package/dist/core-runtime/llm/llm-tool-loop.js +401 -0
  331. package/dist/core-runtime/llm/model-switcher.js +62 -0
  332. package/dist/core-runtime/logger.js +22 -0
  333. package/dist/core-runtime/onboard/detect-review-axes.js +122 -0
  334. package/dist/core-runtime/onboard/detect-review-axes.test.js +127 -0
  335. package/dist/core-runtime/onboard/write-review-block.js +188 -0
  336. package/dist/core-runtime/onboard/write-review-block.test.js +240 -0
  337. package/dist/core-runtime/readers/brownfield-builder.js +150 -0
  338. package/dist/core-runtime/readers/brownfield-builder.test.js +136 -0
  339. package/dist/core-runtime/readers/code-chunk-collector.js +53 -0
  340. package/dist/core-runtime/readers/code-chunk-collector.test.js +136 -0
  341. package/dist/core-runtime/readers/file-utils.js +240 -0
  342. package/dist/core-runtime/readers/file-utils.test.js +146 -0
  343. package/dist/core-runtime/readers/lexicon-citation-check.js +93 -0
  344. package/dist/core-runtime/readers/lexicon-citation-check.test.js +77 -0
  345. package/dist/core-runtime/readers/mcp-figma.js +30 -0
  346. package/dist/core-runtime/readers/mcp-figma.test.js +82 -0
  347. package/dist/core-runtime/readers/mcp-generic.js +31 -0
  348. package/dist/core-runtime/readers/mcp-generic.test.js +76 -0
  349. package/dist/core-runtime/readers/ontology-index.js +148 -0
  350. package/dist/core-runtime/readers/ontology-index.test.js +245 -0
  351. package/dist/core-runtime/readers/ontology-query.js +168 -0
  352. package/dist/core-runtime/readers/ontology-query.test.js +311 -0
  353. package/dist/core-runtime/readers/ontology-resolve.js +48 -0
  354. package/dist/core-runtime/readers/ontology-resolve.test.js +48 -0
  355. package/dist/core-runtime/readers/patterns/index.js +7 -0
  356. package/dist/core-runtime/readers/review-log.js +213 -0
  357. package/dist/core-runtime/readers/review-log.test.js +313 -0
  358. package/dist/core-runtime/readers/scan-local.js +102 -0
  359. package/dist/core-runtime/readers/scan-local.test.js +102 -0
  360. package/dist/core-runtime/readers/scan-tarball.js +121 -0
  361. package/dist/core-runtime/readers/scan-tarball.test.js +283 -0
  362. package/dist/core-runtime/readers/scan-vault.js +34 -0
  363. package/dist/core-runtime/readers/scan-vault.test.js +81 -0
  364. package/dist/core-runtime/readers/types.js +42 -0
  365. package/dist/core-runtime/readers/types.test.js +94 -0
  366. package/dist/core-runtime/readers/viewpoint-collectors.js +229 -0
  367. package/dist/core-runtime/reconstruct/artifact-types.js +1 -0
  368. package/dist/core-runtime/reconstruct/directive-validation.js +123 -0
  369. package/dist/core-runtime/reconstruct/materialize-preparation.js +251 -0
  370. package/dist/core-runtime/reconstruct/record.js +198 -0
  371. package/dist/core-runtime/reconstruct/run.js +578 -0
  372. package/dist/core-runtime/reconstruct/seed-candidate-validation.js +356 -0
  373. package/dist/core-runtime/reconstruct/source-observations.js +62 -0
  374. package/dist/core-runtime/reconstruct/source-profiles.js +73 -0
  375. package/dist/core-runtime/release-channel/release-channel.js +90 -0
  376. package/dist/core-runtime/review/artifact-types.js +13 -0
  377. package/dist/core-runtime/review/citation-audit.js +204 -0
  378. package/dist/core-runtime/review/citation-audit.test.js +165 -0
  379. package/dist/core-runtime/review/controlled-lens-deliberation.js +125 -0
  380. package/dist/core-runtime/review/execution-plan-resolver.js +247 -0
  381. package/dist/core-runtime/review/execution-plan-resolver.test.js +243 -0
  382. package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +246 -0
  383. package/dist/core-runtime/review/execution-topology-resolver.js +401 -0
  384. package/dist/core-runtime/review/execution-topology-resolver.test.js +315 -0
  385. package/dist/core-runtime/review/failure-records.js +57 -0
  386. package/dist/core-runtime/review/inline-context-embedder.js +141 -0
  387. package/dist/core-runtime/review/inline-context-embedder.test.js +154 -0
  388. package/dist/core-runtime/review/issue-artifact-runtime.js +859 -0
  389. package/dist/core-runtime/review/legacy-mode-policy.js +88 -0
  390. package/dist/core-runtime/review/lens-completion-policy.js +17 -0
  391. package/dist/core-runtime/review/materializers-effort-persist.test.js +79 -0
  392. package/dist/core-runtime/review/materializers.js +963 -0
  393. package/dist/core-runtime/review/ontology-path-classifier.js +179 -0
  394. package/dist/core-runtime/review/ontology-path-classifier.test.js +216 -0
  395. package/dist/core-runtime/review/packet-boundary-policy.js +215 -0
  396. package/dist/core-runtime/review/packet-boundary-policy.test.js +107 -0
  397. package/dist/core-runtime/review/participating-lens-paths.js +61 -0
  398. package/dist/core-runtime/review/participating-lens-paths.test.js +73 -0
  399. package/dist/core-runtime/review/review-artifact-utils.js +287 -0
  400. package/dist/core-runtime/review/review-config-legacy-translate.js +244 -0
  401. package/dist/core-runtime/review/review-config-legacy-translate.test.js +161 -0
  402. package/dist/core-runtime/review/review-config-validator.js +289 -0
  403. package/dist/core-runtime/review/review-config-validator.test.js +236 -0
  404. package/dist/core-runtime/review/review-execution-profile.js +193 -0
  405. package/dist/core-runtime/review/review-execution-route.js +52 -0
  406. package/dist/core-runtime/review/review-progress-contract.js +123 -0
  407. package/dist/core-runtime/review/review-record-validation.js +251 -0
  408. package/dist/core-runtime/review/review-result-classification.js +379 -0
  409. package/dist/core-runtime/review/review-state-machine.js +39 -0
  410. package/dist/core-runtime/review/route-visibility.js +125 -0
  411. package/dist/core-runtime/review/shape-pipeline-audit.test.js +311 -0
  412. package/dist/core-runtime/review/shape-to-topology-id.js +117 -0
  413. package/dist/core-runtime/review/shape-to-topology-id.test.js +132 -0
  414. package/dist/core-runtime/review/topology-shape-derivation.js +155 -0
  415. package/dist/core-runtime/review/topology-shape-derivation.test.js +195 -0
  416. package/dist/core-runtime/scope-runtime/constants.js +12 -0
  417. package/dist/core-runtime/scope-runtime/constraint-pool.js +166 -0
  418. package/dist/core-runtime/scope-runtime/constraint-pool.test.js +674 -0
  419. package/dist/core-runtime/scope-runtime/domain-validation-log.js +135 -0
  420. package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +156 -0
  421. package/dist/core-runtime/scope-runtime/eval-persistence.js +65 -0
  422. package/dist/core-runtime/scope-runtime/eval-persistence.test.js +84 -0
  423. package/dist/core-runtime/scope-runtime/event-pipeline.js +64 -0
  424. package/dist/core-runtime/scope-runtime/event-pipeline.test.js +450 -0
  425. package/dist/core-runtime/scope-runtime/event-store.js +39 -0
  426. package/dist/core-runtime/scope-runtime/event-store.test.js +95 -0
  427. package/dist/core-runtime/scope-runtime/gate-guard.js +348 -0
  428. package/dist/core-runtime/scope-runtime/gate-guard.test.js +1047 -0
  429. package/dist/core-runtime/scope-runtime/hash.js +4 -0
  430. package/dist/core-runtime/scope-runtime/hash.test.js +33 -0
  431. package/dist/core-runtime/scope-runtime/id.js +4 -0
  432. package/dist/core-runtime/scope-runtime/id.test.js +17 -0
  433. package/dist/core-runtime/scope-runtime/reducer.js +297 -0
  434. package/dist/core-runtime/scope-runtime/reducer.test.js +759 -0
  435. package/dist/core-runtime/scope-runtime/scope-manager.js +161 -0
  436. package/dist/core-runtime/scope-runtime/state-machine.js +309 -0
  437. package/dist/core-runtime/scope-runtime/state-machine.test.js +704 -0
  438. package/dist/core-runtime/scope-runtime/types.js +116 -0
  439. package/dist/core-runtime/scope-runtime/types.test.js +69 -0
  440. package/dist/core-runtime/target-material-kind.js +256 -0
  441. package/dist/core-runtime/translate/render-for-user.js +169 -0
  442. package/dist/core-runtime/translate/render-for-user.test.js +122 -0
  443. package/dist/mcp/server.js +1011 -0
  444. package/dist/mcp/tool-schemas.js +93 -0
  445. package/dist/providers/capability-contract.js +1 -0
  446. package/package.json +68 -0
  447. package/settings.example.json +33 -0
@@ -0,0 +1,268 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import * as fs from "node:fs";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ import { resolveExecutionRealizationHandoff, detectClaudeCodeHost, detectCodexAvailable, } from "./review-invoke.js";
6
+ // ─── Helpers ───
7
+ const originalEnv = { ...process.env };
8
+ function clearEnv() {
9
+ delete process.env.CLAUDECODE;
10
+ // Don't touch PATH/HOME globally — we override them in tests that need to.
11
+ }
12
+ function restoreEnv() {
13
+ for (const k of Object.keys(process.env)) {
14
+ if (!(k in originalEnv))
15
+ delete process.env[k];
16
+ }
17
+ for (const [k, v] of Object.entries(originalEnv)) {
18
+ process.env[k] = v;
19
+ }
20
+ }
21
+ function createTmpHome() {
22
+ const home = fs.mkdtempSync(path.join(os.tmpdir(), "onto-auto-resolution-test-"));
23
+ fs.mkdirSync(path.join(home, ".codex"), { recursive: true });
24
+ return {
25
+ home,
26
+ cleanup: () => fs.rmSync(home, { recursive: true, force: true }),
27
+ };
28
+ }
29
+ // ─── detectClaudeCodeHost ───
30
+ describe("detectClaudeCodeHost", () => {
31
+ beforeEach(() => {
32
+ clearEnv();
33
+ });
34
+ afterEach(() => {
35
+ restoreEnv();
36
+ });
37
+ it("returns true when CLAUDECODE=1", () => {
38
+ process.env.CLAUDECODE = "1";
39
+ expect(detectClaudeCodeHost()).toBe(true);
40
+ });
41
+ it("returns false when CLAUDECODE unset", () => {
42
+ expect(detectClaudeCodeHost()).toBe(false);
43
+ });
44
+ it("returns false when CLAUDECODE=0 or other value", () => {
45
+ process.env.CLAUDECODE = "0";
46
+ expect(detectClaudeCodeHost()).toBe(false);
47
+ process.env.CLAUDECODE = "true";
48
+ expect(detectClaudeCodeHost()).toBe(false);
49
+ });
50
+ });
51
+ // ─── detectCodexAvailable ───
52
+ describe("detectCodexAvailable", () => {
53
+ let tmp = null;
54
+ const originalPath = process.env.PATH;
55
+ const originalHome = process.env.HOME;
56
+ beforeEach(() => {
57
+ tmp = createTmpHome();
58
+ process.env.HOME = tmp.home;
59
+ });
60
+ afterEach(() => {
61
+ if (tmp)
62
+ tmp.cleanup();
63
+ tmp = null;
64
+ if (originalPath !== undefined)
65
+ process.env.PATH = originalPath;
66
+ if (originalHome !== undefined)
67
+ process.env.HOME = originalHome;
68
+ });
69
+ it("returns false when codex binary not on PATH", () => {
70
+ const emptyDir = fs.mkdtempSync(path.join(os.tmpdir(), "onto-empty-path-"));
71
+ process.env.PATH = emptyDir;
72
+ try {
73
+ expect(detectCodexAvailable()).toBe(false);
74
+ }
75
+ finally {
76
+ fs.rmSync(emptyDir, { recursive: true, force: true });
77
+ }
78
+ });
79
+ it("returns false when binary on PATH but auth.json missing", () => {
80
+ const binDir = fs.mkdtempSync(path.join(os.tmpdir(), "onto-bin-"));
81
+ const fakeCodex = path.join(binDir, "codex");
82
+ fs.writeFileSync(fakeCodex, "#!/bin/sh\necho fake\n");
83
+ fs.chmodSync(fakeCodex, 0o755);
84
+ process.env.PATH = binDir;
85
+ // HOME has tmp with .codex dir but no auth.json
86
+ try {
87
+ expect(detectCodexAvailable()).toBe(false);
88
+ }
89
+ finally {
90
+ fs.rmSync(binDir, { recursive: true, force: true });
91
+ }
92
+ });
93
+ it("returns true when both binary and auth.json exist", () => {
94
+ const binDir = fs.mkdtempSync(path.join(os.tmpdir(), "onto-bin-"));
95
+ const fakeCodex = path.join(binDir, "codex");
96
+ fs.writeFileSync(fakeCodex, "#!/bin/sh\necho fake\n");
97
+ fs.chmodSync(fakeCodex, 0o755);
98
+ process.env.PATH = binDir;
99
+ fs.writeFileSync(path.join(tmp.home, ".codex", "auth.json"), "{}");
100
+ try {
101
+ expect(detectCodexAvailable()).toBe(true);
102
+ }
103
+ finally {
104
+ fs.rmSync(binDir, { recursive: true, force: true });
105
+ }
106
+ });
107
+ });
108
+ // ─── resolveExecutionRealizationHandoff ───
109
+ describe("resolveExecutionRealizationHandoff", () => {
110
+ let tmp = null;
111
+ const originalPath = process.env.PATH;
112
+ const originalHome = process.env.HOME;
113
+ beforeEach(() => {
114
+ clearEnv();
115
+ tmp = createTmpHome();
116
+ process.env.HOME = tmp.home;
117
+ // Default: empty PATH (codex not available) unless test sets it.
118
+ process.env.PATH = "/tmp/none-existing-dir";
119
+ });
120
+ afterEach(() => {
121
+ if (tmp)
122
+ tmp.cleanup();
123
+ tmp = null;
124
+ if (originalPath !== undefined)
125
+ process.env.PATH = originalPath;
126
+ else
127
+ delete process.env.PATH;
128
+ if (originalHome !== undefined)
129
+ process.env.HOME = originalHome;
130
+ restoreEnv();
131
+ });
132
+ it("E1 explicit --codex → self", () => {
133
+ const out = resolveExecutionRealizationHandoff({
134
+ explicitCodex: true,
135
+ prepareOnly: false,
136
+ ontoConfig: {},
137
+ });
138
+ expect(out.type).toBe("self");
139
+ if (out.type === "self") {
140
+ expect(out.profile.host_runtime).toBe("codex");
141
+ }
142
+ });
143
+ it("E1b prepare-only on Claude host → self with Claude profile (artifact seam)", () => {
144
+ // coordinator-state-machine calls reviewPrepareOnly(--prepare-only) from within
145
+ // a Claude Code session; it must receive the Claude profile so prepared session
146
+ // artifacts get recorded as agent-teams+claude, not subagent+codex. This is the
147
+ // artifact seam fix (review consensus #1, 2026-04-16).
148
+ process.env.CLAUDECODE = "1";
149
+ const out = resolveExecutionRealizationHandoff({
150
+ explicitCodex: false,
151
+ prepareOnly: true,
152
+ ontoConfig: {},
153
+ });
154
+ expect(out.type).toBe("self");
155
+ if (out.type === "self") {
156
+ expect(out.profile.host_runtime).toBe("claude");
157
+ expect(out.profile.execution_realization).toBe("agent-teams");
158
+ }
159
+ });
160
+ it("E2 env ONTO_HOST_RUNTIME=claude → coordinator_start with agent-teams default", () => {
161
+ process.env.ONTO_HOST_RUNTIME = "claude";
162
+ const out = resolveExecutionRealizationHandoff({
163
+ explicitCodex: false,
164
+ prepareOnly: false,
165
+ ontoConfig: {},
166
+ });
167
+ expect(out.type).toBe("coordinator_start");
168
+ if (out.type === "coordinator_start") {
169
+ expect(out.profile.execution_realization).toBe("agent-teams");
170
+ }
171
+ });
172
+ it("E2c env ONTO_HOST_RUNTIME=codex → self", () => {
173
+ process.env.ONTO_HOST_RUNTIME = "codex";
174
+ const out = resolveExecutionRealizationHandoff({
175
+ explicitCodex: false,
176
+ prepareOnly: false,
177
+ ontoConfig: {},
178
+ });
179
+ expect(out.type).toBe("self");
180
+ if (out.type === "self") {
181
+ expect(out.profile.host_runtime).toBe("codex");
182
+ }
183
+ });
184
+ it("E3 auto + CLAUDECODE=1 → coordinator_start with agent-teams", () => {
185
+ process.env.CLAUDECODE = "1";
186
+ const out = resolveExecutionRealizationHandoff({
187
+ explicitCodex: false,
188
+ prepareOnly: false,
189
+ ontoConfig: {},
190
+ });
191
+ expect(out.type).toBe("coordinator_start");
192
+ if (out.type === "coordinator_start") {
193
+ expect(out.profile.execution_realization).toBe("agent-teams");
194
+ }
195
+ });
196
+ it("E4 auto + codex available + no CLAUDECODE → self", () => {
197
+ const binDir = fs.mkdtempSync(path.join(os.tmpdir(), "onto-bin-"));
198
+ const fakeCodex = path.join(binDir, "codex");
199
+ fs.writeFileSync(fakeCodex, "#!/bin/sh\n");
200
+ fs.chmodSync(fakeCodex, 0o755);
201
+ process.env.PATH = binDir;
202
+ fs.writeFileSync(path.join(tmp.home, ".codex", "auth.json"), "{}");
203
+ try {
204
+ const out = resolveExecutionRealizationHandoff({
205
+ explicitCodex: false,
206
+ prepareOnly: false,
207
+ ontoConfig: {},
208
+ });
209
+ expect(out.type).toBe("self");
210
+ if (out.type === "self") {
211
+ expect(out.profile.host_runtime).toBe("codex");
212
+ }
213
+ }
214
+ finally {
215
+ fs.rmSync(binDir, { recursive: true, force: true });
216
+ }
217
+ });
218
+ it("E5 auto + both CLAUDECODE and codex available → stay-in-host (Claude wins)", () => {
219
+ process.env.CLAUDECODE = "1";
220
+ const binDir = fs.mkdtempSync(path.join(os.tmpdir(), "onto-bin-"));
221
+ const fakeCodex = path.join(binDir, "codex");
222
+ fs.writeFileSync(fakeCodex, "#!/bin/sh\n");
223
+ fs.chmodSync(fakeCodex, 0o755);
224
+ process.env.PATH = binDir;
225
+ fs.writeFileSync(path.join(tmp.home, ".codex", "auth.json"), "{}");
226
+ try {
227
+ const out = resolveExecutionRealizationHandoff({
228
+ explicitCodex: false,
229
+ prepareOnly: false,
230
+ ontoConfig: {},
231
+ });
232
+ expect(out.type).toBe("coordinator_start");
233
+ if (out.type === "coordinator_start") {
234
+ expect(out.profile.execution_realization).toBe("agent-teams");
235
+ }
236
+ }
237
+ finally {
238
+ fs.rmSync(binDir, { recursive: true, force: true });
239
+ }
240
+ });
241
+ it("E6 auto + nothing available → no_host", () => {
242
+ const out = resolveExecutionRealizationHandoff({
243
+ explicitCodex: false,
244
+ prepareOnly: false,
245
+ ontoConfig: {},
246
+ });
247
+ expect(out).toEqual({ type: "no_host" });
248
+ });
249
+ it("E7 external_http_provider=litellm → ts_inline_http self-execute", () => {
250
+ // LiteLLM wiring is live via the P4 auto-detection branch —
251
+ // `resolveExecutionPlan` sees `external_http_provider` set, routes to
252
+ // the S1 external HTTP path, and the handoff returns `self` so the
253
+ // invoking process runs the executor in-band.
254
+ const out = resolveExecutionRealizationHandoff({
255
+ explicitCodex: false,
256
+ prepareOnly: false,
257
+ ontoConfig: {
258
+ external_http_provider: "litellm",
259
+ llm_base_url: "http://proxy.local",
260
+ litellm: { model: "llama-8b" },
261
+ },
262
+ });
263
+ expect(out).toEqual({
264
+ type: "self",
265
+ profile: { execution_realization: "ts_inline_http", host_runtime: "litellm" },
266
+ });
267
+ });
268
+ });
@@ -0,0 +1,136 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { tryResolveTopologyForHandoff } from "./review-invoke.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Coordinator handoff descriptor invariants (P9.3, 2026-04-21):
5
+ //
6
+ // (1) `tryResolveTopologyForHandoff` attempts axis-first resolution
7
+ // unconditionally; the former opt-in gate (config.review presence)
8
+ // is gone. Every review invocation that reaches a reachable host
9
+ // ships a descriptor.
10
+ // (2) Resolvable topology → non-null descriptor with all 6 static
11
+ // attributes, minus plan_trace (handoff payload stays compact).
12
+ // (3) Descriptor is JSON-serializable with deterministic shape —
13
+ // downstream coordinator consumers parse it unmodified.
14
+ // (4) Returns null ONLY when ontoConfig is undefined (defensive) or
15
+ // the resolver itself returns `no_host` (axis + main_native
16
+ // degrade both failed, i.e. no Claude or Codex host reachable).
17
+ // ---------------------------------------------------------------------------
18
+ const ORIGINAL_ENV = { ...process.env };
19
+ function restoreEnv() {
20
+ for (const k of Object.keys(process.env)) {
21
+ if (!(k in ORIGINAL_ENV))
22
+ delete process.env[k];
23
+ }
24
+ for (const [k, v] of Object.entries(ORIGINAL_ENV)) {
25
+ process.env[k] = v;
26
+ }
27
+ }
28
+ describe("tryResolveTopologyForHandoff — null paths", () => {
29
+ beforeEach(() => {
30
+ delete process.env.CLAUDECODE;
31
+ delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
32
+ });
33
+ afterEach(restoreEnv);
34
+ it("undefined ontoConfig → null (defensive guard)", () => {
35
+ expect(tryResolveTopologyForHandoff(undefined)).toBeNull();
36
+ });
37
+ it("no host signals → null (resolver returns no_host)", () => {
38
+ // No CLAUDECODE, no codex session. With no reachable host even the
39
+ // main_native degrade cannot map — resolver returns no_host and the
40
+ // handoff payload omits the topology field.
41
+ expect(tryResolveTopologyForHandoff({})).toBeNull();
42
+ });
43
+ it("review block declares unreachable subagent → null (axis + degrade both fail)", () => {
44
+ // No CLAUDECODE, no experimental, no codex, no litellm. Axis-first
45
+ // derives `cc-teams-codex-subprocess` which fails requirements; the
46
+ // main_native degrade then fails to map (no host) → no_host.
47
+ expect(tryResolveTopologyForHandoff({
48
+ review: {
49
+ subagent: { provider: "codex", model_id: "gpt-5.4" },
50
+ },
51
+ })).toBeNull();
52
+ });
53
+ });
54
+ describe("tryResolveTopologyForHandoff — always-on axis-first (P9.3)", () => {
55
+ beforeEach(() => {
56
+ delete process.env.CLAUDECODE;
57
+ delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
58
+ });
59
+ afterEach(restoreEnv);
60
+ it("plain CC session without review block → cc-main-agent-subagent descriptor via main_native degrade", () => {
61
+ // P9.3 invariant: every review invocation produces a descriptor
62
+ // when a host is reachable, even without an explicit `review:`
63
+ // axis block. Main_native degrade maps to cc-main-agent-subagent
64
+ // under CLAUDECODE=1.
65
+ process.env.CLAUDECODE = "1";
66
+ const descriptor = tryResolveTopologyForHandoff({});
67
+ expect(descriptor).not.toBeNull();
68
+ expect(descriptor.id).toBe("cc-main-agent-subagent");
69
+ });
70
+ it("empty `review: {}` ALSO resolves via main_native degrade under CC host", () => {
71
+ // The former M2 opt-in guard is gone — empty review blocks are no
72
+ // longer distinct from absent ones at dispatch time. Both produce
73
+ // the same cc-main-agent-subagent descriptor on CLAUDECODE=1.
74
+ process.env.CLAUDECODE = "1";
75
+ const descriptor = tryResolveTopologyForHandoff({
76
+ review: {},
77
+ });
78
+ expect(descriptor).not.toBeNull();
79
+ expect(descriptor.id).toBe("cc-main-agent-subagent");
80
+ });
81
+ });
82
+ describe("tryResolveTopologyForHandoff — resolved descriptor", () => {
83
+ beforeEach(() => {
84
+ delete process.env.CLAUDECODE;
85
+ delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
86
+ });
87
+ afterEach(restoreEnv);
88
+ it("cc-main-agent-subagent resolves to descriptor with 6 static attributes", () => {
89
+ process.env.CLAUDECODE = "1";
90
+ const descriptor = tryResolveTopologyForHandoff({
91
+ review: { subagent: { provider: "main-native" } },
92
+ });
93
+ expect(descriptor).not.toBeNull();
94
+ expect(descriptor.id).toBe("cc-main-agent-subagent");
95
+ expect(descriptor.teamlead_location).toBe("onto-main");
96
+ expect(descriptor.lens_spawn_mechanism).toBe("claude-agent-tool");
97
+ expect(descriptor.max_concurrent_lenses).toBe(10);
98
+ expect(descriptor.transport_rank).toBe("S2");
99
+ expect(descriptor.deliberation_channel).toBe("synthesizer-only");
100
+ });
101
+ it("cc-teams-lens-agent-deliberation resolves when triple opt-in met", () => {
102
+ process.env.CLAUDECODE = "1";
103
+ process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
104
+ // P9.2 (2026-04-21): deliberation topology is selected through the
105
+ // `config.review` axis block (`lens_deliberation: sendmessage-a2a`)
106
+ // + `lens_agent_teams_mode: true` double opt-in.
107
+ const descriptor = tryResolveTopologyForHandoff({
108
+ review: {
109
+ subagent: { provider: "main-native" },
110
+ lens_deliberation: "sendmessage-a2a",
111
+ },
112
+ lens_agent_teams_mode: true,
113
+ });
114
+ expect(descriptor).not.toBeNull();
115
+ expect(descriptor.id).toBe("cc-teams-lens-agent-deliberation");
116
+ expect(descriptor.deliberation_channel).toBe("sendmessage-a2a");
117
+ expect(descriptor.lens_spawn_mechanism).toBe("claude-teamcreate-member");
118
+ });
119
+ it("descriptor does NOT include plan_trace (compact handoff JSON)", () => {
120
+ process.env.CLAUDECODE = "1";
121
+ const descriptor = tryResolveTopologyForHandoff({
122
+ review: { subagent: { provider: "main-native" } },
123
+ });
124
+ expect(descriptor).not.toBeNull();
125
+ expect(Object.keys(descriptor)).not.toContain("plan_trace");
126
+ });
127
+ it("descriptor is JSON round-trip stable", () => {
128
+ process.env.CLAUDECODE = "1";
129
+ const descriptor = tryResolveTopologyForHandoff({
130
+ review: { subagent: { provider: "main-native" } },
131
+ });
132
+ const json = JSON.stringify(descriptor);
133
+ const parsed = JSON.parse(json);
134
+ expect(parsed).toEqual(descriptor);
135
+ });
136
+ });
@@ -0,0 +1,201 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { tryResolveTopologyForHandoff, tryTopologyDerivedExecutor, } from "./review-invoke.js";
3
+ // ---------------------------------------------------------------------------
4
+ // P9.3-m1 Resolver caching invariants (2026-04-21):
5
+ //
6
+ // `runReviewInvokeCli` resolves `resolveExecutionTopology` exactly once
7
+ // per invocation and threads the result as `cached` to 3 downstream
8
+ // consumers. This file protects the cache plumbing from future
9
+ // regressions — a caller that accidentally drops the `cached` argument
10
+ // (reverting to the 3x resolver-call pattern) would re-emit the full
11
+ // `[topology]` STDERR trace, which these tests assert does NOT happen.
12
+ //
13
+ // The `[topology] signals:` line is the most stable counter because
14
+ // `resolveExecutionTopology` emits it exactly once at the very start of
15
+ // each invocation (see execution-topology-resolver.ts:413). When the
16
+ // helpers honour `cached`, they skip the resolver entirely and this
17
+ // line MUST NOT appear.
18
+ // ---------------------------------------------------------------------------
19
+ const FAKE_HOME = "/tmp/fake-onto-home";
20
+ const CACHED_LITELLM_TOPOLOGY = {
21
+ id: "cc-teams-litellm-sessions",
22
+ teamlead_location: "claude-teamcreate",
23
+ lens_spawn_mechanism: "litellm-http",
24
+ max_concurrent_lenses: 3,
25
+ transport_rank: "S2",
26
+ deliberation_channel: "synthesizer-only",
27
+ plan_trace: ["cached-by-runReviewInvokeCli"],
28
+ };
29
+ const CACHED_CC_MAIN_TOPOLOGY = {
30
+ id: "cc-main-agent-subagent",
31
+ teamlead_location: "onto-main",
32
+ lens_spawn_mechanism: "claude-agent-tool",
33
+ max_concurrent_lenses: 3,
34
+ transport_rank: "S0",
35
+ deliberation_channel: "synthesizer-only",
36
+ plan_trace: ["cached-by-runReviewInvokeCli"],
37
+ };
38
+ describe("tryResolveTopologyForHandoff — cached topology bypass", () => {
39
+ const originalEnv = { ...process.env };
40
+ let stderrSpy;
41
+ beforeEach(() => {
42
+ delete process.env.CLAUDECODE;
43
+ delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
44
+ stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
45
+ });
46
+ afterEach(() => {
47
+ stderrSpy.mockRestore();
48
+ for (const k of Object.keys(process.env)) {
49
+ if (!(k in originalEnv))
50
+ delete process.env[k];
51
+ }
52
+ for (const [k, v] of Object.entries(originalEnv)) {
53
+ process.env[k] = v;
54
+ }
55
+ });
56
+ function signalsTraceLines() {
57
+ return stderrSpy.mock.calls
58
+ .map((c) => String(c[0]))
59
+ .filter((l) => l.startsWith("[topology] signals:"));
60
+ }
61
+ it("cached=ExecutionTopology → descriptor returned without re-running resolver", () => {
62
+ const descriptor = tryResolveTopologyForHandoff({}, CACHED_LITELLM_TOPOLOGY);
63
+ expect(descriptor).not.toBeNull();
64
+ expect(descriptor.id).toBe("cc-teams-litellm-sessions");
65
+ expect(descriptor.teamlead_location).toBe("claude-teamcreate");
66
+ expect(signalsTraceLines()).toHaveLength(0);
67
+ });
68
+ it("cached=null → returns null without re-running resolver", () => {
69
+ const descriptor = tryResolveTopologyForHandoff({}, null);
70
+ expect(descriptor).toBeNull();
71
+ expect(signalsTraceLines()).toHaveLength(0);
72
+ });
73
+ it("cached=undefined → legacy behaviour (resolver runs, emits signals)", () => {
74
+ // Two-argument call path preserved for test-harness compatibility;
75
+ // this branch is what existing tests exercise.
76
+ tryResolveTopologyForHandoff({});
77
+ expect(signalsTraceLines()).toHaveLength(1);
78
+ });
79
+ });
80
+ describe("tryTopologyDerivedExecutor — cached topology bypass", () => {
81
+ const originalEnv = { ...process.env };
82
+ let stderrSpy;
83
+ beforeEach(() => {
84
+ delete process.env.CLAUDECODE;
85
+ delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
86
+ stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
87
+ });
88
+ afterEach(() => {
89
+ stderrSpy.mockRestore();
90
+ for (const k of Object.keys(process.env)) {
91
+ if (!(k in originalEnv))
92
+ delete process.env[k];
93
+ }
94
+ for (const [k, v] of Object.entries(originalEnv)) {
95
+ process.env[k] = v;
96
+ }
97
+ });
98
+ function signalsTraceLines() {
99
+ return stderrSpy.mock.calls
100
+ .map((c) => String(c[0]))
101
+ .filter((l) => l.startsWith("[topology] signals:"));
102
+ }
103
+ it("cached=ExecutionTopology (binary-backed) → executor returned without re-running resolver", () => {
104
+ const result = tryTopologyDerivedExecutor({ llm_base_url: "http://localhost:4000" }, FAKE_HOME, CACHED_LITELLM_TOPOLOGY);
105
+ expect(result).not.toBeNull();
106
+ expect(result.bin).toBe("node");
107
+ expect(result.args[0]).toContain("inline-http-review-unit-executor.js");
108
+ expect(signalsTraceLines()).toHaveLength(0);
109
+ });
110
+ it("cached=ExecutionTopology (no standalone binary) → null without re-running resolver", () => {
111
+ const result = tryTopologyDerivedExecutor({}, FAKE_HOME, CACHED_CC_MAIN_TOPOLOGY);
112
+ expect(result).toBeNull();
113
+ expect(signalsTraceLines()).toHaveLength(0);
114
+ });
115
+ it("cached=null → null without re-running resolver", () => {
116
+ const result = tryTopologyDerivedExecutor({}, FAKE_HOME, null);
117
+ expect(result).toBeNull();
118
+ expect(signalsTraceLines()).toHaveLength(0);
119
+ });
120
+ it("cached=undefined → legacy behaviour (resolver runs, emits signals)", () => {
121
+ process.env.CLAUDECODE = "1";
122
+ tryTopologyDerivedExecutor({}, FAKE_HOME);
123
+ expect(signalsTraceLines()).toHaveLength(1);
124
+ });
125
+ });
126
+ // ---------------------------------------------------------------------------
127
+ // Integration-layer invariant: exercise the 3-consumer contract that
128
+ // `runReviewInvokeCli` depends on. The stderr-based tests above prove
129
+ // the helper-level contract; these tests prove the full-dispatch
130
+ // consumer sequence (tryResolveTopologyForHandoff + tryTopologyDerivedExecutor
131
+ // twice — the shape invoked by resolveExecutorConfig for default +
132
+ // synthesize) adds up to ZERO resolver invocations when the cache is
133
+ // threaded. If a future refactor drops the `cached` argument from any
134
+ // consumer, the signals-line count will jump from 0 to 1-or-more and
135
+ // this test will fail — catching the very regression class MINOR-1 of
136
+ // the P9.3-m1 review flagged.
137
+ // ---------------------------------------------------------------------------
138
+ describe("runReviewInvokeCli full-dispatch consumer sequence — invariant", () => {
139
+ const originalEnv = { ...process.env };
140
+ let stderrSpy;
141
+ beforeEach(() => {
142
+ delete process.env.CLAUDECODE;
143
+ delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
144
+ stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
145
+ });
146
+ afterEach(() => {
147
+ stderrSpy.mockRestore();
148
+ for (const k of Object.keys(process.env)) {
149
+ if (!(k in originalEnv))
150
+ delete process.env[k];
151
+ }
152
+ for (const [k, v] of Object.entries(originalEnv)) {
153
+ process.env[k] = v;
154
+ }
155
+ });
156
+ function signalsTraceCount() {
157
+ return stderrSpy.mock.calls
158
+ .map((c) => String(c[0]))
159
+ .filter((l) => l.startsWith("[topology] signals:")).length;
160
+ }
161
+ it("3 consumers with shared cachedTopology → resolver runs 0 times", () => {
162
+ // Simulate the runReviewInvokeCli full-dispatch sequence:
163
+ // 1. runReviewInvokeCli resolves once at the top (we fabricate the
164
+ // result here as `cachedTopology` — NOT included in the spy count).
165
+ // 2. tryResolveTopologyForHandoff(config, cachedTopology) — coordinator_start
166
+ // path would have called this but it returns earlier; included here
167
+ // for completeness of the 3-consumer contract.
168
+ // 3. tryTopologyDerivedExecutor ×2 (default + synthesize via
169
+ // resolveExecutorConfig).
170
+ const cachedTopology = CACHED_LITELLM_TOPOLOGY;
171
+ const config = { llm_base_url: "http://localhost:4000" };
172
+ tryResolveTopologyForHandoff(config, cachedTopology);
173
+ tryTopologyDerivedExecutor(config, FAKE_HOME, cachedTopology);
174
+ tryTopologyDerivedExecutor(config, FAKE_HOME, cachedTopology);
175
+ // ZERO resolver calls: cache bypassed all 3 consumers.
176
+ expect(signalsTraceCount()).toBe(0);
177
+ });
178
+ it("regression probe: 3 consumers with cached=undefined → resolver runs 3 times", () => {
179
+ // This is the PRE-fix behaviour. If someone accidentally reverts the
180
+ // caching (drops the `cached` argument from all 3 consumers), the
181
+ // count would be 3 — proving the test catches the exact regression.
182
+ process.env.CLAUDECODE = "1";
183
+ const config = { llm_base_url: "http://localhost:4000" };
184
+ tryResolveTopologyForHandoff(config);
185
+ tryTopologyDerivedExecutor(config, FAKE_HOME);
186
+ tryTopologyDerivedExecutor(config, FAKE_HOME);
187
+ expect(signalsTraceCount()).toBe(3);
188
+ });
189
+ it("3 consumers with cachedTopology=null → resolver runs 0 times, all return null", () => {
190
+ // `null` propagation: all 3 consumers see cached=null and short-circuit
191
+ // without invoking the resolver.
192
+ const config = { llm_base_url: "http://localhost:4000" };
193
+ const descriptor = tryResolveTopologyForHandoff(config, null);
194
+ const exec1 = tryTopologyDerivedExecutor(config, FAKE_HOME, null);
195
+ const exec2 = tryTopologyDerivedExecutor(config, FAKE_HOME, null);
196
+ expect(descriptor).toBeNull();
197
+ expect(exec1).toBeNull();
198
+ expect(exec2).toBeNull();
199
+ expect(signalsTraceCount()).toBe(0);
200
+ });
201
+ });