scip-query 0.18.0 → 0.19.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/CHANGELOG.md +14 -0
  2. package/README.md +1 -0
  3. package/dist/augment-vue-worker.js +1 -1
  4. package/dist/{chunk-2DBY4MO7.js → chunk-24ET4VLC.js} +2 -2
  5. package/dist/chunk-2NA6TYP4.js +120 -0
  6. package/dist/{chunk-XKWEMFHP.js → chunk-2WCXKANA.js} +2 -2
  7. package/dist/{chunk-LL5NQB5V.js → chunk-34MLC6UI.js} +2 -2
  8. package/dist/chunk-35NLDRZC.js +2 -0
  9. package/dist/{chunk-MNRKD3WP.js → chunk-3WLRW5TC.js} +2 -2
  10. package/dist/{chunk-SW7LKHRU.js → chunk-4BU54UJG.js} +2 -2
  11. package/dist/{chunk-T4P27T6S.js → chunk-4CZJ4YJB.js} +2 -2
  12. package/dist/{chunk-3CJXFMR5.js → chunk-4FMT4HPC.js} +2 -2
  13. package/dist/{chunk-J7IMQRCU.js → chunk-53SUJOJA.js} +2 -2
  14. package/dist/{chunk-27YDE22N.js → chunk-5GOBZI34.js} +2 -2
  15. package/dist/{chunk-4FLF7BHJ.js → chunk-5OZCNAVM.js} +2 -2
  16. package/dist/chunk-5TEUKVSM.js +2 -0
  17. package/dist/{chunk-GTANVH72.js → chunk-5W2VAEVR.js} +2 -2
  18. package/dist/{chunk-43QUXX3E.js → chunk-63P42UR6.js} +2 -2
  19. package/dist/{chunk-OQFPCIXO.js → chunk-64QITTX7.js} +2 -2
  20. package/dist/{chunk-P4L5QQT5.js → chunk-6O5JOS7T.js} +2 -2
  21. package/dist/chunk-6PKO2TNZ.js +2 -0
  22. package/dist/{chunk-OSBLECSI.js → chunk-7SGOWD2Y.js} +2 -2
  23. package/dist/chunk-7TJJY2C3.js +2 -0
  24. package/dist/{chunk-K3UVTL3J.js → chunk-AEM24WSF.js} +2 -2
  25. package/dist/{chunk-PV3GKBO5.js → chunk-AGTATREV.js} +2 -2
  26. package/dist/chunk-AOSFSYEA.js +20 -0
  27. package/dist/{chunk-VCRMI56V.js → chunk-APLNTJPJ.js} +2 -2
  28. package/dist/{chunk-7XP7ZRSI.js → chunk-AYRHVJXW.js} +2 -2
  29. package/dist/chunk-B2WQKQKP.js +3 -0
  30. package/dist/{chunk-SWJEREML.js → chunk-BBBKPOIT.js} +2 -2
  31. package/dist/{chunk-OTTHMUMV.js → chunk-BCMOTIB6.js} +2 -2
  32. package/dist/chunk-BMTBVMA3.js +10 -0
  33. package/dist/{chunk-J7WYG63U.js → chunk-C3KCSAQ4.js} +2 -2
  34. package/dist/{chunk-5CJ6AQN7.js → chunk-CAKPEQZB.js} +2 -2
  35. package/dist/{chunk-UWR52GNZ.js → chunk-CIYUFF24.js} +2 -2
  36. package/dist/{chunk-ABDXTPCT.js → chunk-CKFMZE77.js} +2 -2
  37. package/dist/chunk-DCDOGW32.js +2 -0
  38. package/dist/{chunk-ODH4FT3P.js → chunk-DFQNE73Y.js} +2 -2
  39. package/dist/chunk-DO775SYA.js +2 -0
  40. package/dist/chunk-DRH3AD7W.js +4 -0
  41. package/dist/chunk-DZXFZAZO.js +16 -0
  42. package/dist/chunk-E3KWOHH7.js +5 -0
  43. package/dist/chunk-EMIIOOTM.js +38 -0
  44. package/dist/chunk-ESNRT7QN.js +927 -0
  45. package/dist/{chunk-AWYKDRYV.js → chunk-FB6IKAKZ.js} +2 -2
  46. package/dist/{chunk-BGUYAA3Q.js → chunk-FBUNGRKI.js} +2 -2
  47. package/dist/{chunk-M2TRDR25.js → chunk-FC5K7T35.js} +1 -1
  48. package/dist/{chunk-GWCW25ON.js → chunk-FHLYJVXF.js} +2 -2
  49. package/dist/{chunk-IG6X65MG.js → chunk-FRXB74RQ.js} +2 -2
  50. package/dist/{chunk-IKMOYFUM.js → chunk-FTRNGQGR.js} +2 -2
  51. package/dist/{chunk-NX2YAXVQ.js → chunk-FUFNRZFJ.js} +2 -2
  52. package/dist/{chunk-JLZUM476.js → chunk-GAE7WCBK.js} +2 -2
  53. package/dist/chunk-GIHVWNKQ.js +18 -0
  54. package/dist/{chunk-MPBN5DO4.js → chunk-HCS5LB6U.js} +2 -2
  55. package/dist/{chunk-6JSTKSZH.js → chunk-HFBNIIZX.js} +2 -2
  56. package/dist/{chunk-JHK2DMUQ.js → chunk-HGFDYOVB.js} +1 -1
  57. package/dist/chunk-IOOCKVUA.js +6 -0
  58. package/dist/{chunk-4L4X66GE.js → chunk-J4MYRIYT.js} +2 -2
  59. package/dist/{chunk-TAB7AWKO.js → chunk-J5XJWCB3.js} +2 -2
  60. package/dist/{chunk-POGZSZPX.js → chunk-JBZXJXIS.js} +2 -2
  61. package/dist/chunk-JJZRS2OP.js +5 -0
  62. package/dist/chunk-KC2IFAAU.js +3 -0
  63. package/dist/{chunk-3M2UCPFS.js → chunk-KHE7J5ZN.js} +1 -1
  64. package/dist/{chunk-4XTPZ5CR.js → chunk-KMOMNTB4.js} +2 -2
  65. package/dist/chunk-KMUFGAIK.js +2 -0
  66. package/dist/chunk-LF5CIKWZ.js +26 -0
  67. package/dist/chunk-LM72NQ7T.js +3 -0
  68. package/dist/{chunk-QPF7CS5W.js → chunk-LQUDSHLB.js} +2 -2
  69. package/dist/chunk-MP43RX4O.js +67 -0
  70. package/dist/{chunk-D5OXYOJP.js → chunk-MQ2B33LQ.js} +1 -1
  71. package/dist/{chunk-WA64GKWB.js → chunk-NH7WNNQC.js} +3 -3
  72. package/dist/{chunk-HOZ3IXZ5.js → chunk-NTOBQK5H.js} +2 -2
  73. package/dist/{chunk-SUYCF4SX.js → chunk-OLG2YPLS.js} +2 -2
  74. package/dist/{chunk-O5Y3ISO3.js → chunk-OOUJBAKJ.js} +2 -2
  75. package/dist/{chunk-U244OVE6.js → chunk-OQ6TCHBB.js} +2 -2
  76. package/dist/{chunk-5GAUXLOE.js → chunk-PNESKY2Z.js} +2 -2
  77. package/dist/chunk-PYMZU5EG.js +2 -0
  78. package/dist/chunk-Q2WEWIKX.js +4 -0
  79. package/dist/chunk-QHKXGMOI.js +3 -0
  80. package/dist/{chunk-VXDMXZKC.js → chunk-RPEA7P5Z.js} +2 -2
  81. package/dist/{chunk-K65T4TJS.js → chunk-SJ6XSCG7.js} +2 -2
  82. package/dist/{chunk-LADYDOS5.js → chunk-SSXEYWN3.js} +2 -2
  83. package/dist/chunk-SYGAA54M.js +2 -0
  84. package/dist/{chunk-H4T2AST4.js → chunk-TYEGFDOP.js} +2 -2
  85. package/dist/chunk-UJKZQLDB.js +2 -0
  86. package/dist/{chunk-PZV2PGBR.js → chunk-US44MEVU.js} +2 -2
  87. package/dist/{chunk-EJ65IVPV.js → chunk-V5WBVF6K.js} +2 -2
  88. package/dist/{chunk-AV54WZUK.js → chunk-V7J4A3AH.js} +2 -2
  89. package/dist/{chunk-45QWQSWS.js → chunk-VIKEPD4D.js} +2 -2
  90. package/dist/{chunk-TLTLJ4SW.js → chunk-WAU7HVDI.js} +2 -2
  91. package/dist/chunk-WCZAABYF.js +2 -0
  92. package/dist/{chunk-FMD46HAG.js → chunk-WFRET75Z.js} +2 -2
  93. package/dist/chunk-WWCZCH7W.js +3 -0
  94. package/dist/chunk-XBN5VO53.js +2 -0
  95. package/dist/{chunk-35TZERMO.js → chunk-XCPE3G75.js} +2 -2
  96. package/dist/chunk-XYBNOILR.js +2 -0
  97. package/dist/{chunk-BAMVG4WQ.js → chunk-XZXUMGAA.js} +2 -2
  98. package/dist/{chunk-MN54AGZ3.js → chunk-YCSTKIYU.js} +2 -2
  99. package/dist/{chunk-CMLHZWRS.js → chunk-YGQBJUS6.js} +2 -2
  100. package/dist/{chunk-7ROLM67J.js → chunk-YILKXTIY.js} +2 -2
  101. package/dist/{chunk-YMFHC5J2.js → chunk-ZJGZCBYT.js} +2 -2
  102. package/dist/{chunk-D5F3IQYP.js → chunk-ZNK6K3LB.js} +2 -2
  103. package/dist/cli.js +2 -2
  104. package/dist/{command-descriptors-AQWWJNTT.js → command-descriptors-3EJHQLQZ.js} +173 -167
  105. package/dist/{config-types-70s7NxKB.d.ts → config-types-BA3xLCfG.d.ts} +28 -1
  106. package/dist/{db-BBmJ0v3b.d.ts → db-CzA-9_rL.d.ts} +6 -18
  107. package/dist/direct-navigation-C2A44KFT.js +3 -0
  108. package/dist/{health-CWpFL_6z.d.ts → health-DYy13GAe.d.ts} +3 -1
  109. package/dist/index.d.ts +23 -41
  110. package/dist/index.js +1 -1
  111. package/dist/postinstall.js +1 -1
  112. package/dist/queries/affected.d.ts +2 -2
  113. package/dist/queries/affected.js +1 -1
  114. package/dist/queries/architecture.d.ts +83 -0
  115. package/dist/queries/architecture.js +2 -0
  116. package/dist/queries/bottlenecks.d.ts +2 -2
  117. package/dist/queries/bottlenecks.js +1 -1
  118. package/dist/queries/by-kind.d.ts +2 -2
  119. package/dist/queries/by-kind.js +1 -1
  120. package/dist/queries/call-graph.d.ts +2 -2
  121. package/dist/queries/call-graph.js +1 -1
  122. package/dist/queries/change-surface.d.ts +2 -2
  123. package/dist/queries/change-surface.js +1 -1
  124. package/dist/queries/cleanup-plan.d.ts +2 -2
  125. package/dist/queries/cleanup-plan.js +1 -1
  126. package/dist/queries/co-change.d.ts +2 -2
  127. package/dist/queries/co-change.js +1 -1
  128. package/dist/queries/code.d.ts +2 -2
  129. package/dist/queries/code.js +1 -1
  130. package/dist/queries/complexity-hotspots.d.ts +2 -2
  131. package/dist/queries/complexity-hotspots.js +1 -1
  132. package/dist/queries/complexity.d.ts +2 -2
  133. package/dist/queries/complexity.js +1 -1
  134. package/dist/queries/convergence.d.ts +2 -2
  135. package/dist/queries/convergence.js +1 -1
  136. package/dist/queries/coupling.d.ts +2 -2
  137. package/dist/queries/coupling.js +1 -1
  138. package/dist/queries/cycles.d.ts +2 -2
  139. package/dist/queries/cycles.js +1 -1
  140. package/dist/queries/dataflow.d.ts +2 -2
  141. package/dist/queries/dataflow.js +1 -1
  142. package/dist/queries/dead.d.ts +2 -2
  143. package/dist/queries/dead.js +1 -1
  144. package/dist/queries/decorative-checkers.d.ts +2 -2
  145. package/dist/queries/decorative-checkers.js +1 -1
  146. package/dist/queries/deep-chains.d.ts +2 -2
  147. package/dist/queries/deep-chains.js +1 -1
  148. package/dist/queries/deps.d.ts +2 -2
  149. package/dist/queries/deps.js +1 -1
  150. package/dist/queries/diff-gate.d.ts +5 -3
  151. package/dist/queries/diff-gate.js +1 -1
  152. package/dist/queries/diff-impact.d.ts +2 -2
  153. package/dist/queries/diff-impact.js +1 -1
  154. package/dist/queries/doc-drift.d.ts +2 -2
  155. package/dist/queries/doc-drift.js +1 -1
  156. package/dist/queries/drift.d.ts +27 -10
  157. package/dist/queries/drift.js +1 -1
  158. package/dist/queries/duplicate-bodies.d.ts +2 -2
  159. package/dist/queries/duplicate-bodies.js +1 -1
  160. package/dist/queries/extract-candidates.d.ts +2 -2
  161. package/dist/queries/extract-candidates.js +1 -1
  162. package/dist/queries/fan.d.ts +2 -2
  163. package/dist/queries/fan.js +1 -1
  164. package/dist/queries/files.d.ts +2 -2
  165. package/dist/queries/health.d.ts +3 -3
  166. package/dist/queries/health.js +1 -1
  167. package/dist/queries/hierarchy.d.ts +2 -2
  168. package/dist/queries/hierarchy.js +1 -1
  169. package/dist/queries/hotspots.d.ts +2 -2
  170. package/dist/queries/hotspots.js +1 -1
  171. package/dist/queries/imports.d.ts +2 -2
  172. package/dist/queries/imports.js +1 -1
  173. package/dist/queries/incomplete-migration.d.ts +2 -2
  174. package/dist/queries/incomplete-migration.js +1 -1
  175. package/dist/queries/index.d.ts +5 -4
  176. package/dist/queries/index.js +1 -1
  177. package/dist/queries/isolated.d.ts +2 -2
  178. package/dist/queries/isolated.js +1 -1
  179. package/dist/queries/locality-candidates.d.ts +2 -2
  180. package/dist/queries/locality-candidates.js +1 -1
  181. package/dist/queries/members.d.ts +2 -2
  182. package/dist/queries/members.js +1 -1
  183. package/dist/queries/methods.d.ts +2 -2
  184. package/dist/queries/methods.js +1 -1
  185. package/dist/queries/not-implemented.d.ts +2 -2
  186. package/dist/queries/not-implemented.js +1 -1
  187. package/dist/queries/outline.d.ts +2 -2
  188. package/dist/queries/outline.js +1 -1
  189. package/dist/queries/passthrough-candidates.d.ts +2 -2
  190. package/dist/queries/passthrough-candidates.js +1 -1
  191. package/dist/queries/plan-context.d.ts +2 -2
  192. package/dist/queries/plan-context.js +1 -1
  193. package/dist/queries/react-component-duplicates.d.ts +2 -2
  194. package/dist/queries/react-component-duplicates.js +1 -1
  195. package/dist/queries/react-hook-candidates.d.ts +2 -2
  196. package/dist/queries/react-hook-candidates.js +1 -1
  197. package/dist/queries/react-large-component-pressure.d.ts +2 -2
  198. package/dist/queries/react-large-component-pressure.js +1 -1
  199. package/dist/queries/recent-duplicates.d.ts +2 -2
  200. package/dist/queries/recent-duplicates.js +1 -1
  201. package/dist/queries/redundant-reexports.d.ts +2 -2
  202. package/dist/queries/redundant-reexports.js +1 -1
  203. package/dist/queries/refs.d.ts +2 -2
  204. package/dist/queries/refs.js +1 -1
  205. package/dist/queries/self-audit.d.ts +2 -2
  206. package/dist/queries/self-audit.js +1 -1
  207. package/dist/queries/similar-chains.d.ts +2 -2
  208. package/dist/queries/similar-chains.js +1 -1
  209. package/dist/queries/similar-files.d.ts +2 -2
  210. package/dist/queries/similar-files.js +1 -1
  211. package/dist/queries/similar-signatures.d.ts +2 -2
  212. package/dist/queries/similar-signatures.js +1 -1
  213. package/dist/queries/similar.d.ts +2 -2
  214. package/dist/queries/similar.js +1 -1
  215. package/dist/queries/slice.d.ts +2 -2
  216. package/dist/queries/slice.js +1 -1
  217. package/dist/queries/stale-abstractions.d.ts +2 -2
  218. package/dist/queries/stale-abstractions.js +1 -1
  219. package/dist/queries/stats.d.ts +2 -2
  220. package/dist/queries/surface.d.ts +2 -2
  221. package/dist/queries/surface.js +1 -1
  222. package/dist/queries/symbols.d.ts +2 -2
  223. package/dist/queries/symbols.js +1 -1
  224. package/dist/queries/system.d.ts +2 -2
  225. package/dist/queries/system.js +1 -1
  226. package/dist/queries/test-quality.d.ts +2 -2
  227. package/dist/queries/test-quality.js +1 -1
  228. package/dist/queries/trace.d.ts +2 -2
  229. package/dist/queries/trace.js +1 -1
  230. package/dist/queries/twin-ab.d.ts +2 -2
  231. package/dist/queries/twin-ab.js +1 -1
  232. package/dist/queries/twin-drift.d.ts +2 -2
  233. package/dist/queries/twin-drift.js +1 -1
  234. package/dist/queries/unused-imports.d.ts +2 -2
  235. package/dist/queries/unused-imports.js +1 -1
  236. package/dist/queries/unused-params.d.ts +2 -2
  237. package/dist/queries/unused-params.js +1 -1
  238. package/dist/queries/vue-component-duplicates.d.ts +2 -2
  239. package/dist/queries/vue-component-duplicates.js +1 -1
  240. package/dist/queries/vue-composable-candidates.d.ts +2 -2
  241. package/dist/queries/vue-composable-candidates.js +1 -1
  242. package/dist/queries/vue-large-view-pressure.d.ts +2 -2
  243. package/dist/queries/vue-large-view-pressure.js +1 -1
  244. package/dist/queries/wrapper-candidates.d.ts +2 -2
  245. package/dist/queries/wrapper-candidates.js +1 -1
  246. package/dist/reindex-worker.js +24 -24
  247. package/dist/reindex.d.ts +12 -10
  248. package/dist/reindex.js +38 -38
  249. package/dist/runtime.d.ts +10 -9
  250. package/dist/runtime.js +2 -1
  251. package/dist/rust-semantic-session-server.js +1 -1
  252. package/dist/rust-semantic-session-worker.js +1 -1
  253. package/dist/rust-semantic-worker.js +1 -1
  254. package/dist/{scip-cli-CoMzb7Zu.d.ts → scip-cli-1bVKJgXi.d.ts} +1 -1
  255. package/dist/watch-server.js +7 -6
  256. package/docs/AI_FAILURE_MODES.md +1 -0
  257. package/docs/COMMAND_REFERENCE.md +3 -2
  258. package/docs/DETECTOR_GUIDE.md +5 -3
  259. package/docs/analyzer-inventory.md +16 -6
  260. package/docs/analyzer-validation-ledger.md +12 -1
  261. package/docs/architecture-coherence-vision.md +219 -0
  262. package/package.json +5 -1
  263. package/skills/_shared/SKILL.md +4 -3
  264. package/skills/scip-conductor/SKILL.md +1 -1
  265. package/skills/scip-directory-architecture/SKILL.md +116 -2
  266. package/skills/scip-maintainability/SKILL.md +3 -3
  267. package/skills/scip-query/SKILL.md +1 -1
  268. package/skills/scip-twin-drift/SKILL.md +1 -1
  269. package/skills/scip-verify/SKILL.md +1 -1
  270. package/dist/chunk-2GX3TNOW.js +0 -38
  271. package/dist/chunk-45XOH33S.js +0 -2
  272. package/dist/chunk-4MFMTEJ4.js +0 -5
  273. package/dist/chunk-BECOMXAL.js +0 -2
  274. package/dist/chunk-BJJHBKEC.js +0 -2
  275. package/dist/chunk-DDGO34I2.js +0 -26
  276. package/dist/chunk-DUKRAHV2.js +0 -2
  277. package/dist/chunk-EMEXMHOP.js +0 -7
  278. package/dist/chunk-GWNE2WJN.js +0 -3
  279. package/dist/chunk-H4JNB7RT.js +0 -3
  280. package/dist/chunk-L2RE5P3X.js +0 -2
  281. package/dist/chunk-L2TSLMPT.js +0 -5
  282. package/dist/chunk-NQBMGFFD.js +0 -2
  283. package/dist/chunk-O5A7BTMA.js +0 -3
  284. package/dist/chunk-OINSINYW.js +0 -2
  285. package/dist/chunk-OM6JHEW3.js +0 -16
  286. package/dist/chunk-OUXPJ4H5.js +0 -3
  287. package/dist/chunk-OWXNDSG3.js +0 -2
  288. package/dist/chunk-Q4UM4JJP.js +0 -2
  289. package/dist/chunk-QEIGJJBC.js +0 -20
  290. package/dist/chunk-R4VPIS4D.js +0 -10
  291. package/dist/chunk-RDX6WWHN.js +0 -4
  292. package/dist/chunk-RUQE7DZT.js +0 -2
  293. package/dist/chunk-S43DIBME.js +0 -18
  294. package/dist/chunk-SALRDXWM.js +0 -121
  295. package/dist/chunk-SMBIGBGN.js +0 -67
  296. package/dist/chunk-VQWDZ34M.js +0 -928
  297. package/dist/chunk-W3557RPL.js +0 -3
  298. package/dist/chunk-W3SKYOTF.js +0 -2
  299. package/dist/chunk-XEEQX5X3.js +0 -3
  300. package/dist/direct-navigation-K3CTVVBU.js +0 -3
