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,298 +0,0 @@
1
- /**
2
- * Authority-Consistency Perspective.
3
- *
4
- * Checks whether a design document (or trajectory) maintains
5
- * consistency with the project's authority hierarchy.
6
- *
7
- * Failure modes this perspective detects:
8
- * 1. Self-contradiction: a section contradicts another section
9
- * within the same document.
10
- * 2. Authority violation: a document overrides or conflicts with
11
- * a higher-authority source without explicit justification.
12
- * 3. Ghost axis: a concept is declared removed/derived-only but
13
- * operative prose still treats it as an independent field.
14
- */
15
- /**
16
- * Analyze a design document for authority consistency.
17
- *
18
- * Current implementation: structural analysis only.
19
- * LLM-assisted deep analysis is a future extension.
20
- */
21
- export function checkAuthorityConsistency(input) {
22
- const violations = [];
23
- // Phase 1: detect ghost axes —
24
- // sections that declare a concept removed/derived but still reference it operatively
25
- for (const section of input.sections) {
26
- const declaredRemoved = extractRemovedDeclarations(section.content);
27
- for (const other of input.sections) {
28
- if (other.id === section.id)
29
- continue;
30
- for (const removed of declaredRemoved) {
31
- if (hasOperativeUsage(other.content, removed.term)) {
32
- violations.push({
33
- id: `GHOST-${removed.term}-${other.id}`,
34
- type: "ghost-axis",
35
- severity: "high",
36
- source_section: section.id,
37
- conflicting_section: other.id,
38
- summary: `"${removed.term}" is declared ${removed.declaration} in ${section.id} but used operatively in ${other.id}`,
39
- recommendation: `Remove operative usage of "${removed.term}" from ${other.id}, or revoke the declaration in ${section.id}`,
40
- });
41
- }
42
- }
43
- }
44
- }
45
- // Phase 2: detect authority violations —
46
- // sections that contradict rules from higher-authority sources
47
- for (const section of input.sections) {
48
- const negations = extractNegations(section.content);
49
- for (const ref of input.authority_refs) {
50
- for (const rule of ref.relevant_rules) {
51
- for (const neg of negations) {
52
- if (negationContradictsRule(neg, rule)) {
53
- const vid = `AUTH-${section.id}-${ref.source}`;
54
- // Avoid duplicate ids for same section+source pair
55
- const exists = violations.some((v) => v.id === vid);
56
- if (!exists) {
57
- violations.push({
58
- id: vid,
59
- type: "authority-violation",
60
- severity: "high",
61
- source_section: section.id,
62
- conflicting_section: ref.source,
63
- summary: `${section.id} declares "${neg.statement}" which contradicts authority rule "${rule}" from ${ref.source} (rank ${ref.rank})`,
64
- recommendation: `Align ${section.id} with ${ref.source} or provide explicit justification for the override`,
65
- });
66
- }
67
- }
68
- }
69
- }
70
- }
71
- }
72
- // Phase 3: detect self-contradictions —
73
- // pairs of sections where one negates what the other affirms about the same topic
74
- for (const sA of input.sections) {
75
- const negationsA = extractNegations(sA.content);
76
- for (const sB of input.sections) {
77
- if (sA.id === sB.id)
78
- continue;
79
- // Only process each unordered pair once: skip if sB.id < sA.id
80
- if (sB.id <= sA.id)
81
- continue;
82
- for (const neg of negationsA) {
83
- if (hasAffirmation(sB.content, neg)) {
84
- const vid = `SELF-${sA.id}-${sB.id}-${neg.topic}`;
85
- const exists = violations.some((v) => v.id === vid);
86
- if (!exists) {
87
- violations.push({
88
- id: vid,
89
- type: "self-contradiction",
90
- severity: "medium",
91
- source_section: sA.id,
92
- conflicting_section: sB.id,
93
- summary: `${sA.id} negates "${neg.topic}" ("${neg.statement}") but ${sB.id} affirms it`,
94
- recommendation: `Reconcile the conflicting statements about "${neg.topic}" between ${sA.id} and ${sB.id}`,
95
- });
96
- }
97
- }
98
- }
99
- }
100
- }
101
- const high = violations.filter((v) => v.severity === "high").length;
102
- const medium = violations.filter((v) => v.severity === "medium").length;
103
- const low = violations.filter((v) => v.severity === "low").length;
104
- return {
105
- violations,
106
- summary: { total: violations.length, high, medium, low },
107
- passed: high === 0,
108
- };
109
- }
110
- const REMOVAL_PATTERNS = [
111
- /(?:제거|삭제|deprecated|removed)\s*[::]?\s*[`"]?(\w[\w_-]*)[`"]?/gi,
112
- /[`"]?(\w[\w_-]*)[`"]?\s*(?:를|을|은|는)\s*(?:제거|삭제)/gi,
113
- /[`"]?(\w[\w_-]*)[`"]?\s*(?:is|are)\s+(?:removed|deprecated|derived.only)/gi,
114
- // Korean pattern: "X는 derive-only 축" / "X를 ... 취급하지 않는다"
115
- /[`"]?(\w[\w_-]*)[`"]?\s*(?:는|은)\s*derive[- ]only/gi,
116
- /[`"]?(\w[\w_-]*)[`"]?\s*(?:를|을)\s*(?:.*?)취급하지\s*않/gi,
117
- ];
118
- function extractRemovedDeclarations(content) {
119
- const results = [];
120
- for (const pattern of REMOVAL_PATTERNS) {
121
- const regex = new RegExp(pattern.source, pattern.flags);
122
- let match;
123
- while ((match = regex.exec(content)) !== null) {
124
- if (match[1]) {
125
- results.push({ term: match[1], declaration: "removed" });
126
- }
127
- }
128
- }
129
- return results;
130
- }
131
- function hasOperativeUsage(content, term) {
132
- // Simple heuristic: the term appears outside of declaration/removal context
133
- const termRegex = new RegExp(`\\b${escapeRegex(term)}\\b`, "gi");
134
- const matches = content.match(termRegex);
135
- if (!matches || matches.length === 0)
136
- return false;
137
- // Check if any occurrence is NOT in a removal/declaration context
138
- const lines = content.split("\n");
139
- for (const line of lines) {
140
- if (!termRegex.test(line))
141
- continue;
142
- // Reset lastIndex
143
- termRegex.lastIndex = 0;
144
- // Skip lines that are themselves declarations of removal
145
- const isDeclaration = REMOVAL_PATTERNS.some((p) => {
146
- const r = new RegExp(p.source, p.flags);
147
- return r.test(line);
148
- });
149
- if (!isDeclaration)
150
- return true;
151
- }
152
- return false;
153
- }
154
- function escapeRegex(s) {
155
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
156
- }
157
- // ─── Authority-violation & Self-contradiction Helpers ───
158
- /** Strip common Korean postpositions/particles from a word. */
159
- function stripKoreanParticles(word) {
160
- // Order matters: longer suffixes first
161
- return word.replace(/(?:에서|으로|이며|에게|부터|까지|처럼|만큼|이라|라고|이고|하고|과는|와는|은|는|이|가|을|를|의|에|도|로|와|과|고)$/, "");
162
- }
163
- /** Strip Korean verb/adjective endings to extract stem. */
164
- function stripKoreanVerbEndings(word) {
165
- return word.replace(/(?:하지|하는|한다|하고|하며|해야|합니다|합니|했다|해서|하여|된다|되지|않는다|않다)$/, "");
166
- }
167
- /**
168
- * Korean negation patterns:
169
- * "X는/은 Y하지 않는다", "X를/을 Y하지 않는다"
170
- * "X를/을 차단", "X를/을 금지"
171
- *
172
- * English negation patterns:
173
- * "does not X", "must not X", "cannot X", "X is blocked/prohibited"
174
- */
175
- const NEGATION_PATTERNS = [
176
- // Korean: "A은/는 B하지 않는다" — topic = A, action keywords = B
177
- {
178
- pattern: /([가-힣\w_-]+)(?:은|는)\s+([가-힣\w_-]+(?:을|를)?)\s*(?:저장하지|하지|작성하지|기록하지)\s*않/g,
179
- topicGroup: 1,
180
- keywordGroups: [1, 2],
181
- },
182
- // Korean: "A를/을 차단/금지"
183
- {
184
- pattern: /([가-힣\w_-]+)(?:를|을)\s*(?:차단|금지|거부)/g,
185
- topicGroup: 1,
186
- keywordGroups: [1],
187
- },
188
- // English: "does not / must not / cannot X"
189
- {
190
- pattern: /(\w[\w_-]*)\s+(?:does not|must not|cannot|shall not)\s+(\w[\w_-]*)/gi,
191
- topicGroup: 1,
192
- keywordGroups: [1, 2],
193
- },
194
- ];
195
- function extractNegations(content) {
196
- const results = [];
197
- const sentences = content.split(/[.。!\n]+/).filter((s) => s.trim());
198
- for (const sentence of sentences) {
199
- for (const { pattern, topicGroup, keywordGroups } of NEGATION_PATTERNS) {
200
- const regex = new RegExp(pattern.source, pattern.flags);
201
- let match;
202
- while ((match = regex.exec(sentence)) !== null) {
203
- const topic = match[topicGroup]?.trim();
204
- if (!topic)
205
- continue;
206
- const keywords = [];
207
- for (const g of keywordGroups) {
208
- if (match[g]) {
209
- const raw = match[g].trim();
210
- keywords.push(raw);
211
- keywords.push(stripKoreanParticles(raw));
212
- }
213
- }
214
- // Also extract keywords from surrounding context (with particles and verb endings stripped)
215
- const surroundingWords = sentence
216
- .replace(/[^가-힣a-zA-Z0-9_-]/g, " ")
217
- .split(/\s+/)
218
- .filter((w) => w.length > 1)
219
- .flatMap((w) => {
220
- const stripped = stripKoreanParticles(w);
221
- const stemmed = stripKoreanVerbEndings(w);
222
- const stemmedStripped = stripKoreanVerbEndings(stripped);
223
- return [w, stripped, stemmed, stemmedStripped];
224
- });
225
- results.push({
226
- topic,
227
- statement: sentence.trim(),
228
- keywords: [...new Set([...keywords, ...surroundingWords].filter((k) => k.length > 0))],
229
- });
230
- }
231
- }
232
- }
233
- return results;
234
- }
235
- /**
236
- * Check if a negation contradicts an authority rule.
237
- * A contradiction occurs when the negation's topic/keywords overlap
238
- * significantly with the rule's content, and the rule is affirmative
239
- * (grants permission or defines capability) while the section denies it.
240
- */
241
- function negationContradictsRule(neg, rule) {
242
- // Extract rule words (both raw and particle-stripped)
243
- const rawRuleWords = rule
244
- .replace(/[^가-힣a-zA-Z0-9_-]/g, " ")
245
- .split(/\s+/)
246
- .filter((w) => w.length > 1);
247
- const ruleWords = [...new Set(rawRuleWords.flatMap((w) => [w, stripKoreanParticles(w)]).filter((w) => w.length > 0))];
248
- // The rule must contain affirmative action keywords
249
- const affirmativePatterns = [
250
- /write/i, /저장/i, /생성/i, /기록/i, /자동/i, /권한/i, /정의/i,
251
- ];
252
- const ruleIsAffirmative = affirmativePatterns.some((p) => p.test(rule));
253
- if (!ruleIsAffirmative)
254
- return false;
255
- // Count keyword overlap between negation keywords and rule words
256
- const negKeySet = new Set(neg.keywords.map((k) => k.toLowerCase()));
257
- let overlap = 0;
258
- for (const rw of ruleWords) {
259
- if (negKeySet.has(rw.toLowerCase())) {
260
- overlap++;
261
- }
262
- }
263
- // Also check if the topic itself appears in the rule (partial match),
264
- // or if negation keywords intersect with the rule's core concepts
265
- const strippedTopic = stripKoreanParticles(neg.topic).toLowerCase();
266
- const topicInRule = rule.toLowerCase().includes(strippedTopic) ||
267
- (strippedTopic.includes("learn") && /learn/i.test(rule)) ||
268
- (strippedTopic.includes("학습") && /학습|learn|저장/i.test(rule));
269
- // Require either topic match or significant keyword overlap
270
- return topicInRule || overlap >= 2;
271
- }
272
- /**
273
- * Check if content affirms what a negation denies.
274
- * Used for self-contradiction detection between section pairs.
275
- */
276
- function hasAffirmation(content, neg) {
277
- const topicEscaped = escapeRegex(neg.topic);
278
- const topicRegex = new RegExp(topicEscaped, "gi");
279
- if (!topicRegex.test(content))
280
- return false;
281
- // The content should use the topic in an affirmative/operative way
282
- // (not in another negation)
283
- const lines = content.split("\n");
284
- for (const line of lines) {
285
- const lineTopicRegex = new RegExp(topicEscaped, "gi");
286
- if (!lineTopicRegex.test(line))
287
- continue;
288
- // Check this line is NOT itself a negation
289
- const isNeg = /하지\s*않|차단|금지|does not|must not|cannot|shall not/i.test(line);
290
- if (isNeg)
291
- continue;
292
- // Affirmative usage patterns
293
- const affirmativeUsage = /실재|직접|참여|사용|결정|생성|저장|기록|적용|소비|pipeline|consumer|write|read|create|apply/i.test(line);
294
- if (affirmativeUsage)
295
- return true;
296
- }
297
- return false;
298
- }
@@ -1,70 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { readFileSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { checkAuthorityConsistency, } from "./authority-consistency.js";
5
- // ─── Load v9.3 trajectory fixture ───
6
- const fixturePath = join(import.meta.dirname, "../__fixtures__/v9.3-trajectory.json");
7
- const fixture = JSON.parse(readFileSync(fixturePath, "utf-8"));
8
- describe("authority-consistency perspective", () => {
9
- it("detects ghost-axis violation in v9.3 trajectory", () => {
10
- const input = {
11
- sections: fixture.sections,
12
- authority_refs: fixture.authority_refs,
13
- };
14
- const result = checkAuthorityConsistency(input);
15
- // The v9.3 trajectory has C-3: consumer_assigned declared derive-only in §6.3
16
- // but used operatively in §8.0 and §8.5
17
- const ghostViolations = result.violations.filter((v) => v.type === "ghost-axis");
18
- expect(ghostViolations.length).toBeGreaterThanOrEqual(1);
19
- // At least one ghost-axis should mention consumer_assigned
20
- const consumerAssigned = ghostViolations.find((v) => v.summary.includes("consumer_assigned"));
21
- expect(consumerAssigned).toBeDefined();
22
- expect(consumerAssigned.source_section).toBe("§6.3");
23
- });
24
- it("returns passed=false when high-severity violations exist", () => {
25
- const input = {
26
- sections: fixture.sections,
27
- authority_refs: fixture.authority_refs,
28
- };
29
- const result = checkAuthorityConsistency(input);
30
- expect(result.passed).toBe(false);
31
- expect(result.summary.high).toBeGreaterThanOrEqual(1);
32
- });
33
- it("detects authority-violation when section contradicts authority refs", () => {
34
- const input = {
35
- sections: fixture.sections,
36
- authority_refs: fixture.authority_refs,
37
- };
38
- const result = checkAuthorityConsistency(input);
39
- // §6.3 says "design은 학습을 저장하지 않는다" which contradicts
40
- // authority refs that define learn write permissions (build.md, review.md)
41
- const authViolations = result.violations.filter((v) => v.type === "authority-violation");
42
- expect(authViolations.length).toBeGreaterThanOrEqual(1);
43
- // At least one violation should originate from §6.3
44
- const fromSection63 = authViolations.find((v) => v.source_section === "§6.3");
45
- expect(fromSection63).toBeDefined();
46
- });
47
- it("detects self-contradiction between sections", () => {
48
- const input = {
49
- sections: fixture.sections,
50
- authority_refs: fixture.authority_refs,
51
- };
52
- const result = checkAuthorityConsistency(input);
53
- // §6.3 negates learn participation ("학습을 저장하지 않는다")
54
- // but §8.0 affirms learn as a real consumer with direct participation
55
- const selfContradictions = result.violations.filter((v) => v.type === "self-contradiction");
56
- expect(selfContradictions.length).toBeGreaterThanOrEqual(1);
57
- });
58
- it("returns passed=true for clean document", () => {
59
- const input = {
60
- sections: [
61
- { id: "§1", title: "Introduction", content: "This document defines the process." },
62
- { id: "§2", title: "Rules", content: "Rule A applies. Rule B applies." },
63
- ],
64
- authority_refs: [],
65
- };
66
- const result = checkAuthorityConsistency(input);
67
- expect(result.passed).toBe(true);
68
- expect(result.violations).toHaveLength(0);
69
- });
70
- });
@@ -1,46 +0,0 @@
1
- /**
2
- * Process Scope Type.
3
- *
4
- * Defines the "process" scope type for designing methodologies,
5
- * processes, and governance structures.
6
- *
7
- * A process scope differs from a code-product scope in:
8
- * 1. Grounding sources are authority documents, not code files.
9
- * 2. Surface is a process document (Markdown), not a UI mockup or API spec.
10
- * 3. Constraints come from authority consistency, not code architecture.
11
- * 4. Validation checks document coherence, not test execution.
12
- *
13
- * Perspectives are derived from the methodology adapter (adapter.ts = SSOT).
14
- * This eliminates UF-CONCISENESS-METADATA-DUPLICATION.
15
- */
16
- import { methodologyAdapter } from "../adapter.js";
17
- export const processScopeDefaults = {
18
- /** Derived from adapter.ts — single source of truth for methodology capabilities. */
19
- perspectives: methodologyAdapter.perspectives,
20
- entry_mode: "experience",
21
- surface_type: "markdown",
22
- };
23
- /**
24
- * Validate that a process scope configuration is well-formed.
25
- */
26
- export function validateProcessScopeConfig(config) {
27
- const errors = [];
28
- if (config.authority_sources.length === 0) {
29
- errors.push("At least one authority source is required for a process scope");
30
- }
31
- if (!config.target_document) {
32
- errors.push("target_document must be specified");
33
- }
34
- if (config.perspectives.length === 0) {
35
- errors.push("At least one perspective is required");
36
- }
37
- // Authority sources at the same rank are allowed (e.g., onto authority
38
- // hierarchy has rank 2 for both OaC and LLM-Native guidelines).
39
- // Only validate that ranks are positive integers.
40
- for (const source of config.authority_sources) {
41
- if (!Number.isInteger(source.rank) || source.rank < 1) {
42
- errors.push(`Authority source rank must be a positive integer: ${source.path} has rank ${source.rank}`);
43
- }
44
- }
45
- return { valid: errors.length === 0, errors };
46
- }
@@ -1,73 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { validateProcessScopeConfig, processScopeDefaults, } from "./process.js";
3
- describe("process scope type", () => {
4
- it("has correct defaults", () => {
5
- expect(processScopeDefaults.perspectives).toContain("authority-consistency");
6
- expect(processScopeDefaults.entry_mode).toBe("experience");
7
- expect(processScopeDefaults.surface_type).toBe("markdown");
8
- });
9
- it("validates a well-formed config", () => {
10
- const config = {
11
- authority_sources: [
12
- { path: ".onto/authority/core-lexicon.yaml", rank: 1, description: "Core concepts" },
13
- { path: ".onto/principles/ontology-as-code-guideline.md", rank: 2, description: "OaC principles" },
14
- ],
15
- target_document: ".onto/processes/evolve.md",
16
- perspectives: ["authority-consistency"],
17
- };
18
- const result = validateProcessScopeConfig(config);
19
- expect(result.valid).toBe(true);
20
- expect(result.errors).toHaveLength(0);
21
- });
22
- it("rejects config with no authority sources", () => {
23
- const config = {
24
- authority_sources: [],
25
- target_document: ".onto/processes/evolve.md",
26
- perspectives: ["authority-consistency"],
27
- };
28
- const result = validateProcessScopeConfig(config);
29
- expect(result.valid).toBe(false);
30
- expect(result.errors).toContain("At least one authority source is required for a process scope");
31
- });
32
- it("allows duplicate authority ranks (onto hierarchy has shared ranks)", () => {
33
- const config = {
34
- authority_sources: [
35
- { path: ".onto/principles/oac.md", rank: 2, description: "OaC" },
36
- { path: ".onto/principles/llm-native.md", rank: 2, description: "LLM-Native" },
37
- ],
38
- target_document: ".onto/processes/evolve.md",
39
- perspectives: ["authority-consistency"],
40
- };
41
- const result = validateProcessScopeConfig(config);
42
- expect(result.valid).toBe(true);
43
- });
44
- it("rejects config with non-positive authority rank", () => {
45
- const config = {
46
- authority_sources: [
47
- { path: "a.md", rank: 0, description: "A" },
48
- ],
49
- target_document: ".onto/processes/evolve.md",
50
- perspectives: ["authority-consistency"],
51
- };
52
- const result = validateProcessScopeConfig(config);
53
- expect(result.valid).toBe(false);
54
- });
55
- it("rejects config with empty target_document", () => {
56
- const config = {
57
- authority_sources: [{ path: "a.md", rank: 1, description: "A" }],
58
- target_document: "",
59
- perspectives: ["authority-consistency"],
60
- };
61
- const result = validateProcessScopeConfig(config);
62
- expect(result.valid).toBe(false);
63
- });
64
- it("rejects config with no perspectives", () => {
65
- const config = {
66
- authority_sources: [{ path: "a.md", rank: 1, description: "A" }],
67
- target_document: ".onto/processes/evolve.md",
68
- perspectives: [],
69
- };
70
- const result = validateProcessScopeConfig(config);
71
- expect(result.valid).toBe(false);
72
- });
73
- });
@@ -1,47 +0,0 @@
1
- /**
2
- * Adapter Registry — single dispatch table for design adapters.
3
- *
4
- * Each adapter handles a specific family of scope types. The registry
5
- * enables runtime selection of the correct adapter based on scope_kind,
6
- * resolving C2 (methodology adapter has no runtime dispatch).
7
- *
8
- * Adapters registered:
9
- * - code-product: experience/interface scopes for building software
10
- * - methodology: process scopes for designing processes and governance
11
- */
12
- import { methodologyAdapter } from "./methodology/adapter.js";
13
- // ─── Registry Data ───
14
- const codeProductEntry = {
15
- id: "code-product",
16
- name: "Code-Product Adapter",
17
- scope_kinds: ["experience", "interface"],
18
- perspectives: ["experience", "policy", "code"],
19
- surface_types: ["mockup", "api-contract"],
20
- };
21
- const methodologyEntry = {
22
- id: methodologyAdapter.name,
23
- name: "Methodology Adapter",
24
- scope_kinds: methodologyAdapter.scope_types,
25
- perspectives: methodologyAdapter.perspectives,
26
- surface_types: ["markdown"],
27
- };
28
- const REGISTRY = [
29
- codeProductEntry,
30
- methodologyEntry,
31
- ];
32
- // ─── Public API ───
33
- /**
34
- * Look up the adapter that handles a given scope kind.
35
- *
36
- * @param scopeKind - e.g. "experience", "interface", "process"
37
- * @returns The matching adapter entry, or undefined if none matches.
38
- */
39
- export function getAdapter(scopeKind) {
40
- return REGISTRY.find((entry) => entry.scope_kinds.includes(scopeKind));
41
- }
42
- /**
43
- * List all registered adapters for discovery / introspection.
44
- */
45
- export function listAdapters() {
46
- return REGISTRY;
47
- }
@@ -1,67 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { getAdapter, listAdapters } from "./registry.js";
3
- import { methodologyAdapter } from "./methodology/adapter.js";
4
- describe("adapter registry", () => {
5
- // ─── getAdapter ───
6
- it("returns code-product for 'experience' scope", () => {
7
- const entry = getAdapter("experience");
8
- expect(entry).toBeDefined();
9
- expect(entry.id).toBe("code-product");
10
- expect(entry.scope_kinds).toContain("experience");
11
- });
12
- it("returns code-product for 'interface' scope", () => {
13
- const entry = getAdapter("interface");
14
- expect(entry).toBeDefined();
15
- expect(entry.id).toBe("code-product");
16
- expect(entry.scope_kinds).toContain("interface");
17
- });
18
- it("returns methodology for 'process' scope", () => {
19
- const entry = getAdapter("process");
20
- expect(entry).toBeDefined();
21
- expect(entry.id).toBe("methodology");
22
- expect(entry.scope_kinds).toContain("process");
23
- });
24
- it("returns undefined for unknown scope kind", () => {
25
- const entry = getAdapter("unknown-kind");
26
- expect(entry).toBeUndefined();
27
- });
28
- // ─── methodology adapter metadata consistency ───
29
- it("methodology entry perspectives match adapter.ts SSOT", () => {
30
- const entry = getAdapter("process");
31
- expect(entry.perspectives).toEqual(methodologyAdapter.perspectives);
32
- });
33
- it("methodology entry scope_kinds match adapter.ts scope_types", () => {
34
- const entry = getAdapter("process");
35
- expect(entry.scope_kinds).toEqual(methodologyAdapter.scope_types);
36
- });
37
- // ─── listAdapters ───
38
- it("lists exactly 2 adapters", () => {
39
- const all = listAdapters();
40
- expect(all).toHaveLength(2);
41
- });
42
- it("returned list is readonly (immutable reference)", () => {
43
- const a = listAdapters();
44
- const b = listAdapters();
45
- expect(a).toBe(b); // same reference
46
- });
47
- it("every entry has required fields", () => {
48
- for (const entry of listAdapters()) {
49
- expect(entry.id).toBeTruthy();
50
- expect(entry.name).toBeTruthy();
51
- expect(entry.scope_kinds.length).toBeGreaterThan(0);
52
- expect(entry.perspectives.length).toBeGreaterThan(0);
53
- expect(entry.surface_types.length).toBeGreaterThan(0);
54
- }
55
- });
56
- // ─── No scope_kind collision ───
57
- it("no scope_kind is claimed by two adapters", () => {
58
- const all = listAdapters();
59
- const seen = new Map();
60
- for (const entry of all) {
61
- for (const kind of entry.scope_kinds) {
62
- expect(seen.has(kind)).toBe(false);
63
- seen.set(kind, entry.id);
64
- }
65
- }
66
- });
67
- });