@@ -0,0 +1,219 @@
1
+ # Architecture Coherence Vision
2
+
3
+ ## Purpose
4
+
5
+ scip-query should help a maintainer answer two different questions:
6
+
7
+ 1. What architecture does this codebase actually have?
8
+ 2. Where does the implementation contradict the architecture the project intends to preserve?
9
+
10
+ The dependency graph can answer neither question alone. It records which files rely on which other files. Architectural judgment connects those facts to the real responsibilities, public contracts, runtime boundaries, and maintenance work that gave the code its structure.
11
+
12
+ The product vision is therefore a combination of:
13
+
14
+ - an `architecture` query that measures declared boundaries and dependency rules;
15
+ - a directory-architecture skill that helps an agent discover, name, test, and gradually enforce those rules;
16
+ - drift and health integrations that expose architectural changes without pretending every unusual import is a defect.
17
+
18
+ ## Vocabulary
19
+
20
+ An architectural boundary is a named group of code with one stable reason to change, such as a domain model, rendering subsystem, persistence adapter, compiler frontend, or deployable service. A folder often represents a boundary, but a folder is only evidence of one: the decisive fact is the responsibility its files jointly serve.
21
+
22
+ A dependency edge is a directed relationship from code that relies on something to the code it relies on. For an import, `A -> B` means file A imports file B. The direction matters because changes to B can force changes in A.
23
+
24
+ A boundary edge is the same relationship after file edges are grouped by their architectural boundaries. Ten imports from UI files into domain files form one `ui -> domain` boundary edge with ten pieces of file-level evidence.
25
+
26
+ An allowed edge is a boundary dependency that agrees with a declared rule. A forbidden edge is an actual dependency that contradicts a declared rule about which responsibilities may rely on which others. Files being far apart or living under different directories does not by itself make the edge forbidden.
27
+
28
+ A reciprocal dependency is a pair of boundary edges in both directions, such as `source -> parser` and `parser -> source`. It is a review signal because neither boundary can change independently, but it can be intentional when the named boundaries are really one subsystem or meet through a deliberately shared contract.
29
+
30
+ A strongly connected component is a group of boundaries where every member can reach every other member through dependency edges. Its essential consequence is mutual change pressure: no member is directionally independent of the group. A component with many boundaries is evidence that the current names may not describe real separation.
31
+
32
+ A cycle-break candidate is a boundary edge inside a dependency cycle whose small amount of file-level evidence makes it a plausible place to inspect first. It is not automatically the correct edge to remove; a single import can expose either an accidental shortcut or a legitimate contract that the boundary model failed to name.
33
+
34
+ An architecture policy is the project-owned configuration that names boundaries and records dependency directions the maintainers are prepared to defend. Its rules are stronger than inferred folder conventions because the project explicitly chose them.
35
+
36
+ An architecture ratchet is an enforcement rule that permits recorded existing debt while preventing new violations. It lets a large codebase improve incrementally without requiring a speculative rewrite before the policy becomes useful.
37
+
38
+ Architectural coherence is the degree to which actual dependencies, named responsibilities, and declared dependency rules describe the same system. The tool should report the evidence needed to improve that alignment, not reduce coherence to a single score.
39
+
40
+ ## Why `drift` Is Not Enough
41
+
42
+ Drift is movement away from a reference state or established pattern. A system can be statically incoherent without having changed recently, and it can change while remaining coherent. Therefore architecture needs a first-class report rather than being hidden inside `drift`.
43
+
44
+ `scip-query architecture` owns the complete boundary graph and policy
45
+ evaluation. `scip-query drift --architecture` reuses that report to show
46
+ direct declared violations together with mapping coverage and report-only
47
+ signals; it does not maintain a second policy engine.
48
+
49
+ Before this work, the source-layer table in
50
+ `src/queries/cleanup/drift-policy.ts` embedded repository-specific knowledge in
51
+ a general-purpose command. An unrelated repository using folders such as
52
+ `src/core` and `src/runtime` could therefore inherit scip-query's rules. That
53
+ table has now been removed: drift consumes only explicit project
54
+ configuration, and an unconfigured repository receives no architecture
55
+ violations.
56
+
57
+ ## Configuration Model
58
+
59
+ The first configuration shape should be small enough to understand without learning a policy language:
60
+
61
+ ```json
62
+ {
63
+ "architecture": {
64
+ "boundaries": [
65
+ { "name": "domain", "paths": ["src/domain/**"] },
66
+ { "name": "source", "paths": ["src/source/**"] },
67
+ { "name": "runtime", "paths": ["src/runtime/**"] }
68
+ ],
69
+ "allowedDependencies": {
70
+ "domain": [],
71
+ "source": ["domain"],
72
+ "runtime": ["domain", "source"]
73
+ },
74
+ "requireCompletePolicy": true,
75
+ "requireAcyclic": true
76
+ }
77
+ }
78
+ ```
79
+
80
+ A boundary row names code; it does not yet prohibit anything. An `allowedDependencies` row is closed: when a row exists for `source`, every cross-boundary dependency not listed in that row is forbidden. A missing row means the project has not made a rule for that boundary yet. Same-boundary dependencies remain allowed.
81
+
82
+ This distinction lets a large repository describe mature boundaries first while leaving emerging or disputed areas in discovery mode.
83
+
84
+ `requireCompletePolicy` turns that gradual-discovery model into a finished
85
+ contract: every configured boundary must have a closed row, including an empty
86
+ row for a boundary that may depend on nothing. `requireAcyclic` independently
87
+ forbids multi-boundary strongly connected components. A project should enable
88
+ both only after the observed graph has been classified and repaired.
89
+
90
+ ## What the Analyzer Should Report
91
+
92
+ The report should preserve both policy truth and graph evidence:
93
+
94
+ - mapped, unmapped, and ambiguously mapped files;
95
+ - boundary edges with importer count, imported-file count, total file-edge count, and representative file edges;
96
+ - forbidden edges, grouped by boundary pair rather than emitted as a flood of individual imports;
97
+ - reciprocal boundary pairs;
98
+ - strongly connected boundary components;
99
+ - the narrowest internal edges to inspect first for each component;
100
+ - policy coverage: which boundaries have closed dependency rows and which remain descriptive only.
101
+ - resolved `export ... from` dependencies as well as ordinary imports, so
102
+ published barrel and package surfaces are governed;
103
+
104
+ The output tiers should remain explicit:
105
+
106
+ - **Direct finding:** an actual edge contradicts a declared rule, or a declared acyclicity rule is violated.
107
+ - **Signal:** reciprocity, a large connected component, low policy coverage, an unmapped file, or a narrow cycle-break candidate.
108
+
109
+ Inferred signals should not reduce health scores or block diffs until external calibration shows that acting on them reliably improves real codebases.
110
+
111
+ ## Applying This to an Existing Large Codebase
112
+
113
+ The tool cannot discover the “best architecture” by optimizing graph shape. The best available architecture is the clearest model that preserves the system's real responsibilities and necessary behavior while reducing accidental change pressure. Finding it requires a staged investigation.
114
+
115
+ ### 1. Inventory the system's referents
116
+
117
+ Read the repository guidance, package manifests, deployable entry points, routes, public exports, databases, message boundaries, tests, and build graph. Use scip-query to map consumers, dependencies, change surfaces, cycles, locality candidates, and historical co-change.
118
+
119
+ This identifies what the code actually does and which units already behave as maintenance units.
120
+
121
+ ### 2. Name candidate boundaries
122
+
123
+ Do not assume every top-level directory is a layer. A layer is a responsibility ordered by dependency direction, such as presentation over application over domain. A subsystem is a responsibility that owns an end-to-end capability, such as authentication or a compiler. A package is a publication or build unit. A service is an independently running unit.
124
+
125
+ The architecture model may contain all four. The useful name is the one that predicts why its code changes and what it may depend on.
126
+
127
+ ### 3. Classify boundary maturity
128
+
129
+ - A mature boundary is repeatedly expressed by code, documentation, tests, entry points, ownership, or history.
130
+ - An emerging boundary has a coherent responsibility but inconsistent placement or dependencies.
131
+ - An accidental boundary is mainly a convenience bucket, legacy pile, generated directory, or recent edit cluster.
132
+
133
+ Only mature boundaries should receive closed dependency rules initially.
134
+
135
+ ### 4. Build a descriptive model first
136
+
137
+ Add boundary path patterns without `allowedDependencies` rows. Run `scip-query architecture --json` to inspect mapping coverage, actual boundary edges, reciprocal pairs, and connected components.
138
+
139
+ Revise names and path membership when the graph reveals that a supposed boundary has no independent responsibility or that one responsibility is split across several folders.
140
+
141
+ ### 5. Declare the rules supported by evidence
142
+
143
+ For each mature boundary, state which other boundaries it is allowed to depend on and why. Record uncertain edges as unresolved decisions instead of silently allowing the entire current graph.
144
+
145
+ Run the report again. A forbidden edge is now a testable disagreement between implementation and policy, not the tool's opinion about directory distance.
146
+
147
+ ### 6. Baseline and ratchet
148
+
149
+ Record reviewed existing violations with `scip-query health
150
+ --write-baseline`. Architecture identities name a forbidden boundary pair or
151
+ an explicitly forbidden boundary cycle, so moving a representative file does
152
+ not churn the ratchet. The default `scip-query diff-gate` architecture check
153
+ then rejects new identities while preserving visibility into recorded debt.
154
+ This turns architecture from a one-time diagram into a maintained contract.
155
+
156
+ ### 7. Migrate narrow seams
157
+
158
+ Start with a narrow edge whose few file dependencies cross a mature rule. Determine whether the right repair is to move code, invert a dependency, extract a genuinely shared contract, combine falsely separated boundaries, or revise the policy.
159
+
160
+ Verify each slice with tests, typechecking, incomplete-migration checks, architecture analysis, and diff-gate before taking the next one.
161
+
162
+ ## Example: Vega 2.0
163
+
164
+ For a codebase the size of Vega 2.0, the first pass should not invent a universal stack of layers. It should:
165
+
166
+ 1. identify workspace packages, applications, servers, public entry points, data stores, and major feature or compiler/rendering subsystems;
167
+ 2. map actual dependency traffic between those units;
168
+ 3. read the architecture and ownership claims already present in docs and package surfaces;
169
+ 4. classify candidate boundaries as mature, emerging, or accidental;
170
+ 5. configure the mature boundaries descriptively;
171
+ 6. inspect reciprocal pairs and large connected components with their file-edge breadth;
172
+ 7. close dependency rows only where the intended direction is supported;
173
+ 8. baseline existing violations and prevent new ones;
174
+ 9. migrate one narrow, high-confidence seam at a time.
175
+
176
+ The initial result may be a mixture of layers and subsystems. That is preferable to forcing a neat diagram that contradicts the software. The model becomes stronger as verified migrations and maintenance history provide new facts.
177
+
178
+ ## Delivery Sequence
179
+
180
+ ### Slice 1: explicit measurement — implemented
181
+
182
+ - Add architecture configuration types and validation.
183
+ - Extract the reusable strongly-connected-component algorithm already embedded in `deep-chains`.
184
+ - Add a pure architecture graph analyzer and `scip-query architecture`.
185
+ - Extend the directory-architecture skill with the discover, declare, measure, and ratchet workflow.
186
+ - Keep architecture outside health scoring and diff-gate blocking.
187
+
188
+ ### Slice 2: replace implicit drift policy — implemented
189
+
190
+ - Move scip-query's source-boundary rules into its `.scipquery.json`.
191
+ - Make drift consume architecture findings instead of repository-specific hardcoded folder rules.
192
+ - Add `drift --architecture` as a summary view.
193
+ - Preserve unused-import drift and keep sibling-pattern deviation opt-in.
194
+
195
+ ### Slice 3: baselines and enforcement — implemented locally; external calibration remains
196
+
197
+ - Give architecture findings stable identities.
198
+ - Add report-only health visibility.
199
+ - Add a narrow default diff-gate ratchet for newly introduced declared violations, backed by the shared health baseline.
200
+ - Calibrate on scip-query, Vega 2.0, Stable Management, and structurally different external repositories before any score deduction.
201
+
202
+ ### Slice 4: discovery assistance
203
+
204
+ - Add candidate-boundary evidence that combines paths, entry points, public surfaces, dependency neighborhoods, and co-change history.
205
+ - Have the skill produce a reviewable architecture draft, never silently write closed rules.
206
+ - Measure whether suggested boundaries and repairs survive maintainer review and reduce future cross-boundary churn.
207
+
208
+ ## Success Criteria
209
+
210
+ The architecture feature is effective when:
211
+
212
+ - an unconfigured repository never inherits scip-query-specific rules;
213
+ - a configured forbidden edge is reported with concrete import evidence;
214
+ - broad and narrow boundary edges are distinguishable;
215
+ - large cycles are summarized without flooding the user;
216
+ - the agent can explain why each proposed boundary exists in the running system;
217
+ - existing debt can be ratcheted without a rewrite;
218
+ - acting on a recommendation improves ownership or dependency direction in externally reviewed codebases;
219
+ - the tool is willing to say “the policy is incomplete” instead of manufacturing certainty.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scip-query",
3
- "version": "0.18.0",
3
+ "version": "0.19.1",
4
4
  "description": "Evidence and verification for AI coding agents: map code, reuse concepts, finish migrations, and gate diffs.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -33,6 +33,10 @@
33
33
  "import": "./dist/queries/affected.js",
34
34
  "types": "./dist/queries/affected.d.ts"
35
35
  },
36
+ "./queries/architecture": {
37
+ "import": "./dist/queries/architecture.js",
38
+ "types": "./dist/queries/architecture.d.ts"
39
+ },
36
40
  "./queries/bottlenecks": {
37
41
  "import": "./dist/queries/bottlenecks.js",
38
42
  "types": "./dist/queries/bottlenecks.d.ts"
@@ -110,7 +110,7 @@ scip-query cleanup-apply # Apply a compiler-verified cleanup-plan batch to the w
110
110
  scip-query recent-duplicates # Directional duplicate candidates: recent code that re-implements established callable, React, or Vue code
111
111
  scip-query doc-drift [doc] # Stale-doc candidates: code the doc references or co-changed with kept changing after the doc stopped
112
112
  scip-query unused-params # Speculative-generality candidates: trailing parameters no body ever uses (TS/JS)
113
- scip-query drift [module] # Detect heuristic drift candidates: unused imports and layer violations by default; pass --patterns for pattern deviations too
113
+ scip-query drift [module] # Detect drift candidates: unused imports and declared architecture violations; pass --architecture for boundary context
114
114
  scip-query wrapper-candidates # Find heuristic wrapper candidates only called by one consumer (high false-positive rate on codebases with intentional layering/ambient types — treat as exploration, not findings)
115
115
  scip-query passthrough-candidates # Find heuristic passthrough candidates that forward to one callee
116
116
  scip-query stale-abstractions # Find heuristic stale abstraction candidates with 0-1 consumers (high false-positive rate on codebases with intentional layering/ambient types — treat as exploration, not findings)
@@ -134,6 +134,7 @@ scip-query fan-in [symbol] # Count files referencing an exact symbol; top JSON r
134
134
  scip-query fan-out [file] # How many external symbols a file uses (or top fan-out across codebase)
135
135
  scip-query coupling [file1] [file2] # Coupling between two files, or top coupled pairs in codebase
136
136
  scip-query cycles # Detect circular dependency chains between files
137
+ scip-query architecture # Evaluate project-owned architectural boundaries and dependency rules
137
138
  scip-query bottlenecks # Find coupling hubs: high fan-in AND high fan-out
138
139
  scip-query deep-chains # Find the longest condensed dependency-component chains
139
140
  scip-query call-graph <symbol> # Show incoming callers and outgoing callees for a symbol
@@ -145,7 +146,7 @@ scip-query call-graph <symbol> # Show incoming callers and outgoing callees for
145
146
  scip-query affected <symbol> # Transitive closure of symbols that could break if this symbol changes
146
147
  scip-query change-surface <file> # Pre-change briefing: exports, consumers, and blast-radius risk
147
148
  scip-query co-change [file] # Files that change together in git history without a dependency edge — hidden coupling candidates
148
- scip-query diff-gate # Gate the current diff: echo candidates, incomplete migrations, missing co-change partners, unedited twin partners (advisory), uncited doc updates, unused params, new dead symbols; exit 1 on blocking findings
149
+ scip-query diff-gate # Gate the current diff: architecture regressions plus echo, migration, coordination, doc-drift, unused-param, and new-dead candidates; exit 1 on blocking findings
149
150
  scip-query incomplete-migration # Partially-completed extraction candidates: new helpers in the diff wired into some sites while similar un-migrated sites remain
150
151
  scip-query diff-impact # Compute changed symbols and downstream consumers from current git diff
151
152
  ```
@@ -211,7 +212,7 @@ measured precision, not by volume:
211
212
 
212
213
  ## Diff Gate Checks
213
214
 
214
- `diff-gate` runs nine checks (`--skip <check>` accepts any of these): `echo` (recent-duplicate-style echoes in the diff), `incomplete-migration`, `co-change-partner` (missing historically-paired file), `twin-partner` (advisory — unedited same-name twin), `coverage-contract` (a configured `coverageContracts` enumeration drifted from its ground truth — see `scip-setup`), `doc-reference` (uncited or stale doc claim), `unused-params`, `new-dead` (dead code introduced by this diff), and `baseline` (only with `--baseline`: compares against the committed `.scipquery-baseline.json`, distinct from `health --baseline`). Findings print grouped under a `Root-cause groups (N):` header before the flat list — a group's remediation usually clears every finding under it, and the same remediation may then repeat in the flat list below; that repetition is expected, not a separate issue. `--baseline` findings additionally carry an `actionTier`: `direct` (act on this finding alone), `signal` (corroborating evidence — read before acting), `support` (context only).
215
+ `diff-gate` recognizes ten checks (`--skip <check>` accepts any of these): `echo` (recent-duplicate-style echoes in the diff), `incomplete-migration`, `co-change-partner` (missing historically-paired file), `twin-partner` (advisory — unedited same-name twin), `coverage-contract` (a configured `coverageContracts` enumeration drifted from its ground truth — see `scip-setup`), `architecture` (a declared boundary violation absent from the shared baseline), `doc-reference` (uncited or stale doc claim), `unused-params`, `new-dead` (dead code introduced by this diff), and `baseline` (only with `--baseline`: compares all non-architecture health identities against the committed `.scipquery-baseline.json`, distinct from `health --baseline`). The architecture check runs by default only when enforceable architecture rules and a baseline exist; it uses that same file without running the full health suite. Findings print grouped under a `Root-cause groups (N):` header before the flat list — a group's remediation usually clears every finding under it, and the same remediation may then repeat in the flat list below; that repetition is expected, not a separate issue. Baseline-backed findings additionally carry an `actionTier`: `direct` (act on this finding alone), `signal` (corroborating evidence — read before acting), `support` (context only).
215
216
 
216
217
  ## Postchecks
217
218
 
@@ -24,7 +24,7 @@ Load shared mechanics from [`../_shared/SKILL.md`](../_shared/SKILL.md).
24
24
  | Command | Purpose | When |
25
25
  | --- | --- | --- |
26
26
  | `scip-query plan-context <target>` | Pre-edit planning context for a symbol, file, or module | Anchor each phase's step before delegating it. |
27
- | `scip-query diff-gate --json` | Gate the current diff: echo candidates, incomplete migrations, missing co-change partners, unedited twin partners (advisory), uncited doc updates, unused params, new dead symbols; exit 1 on blocking findings | Verify a handoff before accepting it and before closing the program. |
27
+ | `scip-query diff-gate --json` | Gate the current diff: architecture regressions plus echo, migration, coordination, doc-drift, unused-param, and new-dead candidates; exit 1 on blocking findings | Verify a handoff before accepting it and before closing the program. |
28
28
  | `scip-query health --json` | Composite codebase health report with prioritized action list | Pre-register or check a program-level health benchmark. |
29
29
 
30
30
  Use this shortlist first. Open [`../_shared/SKILL.md`](../_shared/SKILL.md) only when it is insufficient.
@@ -10,8 +10,16 @@ commands:
10
10
  when: "Inventory evidence: files with overlapping dependency profiles."
11
11
  - template: "scip-query cycles"
12
12
  when: "Inventory evidence: circular dependency chains between files."
13
+ - template: "scip-query architecture --json"
14
+ when: "Measure configured boundaries, actual dependency traffic, forbidden edges, reciprocal pairs, and boundary cycles."
15
+ - template: "scip-query drift --architecture"
16
+ when: "Review direct drift findings together with boundary coverage and architecture signals."
13
17
  - template: "scip-query co-change --json --full"
14
18
  when: "Inventory evidence: hidden file-level coupling from git history."
19
+ - template: "scip-query health --write-baseline"
20
+ when: "Record reviewed existing debt before enabling architecture regression enforcement."
21
+ - template: "scip-query diff-gate"
22
+ when: "Verify that the current diff introduces no new declared architecture violation."
15
23
  - template: "scip-query config-validate --json"
16
24
  when: "Implement a slice: validate locality config after a move."
17
25
  ---
@@ -31,7 +39,11 @@ Load shared mechanics from [`../_shared/SKILL.md`](../_shared/SKILL.md).
31
39
  | `scip-query locality-candidates --json --full` | Find directory-locality and ancestry candidates from consumer ownership | Inventory evidence: directory-locality candidates from consumer ownership. |
32
40
  | `scip-query similar-files --full --json` | Find heuristic similar-file candidates from dependency profiles | Inventory evidence: files with overlapping dependency profiles. |
33
41
  | `scip-query cycles` | Detect circular dependency chains between files | Inventory evidence: circular dependency chains between files. |
42
+ | `scip-query architecture --json` | Evaluate project-owned architectural boundaries and dependency rules | Measure configured boundaries, actual dependency traffic, forbidden edges, reciprocal pairs, and boundary cycles. |
43
+ | `scip-query drift --architecture` | Detect drift candidates: unused imports and declared architecture violations; pass --architecture for boundary context | Review direct drift findings together with boundary coverage and architecture signals. |
34
44
  | `scip-query co-change --json --full` | Files that change together in git history without a dependency edge — hidden coupling candidates | Inventory evidence: hidden file-level coupling from git history. |
45
+ | `scip-query health --write-baseline` | Composite codebase health report with prioritized action list | Record reviewed existing debt before enabling architecture regression enforcement. |
46
+ | `scip-query diff-gate` | Gate the current diff: architecture regressions plus echo, migration, coordination, doc-drift, unused-param, and new-dead candidates; exit 1 on blocking findings | Verify that the current diff introduces no new declared architecture violation. |
35
47
  | `scip-query config-validate --json` | Validate .scipquery.json, including structured suppressions and declared coupling groups | Implement a slice: validate locality config after a move. |
36
48
 
37
49
  Use this shortlist first. Open [`../_shared/SKILL.md`](../_shared/SKILL.md) only when it is insufficient.
@@ -41,6 +53,16 @@ Use this shortlist first. Open [`../_shared/SKILL.md`](../_shared/SKILL.md) only
41
53
 
42
54
  An ownership boundary is a folder, package, module, or convention that groups code around one stable responsibility.
43
55
 
56
+ A dependency edge points from code that relies on something to the code it relies on. For imports, `A -> B` means A imports B.
57
+
58
+ A forbidden edge is an actual cross-boundary dependency rejected by an explicit project rule. Directory distance or an unusual import does not make an edge forbidden by itself.
59
+
60
+ A layer is a responsibility ordered by dependency direction, such as presentation depending on application. A subsystem is a responsibility that owns an end-to-end capability, such as authentication or rendering. A package is a publication or build unit. A service is an independently running unit. Do not force all four into one layer hierarchy.
61
+
62
+ A reciprocal dependency is dependency traffic in both directions between two boundaries. It is a review signal because the boundaries exert mutual change pressure, not proof that either import is wrong.
63
+
64
+ An architecture ratchet is an enforcement rule that records existing violations while preventing new ones, allowing a large codebase to improve without a speculative rewrite.
65
+
44
66
  A target structure is a proposed future layout that expresses an ownership model, not merely a prettier tree.
45
67
 
46
68
  A migration slice is the smallest set of file moves and import updates that can be verified independently.
@@ -55,6 +77,8 @@ A slop codebase is a codebase whose files are arranged by accident, convenience,
55
77
  4. Do not reward generic `shared` unless the shared concept has a name, owner, and cross-boundary consumers.
56
78
  5. For messy repos, produce a discovery map and decisions instead of pretending the target is obvious.
57
79
  6. Prefer small verified moves.
80
+ 7. Configure descriptive boundaries before closing dependency rules.
81
+ 8. Treat graph shape as evidence about responsibilities, never as a substitute for identifying them.
58
82
 
59
83
  ## Workflow
60
84
 
@@ -77,6 +101,8 @@ scip-query change-surface <file>
77
101
  scip-query plan-context <file-or-symbol>
78
102
  scip-query locality-candidates --json --full
79
103
  scip-query cycles
104
+ scip-query architecture --json
105
+ scip-query drift --architecture
80
106
  scip-query co-change
81
107
  scip-query similar-files --min-similarity 0.6 --min-deps 3
82
108
  scip-query similar-chains --min-similarity 0.5
@@ -98,7 +124,66 @@ Classify each candidate:
98
124
 
99
125
  This step is complete only when mature, emerging, and accidental boundaries are separated.
100
126
 
101
- ### 4. Propose structure or decisions
127
+ ### 4. Build a descriptive architecture model
128
+
129
+ For a large existing codebase, identify real system units before calling them layers. Inventory:
130
+
131
+ - workspace packages and public exports;
132
+ - applications, services, and deployable entry points;
133
+ - domain capabilities and end-to-end subsystems;
134
+ - persistence, network, rendering, compiler, and other technical responsibilities;
135
+ - tests, routes, contracts, and ownership or architecture documentation;
136
+ - dependency and co-change evidence that shows which files already move as a unit.
137
+
138
+ Add mature boundary path patterns to `.scipquery.json` without `allowedDependencies` rows first:
139
+
140
+ ```json
141
+ {
142
+ "architecture": {
143
+ "boundaries": [
144
+ { "name": "domain", "paths": ["src/domain/**"] },
145
+ { "name": "runtime", "paths": ["src/runtime/**"] }
146
+ ]
147
+ }
148
+ }
149
+ ```
150
+
151
+ Then run:
152
+
153
+ ```bash
154
+ scip-query config-validate --json
155
+ scip-query architecture --json
156
+ ```
157
+
158
+ Use unmapped and ambiguous files to repair boundary membership. Use actual boundary edges, reciprocal pairs, and strongly connected groups to test whether the names describe real separation.
159
+
160
+ This step is complete only when every configured boundary has a stated responsibility and the mapping gaps are understood.
161
+
162
+ ### 5. Declare only supported dependency rules
163
+
164
+ An `allowedDependencies` row is closed: an outgoing target omitted from a present row is forbidden. A missing row makes no dependency claim.
165
+
166
+ ```json
167
+ {
168
+ "architecture": {
169
+ "boundaries": [
170
+ { "name": "domain", "paths": ["src/domain/**"] },
171
+ { "name": "runtime", "paths": ["src/runtime/**"] }
172
+ ],
173
+ "allowedDependencies": {
174
+ "domain": [],
175
+ "runtime": ["domain"]
176
+ },
177
+ "requireAcyclic": true
178
+ }
179
+ }
180
+ ```
181
+
182
+ For each closed row, record the evidence for its intended direction. Do not copy the current dependency graph into the allow-list merely to obtain zero findings. Leave emerging or disputed rows undeclared.
183
+
184
+ This step is complete only when every forbidden edge is understood as either implementation debt, a false boundary, or a policy mistake.
185
+
186
+ ### 6. Propose structure or decisions
102
187
 
103
188
  Use this shape:
104
189
 
@@ -108,6 +193,10 @@ Use this shape:
108
193
  ## Scope
109
194
  ## Current Structure Map
110
195
  ## Boundary Maturity
196
+ ## Descriptive Architecture Model
197
+ ## Dependency Rules
198
+ ## Forbidden-Edge Ledger
199
+ ## Reciprocal and Cycle Review
111
200
  ## Target Structure
112
201
  ## Move Ledger
113
202
  ## Locality Config
@@ -120,7 +209,29 @@ List no-move decisions when broad consumers, route/package/contract surfaces, in
120
209
 
121
210
  This step is complete only when every proposed move has a reason and verification path.
122
211
 
123
- ### 5. Implement one slice when asked
212
+ ### 7. Ratchet, then implement one slice when asked
213
+
214
+ For a large repository with existing violations, review the direct findings and
215
+ write the shared health baseline:
216
+
217
+ ```bash
218
+ scip-query drift --architecture
219
+ scip-query health --write-baseline
220
+ ```
221
+
222
+ The baseline records stable architecture identities by boundary pair, not by
223
+ whichever example file happens to sort first. The default `scip-query
224
+ diff-gate` architecture check then compares only architecture identities; it
225
+ does not run every health detector. `diff-gate --baseline` remains the opt-in
226
+ full health ratchet and does not duplicate architecture findings.
227
+
228
+ Commit `.scipquery-baseline.json` with `.scipquery.json`. A missing baseline
229
+ causes the architecture gate to report that enforcement is not enabled; it
230
+ does not silently treat the current graph as accepted.
231
+
232
+ Prefer inspecting the least-broad edge inside a boundary cycle first, but
233
+ determine whether the repair is a move, dependency inversion, named shared
234
+ contract, boundary merge, or policy correction.
124
235
 
125
236
  Before editing, state files to move, imports/exports/tests/docs to update, expected verification, and rollback risk. Then move the smallest high-confidence slice and run:
126
237
 
@@ -135,6 +246,9 @@ Also run project tests or typecheck for the affected workspace. If `.scipquery.j
135
246
  ```bash
136
247
  scip-query config-validate
137
248
  scip-query locality-candidates --json --full
249
+ scip-query architecture --json
250
+ scip-query drift --architecture
251
+ scip-query diff-gate
138
252
  ```
139
253
 
140
254
  Then invoke `scip-verify`. The implementation is complete only when imports, tests, locality signals, and verification are checked.
@@ -12,8 +12,8 @@ commands:
12
12
  when: "Map evidence: exports, consumers, and blast-radius risk."
13
13
  - template: "scip-query affected <symbol>"
14
14
  when: "Map evidence: transitive consumers of a candidate symbol."
15
- - template: "scip-query drift --patterns"
16
- when: "Map evidence: layer violations and pattern deviations as probes (--patterns is off by default and near-zero precision; treat hits as leads, not findings)."
15
+ - template: "scip-query drift --patterns --architecture"
16
+ when: "Map evidence: declared architecture violations plus boundary and pattern signals; treat opt-in pattern hits as leads, not findings."
17
17
  ---
18
18
 
19
19
  # scip-maintainability
@@ -32,7 +32,7 @@ Load shared mechanics from [`../_shared/SKILL.md`](../_shared/SKILL.md).
32
32
  | `scip-query surface <scope>` | What symbols consumers actually use from this module | Map evidence: what consumers actually use from the scope. |
33
33
  | `scip-query change-surface <file>` | Pre-change briefing: exports, consumers, and blast-radius risk | Map evidence: exports, consumers, and blast-radius risk. |
34
34
  | `scip-query affected <symbol>` | Transitive closure of symbols that could break if this symbol changes | Map evidence: transitive consumers of a candidate symbol. |
35
- | `scip-query drift --patterns` | Detect heuristic drift candidates: unused imports and layer violations by default; pass --patterns for pattern deviations too | Map evidence: layer violations and pattern deviations as probes (--patterns is off by default and near-zero precision; treat hits as leads, not findings). |
35
+ | `scip-query drift --patterns --architecture` | Detect drift candidates: unused imports and declared architecture violations; pass --architecture for boundary context | Map evidence: declared architecture violations plus boundary and pattern signals; treat opt-in pattern hits as leads, not findings. |
36
36
 
37
37
  Use this shortlist first. Open [`../_shared/SKILL.md`](../_shared/SKILL.md) only when it is insufficient.
38
38
  <!-- END GENERATED SKILL COMMANDS -->
@@ -23,7 +23,7 @@ Load shared mechanics from [`../_shared/SKILL.md`](../_shared/SKILL.md) when you
23
23
  | --- | --- | --- |
24
24
  | `scip-query status --capabilities` | Show index status for this project | Before routing: confirm the index is fresh. |
25
25
  | `scip-query plan-context <target>` | Pre-edit planning context for a symbol, file, or module | Default loop: anchor a plan for the routed skill. |
26
- | `scip-query diff-gate --json` | Gate the current diff: echo candidates, incomplete migrations, missing co-change partners, unedited twin partners (advisory), uncited doc updates, unused params, new dead symbols; exit 1 on blocking findings | Default loop: the loop is complete only when this passes or is explained. |
26
+ | `scip-query diff-gate --json` | Gate the current diff: architecture regressions plus echo, migration, coordination, doc-drift, unused-param, and new-dead candidates; exit 1 on blocking findings | Default loop: the loop is complete only when this passes or is explained. |
27
27
 
28
28
  Use this shortlist first. Open [`../_shared/SKILL.md`](../_shared/SKILL.md) only when it is insufficient.
29
29
  <!-- END GENERATED SKILL COMMANDS -->
@@ -29,7 +29,7 @@ Load shared mechanics from [`../_shared/SKILL.md`](../_shared/SKILL.md).
29
29
  | `scip-query duplicate-bodies --json --full` | Find exact duplicate small-body candidates across files | Cross-check: IDENTICAL groups are duplicate-bodies' job, not this skill's. |
30
30
  | `scip-query code <symbol>` | Read the source code for a symbol (bounded to its definition range) | Classify a divergent group: read every member's body. |
31
31
  | `scip-query refs <symbol>` | Find all files referencing a symbol | Pick the canonical twin: consumer count per member. |
32
- | `scip-query diff-gate --json` | Gate the current diff: echo candidates, incomplete migrations, missing co-change partners, unedited twin partners (advisory), uncited doc updates, unused params, new dead symbols; exit 1 on blocking findings | Verify: the twin-partner check must not flag a one-sided fix. |
32
+ | `scip-query diff-gate --json` | Gate the current diff: architecture regressions plus echo, migration, coordination, doc-drift, unused-param, and new-dead candidates; exit 1 on blocking findings | Verify: the twin-partner check must not flag a one-sided fix. |
33
33
 
34
34
  Use this shortlist first. Open [`../_shared/SKILL.md`](../_shared/SKILL.md) only when it is insufficient.
35
35
  <!-- END GENERATED SKILL COMMANDS -->
@@ -30,7 +30,7 @@ Load shared mechanics from [`../_shared/SKILL.md`](../_shared/SKILL.md).
30
30
  | `scip-query doctor` | Diagnose config, index freshness, dependency readiness, and project capabilities | Prove the workspace: index freshness and dependency readiness. |
31
31
  | `scip-query status --capabilities` | Show index status for this project | Prove the workspace: which evidence and verification capabilities are available. |
32
32
  | `scip-query diff-impact --json` | Compute changed symbols and downstream consumers from current git diff | Assess the diff: changed symbols and downstream consumers. |
33
- | `scip-query diff-gate --json` | Gate the current diff: echo candidates, incomplete migrations, missing co-change partners, unedited twin partners (advisory), uncited doc updates, unused params, new dead symbols; exit 1 on blocking findings | Run the gate: the primary blocker for diff-specific risk. |
33
+ | `scip-query diff-gate --json` | Gate the current diff: architecture regressions plus echo, migration, coordination, doc-drift, unused-param, and new-dead candidates; exit 1 on blocking findings | Run the gate: the primary blocker for diff-specific risk. |
34
34
  | `scip-query health --baseline` | Composite codebase health report with prioritized action list | Check health: compare findings against the committed baseline. |
35
35
  | `scip-query doc-drift --json --full` | Stale-doc candidates: code the doc references or co-changed with kept changing after the doc stopped | Check docs: run when docs, AGENTS.md, or command surfaces changed. |
36
36
 
@@ -1,38 +0,0 @@
1
- import{b as le,c as O,d as T,e as H,k as be,l as ye}from"./chunk-OM6JHEW3.js";import{d as re,e as de,f as $,g as ue,l as fe,m as pe}from"./chunk-PZV2PGBR.js";import{D as me,n as ce,x as j}from"./chunk-4MFMTEJ4.js";import{a as te}from"./chunk-QEIGJJBC.js";import{d as ge,e as he}from"./chunk-MTDBHTSF.js";import{e as N,g as oe,s as ie,t as P,y as ae,z as se}from"./chunk-7XP7ZRSI.js";import{k as E,m as ee,p as ne}from"./chunk-JLZUM476.js";import{B as D,c as q}from"./chunk-TLTLJ4SW.js";import{a as Z}from"./chunk-64MNV6AB.js";import{c as z,d as Q,g as G,h as x,j as Y,l as K,q as X,s as _,y as F}from"./chunk-M2TRDR25.js";function Rn(e,n,t={}){let o=Me(e,[n],{additive:t.additive,semantic:t.semantic}),i=t.callableOnly?(o.get(n.symbolId)??[]).filter(s=>oe(s.symbol)||s.source==="ast-callsite"):o.get(n.symbolId)??[];return typeof t.limit=="number"?i.slice(0,t.limit):i}function Ce(e,n,t={}){return U(e,[n],t).get(n.symbolId)??[]}function U(e,n,t={}){let o=De(e)?Ee(e,n,{semantic:t.semantic!==!1}):ke(e);return typeof t.limit!="number"?new Map(n.map(i=>[i.symbolId,o.get(i.symbolId)??[]])):new Map(n.map(i=>[i.symbolId,(o.get(i.symbolId)??[]).slice(0,t.limit)]))}var Le=Q("caller-rows",{clearGroups:["whole-project"]}),_e=2e4;function De(e){return(e.get("SELECT COUNT(*) AS count FROM global_symbols")?.count??0)>_e}function ke(e){return Le.get(e,()=>{let n=P(e),t=Me(e,n),o=new Map;for(let a of n)o.set(a.symbol,a.symbolId);let i=new Map,s=new Map;for(let a of n){let r=t.get(a.symbolId);if(!(!r||r.length===0))for(let d of r){let c=o.get(d.symbol);if(c===void 0||c===a.symbolId)continue;let m=i.get(c);m||(m=[],i.set(c,m),s.set(c,new Set));let b=`${a.symbol}|${a.relativePath}`;s.get(c).has(b)||(s.get(c).add(b),m.push({symbol:a.symbol,file:a.relativePath,source:"caller-map-inversion"}))}}return i})}function Ee(e,n,t){let o=t.semantic?n.flatMap(r=>{let d=ve(e,r);return d?[d]:[]}):[],i=new Map(o.map(r=>[r.symbolId,r])),s=fe(e,o),a=new Map;for(let r of n){let d=[],c=new Set,m=p=>{if(p.symbol===r.symbol)return;let l=`${p.symbol}|${p.file}`;c.has(l)||(c.add(l),d.push(p))};for(let p of ye(e,r))p.file!==r.relativePath&&m({symbol:p.enclosingSymbol??p.file,file:p.file,source:"resolved-reference"});let b=i.get(r.symbolId);if(b)for(let p of s.get(b.symbolId)??[]){if(p.file===r.relativePath||e.isIgnored(p.file))continue;let l=se(ie(e,p.file),p.line);m({symbol:l?.symbol??p.file,file:p.file,source:"semantic-reference"})}a.set(r.symbolId,d)}return a}function ve(e,n){let t=ge().join(", "),o=he().join(", ");return e.get(`SELECT
2
- d.id AS documentId,
3
- gs.id AS symbolId,
4
- gs.symbol,
5
- d.relative_path AS relativePath,
6
- COALESCE(der.start_line, c.start_line) AS startLine,
7
- COALESCE(der.end_line, c.end_line) AS endLine,
8
- COALESCE(gs.display_name, '') AS leaf,
9
- NULL AS parentTypeName,
10
- CASE WHEN gs.kind IN (${t}) OR gs.symbol LIKE '%().' THEN 1 ELSE 0 END AS isFunctionLike,
11
- CASE WHEN gs.kind IN (${o}) THEN 1 ELSE 0 END AS isTypeLike,
12
- gs.kind AS kind,
13
- gs.documentation AS documentation,
14
- gs.enclosing_symbol AS enclosingSymbol
15
- FROM global_symbols gs
16
- LEFT JOIN defn_enclosing_ranges der ON der.symbol_id = gs.id
17
- LEFT JOIN chunks c ON c.document_id = der.document_id
18
- JOIN documents d ON d.id = COALESCE(der.document_id, c.document_id)
19
- WHERE gs.id = ?
20
- LIMIT 1`,n.symbolId)??null}function Me(e,n,t={}){if(n.length===0)return new Map;let o=t.additive??!1,i=[],s=[];for(let m of n)D(m.relativePath)&&E(e,m.relativePath)!==null?i.push(m):s.push(m);let a=new Map,r=new Map,d=m=>{for(let[b,p]of m){let l=a.get(b);l||(l=[],a.set(b,l));let g=r.get(b);g||(g=new Set,r.set(b,g));for(let R of p){let C=`${R.symbol}|${R.chunkId}`;g.has(C)||(g.add(C),l.push(R))}}};i.length>0&&d(Te(e,i)),t.semantic!==!1&&d(Ke(Ae(e,n)));let c=o?n:s;return c.length>0&&d(Be(e,c)),a}function Ae(e,n){let t=X(),o=new Map,i=ue(e,n),s=[],a=[],r=0,d=0,c=0,m=0,b=0,p=0,l=0;for(let{definition:f,callees:u}of i.hits)b+=1,u.length>0&&(p+=1,l+=u.length,o.set(f.symbolId,u));let g=xe(e,i.hits);if(g.entries.length>0&&_("semantic.callees.prefetch-cache-write",()=>K(e,g.entries),()=>({entries:g.entries.length,sourceMissing:g.sourceMissing,skippedUnsupportedLanguage:g.skippedUnsupportedLanguage})),_("semantic.callees.cache-scan",()=>{for(let[f,u]of de(i.misses)){if(!j(f)){t&&(r+=u.length);continue}let h=F(e,f);if(!h){t&&(d+=u.length),a.push(...u);continue}let k=x(e,f,h),I=Re(e,f);if(!I){a.push(...u);continue}let B=Y(e,f,k,I);for(let y of u){let S=B.get(y.symbol)??null;if(S!==null){let w=Ne(S);if(w){t&&(c+=1),w.length>0&&o.set(y.symbolId,w);continue}t&&(m+=1)}s.push({def:y,contentHash:k,depsDigest:I})}}},()=>({definitions:n.length,skippedUnsupportedLanguage:r,sourceMissing:d,cacheHits:c,parseFailures:m,misses:s.length,unkeyed:a.length,inMemoryHits:b,inMemoryRows:p,inMemoryCalleeCount:l,resultRows:o.size})),s.length===0&&a.length===0)return o;let R=[...a,...s.map(f=>f.def)],C=0,v=_("semantic.callees.compute-misses",()=>{let f=pe(e,R);return C=f.size,f},()=>({definitions:R.length,misses:s.length,unkeyed:a.length,rows:C}));for(let[f,u]of v)o.set(f,u);let M=s.filter(f=>$(e).capability("semantic-callees",f.def.relativePath).available).map(f=>({relativePath:f.def.relativePath,symbol:f.def.symbol,contentHash:f.contentHash,depsDigest:f.depsDigest,payload:JSON.stringify(v.get(f.def.symbolId)??[])}));return M.length>0?_("semantic.callees.cache-write",()=>K(e,M),()=>({entries:M.length})):_("semantic.callees.cache-write-skip",()=>{},()=>({reason:"provider-unavailable",misses:s.length})),o}function xe(e,n){let t=[],o=new Map,i=0,s=0;for(let{definition:a,callees:r}of n){if(!j(a.relativePath)){s+=1;continue}if(!o.has(a.relativePath)){let c=F(e,a.relativePath),m=c?Re(e,a.relativePath):null;o.set(a.relativePath,c&&m?{contentHash:x(e,a.relativePath,c),depsDigest:m}:null)}let d=o.get(a.relativePath);if(!d){i+=1;continue}t.push({relativePath:a.relativePath,symbol:a.symbol,contentHash:d.contentHash,depsDigest:d.depsDigest,payload:JSON.stringify(r)})}return{entries:t,sourceMissing:i,skippedUnsupportedLanguage:s}}var Fe="typescript-callees-v1";function Re(e,n){let t=j(n);if(t==="typescript")return me(e,n,Fe)?.key??null;let o=Oe(e,n);return t==="rust"?G(JSON.stringify({kind:"semantic-callees",language:t,engine:ce(e.config.projectRoot),positionMapping:"nearby-leaf-v1",depsDigest:o})):o}function Ne(e){try{return JSON.parse(e)}catch{return null}}var Pe=z("semantic-deps-digest",{clearGroups:["whole-project","source-file"]});function Oe(e,n){return Pe.get(e,n,()=>{let o=[...te(e).get(n)??[]].sort().map(i=>`${i}:${x(e,i,F(e,i))}`);return G(o.join("|"))})}function Te(e,n){let t=new Map,o=He(n,t),i=H(e);for(let[s,a]of o){let r=E(e,s);if(!r)continue;let d=ae(a);for(let c of r){let m=d.get(c.line);if(!m)continue;let b=je(e,s,i,c);b&&b.symbol!==m.symbol&&t.get(m.symbolId).push({symbol:b.symbol,file:b.file,chunkId:c.line,source:"ast-callsite"})}}return t}function He(e,n){let t=new Map;for(let o of e){let i=t.get(o.relativePath);i?i.push(o):t.set(o.relativePath,[o]),n.set(o.symbolId,[])}for(let o of t.values())o.sort((i,s)=>i.endLine-i.startLine-(s.endLine-s.startLine));return t}function je(e,n,t,o){let i=O(n,t.get(o.calleeLeaf)??[]);if(i.length===0)return null;let s=$e(e,n,i,o.calleeQualifier);return s||T(e,n,i,o.memberAccess)}function $e(e,n,t,o){if(!o||D(n)!=="clojure")return null;let s=ne(e,n).filter(a=>a.kind==="namespace"&&a.localName===o&&a.sourcePath).map(a=>a.sourcePath);for(let a of s){let r=t.find(d=>q(a,d.file));if(r)return r}return t.find(a=>/`([^`]+)`\//.exec(a.symbol)?.[1]===o)??null}function Be(e,n){if(n.length===0)return new Map;let o=J(n.map(l=>l.documentId)).flatMap(l=>e.all(`SELECT c.document_id, c.id AS chunk_id, c.start_line, c.end_line, m.symbol_id
21
- FROM mentions m
22
- JOIN chunks c ON m.chunk_id = c.id
23
- WHERE m.role != 1
24
- AND c.document_id IN (${l.map(()=>"?").join(",")})`,...l)),i=new Map;for(let l of o)i.has(l.document_id)||i.set(l.document_id,[]),i.get(l.document_id).push(l);let a=J(o.map(l=>l.symbol_id)).flatMap(l=>e.all(`SELECT gs.id AS symbol_id, gs.symbol,
25
- COALESCE(der.document_id, def_chunk.document_id) AS document_id
26
- FROM global_symbols gs
27
- LEFT JOIN defn_enclosing_ranges der ON der.symbol_id = gs.id
28
- LEFT JOIN (
29
- SELECT m.symbol_id, MIN(c.document_id) AS document_id
30
- FROM mentions m
31
- JOIN chunks c ON m.chunk_id = c.id
32
- WHERE m.role = 1
33
- AND m.symbol_id IN (${l.map(()=>"?").join(",")})
34
- GROUP BY m.symbol_id
35
- ) def_chunk ON def_chunk.symbol_id = gs.id
36
- WHERE gs.id IN (${l.map(()=>"?").join(",")})`,...l,...l)),r=J([...n.map(l=>l.documentId),...a.flatMap(l=>l.document_id===null?[]:[l.document_id])]),d=new Map(r.flatMap(l=>e.all(`SELECT id, relative_path FROM documents
37
- WHERE id IN (${l.map(()=>"?").join(",")})`,...l).map(g=>[g.id,g.relative_path]))),c=new Map;for(let l of a)c.has(l.symbol_id)||c.set(l.symbol_id,{symbol:l.symbol,file:l.document_id!==null?d.get(l.document_id)??"":""});let m=new Map,b=d,p=Ge(n);for(let[l,g]of p){let C=[...i.get(l)??[]].sort((u,h)=>u.start_line-h.start_line||u.end_line-h.end_line),v=[...g].sort((u,h)=>u.startLine-h.startLine||u.endLine-h.endLine),M=new Set,f=0;for(let u of v){for(;f<C.length&&C[f].start_line<=u.endLine;)M.add(C[f]),f+=1;for(let y of M)y.end_line<u.startLine&&M.delete(y);let h=new Set,k=[],I=null,B=()=>{if(I)return I;let y=b.get(u.documentId)??"",S=new Set;if(y){let w=le(e,y),A=Math.max(0,u.startLine),V=Math.min(w.length-1,u.endLine);for(let L=A;L<=V;L+=1)for(let we of w[L])S.add(we)}return I=S,S};for(let y of M){if(y.symbol_id===u.symbolId)continue;let S=c.get(y.symbol_id);if(!S)continue;if(!(y.start_line>=u.startLine&&y.end_line<=u.endLine)){if(!(y.start_line<=u.endLine&&y.end_line>=u.startLine))continue;let L=N(S.symbol);if(!L||!B().has(L))continue}let A=`${S.symbol}|${y.chunk_id}`;h.has(A)||(h.add(A),k.push({...S,chunkId:y.chunk_id,source:"scip-chunk"}))}m.set(u.symbolId,k)}}return m}var Se=500;function J(e){let n=[...new Set(e)],t=[];for(let o=0;o<n.length;o+=Se)t.push(n.slice(o,o+Se));return t}function Ge(e){let n=new Map;for(let t of e){let o=n.get(t.documentId);o?o.push(t):n.set(t.documentId,[t])}return n}function Ke(e){let n=new Map;for(let[t,o]of e){let i=[];for(let s of o)i.push({symbol:s.symbol,file:s.file,chunkId:-1,source:"semantic-callee"});n.set(t,i)}return n}function Ie(e,n,t={}){let o=new Map;if(n&&n.length===0)return o;let i=Z(e,{includeIgnored:!1}),s=H(e),a=n??P(e),r=new Set(a.map(c=>c.symbolId)),d=Ye(a);if(Je(e,o,i,s,r,d),Ue(e,o,a,r),Qe(e,o,i,s,r,d),t.semantic!==!1){let c=$(e);qe(o,c.callerMap(Ze(a)))}return o}function Je(e,n,t,o,i,s){for(let a of t){if(!D(a))continue;let r=E(e,a);if(r)for(let d of r){if(s&&!s.has(d.calleeLeaf))continue;let c=O(a,o.get(d.calleeLeaf)??[]);if(!c||c.length===0)continue;let m=T(e,a,c,d.memberAccess);m&&i.has(m.symbolId)&&m.file!==a&&W(n,m.symbolId,a)}}}function Ue(e,n,t,o){let i=Ve(t);for(let s of We(e,o))e.isIgnored(s.relative_path)||ze(s,i.get(s.symbol_id))||W(n,s.symbol_id,s.relative_path)}function We(e,n){return re(e,n?[...n]:void 0)}function Ve(e){let n=new Map;for(let t of e)n.set(t.symbolId,{docId:t.documentId,startLine:t.startLine,endLine:t.endLine});return n}function ze(e,n){return!!n&&n.docId===e.document_id&&e.chunk_start>=n.startLine&&e.chunk_end<=n.endLine}function Qe(e,n,t,o,i,s){for(let a of t){if(D(a)!=="rust")continue;let r=ee(e,a,{includeRustAttributeNames:!0});if(r.length!==0)for(let{name:d}of r){if(s&&!s.has(d))continue;let c=o.get(d);if(c)for(let m of c)i.has(m.symbolId)&&m.file!==a&&W(n,m.symbolId,a)}}}function W(e,n,t){let o=e.get(n);o||(o=new Set,e.set(n,o)),o.add(t)}function Ye(e){let n=new Set;for(let t of e){let o="leaf"in t&&typeof t.leaf=="string"?t.leaf:"symbol"in t&&typeof t.symbol=="string"?N(t.symbol):"";o&&n.add(o)}return n.size>0?n:null}function Ze(e){return e.filter(n=>"relativePath"in n&&"symbol"in n&&"leaf"in n)}function qe(e,n){for(let[t,o]of n){let i=e.get(t);i||(i=new Set,e.set(t,i));for(let s of o)i.add(s)}}function Pn(e,n,t={}){return Ce(e,n,t)}function On(e,n,t={}){return U(e,n,t)}function Xe(e,n,t={}){return Ie(e,n,t)}function en(e,n,t={}){return be(e,n,t)}function Tn(e,n,t={}){let o=Xe(e,n,{semantic:t.semantic});return t.sourceFallback===!1?o:nn(o,en(e,n))}function nn(e,n){let t=new Map;for(let[o,i]of e)t.set(o,new Set(i));for(let[o,i]of n){let s=t.get(o)??new Set;for(let a of i)s.add(a);t.set(o,s)}return t}export{Rn as a,Me as b,Pn as c,On as d,Xe as e,en as f,Tn as g,nn as h};
38
- //# sourceMappingURL=chunk-2GX3TNOW.js.map
@@ -1,2 +0,0 @@
1
- import{a as C}from"./chunk-L2RE5P3X.js";import{m as v}from"./chunk-OM6JHEW3.js";import{f as O,i as x,m as T}from"./chunk-PZV2PGBR.js";import{d as A}from"./chunk-7XP7ZRSI.js";import{f as b}from"./chunk-JLZUM476.js";import{B as g}from"./chunk-TLTLJ4SW.js";function H(e,n={}){let{samples:o=50,scope:r,maxDisagreements:u=5}=n,l=new C(e),a=B(l.productionCallableDefinitions({scope:r,minLoc:2,requireFunctionLikeSymbol:!0}),o),c=K(e,a);if(a.length===0||!c)return{available:!1,sampleSize:a.length,oracleCoverage:0,scores:[],topDisagreements:[]};let t={references:P(),callees:P()},i=[],f=0,m=c==="semantic"?T(e,a):new Map,I=c==="source"?E(e,l,a):null;for(let s of a){let p=S(s,c==="semantic"?x(e,s).map(d=>d.file):[...I?.referencesBySymbolId.get(s.symbolId)??[]]),j=S(s,c==="semantic"?(m.get(s.symbolId)??[]).map(d=>d.file):[...I?.calleesBySymbolId.get(s.symbolId)??[]]);f+=1;let L=S(s,v(e,s).map(d=>d.file)),k=S(s,(l.calleeMap([s],{semantic:!1}).get(s.symbolId)??[]).map(d=>d.file)),w=y(c,"references"),R=y(c,"callees");Q(t.references,s,"references",L,p,w,i),Q(t.callees,s,"callees",k,j,R,i)}return i.sort((s,p)=>p.cheapOnly.length+p.oracleOnly.length-(s.cheapOnly.length+s.oracleOnly.length)),{available:!0,sampleSize:a.length,oracleCoverage:a.length>0?D(f/a.length):0,oracleKind:c,scores:["references","callees"].map(s=>F(s,t[s],c)),topDisagreements:i.slice(0,u)}}function P(){return{comparedSymbols:0,agreed:0,cheapTotal:0,oracleTotal:0,skippedOraclePartial:0}}function B(e,n){let o=[...e].sort((l,a)=>l.symbolId-a.symbolId);if(o.length<=n)return o;let r=o.length/n,u=[];for(let l=0;l<n;l++)u.push(o[Math.floor(l*r)]);return u}function K(e,n){let o=n[0];if(!o)return null;if(h(e,o))return"source";try{if(O(e).capability("semantic-references",o.relativePath).available)return"semantic"}catch{}return n.some(r=>h(e,r))?"source":null}function S(e,n){let o=new Set;for(let r of n)r!==e.relativePath&&o.add(r);return o}function Q(e,n,o,r,u,l,a){if(!l&&u.size===0){e.skippedOraclePartial+=1;return}e.comparedSymbols+=1,e.cheapTotal+=r.size,e.oracleTotal+=u.size;let c=[],t=[];for(let i of r)u.has(i)?e.agreed+=1:c.push(i);for(let i of u)r.has(i)||t.push(i);(c.length>0||t.length>0)&&a.push({symbol:A(n.symbol),question:o,cheapOnly:c,oracleOnly:t})}var z={references:!0,callees:!1};function F(e,n,o){let r=n.oracleTotal>0?n.agreed/n.oracleTotal:1,u=n.cheapTotal-n.agreed,l=y(o,e);return{question:e,comparedSymbols:n.comparedSymbols,precision:l&&n.cheapTotal>0?D(n.agreed/n.cheapTotal):null,recall:D(r),unverified:u,skippedOraclePartial:n.skippedOraclePartial}}function y(e,n){return e==="semantic"?z[n]:!1}function h(e,n){return g(n.relativePath)==="clojure"&&b(e,n.relativePath)!==null}function E(e,n,o){let r=new Map,u=new Map,l=o.filter(t=>h(e,t)),a=new Map;for(let t of l){let i=a.get(t.leaf)??[];i.push(t),a.set(t.leaf,i)}for(let t of n.sourceFiles()){if(g(t)!=="clojure")continue;let i=b(e,t);if(i)for(let f of i.fileIdentifiers)for(let m of a.get(f)??[])M(r,m.symbolId,t)}let c=new Map;for(let t of n.scopedDefinitions()){if(g(t.relativePath)!=="clojure")continue;let i=c.get(t.leaf)??[];i.push(t),c.set(t.leaf,i)}for(let t of l){let i=b(e,t.relativePath);if(i){for(let f of i.callSites)if(!(f.line<t.startLine||f.line>t.endLine))for(let m of c.get(f.calleeLeaf)??[])M(u,t.symbolId,m.relativePath)}}return{referencesBySymbolId:r,calleesBySymbolId:u}}function M(e,n,o){let r=e.get(n);if(r){r.add(o);return}e.set(n,new Set([o]))}function D(e){return Math.round(e*1e3)/1e3}export{H as a};
2
- //# sourceMappingURL=chunk-45XOH33S.js.map