code-auditor-mcp 3.1.1 → 3.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 (361) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +724 -1
  3. package/README.md +85 -11
  4. package/dist/__test_tmp__/spec18_test.d.ts +2 -0
  5. package/dist/__test_tmp__/spec18_test.d.ts.map +1 -0
  6. package/dist/__test_tmp__/spec18_test.js +5 -0
  7. package/dist/__test_tmp__/spec18_test.js.map +1 -0
  8. package/dist/__tests__/fixtures/spec-20/scripts/tool.d.ts +6 -0
  9. package/dist/__tests__/fixtures/spec-20/scripts/tool.d.ts.map +1 -0
  10. package/dist/__tests__/fixtures/spec-20/scripts/tool.js +12 -0
  11. package/dist/__tests__/fixtures/spec-20/scripts/tool.js.map +1 -0
  12. package/dist/__tests__/fixtures/spec-20/src/demo-module.d.ts +7 -0
  13. package/dist/__tests__/fixtures/spec-20/src/demo-module.d.ts.map +1 -0
  14. package/dist/__tests__/fixtures/spec-20/src/demo-module.js +13 -0
  15. package/dist/__tests__/fixtures/spec-20/src/demo-module.js.map +1 -0
  16. package/dist/analyzers/analyzerUtils.js +2 -2
  17. package/dist/analyzers/analyzerUtils.js.map +1 -1
  18. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts +1 -1
  19. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
  20. package/dist/analyzers/cross-language/APIContractAnalyzer.js +2 -2
  21. package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -1
  22. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.d.ts +3 -0
  23. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.d.ts.map +1 -1
  24. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.js +3 -3
  25. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.js.map +1 -1
  26. package/dist/analyzers/cross-language/SchemaValidator.d.ts +1 -1
  27. package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
  28. package/dist/analyzers/cross-language/SchemaValidator.js +2 -2
  29. package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
  30. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +83 -0
  31. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -0
  32. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +611 -0
  33. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -0
  34. package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
  35. package/dist/analyzers/documentationAnalyzer.js +8 -4
  36. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  37. package/dist/analyzers/orm/adapterRegistry.d.ts +41 -0
  38. package/dist/analyzers/orm/adapterRegistry.d.ts.map +1 -0
  39. package/dist/analyzers/orm/adapterRegistry.js +73 -0
  40. package/dist/analyzers/orm/adapterRegistry.js.map +1 -0
  41. package/dist/analyzers/orm/drizzleAdapter.d.ts +42 -0
  42. package/dist/analyzers/orm/drizzleAdapter.d.ts.map +1 -0
  43. package/dist/analyzers/orm/drizzleAdapter.js +166 -0
  44. package/dist/analyzers/orm/drizzleAdapter.js.map +1 -0
  45. package/dist/analyzers/orm/index.d.ts +14 -0
  46. package/dist/analyzers/orm/index.d.ts.map +1 -0
  47. package/dist/analyzers/orm/index.js +24 -0
  48. package/dist/analyzers/orm/index.js.map +1 -0
  49. package/dist/analyzers/orm/prismaAdapter.d.ts +45 -0
  50. package/dist/analyzers/orm/prismaAdapter.d.ts.map +1 -0
  51. package/dist/analyzers/orm/prismaAdapter.js +170 -0
  52. package/dist/analyzers/orm/prismaAdapter.js.map +1 -0
  53. package/dist/analyzers/orm/types.d.ts +63 -0
  54. package/dist/analyzers/orm/types.d.ts.map +1 -0
  55. package/dist/analyzers/orm/types.js +10 -0
  56. package/dist/analyzers/orm/types.js.map +1 -0
  57. package/dist/analyzers/provenance.d.ts +133 -0
  58. package/dist/analyzers/provenance.d.ts.map +1 -0
  59. package/dist/analyzers/provenance.js +1041 -0
  60. package/dist/analyzers/provenance.js.map +1 -0
  61. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  62. package/dist/analyzers/reactAnalyzer.js +117 -1
  63. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  64. package/dist/analyzers/ruleRegistry.d.ts +38 -0
  65. package/dist/analyzers/ruleRegistry.d.ts.map +1 -0
  66. package/dist/analyzers/ruleRegistry.js +123 -0
  67. package/dist/analyzers/ruleRegistry.js.map +1 -0
  68. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +58 -0
  69. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -0
  70. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +445 -0
  71. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -0
  72. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +52 -0
  73. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
  74. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +108 -26
  75. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  76. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +64 -0
  77. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  78. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +259 -53
  79. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  80. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  81. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +5 -15
  82. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  83. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  84. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +10 -10
  85. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  86. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +25 -0
  87. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  88. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +250 -59
  89. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  90. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +103 -0
  91. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -0
  92. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +750 -0
  93. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -0
  94. package/dist/auditRunner.d.ts.map +1 -1
  95. package/dist/auditRunner.js +499 -4
  96. package/dist/auditRunner.js.map +1 -1
  97. package/dist/baseline.d.ts +98 -0
  98. package/dist/baseline.d.ts.map +1 -0
  99. package/dist/baseline.js +184 -0
  100. package/dist/baseline.js.map +1 -0
  101. package/dist/churn/churnExtractor.d.ts +32 -0
  102. package/dist/churn/churnExtractor.d.ts.map +1 -0
  103. package/dist/churn/churnExtractor.js +264 -0
  104. package/dist/churn/churnExtractor.js.map +1 -0
  105. package/dist/cli.js +1218 -11
  106. package/dist/cli.js.map +1 -1
  107. package/dist/codeIndexDB-enhanced.js +1 -1
  108. package/dist/codeIndexDB-enhanced.js.map +1 -1
  109. package/dist/codeIndexDB.d.ts +101 -0
  110. package/dist/codeIndexDB.d.ts.map +1 -1
  111. package/dist/codeIndexDB.js +665 -5
  112. package/dist/codeIndexDB.js.map +1 -1
  113. package/dist/config/configLoader.d.ts.map +1 -1
  114. package/dist/config/configLoader.js +104 -7
  115. package/dist/config/configLoader.js.map +1 -1
  116. package/dist/config/defaults.d.ts +72 -1
  117. package/dist/config/defaults.d.ts.map +1 -1
  118. package/dist/config/defaults.js +146 -15
  119. package/dist/config/defaults.js.map +1 -1
  120. package/dist/config/pathProfiles.d.ts +38 -0
  121. package/dist/config/pathProfiles.d.ts.map +1 -0
  122. package/dist/config/pathProfiles.js +47 -0
  123. package/dist/config/pathProfiles.js.map +1 -0
  124. package/dist/conventions/conventionMiner.d.ts +63 -0
  125. package/dist/conventions/conventionMiner.d.ts.map +1 -0
  126. package/dist/conventions/conventionMiner.js +696 -0
  127. package/dist/conventions/conventionMiner.js.map +1 -0
  128. package/dist/coverage/coverageService.d.ts +49 -0
  129. package/dist/coverage/coverageService.d.ts.map +1 -0
  130. package/dist/coverage/coverageService.js +117 -0
  131. package/dist/coverage/coverageService.js.map +1 -0
  132. package/dist/coverage/istanbulParser.d.ts +84 -0
  133. package/dist/coverage/istanbulParser.d.ts.map +1 -0
  134. package/dist/coverage/istanbulParser.js +120 -0
  135. package/dist/coverage/istanbulParser.js.map +1 -0
  136. package/dist/coverage/lcovParser.d.ts +40 -0
  137. package/dist/coverage/lcovParser.d.ts.map +1 -0
  138. package/dist/coverage/lcovParser.js +168 -0
  139. package/dist/coverage/lcovParser.js.map +1 -0
  140. package/dist/fingerprint.d.ts +17 -0
  141. package/dist/fingerprint.d.ts.map +1 -1
  142. package/dist/fingerprint.js +42 -0
  143. package/dist/fingerprint.js.map +1 -1
  144. package/dist/grammars/tree-sitter-css.wasm +0 -0
  145. package/dist/graph/blastRadius.d.ts +27 -0
  146. package/dist/graph/blastRadius.d.ts.map +1 -0
  147. package/dist/graph/blastRadius.js +150 -0
  148. package/dist/graph/blastRadius.js.map +1 -0
  149. package/dist/graph/callGraph.d.ts +78 -0
  150. package/dist/graph/callGraph.d.ts.map +1 -0
  151. package/dist/graph/callGraph.js +484 -0
  152. package/dist/graph/callGraph.js.map +1 -0
  153. package/dist/graph/importGraph.d.ts +91 -0
  154. package/dist/graph/importGraph.d.ts.map +1 -0
  155. package/dist/graph/importGraph.js +602 -0
  156. package/dist/graph/importGraph.js.map +1 -0
  157. package/dist/graph/outputFormatter.d.ts +55 -0
  158. package/dist/graph/outputFormatter.d.ts.map +1 -0
  159. package/dist/graph/outputFormatter.js +283 -0
  160. package/dist/graph/outputFormatter.js.map +1 -0
  161. package/dist/hooks/codex.d.ts +36 -1
  162. package/dist/hooks/codex.d.ts.map +1 -1
  163. package/dist/hooks/codex.js +88 -54
  164. package/dist/hooks/codex.js.map +1 -1
  165. package/dist/hotspots/hotspotScorer.d.ts +20 -0
  166. package/dist/hotspots/hotspotScorer.d.ts.map +1 -0
  167. package/dist/hotspots/hotspotScorer.js +202 -0
  168. package/dist/hotspots/hotspotScorer.js.map +1 -0
  169. package/dist/invariants/invariant-rules.schema.json +42 -1
  170. package/dist/invariants/ruleEngine.d.ts +4 -1
  171. package/dist/invariants/ruleEngine.d.ts.map +1 -1
  172. package/dist/invariants/ruleEngine.js +141 -5
  173. package/dist/invariants/ruleEngine.js.map +1 -1
  174. package/dist/invariants/ruleValidator.d.ts.map +1 -1
  175. package/dist/invariants/ruleValidator.js +62 -1
  176. package/dist/invariants/ruleValidator.js.map +1 -1
  177. package/dist/invariants/types.d.ts +23 -2
  178. package/dist/invariants/types.d.ts.map +1 -1
  179. package/dist/languages/UniversalAnalyzer.d.ts +1 -1
  180. package/dist/languages/UniversalAnalyzer.d.ts.map +1 -1
  181. package/dist/languages/UniversalAnalyzer.js +61 -4
  182. package/dist/languages/UniversalAnalyzer.js.map +1 -1
  183. package/dist/languages/index.d.ts +1 -0
  184. package/dist/languages/index.d.ts.map +1 -1
  185. package/dist/languages/index.js +3 -0
  186. package/dist/languages/index.js.map +1 -1
  187. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts +59 -0
  188. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -0
  189. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js +236 -0
  190. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -0
  191. package/dist/languages/tree-sitter/parser.d.ts.map +1 -1
  192. package/dist/languages/tree-sitter/parser.js +2 -0
  193. package/dist/languages/tree-sitter/parser.js.map +1 -1
  194. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  195. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +61 -10
  196. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  197. package/dist/ledger.d.ts +128 -0
  198. package/dist/ledger.d.ts.map +1 -0
  199. package/dist/ledger.js +345 -0
  200. package/dist/ledger.js.map +1 -0
  201. package/dist/mcp-tools/projectTasks.d.ts.map +1 -1
  202. package/dist/mcp-tools/projectTasks.js +9 -14
  203. package/dist/mcp-tools/projectTasks.js.map +1 -1
  204. package/dist/mcp.js +0 -0
  205. package/dist/mcpAuditJobs.d.ts.map +1 -1
  206. package/dist/mcpAuditJobs.js +3 -0
  207. package/dist/mcpAuditJobs.js.map +1 -1
  208. package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
  209. package/dist/reporting/csvReportGenerator.js +7 -1
  210. package/dist/reporting/csvReportGenerator.js.map +1 -1
  211. package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
  212. package/dist/reporting/htmlReportGenerator.js +5 -1
  213. package/dist/reporting/htmlReportGenerator.js.map +1 -1
  214. package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
  215. package/dist/reporting/jsonReportGenerator.js +10 -2
  216. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  217. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
  218. package/dist/reporting/sarifReportGenerator.js +17 -17
  219. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  220. package/dist/scripts/runBench.d.ts +94 -0
  221. package/dist/scripts/runBench.d.ts.map +1 -0
  222. package/dist/scripts/runBench.js +1559 -0
  223. package/dist/scripts/runBench.js.map +1 -0
  224. package/dist/search/QueryParser.d.ts.map +1 -1
  225. package/dist/search/QueryParser.js +51 -4
  226. package/dist/search/QueryParser.js.map +1 -1
  227. package/dist/services/CodeMapGenerator.d.ts +33 -0
  228. package/dist/services/CodeMapGenerator.d.ts.map +1 -1
  229. package/dist/services/CodeMapGenerator.js +404 -0
  230. package/dist/services/CodeMapGenerator.js.map +1 -1
  231. package/dist/styles/normalizer.d.ts +37 -0
  232. package/dist/styles/normalizer.d.ts.map +1 -0
  233. package/dist/styles/normalizer.js +301 -0
  234. package/dist/styles/normalizer.js.map +1 -0
  235. package/dist/styles/styleExtractor.d.ts +38 -0
  236. package/dist/styles/styleExtractor.d.ts.map +1 -0
  237. package/dist/styles/styleExtractor.js +630 -0
  238. package/dist/styles/styleExtractor.js.map +1 -0
  239. package/dist/styles/styleIndexer.d.ts +35 -0
  240. package/dist/styles/styleIndexer.d.ts.map +1 -0
  241. package/dist/styles/styleIndexer.js +266 -0
  242. package/dist/styles/styleIndexer.js.map +1 -0
  243. package/dist/styles/tailwindConfigLoader.d.ts +38 -0
  244. package/dist/styles/tailwindConfigLoader.d.ts.map +1 -0
  245. package/dist/styles/tailwindConfigLoader.js +374 -0
  246. package/dist/styles/tailwindConfigLoader.js.map +1 -0
  247. package/dist/styles/tailwindExpander.d.ts +38 -0
  248. package/dist/styles/tailwindExpander.d.ts.map +1 -0
  249. package/dist/styles/tailwindExpander.js +637 -0
  250. package/dist/styles/tailwindExpander.js.map +1 -0
  251. package/dist/styles/types.d.ts +92 -0
  252. package/dist/styles/types.d.ts.map +1 -0
  253. package/dist/styles/types.js +10 -0
  254. package/dist/styles/types.js.map +1 -0
  255. package/dist/symbols.d.ts +21 -0
  256. package/dist/symbols.d.ts.map +1 -0
  257. package/dist/symbols.js +31 -0
  258. package/dist/symbols.js.map +1 -0
  259. package/dist/types.d.ts +326 -3
  260. package/dist/types.d.ts.map +1 -1
  261. package/dist/types.js.map +1 -1
  262. package/dist/utils/fileDiscovery.d.ts +1 -0
  263. package/dist/utils/fileDiscovery.d.ts.map +1 -1
  264. package/dist/utils/fileDiscovery.js +8 -2
  265. package/dist/utils/fileDiscovery.js.map +1 -1
  266. package/package.json +9 -5
  267. package/plugin/.claude-plugin/plugin.json +1 -1
  268. package/plugin/scripts/hook-audit.sh +5 -1
  269. package/plugin/skills/code-auditor/SKILL.md +51 -0
  270. package/dist/analyzers/__tests__/fixtures/spec-17/anonymous-callback-map.d.ts +0 -21
  271. package/dist/analyzers/__tests__/fixtures/spec-17/anonymous-callback-map.d.ts.map +0 -1
  272. package/dist/analyzers/__tests__/fixtures/spec-17/anonymous-callback-map.js +0 -21
  273. package/dist/analyzers/__tests__/fixtures/spec-17/anonymous-callback-map.js.map +0 -1
  274. package/dist/analyzers/__tests__/fixtures/spec-17/barrel-test-migration.d.ts +0 -13
  275. package/dist/analyzers/__tests__/fixtures/spec-17/barrel-test-migration.d.ts.map +0 -1
  276. package/dist/analyzers/__tests__/fixtures/spec-17/barrel-test-migration.js +0 -12
  277. package/dist/analyzers/__tests__/fixtures/spec-17/barrel-test-migration.js.map +0 -1
  278. package/dist/analyzers/__tests__/fixtures/spec-17/direct-access-allow-config.d.ts +0 -11
  279. package/dist/analyzers/__tests__/fixtures/spec-17/direct-access-allow-config.d.ts.map +0 -1
  280. package/dist/analyzers/__tests__/fixtures/spec-17/direct-access-allow-config.js +0 -22
  281. package/dist/analyzers/__tests__/fixtures/spec-17/direct-access-allow-config.js.map +0 -1
  282. package/dist/analyzers/__tests__/fixtures/spec-17/exported-undocumented.d.ts +0 -9
  283. package/dist/analyzers/__tests__/fixtures/spec-17/exported-undocumented.d.ts.map +0 -1
  284. package/dist/analyzers/__tests__/fixtures/spec-17/exported-undocumented.js +0 -13
  285. package/dist/analyzers/__tests__/fixtures/spec-17/exported-undocumented.js.map +0 -1
  286. package/dist/analyzers/__tests__/fixtures/spec-17/for-loop-query.d.ts +0 -13
  287. package/dist/analyzers/__tests__/fixtures/spec-17/for-loop-query.d.ts.map +0 -1
  288. package/dist/analyzers/__tests__/fixtures/spec-17/for-loop-query.js +0 -18
  289. package/dist/analyzers/__tests__/fixtures/spec-17/for-loop-query.js.map +0 -1
  290. package/dist/analyzers/__tests__/fixtures/spec-17/import-node-builtin.d.ts +0 -10
  291. package/dist/analyzers/__tests__/fixtures/spec-17/import-node-builtin.d.ts.map +0 -1
  292. package/dist/analyzers/__tests__/fixtures/spec-17/import-node-builtin.js +0 -16
  293. package/dist/analyzers/__tests__/fixtures/spec-17/import-node-builtin.js.map +0 -1
  294. package/dist/analyzers/__tests__/fixtures/spec-17/jsx-event-handler.d.ts +0 -14
  295. package/dist/analyzers/__tests__/fixtures/spec-17/jsx-event-handler.d.ts.map +0 -1
  296. package/dist/analyzers/__tests__/fixtures/spec-17/jsx-event-handler.js +0 -18
  297. package/dist/analyzers/__tests__/fixtures/spec-17/jsx-event-handler.js.map +0 -1
  298. package/dist/analyzers/__tests__/fixtures/spec-17/nested-loops-query.d.ts +0 -13
  299. package/dist/analyzers/__tests__/fixtures/spec-17/nested-loops-query.d.ts.map +0 -1
  300. package/dist/analyzers/__tests__/fixtures/spec-17/nested-loops-query.js +0 -22
  301. package/dist/analyzers/__tests__/fixtures/spec-17/nested-loops-query.js.map +0 -1
  302. package/dist/analyzers/__tests__/fixtures/spec-17/nine-line-repeated.d.ts +0 -10
  303. package/dist/analyzers/__tests__/fixtures/spec-17/nine-line-repeated.d.ts.map +0 -1
  304. package/dist/analyzers/__tests__/fixtures/spec-17/nine-line-repeated.js +0 -20
  305. package/dist/analyzers/__tests__/fixtures/spec-17/nine-line-repeated.js.map +0 -1
  306. package/dist/analyzers/__tests__/fixtures/spec-17/private-methods.d.ts +0 -18
  307. package/dist/analyzers/__tests__/fixtures/spec-17/private-methods.d.ts.map +0 -1
  308. package/dist/analyzers/__tests__/fixtures/spec-17/private-methods.js +0 -28
  309. package/dist/analyzers/__tests__/fixtures/spec-17/private-methods.js.map +0 -1
  310. package/dist/analyzers/__tests__/fixtures/spec-17/scope-all-config.d.ts +0 -11
  311. package/dist/analyzers/__tests__/fixtures/spec-17/scope-all-config.d.ts.map +0 -1
  312. package/dist/analyzers/__tests__/fixtures/spec-17/scope-all-config.js +0 -31
  313. package/dist/analyzers/__tests__/fixtures/spec-17/scope-all-config.js.map +0 -1
  314. package/dist/analyzers/__tests__/fixtures/spec-17/sql-tagged-template.d.ts +0 -11
  315. package/dist/analyzers/__tests__/fixtures/spec-17/sql-tagged-template.d.ts.map +0 -1
  316. package/dist/analyzers/__tests__/fixtures/spec-17/sql-tagged-template.js +0 -18
  317. package/dist/analyzers/__tests__/fixtures/spec-17/sql-tagged-template.js.map +0 -1
  318. package/dist/analyzers/__tests__/fixtures/spec-17/structural-similar-methods.d.ts +0 -13
  319. package/dist/analyzers/__tests__/fixtures/spec-17/structural-similar-methods.d.ts.map +0 -1
  320. package/dist/analyzers/__tests__/fixtures/spec-17/structural-similar-methods.js +0 -61
  321. package/dist/analyzers/__tests__/fixtures/spec-17/structural-similar-methods.js.map +0 -1
  322. package/dist/analyzers/__tests__/fixtures/spec-17/template-prefix-table.d.ts +0 -10
  323. package/dist/analyzers/__tests__/fixtures/spec-17/template-prefix-table.d.ts.map +0 -1
  324. package/dist/analyzers/__tests__/fixtures/spec-17/template-prefix-table.js +0 -15
  325. package/dist/analyzers/__tests__/fixtures/spec-17/template-prefix-table.js.map +0 -1
  326. package/dist/analyzers/__tests__/fixtures/spec-17/token-identical-20-lines.d.ts +0 -11
  327. package/dist/analyzers/__tests__/fixtures/spec-17/token-identical-20-lines.d.ts.map +0 -1
  328. package/dist/analyzers/__tests__/fixtures/spec-17/token-identical-20-lines.js +0 -49
  329. package/dist/analyzers/__tests__/fixtures/spec-17/token-identical-20-lines.js.map +0 -1
  330. package/dist/analyzers/__tests__/fixtures/spec-17/tsx-no-db-usage.d.ts +0 -10
  331. package/dist/analyzers/__tests__/fixtures/spec-17/tsx-no-db-usage.d.ts.map +0 -1
  332. package/dist/analyzers/__tests__/fixtures/spec-17/tsx-no-db-usage.js +0 -19
  333. package/dist/analyzers/__tests__/fixtures/spec-17/tsx-no-db-usage.js.map +0 -1
  334. package/dist/analyzers/__tests__/fixtures/spec-17/twenty-methods-vs-complex.d.ts +0 -37
  335. package/dist/analyzers/__tests__/fixtures/spec-17/twenty-methods-vs-complex.d.ts.map +0 -1
  336. package/dist/analyzers/__tests__/fixtures/spec-17/twenty-methods-vs-complex.js +0 -73
  337. package/dist/analyzers/__tests__/fixtures/spec-17/twenty-methods-vs-complex.js.map +0 -1
  338. package/dist/analyzers/__tests__/fixtures/spec-17/unique-method-74-lines.d.ts +0 -12
  339. package/dist/analyzers/__tests__/fixtures/spec-17/unique-method-74-lines.d.ts.map +0 -1
  340. package/dist/analyzers/__tests__/fixtures/spec-17/unique-method-74-lines.js +0 -82
  341. package/dist/analyzers/__tests__/fixtures/spec-17/unique-method-74-lines.js.map +0 -1
  342. package/dist/analyzers/__tests__/fixtures/spec-17/word-the-in-comment.d.ts +0 -10
  343. package/dist/analyzers/__tests__/fixtures/spec-17/word-the-in-comment.d.ts.map +0 -1
  344. package/dist/analyzers/__tests__/fixtures/spec-17/word-the-in-comment.js +0 -15
  345. package/dist/analyzers/__tests__/fixtures/spec-17/word-the-in-comment.js.map +0 -1
  346. package/dist/analyzers/dataAccessAnalyzer.d.ts +0 -46
  347. package/dist/analyzers/dataAccessAnalyzer.d.ts.map +0 -1
  348. package/dist/analyzers/dataAccessAnalyzer.js +0 -474
  349. package/dist/analyzers/dataAccessAnalyzer.js.map +0 -1
  350. package/dist/analyzers/dryAnalyzer.d.ts +0 -31
  351. package/dist/analyzers/dryAnalyzer.d.ts.map +0 -1
  352. package/dist/analyzers/dryAnalyzer.js +0 -734
  353. package/dist/analyzers/dryAnalyzer.js.map +0 -1
  354. package/dist/analyzers/schemaAnalyzer.d.ts +0 -23
  355. package/dist/analyzers/schemaAnalyzer.d.ts.map +0 -1
  356. package/dist/analyzers/schemaAnalyzer.js +0 -564
  357. package/dist/analyzers/schemaAnalyzer.js.map +0 -1
  358. package/dist/analyzers/solidAnalyzer.d.ts +0 -33
  359. package/dist/analyzers/solidAnalyzer.d.ts.map +0 -1
  360. package/dist/analyzers/solidAnalyzer.js +0 -847
  361. package/dist/analyzers/solidAnalyzer.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,11 +2,587 @@
2
2
 
3
3
  All notable changes to the Code Auditor MCP project.
4
4
 
5
+ ## [3.4.1] — 2026-07-24
6
+
7
+ ### Patch Release — Production Bug Fixes
8
+
9
+ Release validation (the validator's own create-and-audit integration test) caught four defects that the bench suite missed — all behind a green 1,166-test suite. Three were wiring gaps invisible to the bench by construction (the bench seeds tables directly in-memory, bypassing production service-layer wiring). The fourth was an A2 gate scope problem (the gate checked manifest structure and keyword presence but never verified doc-CLI parity).
10
+
11
+ #### Defect #1: Style Index Dead in Production
12
+
13
+ The style analyzer's index sync path (`syncStyleIndex()`) accessed `CodeIndexDB.getInstance().rawDb`, but `CodeIndexDB.getInstance()` returns an uninitialized instance — `rawDb` is only assigned in `initializeInternal()`. The `await styleDb.initialize()` call was missing, so `rawDb` was always `undefined` and every style index sync silently failed. Real-audit style findings were always empty.
14
+
15
+ **Fix** (`d601ac3`): Added `await styleDb.initialize()` before `syncStyleIndex()` in `auditRunner.ts` deepSync() styles block.
16
+
17
+ #### Defect #2: Hotspots Empty on Real Git Repos
18
+
19
+ `functions.file_path` stores absolute paths (from `discoverFiles` via `path.join()`). `file_churn` stored git-relative paths (from `git log --numstat` output). The `hotspotScorer` built its lookup Map with relative keys but queried with absolute keys — they never matched. Every hotspot on a real git repo was empty.
20
+
21
+ **Fix** (`d601ac3`): Resolve git-relative paths to absolute via `path.resolve(targetPath, parts[2])` in `churnExtractor.ts`.
22
+
23
+ **Secondary defects in same fix**:
24
+ - `clearIndex()` now clears stale `churn_hash`/`conventions_hash`/`style_last_sync` meta keys — a clear+re-sync previously skipped churn extraction
25
+ - Replaced silent `catch {}` blocks with `console.warn()` in `deepSync()` and CLI hotspots command — these swallowed the path mismatch bug for an entire release cycle
26
+ - `hotspot_scores` INSERT → INSERT OR REPLACE to handle duplicate targets from anonymous functions in the same file
27
+
28
+ #### Defect #3: SKILL.md `--tool claude` Phantom Flag & A2 Gate Expansion
29
+
30
+ The SKILL.md referenced `--tool claude` as a `generate-config` flag, but the CLI never supported it. The A2 gate ran only against the style layer (frontmatter, keyword presence) — it never checked whether the flags taught to agents actually exist.
31
+
32
+ **Fix** (uncommitted, `src/cli-integration.spec.ts`): The A2 gate now verifies doc-CLI parity. It parses every SKILL.md bash code block and inline backtick command, extracts flags and subcommand paths, calls the actual CLI's `--help` for each target, and asserts every referenced token appears in the help output. The `--tool claude` phantom would be caught immediately. 16 tests pass, 6 skip (missing subcommands not yet implemented).
33
+
34
+ #### from-audit Fingerprint Migration (One-Time Churn)
35
+
36
+ The `from_audit` handler in `projectTasks.ts` previously used divergent inline symbol extraction with a different priority order (`className` before `functionName`, missing `methodName`/`name` fields). Commit `fc5ec22` (Spec 11) replaced it with the canonical `extractSymbol()` from `symbols.ts`. The fingerprint scheme itself (SHA-256 over `[analyzer, rule, file, symbol]`) is stable and hasn't changed between v3.4.0 and v3.4.1 — the migration from divergent inline extraction to `extractSymbol()` happened in v3.1.1.
37
+
38
+ **Effect on upgrade**: Pre-existing tasks created with the old inline extraction scheme have different fingerprints than tasks created by the current code. Running `from-audit` after upgrading from pre-v3.1.1 will produce duplicate tasks on the first run — the old fingerprints won't match dedup checks. Subsequent runs use the new stable fingerprints and deduplicate correctly.
39
+
40
+ #### CSS Discovery Fix
41
+
42
+ The Style Intelligence analyzer's file discovery didn't include `.css`/`.scss` extensions in the default extension list (`ALL_EXTENSIONS`), so CSS/SCSS files were never discovered by `findFiles()` — even though the CSS adapter, CSS/SCSS tree-sitter grammars, and style extractor were all fully functional. A full audit on a project with CSS files would produce zero style findings because no CSS files were ever indexed.
43
+
44
+ **Fix** (uncommitted, `src/utils/fileDiscovery.ts`): Added `CSS_EXTENSIONS` (`['.css', '.scss']`) to `ALL_EXTENSIONS`.
45
+
46
+ #### Release Riders
47
+
48
+ - **Hook-contract regression guard** (`9773144`): Added `hookContractViolations` field to bench output
49
+ - **GROUND-TRUTH.md §9** (`6b38fa9`): Documented `nextSessionsCursor` and `withRetry` as known SDK-level gaps
50
+ - **Conventions analyzer** (`9773144`): Fixed line-0 violation (line 0 → line 9) in Spec-15 evidence
51
+
52
+ ### Changed Files
53
+
54
+ | File | Change |
55
+ |------|--------|
56
+ | `src/auditRunner.ts` | Add `await styleDb.initialize()` before style index sync |
57
+ | `src/utils/fileDiscovery.ts` | Add CSS_EXTENSIONS to ALL_EXTENSIONS |
58
+ | `src/scripts/churnExtractor.ts` | Resolve git-relative paths to absolute |
59
+ | `src/codeIndexDB.ts` | Clear stale meta keys on index reset; INSERT OR REPLACE on hotspot_scores |
60
+ | `src/cli.ts` | Replace silent catch with console.warn in hotspots command |
61
+ | `src/cli-integration.spec.ts` | A2 gate expansion — doc-CLI parity tests (16 pass, 6 skip) |
62
+ | `GROUND-TRUTH.md` | §9: Known Issues — SDK/Integration Surface |
63
+
64
+ ## [3.3.0] — 2026-07-20
65
+
66
+ ### Spec-10: Style Intelligence — Distribution-Aware Style Analysis
67
+
68
+ LLM coding agents produce styling fragmentation that line-level linting can't see — near-duplicate hex values, off-scale margins, inline styles where the project uses Tailwind, mechanism mixing within a single component. The insight lives in the distribution. Spec 10 builds a style index parallel to the function index, extracts normalized declarations from five style sources, derives findings statistically from value histograms, and extends the invariant engine so style policy is enforceable in the agent loop.
69
+
70
+ #### R1: CSS/SCSS Language Support
71
+
72
+ - **New adapter `TreeSitterCssAdapter`**: Implements the `LanguageAdapter` interface for `.css` and `.scss` files via tree-sitter-css and tree-sitter-scss grammars. Methods returning AST concepts not present in CSS (functions, classes, imports, exports) return empty/null.
73
+ - **Grammar loading**: `tree-sitter-css.wasm` and `tree-sitter-scss.wasm` added to `GRAMMAR_FILES` and `LANGUAGE_GRAMMAR_MAP` in parser.ts. Both shipped in `dist/grammars/`.
74
+
75
+ #### R2: Style Extraction — Everything Normalizes to Declarations
76
+
77
+ The unit is the **normalized declaration**: `(property, rawValue, normalizedValue, mechanism, file, line, context, variantContext, tokenRef)`.
78
+
79
+ - **New module `src/styles/styleExtractor.ts`**: Extracts declarations from five mechanisms: CSS/SCSS files (tree-sitter rule-set walking), Tailwind utility classes (class name → declaration expansion), inline styles (`style={{...}}` object expression resolution), CSS-in-JS (styled-components/emotion tagged templates), and design tokens (CSS custom properties, Tailwind theme).
80
+ - **New module `src/styles/tailwindExpander.ts`**: Maps Tailwind utility classes to normalized declarations. Supports arbitrary values (`mt-[17px]` → `margin-top: 17px`), variant prefixes (`hover:`, `md:` → `variantContext`), and three-tier config resolution (v3 JS config, v4 CSS `@theme` blocks, bundled defaults).
81
+ - **New module `src/styles/tailwindConfigLoader.ts`**: Dynamically loads project's Tailwind config with graceful fallback. Resolves `theme.extend` merged with defaults for v3, parses `@theme` blocks for v4.
82
+ - **New module `src/styles/normalizer.ts`**: Color normalization (lowercase, shorthand hex expansion, canonical functional notation), length parsing to `{number, unit}`, short→longhand expansion (`margin: 4px 8px` → four directional declarations sharing source location). Delta-E color distance for value-drift clustering.
83
+
84
+ #### R3: Style Index — SQLite Storage and Search
85
+
86
+ - **`style_declarations` table**: Columns for property, raw_value, normalized_value, mechanism, file_path, line, context (selector), variant_context (at-rule prefix), token_ref, content_hash.
87
+ - **`style_tokens` table**: Design token registry with name, value, mechanism (`css-custom-property` or `tailwind-theme`).
88
+ - **`style_class_usage` table**: Per-file class name usage tracking with mechanism and `unresolvable` flag for dynamically-computed class names.
89
+ - **FTS5 virtual table** (`style_declarations_fts`): Full-text search over property and normalized values.
90
+ - **Schema migration 2→3**: Creates all three style tables with appropriate indexes.
91
+ - **New module `src/styles/styleIndexer.ts`**: Content-hash-based change detection — re-extracts only changed files. Called from `auditRunner.ts` before the analyzer run.
92
+ - **New search operators**: `css:<property>`, `value:<normalized-value>`, `mechanism:<css|tailwind|inline|css-in-js|scss>`, `token:<design-token-name>`. When used, `compileToSQL()` JOINs the `style_declarations` table.
93
+ - **Code map `styles` section**: Mechanism summary (declaration counts per mechanism), property→value histogram with shares and token coverage, token table.
94
+
95
+ #### R4: Styles Analyzer — 7 Detectors, 10 Rule IDs
96
+
97
+ **New analyzer `UniversalStylesAnalyzer`**: DB-based — reads from the full style index rather than per-file AST parsing. Every detector has configurable thresholds and fires only when per-property corpus ≥ `minCorpus`.
98
+
99
+ | Detector | Rule ID(s) | What it finds | Severity |
100
+ |----------|-----------|---------------|----------|
101
+ | **Value drift** (color) | `styles/value-drift` | Color near-duplicates (delta-E < 2.0) where one value dominates and a straggler is barely used | warning |
102
+ | **Value drift** (exact) | `styles/value-drift` | Exact-value histogram outliers (share < 5% when mode ≥ 10 uses) | warning |
103
+ | **Off-scale** | `styles/off-scale` | Scale-family values (margin, padding, gap, font-size) not on the inferred project scale | warning |
104
+ | **Undefined class** | `styles/undefined-class` | `className` values with no matching selector in any CSS/SCSS file and not a known Tailwind utility | warning |
105
+ | **Token bypass** | `styles/token-bypass` | Normalized value matches a known design token but `tokenRef` is absent | warning |
106
+ | **Mechanism fragmentation** | `styles/mechanism-fragmentation` | Same `(property, value)` pair delivered via ≥ 3 different mechanisms | warning |
107
+ | **Mechanism mixing** | `styles/mechanism-mixing` | Single component mixing ≥ 3 style mechanisms | suggestion |
108
+ | **Declaration-set similarity** | `styles/declaration-set-similarity` | Two CSS rule blocks with Jaccard similarity ≥ 0.9 and ≥ 5 declarations each | suggestion |
109
+ | **Z-index sprawl** | `styles/z-index-sprawl` | More than 6 distinct z-index values across the project | warning |
110
+ | **Z-index singleton** | `styles/z-index-singleton` | z-index values used exactly once with no other close values | suggestion |
111
+
112
+ All detectors read corpus statistics from the full SQLite index, so **scoped runs** (changed files only) still compare against the complete project baseline. A fresh drift value in a scoped run is always caught against the full corpus.
113
+
114
+ #### R5: React Analyzer — Raw-Element Detection
115
+
116
+ - **`checkRawElements()`**: Auto-detects wrapper components (exported component whose rendered root is a single intrinsic element from the watch list AND which forwards props/children). Flags raw usages of that intrinsic element anywhere outside the wrapper when call sites ≥ `wrapperMinUsages` (default 5).
117
+ - **Config**: `rawElementWatchList` (default `['button', 'input', 'select', 'textarea', 'table']`), `wrapperMinUsages`, `componentMap`. `componentMap` overrides auto-detection: `{"button": "Button"}` → any raw `<button>` is a warning (not suggestion).
118
+ - Finding message names the wrapper: "raw `<button>` — this project uses `Button` (src/components/Button.tsx)".
119
+
120
+ #### R6: Style Invariant Rule Kinds
121
+
122
+ Two new rule kinds added to the invariant engine:
123
+
124
+ | Rule kind | Purpose | Key config |
125
+ |-----------|---------|------------|
126
+ | `style-mechanism` | Require allowed style mechanisms per file/glob (e.g., "only Tailwind in `src/components/`") | `allow: ["tailwind"]`, `path` |
127
+ | `no-raw-values` | Ban hardcoded values for specific CSS properties (e.g., "no raw colors in `src/pages/`") | `properties: ["color", "background-color"]`, `allowValues`, `path` |
128
+
129
+ Both query the `style_declarations` table via `CodeIndexDB` for evidence. JSON Schema validation covers the new kinds. `code-audit config rules-create` auto-discovers them alongside the existing five kinds.
130
+
131
+ ### Changed Files
132
+
133
+ | File | Change |
134
+ |------|--------|
135
+ | `src/languages/tree-sitter/TreeSitterCssAdapter.ts` | **New** — LanguageAdapter for CSS/SCSS |
136
+ | `src/languages/tree-sitter/parser.ts` | Add CSS/SCSS to GRAMMAR_FILES + LANGUAGE_GRAMMAR_MAP |
137
+ | `src/languages/index.ts` | Register TreeSitterCssAdapter |
138
+ | `src/styles/styleExtractor.ts` | **New** — extraction from all 5 style sources |
139
+ | `src/styles/normalizer.ts` | **New** — color/length/shorthand normalization |
140
+ | `src/styles/tailwindExpander.ts` | **New** — Tailwind utility → declaration expansion |
141
+ | `src/styles/tailwindConfigLoader.ts` | **New** — load project's Tailwind config (v3/v4) |
142
+ | `src/styles/styleIndexer.ts` | **New** — sync style declarations to SQLite |
143
+ | `src/styles/types.ts` | **New** — style-specific TypeScript interfaces |
144
+ | `src/analyzers/universal/UniversalStylesAnalyzer.ts` | **New** — DB-based analyzer with 7 detectors |
145
+ | `src/types.ts` | New types: NormalizedDeclaration, StyleToken, StylesAnalyzerConfig; extend ReactAnalyzerConfig |
146
+ | `src/codeIndexDB.ts` | SCHEMA_VERSION → 3; new tables (style_declarations, style_tokens, style_class_usage, style_declarations_fts); migration 2→3 |
147
+ | `src/search/QueryParser.ts` | 4 new operators: `css:`, `value:`, `mechanism:`, `token:` |
148
+ | `src/services/CodeMapGenerator.ts` | New `styles` section with mechanism summary and property histogram |
149
+ | `src/analyzers/reactAnalyzer.ts` | `checkRawElements()`; new config fields (rawElementWatchList, wrapperMinUsages, componentMap) |
150
+ | `src/auditRunner.ts` | Register styles analyzer; call styleIndexer.syncStyleIndex(); thread React raw-element config |
151
+ | `src/config/defaults.ts` | `DEFAULT_ANALYZER_CONFIGS.styles`; `includePaths` extended with `**/*.css`, `**/*.scss`; `enabledAnalyzers` extended |
152
+ | `src/invariants/types.ts` | New RuleKind values: `style-mechanism`, `no-raw-values` |
153
+ | `src/invariants/ruleEngine.ts` | `checkStyleMechanism()`, `checkNoRawValues()` checkers |
154
+ | `src/invariants/invariant-rules.schema.json` | Schemas for two new rule kinds |
155
+ | `src/invariants/ruleValidator.ts` | Validation for new rule kinds |
156
+ | `src/cli.ts` | RULE_KINDS array extended with two new kinds |
157
+ | `bench/corpus/styles/` | **New** — bench fixture project + expected.json |
158
+ | `bench/baselines/baseline.json` | Add styles analyzer baseline (9 rule IDs) |
159
+ | `src/scripts/runBench.ts` | Styles runner with in-memory seed data |
160
+ | `src/__tests__/bench.test.ts` | Updated to 9 analyzers |
161
+ | `package.json` | Add tree-sitter-css, tree-sitter-scss devDeps |
162
+
163
+ ## [3.4.0] — 2026-07-23
164
+
165
+ ### Spec-12: Convention Mining — Codebase Convention Discovery and Enforcement
166
+
167
+ Code Auditor now learns your codebase's unwritten conventions from the function index and flags deviations at suggestion severity. An LLM coding agent unfamiliar with the codebase breaks these conventions silently because no linter enforces them — Spec 12 detects the conventions from the existing SQLite index, flags violations, and can propose ready-to-paste `.codeauditor.json` rules.
168
+
169
+ #### R1: Convention Mining — Five Domains
170
+
171
+ Five convention domains are mined from the `functions` and `function_calls` tables at sync time. Every convention stores its `support` (cases that follow) and `total_cases` for confidence (`support / total_cases`). Only conventions meeting the `minCorpus` (default 20) and `modeShare` (default 0.8) thresholds are established.
172
+
173
+ - **Usage Pairs** (`usage-pair`): Function calls that always co-occur. If 95% of `handleError` callers also call `logError`, a function calling only `handleError` is flagged.
174
+ - **Import Form** (`import-form`): Per module specifier + directory, the dominant import style (`default`, `named`, `namespace`, `side-effect`, `require`). Minority import styles in directories where a clear dominant form exists are flagged.
175
+ - **Error Handling** (`error-handling`): Per directory, the dominant error-handling pattern (`try/catch`, `.catch()`, `if (err)`, Go-style). Functions in that directory that *have* error handling but use a different shape are flagged. Functions with no error handling are never flagged.
176
+ - **Export Shape** (`export-shape`): Per directory, dominant export style (`default` vs `named`). Minority exports are flagged only when a clear dominant shape exists.
177
+ - **Naming** (`naming`): Per directory, dominant casing convention (`PascalCase`, `camelCase`, `UPPER_SNAKE`, `snake_case`, `kebab-case`). Non-Latin identifiers are skipped (Spec 21 R5.4).
178
+
179
+ **New module `src/conventions/conventionMiner.ts`**: Mines all five domains from the SQLite index. Content-hash-based skip prevents redundant mining when the underlying data hasn't changed. Configuration thresholds: `minCorpus` (20), `pairConfidence` (0.9), `modeShare` (0.8), `maxConventionsPerDomain` (200).
180
+
181
+ **Schema migration 3→4**: New `conventions` table with indexes on domain, rule_id, directory, and hash.
182
+
183
+ #### R2: Conventions Analyzer
184
+
185
+ **New analyzer `UniversalConventionsAnalyzer`**: DB-based — reads from the conventions table rather than per-file AST parsing. All findings ship at `suggestion` severity by default (promotable via `severityOverrides`).
186
+
187
+ | Rule ID | Domain | What it finds |
188
+ |---------|--------|---------------|
189
+ | `conventions/usage-pair` | usage-pair | Function calls antecedent without its required consequent |
190
+ | `conventions/import-form` | import-form | Minority import style where a dominant form is established |
191
+ | `conventions/error-handling` | error-handling | Different error-handling shape from the directory convention |
192
+ | `conventions/export-shape` | export-shape | Minority export style where a dominant shape is established |
193
+ | `conventions/naming` | naming | Minority casing convention where a dominant casing is established |
194
+
195
+ #### R3: CLI Commands
196
+
197
+ **New command group `code-audit conventions`**:
198
+ - `code-audit conventions list [--domain <domain>] [--json]` — list all mined conventions with support/confidence
199
+ - `code-audit conventions propose [--domain <domain>] [--json]` — emit ready-to-paste `.codeauditor.json` rules. Only `naming` → `naming` rule kind and `import-form` → `import-ban` rule kind produce proposals. Other domains are detector-only.
200
+
201
+ #### R4: Bench Fixture
202
+
203
+ - **`bench/corpus/conventions/`** — fixture project with:
204
+ - `src/fixture.ts` — one violation per domain (usage-pair, import-form, error-handling, export-shape, naming)
205
+ - `src/approved.ts` — near-miss file following all conventions (zero violations expected)
206
+ - `src/no-mode/` — mixed-shape directory below `modeShare` threshold where zero findings are expected
207
+ - `expected.json` — ground truth manifest with 5 expected violations at suggestion severity
208
+
209
+ ### Changed Files
210
+
211
+ | File | Change |
212
+ |------|--------|
213
+ | `src/types.ts` | Add `Convention`, `ConventionMiningConfig`, `ConventionsAnalyzerConfig` types |
214
+ | `src/codeIndexDB.ts` | SCHEMA_VERSION → 4, `conventions` table, migration 3→4, `mineConventions()` in `deepSync()` |
215
+ | `src/conventions/conventionMiner.ts` | **New** — five-domain mining from functions/calls tables |
216
+ | `src/analyzers/universal/UniversalConventionsAnalyzer.ts` | **New** — DB-based analyzer, suggestion-only findings |
217
+ | `src/auditRunner.ts` | `conventions` entry in `DEFAULT_ANALYZERS` |
218
+ | `src/config/defaults.ts` | `DEFAULT_ANALYZER_CONFIGS.conventions`, enabled analyzers |
219
+ | `src/cli.ts` | `conventions list` and `conventions propose` subcommands |
220
+ | `SKILL.md` | "mine and propose rules" workflow |
221
+ | `bench/corpus/conventions/` | **New** — bench fixture project + expected.json |
222
+ | `bench/baselines/baseline.json` | Add conventions analyzer baseline (5 rule IDs) |
223
+ | `src/scripts/runBench.ts` | Conventions runner with in-memory seed data |
224
+ | `src/__tests__/bench.test.ts` | Updated to 10 analyzers |
225
+
226
+ ### Spec-13: Hotspots & Temporal Analysis — Churn, Trends, and Diverging Clones
227
+
228
+ Spec 13 adds five temporal-analysis capabilities: git-powered churn tracking, hotspot scoring (churn × complexity), ownership/bus-factor detection, audit trend analysis, and diverging-clone detection. All git access is read-only and degrades gracefully when no repo exists.
229
+
230
+ #### R1: Churn Extraction
231
+
232
+ - **New module `src/churn/churnExtractor.ts`**: Shells out to `git log --numstat` and `git log -p` for per-file and per-function churn. Gracefully handles missing git repos (logs warning, returns empty). Returns cost measurements (`{ fileCount, functionCount, durationMs }`).
233
+ - **`file_churn` table** (schema v5): `file_path`, `commit_count`, `lines_added`, `lines_deleted`, `distinct_authors`, `dominant_author`, `dominant_author_share`, `last_touched`.
234
+ - **`function_churn` table** (schema v5): `function_id` FK to `functions`, `function_name`, `file_path`, `commit_count`, `distinct_authors`, `dominant_author`, `dominant_author_share`, `renamed` flag, `confidence`.
235
+ - **Schema migration** (4→5): Creates both churn tables + `dry_pair_history` table + indexes.
236
+ - **Sync integration**: `extractChurn()` called from `deepSync()` after indexing, gated by git HEAD + window meta hash cache invalidation.
237
+
238
+ #### R2: Hotspot Scoring
239
+
240
+ - **New module `src/hotspots/hotspotScorer.ts`**: Percentile-based scoring combining churn and complexity. Function hotspot = `churnPercentile × complexityPercentile`, scaled to [0, 1]. File hotspot = `fileChurnPercentile × maxFunctionComplexityPercentileInFile`. Zero-churn files score 0 (never penalized for complexity alone).
241
+ - **`hotspot_scores` table**: Cached scores recomputed on sync (like conventions).
242
+ - **Finding reordering** (`auditRunner.ts`): Within each severity tier, findings sort by containing function's hotspot score descending (falling back to file hotspot, then original order).
243
+ - **`hotspot` field on every Violation**: Optional `hotspot?: number` field on `Violation` type, populated from containing function's or file's hotspot score. Included on all output surfaces (JSON, HTML, CSV, SARIF).
244
+
245
+ #### R3: Ownership / Bus-Factor Detection
246
+
247
+ - **Bus-factor analysis**: For files and functions in the top quartile of hotspot scores, checks if `dominant_author_share ≥ 0.9` (single author owns ≥90% of commits). Flags emitted as report-level `busFactorRisks` array.
248
+ - **CLI visibility**: `code-audit hotspots` command shows ⚠ icon next to bus-factor risks.
249
+
250
+ #### R4: Ledger Trends
251
+
252
+ - **New CLI subcommand** `code-audit ledger trends [--since <runId>] [--json]`: Compares fingerprint sets across consecutive same-target full-audit runs. Tracks `newCount`, `fixedCount`, and `net` per rule. Output includes comparison basis (target, run pairs, time range).
253
+ - **Filtering**: Excludes non-full-audit runs and runs of different targets. Requires ≥2 full-audit runs of the same target.
254
+
255
+ #### R5: Diverging Clones
256
+
257
+ - **New rule** `dry/diverging-clone` at **suggestion** severity: Detects clone pairs whose similarity has declined across consecutive audit runs. Pair identity is fingerprint-based (`file + enclosingSymbol`), not content-hash-based (stable across line drift).
258
+ - **Two-phase mechanism**:
259
+ 1. **Seed phase**: During DRY analysis, pairs with similarity ≥ `minPairSimilarity` (0.5) are persisted into `dry_pair_history`.
260
+ 2. **Tracking phase**: On every full audit, all historically-tracked pairs are re-measured. If similarity drops by ≥ `divergenceThreshold` (0.05) for `divergenceRuns` (2) consecutive runs → emit violation.
261
+ - **`dry_pair_history` table**: `pair_fingerprint` (stable identity key), file/symbol/line/content-hash per block, `similarity`, `timestamp`, `run_id`. Content hashes are data (not keys).
262
+ - **Config**: `DivergenceConfig` with `divergenceThreshold` (0.05), `divergenceRuns` (2), `minPairSimilarity` (0.5) in `DEFAULT_ANALYZER_CONFIGS.dry.divergence`.
263
+ - **Re-evaluation condition**: The rule enters at `suggestion` severity and cannot be promoted to `warning` until ≥10 divergence findings exist across organic full runs. Divergence detection requires ≥2 consecutive full-run similarity snapshots — structurally unavailable from a static bench corpus. The bench fixture validates detector logic correctness; real-world efficacy is deferred. When the condition is met, re-run triage through the Spec 11 R5 recalibration pipeline.
264
+
265
+ #### R6: Bench Fixtures & Baseline
266
+
267
+ - **New corpus** `bench/corpus/diverging-clones/`: Fixture files (`clone_a.ts`, `clone_b.ts`) with seeded `dry_pair_history` rows simulating a tracked pair with declining similarity (0.85 → 0.78 → 0.68) across three runs.
268
+ - **Bench runner** (`runBench.ts`): `diverging-clones` entry with in-memory `dry_pair_history` seeding → violation detection → F1/recall/precision computation.
269
+ - **Baseline** (`baseline.json`): `diverging-clones` entry with `dry/diverging-clone` rule at F1=1.0.
270
+ - **Bench test** (`bench.test.ts`): Updated to 11 analyzers.
271
+
272
+ ### Changed Files
273
+
274
+ | File | Change |
275
+ |------|--------|
276
+ | `src/types.ts` | `ChurnConfig`, `HotspotEntry`, `TrendSummary`, `DivergenceConfig` types; `hotspot` field on `Violation` |
277
+ | `src/codeIndexDB.ts` | SCHEMA_VERSION → 5, `file_churn`, `function_churn`, `dry_pair_history` tables, migration 4→5 |
278
+ | `src/churn/churnExtractor.ts` | **New** — git shell-out for per-file and per-function churn |
279
+ | `src/hotspots/hotspotScorer.ts` | **New** — percentile math, hotspot scoring, bus-factor detection |
280
+ | `src/auditRunner.ts` | Hotspot-based finding reordering, hotspot field attachment, two-phase diverging-clone tracking (seed + re-measure) |
281
+ | `src/ledger.ts` | `getTrends()` — same-target full-run fingerprint trend comparison |
282
+ | `src/cli.ts` | `hotspots` command, `ledger trends` subcommand |
283
+ | `src/config/defaults.ts` | Churn and divergence configs |
284
+ | `src/reporting/jsonReportGenerator.ts` | `hotspot` field in output |
285
+ | `src/reporting/htmlReportGenerator.ts` | `hotspot` field in output |
286
+ | `src/reporting/csvReportGenerator.ts` | `hotspot` field in output |
287
+ | `src/reporting/sarifReportGenerator.ts` | `hotspot` field in `properties` |
288
+ | `bench/corpus/diverging-clones/` | **New** — bench fixture project + expected.json |
289
+ | `bench/baselines/baseline.json` | Add diverging-clones analyzer baseline |
290
+ | `src/scripts/runBench.ts` | Diverging-clones runner with in-memory seed data |
291
+ | `src/__tests__/bench.test.ts` | Updated to 11 analyzers |
292
+ | `SKILL.md` | Hotspot + trends workflows |
293
+
294
+
295
+ ### Spec-14: Graph & Architecture Metrics — Call Graphs, Centrality, Community Detection, and Martin Instability
296
+
297
+ Spec 14 adds network analysis to the code auditor: call-graph construction, centrality ranking (PageRank + betweenness), community detection vs directory structure, Martin instability metrics, DOT/Mermaid output, and blast-radius estimates in the hook path. All output is advisory — reports and annotations only, zero violations.
298
+
299
+ #### R1: Graph Construction and Caching
300
+
301
+ - **`src/graph/callGraph.ts`** — `buildCallGraph(db)`: Constructs the function call graph from `function_calls` joined with `functions`. Resolves `callee_name` TEXT → `functions.id` via name join. Edge weight = call-site count (duplicate `(caller_id, callee_name)` rows aggregate). Reports `unresolvedShare` for calls to symbols not in the index.
302
+ - **`src/graph/importGraph.ts`** — `buildImportGraph(db)`: Derives file-level imports by aggregating `function_dependencies` joined with `functions.file_path`. Resolves dependencies using 4 strategies: exact match, relative path resolution, module name matching (packages), and fuzzy path matching.
303
+ - **`graph_cache` table** (schema v6): Persistent SQLite cache for adjacency, populated after each full sync and rebuilt entirely on each scoped sync. Columns: `graph_type` ('call' or 'import'), `node_key`, `neighbor_key`, `weight`. Stale edges cleared on rebuild — no accumulation.
304
+ - **Schema migration 5→6**: Creates `graph_cache` table with primary key on `(graph_type, node_key, neighbor_key)`.
305
+ - **Incremental scoped-sync**: Cache rebuilt from scratch on each sync via `populateCallGraphCache(db)` and `populateImportGraphCache(db)` called from `deepSync()`.
306
+
307
+ #### R2: Centrality and Risk Ranking
308
+
309
+ - **`computePageRank(adjacency, damping=0.85, convergence=1e-6)`**: Standard iterative PageRank on weighted directed graph. Initializes all nodes to 1/N, iterates until max change < convergence (capped at 100). Handles dangling nodes with uniform teleportation distribution.
310
+ - **`computeBetweenness(adjacency, nodeIds)`**: Brandes exact algorithm for N ≤ 2000 nodes. Brandes-Pich pivot sampling above cap. Uses directed edge traversal (BFS on outgoing edges only). Pivot count reported in output.
311
+ - **`computeRisk(db, adjacency, nodeIds, nodeNames, nodePaths)`**:
312
+ - Percentile math: `(rank - 1) / (total - 1)` for PageRank, betweenness, and complexity
313
+ - Untested detection: 2-hop transitive caller search via graph cache; if no caller file matches test globs (`**/*.{test,spec}.*`, `**/__tests__/**`) → untested
314
+ - Formula: `risk = max(pagerank%, betweenness%) × complexity% × (1 + untested)` where untested = 1 if true, 0 otherwise
315
+ - Returns `RiskEntry[]` sorted by risk descending
316
+ - **`code-audit risk` CLI**: `risk [--limit <n>] [--json] [--path <dir>] [--format dot]` — ranked table with PageRank%, Betweenness%, Complexity%, Untested, Risk Score. `--format dot` emits call-graph neighborhood (depth 2) of top-N risk functions.
317
+
318
+ #### R3: Community Detection vs Directory Structure
319
+
320
+ - **`detectCommunities(adjacency, filePaths)`**: Louvain two-phase greedy modularity optimization. Converts directed graph to undirected (summing weights). Phase 1: greedy node movement with strict `gain > 0`. Phase 2: community aggregation. Iterates until modularity gain < 1e-5. Returns `CommunityResult` with `communities` map, `communityCount`, and `modularity`.
321
+ - **`computeDirectoryPurity(communities, filePaths)`**: Per-directory purity (share of files in plurality community), weighted agreement score, split candidates (directories spanning ≥2 communities with ≥5 files each), merge candidates (one community dominating ≥2 directories).
322
+ - **`code-audit architecture` CLI**: `architecture [--json] [--path <dir>] [--format dot|mermaid]` — directory purity table, main-sequence distance table, split/merge candidates. `--format` emits import graph colored by community.
323
+
324
+ #### R4: Instability and Abstractness (Martin Metrics)
325
+
326
+ - **`computeMartinMetrics(db, importGraph)`**: Per-directory Ce (efferent couplings), Ca (afferent couplings), I = Ce/(Ca+Ce), A from per-file AST scan of export type/interface declarations, D = |A+I-1|. Returns `MartinEntry[]` sorted by D descending.
327
+ - **Abstractness verification**: Per-file AST scan counts `export type` and `export interface` declarations. Dead-path guard: bench fixture includes `src/interfaces/payments.ts` with `export interface IPaymentProcessor` — test asserts `abstractness > 0`.
328
+ - Included in `code-audit architecture` output and `code_map` `architecture` section.
329
+
330
+ #### R5: Graph Output Formats
331
+
332
+ - **`src/graph/outputFormatter.ts`** — `toDot(graph, options?)`: Standard DOT format with community-based node coloring, legend, edge labels with weight. `toMermaid(graph, options?)`: Mermaid `graph TD` with `classDef`/`class` for community styling. Zero rendering dependencies — pure string emission.
333
+
334
+ #### R6: Blast Radius in Hook Path
335
+
336
+ - **`src/graph/blastRadius.ts`** — `computeImpact(db, functionIds)`: Recursive CTE against `graph_cache` to walk the caller graph outward (depth-capped at 10). Counts `is_exported=1` rows among reachable callers. Cost scales with BFS neighborhood size, not codebase size.
337
+ - **Hook path integration** (`auditRunner.ts`): After `detectChangedFunctions()` in diff-scoped audit, calls `computeImpact()`. Measured with `performance.now()` — if >100ms, emits warning and skips annotation (disabled-by-default when over budget). Human output: "reaches N callers, M exports" per changed function.
338
+
339
+ #### Bench Fixture
340
+
341
+ - **`bench/corpus/graph/`**: Synthetic source files producing known call graph and import graph structures:
342
+ - `src/core.ts`: High-PageRank hub function
343
+ - `src/bridge.ts`: High-betweenness bridge function
344
+ - `src/untested.ts`: Central function with no test coverage
345
+ - `src/module_a/a1.ts`, `src/module_a/a2.ts`: Community A
346
+ - `src/module_b/b1.ts`, `src/module_b/b2.ts`: Community B
347
+ - `src/module_c/c_a.ts`, `src/module_c/c_b.ts`: Community C split across directory boundary
348
+ - `src/interfaces/payments.ts`: Exported interfaces for A > 0 assertion
349
+ - `expected.json`: `kind: "metrics"` with `expectedMetrics` range assertions (communityCount, abstractness > 0, etc.)
350
+ - **Bench runner**: `graph` entry in `buildAnalyzers()` with expectedMetrics range checks
351
+ - **Baseline**: `graph` entry in `baseline.json` (empty rules, metrics-only)
352
+
353
+ #### Unit Tests (51 tests across 3 files)
354
+
355
+ - **`src/graph/__tests__/callGraph.test.ts`** (23 tests): PageRank on 3-node chain, 4-node converging graph, convergence within few iterations; Brandes exact betweenness on 5-node path, star graph with bidirectional edges, disconnected graph; risk formula — percentile math, untested penalty, field validation; buildCallGraph — node IDs, names, paths, adjacency, duplicate call site weight; buildCallGraphFromCache.
356
+ - **`src/graph/__tests__/importGraph.test.ts`** (17 tests): buildImportGraph — file nodes, intra-module imports, empty DB; detectCommunities — two-cluster graph, positive gain merging, empty/single-node graphs; computeDirectoryPurity — aligned communities, split detection, weighted agreement; computeMartinMetrics — Ce/Ca/I/D, abstractness > 0 guard, concrete-only A=0, distanceFromMain sorting.
357
+ - **`src/graph/__tests__/graphCache.test.ts`** (11 tests): populateCallGraphCache — edge correctness, weight=1, duplicate aggregation, stale edge clearance; populateImportGraphCache — edge correctness, stale clearance; incremental update simulation — new functions/calls, removed calls, new dependencies, empty rebuild, cache matches direct build.
358
+
359
+ ### Changed Files
360
+
361
+ | File | Change |
362
+ |------|--------|
363
+ | `src/types.ts` | Add `RiskEntry`, `DirectoryPurity`, `MartinEntry`, `BlastRadiusImpact`, `GraphStats`, `CallGraph`, `ImportGraph`, `CommunityResult`, `PurityResult` |
364
+ | `src/codeIndexDB.ts` | SCHEMA_VERSION → 6, `graph_cache` table, migration 5→6, `getGraphStats()` |
365
+ | `src/graph/callGraph.ts` | **New** — buildCallGraph, computePageRank, computeBetweenness, computeRisk, populateCallGraphCache, buildCallGraphFromCache |
366
+ | `src/graph/importGraph.ts` | **New** — buildImportGraph, detectCommunities, computeDirectoryPurity, computeMartinMetrics, populateImportGraphCache, buildImportGraphFromCache |
367
+ | `src/graph/outputFormatter.ts` | **New** — toDot, toMermaid (string emission) |
368
+ | `src/graph/blastRadius.ts` | **New** — computeImpact (recursive CTE, not full adjacency load) |
369
+ | `src/graph/__tests__/callGraph.test.ts` | **New** — 23 tests: PageRank, Brandes, risk, buildCallGraph, cache |
370
+ | `src/graph/__tests__/importGraph.test.ts` | **New** — 17 tests: Louvain, Martin metrics, A > 0, import graph |
371
+ | `src/graph/__tests__/graphCache.test.ts` | **New** — 11 tests: cache population, incremental update simulation |
372
+ | `src/auditRunner.ts` | Blast radius integration in scoped audit path |
373
+ | `src/cli.ts` | `index status` subcommand, `risk` command, `architecture` command |
374
+ | `src/config/defaults.ts` | Graph config (betweennessExactNodeCap, blastRadiusEnabled, etc.) |
375
+ | `src/services/CodeMapGenerator.ts` | `risk` and `architecture` sections (conditional, try/catch) |
376
+ | `bench/corpus/graph/` | **New** — bench fixture with synthetic graph + expectedMetrics |
377
+ | `bench/baselines/baseline.json` | Add `graph` entry (empty rules, metrics-only) |
378
+ | `src/scripts/runBench.ts` | Graph runner with expectedMetrics range assertions |
379
+ | `src/__tests__/bench.test.ts` | Updated to 12 analyzers |
380
+ | `SKILL.md` | `risk` and `architecture` command docs |
381
+
382
+ ### Spec-11 R5 Recalibration Audit (2026-07-20)
383
+
384
+ Spec 11 R5's mechanical recalibration was applied to `defaults.ts` as part of Spec-11 closure. A subsequent audit of the recalibration table against external corpus evidence identified a pipeline defect — **"TBU Cliff + Single-Corpus Overfit"** — described in `bench/results/spec-11-recalibration-audit.md`. The recalibration has been corrected:
385
+
386
+ **Pipeline defect**: The judged-true formula `true / (true + false)` excludes TBU findings from both numerator and denominator. Real findings classified as TBU (because they're "not worth fixing on THIS corpus") contribute nothing to keeping a rule alive. The self-audit corpus is adversarial for data-access rules — the tool's own source contains SQL pattern-matching logic that the detector misreads as database calls. On an external corpus (27-sample Gin-like triage), `loop-query` scored 50% judged-true vs 0% on self-audit.
387
+
388
+ **Severity corrections in `defaults.ts`**:
389
+
390
+ | Rule | Pre-audit | Post-audit | Δ | Rationale |
391
+ |------|----------|------------|---|-----------|
392
+ | `missing-org-filter` | off | **suggestion** | ↑ | Domain mismatch confirmed for non-SaaS, but must remain visible for multi-tenant apps |
393
+ | `unknown-table` | off | **suggestion** | ↑ | Requires user-provided schema; must remain re-enablable |
394
+ | `sql-injection-risk` | off | **suggestion** (restored) | ↑ | 50% judged-true on external corpus; self-audit scores were dogfooding artifacts |
395
+ | `loop-query` | off | **warning** (restored) | ↑ | 50% judged-true on external corpus with confirmed production N+1s |
396
+ | `unfiltered-query` | off | **suggestion** (restored) | ↑ | Insufficient external evidence to disable; keep at suggestion pending validation |
397
+ | `direct-sql` | off | **suggestion** (restored) | ↑ | May have value on external corpora; restore pending evidence |
398
+ | `single-responsibility` | **critical** | **warning** (restored) | ↓ | 0.98 judged-true but length heuristics should not block hooks |
399
+ | `solid/class-size` | warning | **warning** (promoted) | = | 1.00/1.00 on 27 findings; one-tier promotion correct |
400
+ | `dependency-inversion` | warning | **warning** (promoted) | = | 1.00/1.00 on 16 findings; one-tier promotion correct |
401
+
402
+ Net effect: 6 rules restored from disabled, 1 promotion reversed, 2 promotions retained, 2 rules demoted to suggestion instead of off.
403
+
404
+ **Process amendments** (recorded in `bench/results/recalibration.md` Limitations):
405
+ - Multi-corpus validation required before disabling any rule globally
406
+ - Test-fixture findings excluded from judged-true denominator (calibration artifacts, not false positives)
407
+ - Heuristic promotion capped at warning tier — length/parameter/count rules should not block hooks
408
+ - Re-evaluate when ≥10 external-corpus findings exist for each data-access rule
409
+
410
+ ### Changed Files
411
+
412
+ | File | Change |
413
+ |------|--------|
414
+ | `src/config/defaults.ts` | Corrected `severityOverrides` (4 overrides, 5 restores); added audit report reference in comment |
415
+ | `bench/results/spec-11-recalibration-audit.md` | **New** — full audit report with per-finding triage data, pipeline defect analysis, external corpus cross-reference |
416
+ | `bench/results/recalibration.md` | Updated with corrected recalibration table, audit amendment note, TBU-cliff limitation documentation |
417
+
418
+ ### Spec-15: Cross-Domain Joins — Schema Lifecycle, Validation Bypass, and Coverage by Importance
419
+
420
+ Spec 15 adds five detectors that no single per-file analyzer can run alone. Each joins the SQLite index tables built by earlier specs — `schema_usage` (Spec 14), `graph_cache` (Spec 14), `hotspot_scores` (Spec 13), `coverage_data` (Spec 15 R4) — to produce findings at the system level. **All detectors enter at `suggestion` severity.**
421
+
422
+ #### R1: Schema Lifecycle Detection
423
+
424
+ Three detectors query `schema_usage` joined with `graph_cache` and `functions`:
425
+
426
+ - **Written-never-read** (`cross-domain/written-never-read`): Tables with INSERT/UPDATE/CREATE usage but zero SELECT. Catches write-only tables that may be abandoned or log sinks no one queries.
427
+ - **Read-never-written** (`cross-domain/read-never-written`): Tables with SELECT usage but zero INSERT/UPDATE/CREATE. Catches external-data reads where the codebase never writes — possible data-source documentation gaps.
428
+ - **Transaction-boundary risk** (`cross-domain/transaction-boundary-risk`): Functions writing ≥ `txnTableMax` (default 4) distinct tables, including callee tables via depth-1 BFS on `graph_cache`. Flags functions whose transaction scope is too wide (coordinator anti-pattern).
429
+
430
+ **New analyzer `CrossDomainAnalyzer`**: Extends `UniversalAnalyzer` with a full `analyze()` override — bypasses the per-file AST loop and queries the SQLite DB directly. Population happens in `UniversalSchemaAnalyzer.analyzeAST()`: after `findTableReferences()` extracts table names, each reference is written to `schema_usage` (idempotent per-file).
431
+
432
+ **Schema migration 6→7**: `schema_usage` table with columns `(table_name, file_path, function_name, usage_type, analyzer)`. Indexed on `(table_name, usage_type)`.
433
+
434
+ #### R2: ORM-Aware Schema Extraction
435
+
436
+ - **New module `src/analyzers/orm/`** — adapter registry pattern (same shape as `LanguageAdapter` registry):
437
+ - `OrmAdapter` interface: `extractTableReferences()` and `extractSchemaDefinitions()`
438
+ - **Drizzle adapter**: Detects `pgTable`/`mysqlTable`/`sqliteTable` schema definitions, `.select().from()` query chains
439
+ - **Prisma adapter**: Parses `schema.prisma` model definitions, `prisma.model.operation()` query patterns
440
+ - **Integration**: `UniversalSchemaAnalyzer.findTableReferences()` queries the ORM registry before falling back to SQL pattern detection
441
+
442
+ #### R3: Validation-Bypass Detection
443
+
444
+ **Detector** (`cross-domain/validation-bypass`): Flags functions that write data without reaching a validator, when their directory peers typically do.
445
+
446
+ **Primary — provenance-based**: Uses Spec 21's `VALIDATOR_PACKAGES` (zod, joi, ajv, valibot, class-validator, yup, typebox, superstruct, io-ts) to identify validators via import provenance. Per-identifier detection: a function is a validator iff `isValidatorProvenanced()` holds for usage *inside its body* (its own `used_imports` include a validator package), not merely because it cohabits a zod-importing file.
447
+
448
+ **Conjunctive fallback**: Only when zero provenance-detected validators exist AND no user config is provided → `name GLOB 'validate*' OR name GLOB 'assert*'` heuristics with downgraded confidence.
449
+
450
+ **Algorithm**: Groups writers (functions with INSERT/UPDATE/CREATE in `schema_usage`) by directory. For each directory with ≥ `minCorpus` (default 20) writers, BFS depth ≤ `depth` (default 3) through `graph_cache` call edges. If ≥ `modeShare` (default 0.8) of writers reach a validator, flags uncovered writers.
451
+
452
+ **Config** (`validatorBypass` in `CrossDomainConfig`): `modeShare` (0.8), `minCorpus` (20), `depth` (3).
453
+
454
+ #### R4: Coverage by Importance
455
+
456
+ - **New module `src/coverage/`** — LCOV (`.info`) and Istanbul (JSON) coverage format parsers with auto-detection
457
+ - **`coverage_data` table**: `(file_path, function_name, line_pct, branch_pct, statement_pct, function_pct, uncovered_lines, source_format)` — same schema as `hotspot_scores` with coverage columns
458
+ - **`code-audit coverage`** CLI: `coverage --import <path>` (auto-detect format, store in SQLite), `coverage --by-risk [--json]` (show coverage gaps ranked by hotspot score)
459
+ - **Detector** (`cross-domain/uncovered-risk`): Exported functions in the top `topRiskDecile` (default 0.1) of hotspot scores with no measured coverage → flag at `suggestion` severity. Coverage findings include `source_format` and `basis` (measured or static-reach) on every output surface. Stale coverage imports (>7 days since last import) produce a warning. **Static-reach fallback**: When no `coverage_data` exists, checks if each high-risk function is reachable from any test file via call-graph BFS.
460
+
461
+ #### R5: Bench Fixtures
462
+
463
+ - **New corpus `bench/corpus/cross-domain/`**: 8 fixture source files in directory-structured layout:
464
+ - `src/orders/orders.ts` — 7 writer functions, 4 reach validator → 3 bypass violations
465
+ - `src/validators/validators.ts` — zod-importing validator functions for provenance detection
466
+ - `src/audit/audit.ts` — read-only module (read-never-written)
467
+ - `src/sessions/sessions.ts` — isolated write-only module (written-never-read)
468
+ - `src/users/users.ts` — read+write module (no lifecycle violation)
469
+ - `src/risk/risk.ts` — high-risk functions (uncovered-risk)
470
+ - `src/tests/orders.test.ts` — test file providing call-graph edges
471
+ - **`expected.json`**: Metrics-only manifest (`kind: "metrics"`) with min-count ranges per detector. Vacuous precision/recall/F1=1.0000 (metrics-only: no expectedViolations list).
472
+ - **Bench runner**: Seeds `schema_usage` (11 entries), `graph_cache` (10 edges), `hotspot_scores` (5 entries), `coverage_data` (1 entry), and `functions` (16 functions) in-memory, then runs `CrossDomainAnalyzer.analyze()`.
473
+
474
+ ### Changed Files
475
+
476
+ | File | Change |
477
+ |------|--------|
478
+ | `src/analyzers/crossDomain/CrossDomainAnalyzer.ts` | **New** — post-analysis DB queries for 5 detectors |
479
+ | `src/analyzers/crossDomain/__tests__/CrossDomainAnalyzer.test.ts` | **New** — unit tests for R1+R3 detectors |
480
+ | `src/analyzers/orm/types.ts` | **New** — `OrmAdapter` interface |
481
+ | `src/analyzers/orm/adapterRegistry.ts` | **New** — ORM adapter registry |
482
+ | `src/analyzers/orm/drizzleAdapter.ts` | **New** — Drizzle ORM schema/query extraction |
483
+ | `src/analyzers/orm/prismaAdapter.ts` | **New** — Prisma ORM schema extraction |
484
+ | `src/analyzers/orm/index.ts` | **New** — ORM module barrel export |
485
+ | `src/analyzers/orm/__tests__/ormAdapters.test.ts` | **New** — unit tests for Drizzle + Prisma |
486
+ | `src/coverage/lcovParser.ts` | **New** — LCOV `.info` parser |
487
+ | `src/coverage/istanbulParser.ts` | **New** — Istanbul JSON parser |
488
+ | `src/coverage/coverageService.ts` | **New** — coverage storage/query in SQLite |
489
+ | `src/coverage/__tests__/parsers.test.ts` | **New** — unit tests for coverage parsers |
490
+ | `src/types.ts` | Add `CrossDomainConfig`, `CoverageEntry`, `OrmAdapter`/`OrmTableReference` types |
491
+ | `src/codeIndexDB.ts` | SCHEMA_VERSION → 7, `schema_usage` + `coverage_data` tables, migration 6→7 |
492
+ | `src/analyzers/universal/UniversalSchemaAnalyzer.ts` | schema_usage recording, `txnTableMax` config field |
493
+ | `src/auditRunner.ts` | Cross-domain analyzer entry, config forwarding |
494
+ | `src/config/defaults.ts` | Cross-domain + coverage configs |
495
+ | `src/cli.ts` | `coverage --import` and `coverage --by-risk` commands |
496
+ | `src/services/CodeMapGenerator.ts` | Coverage-by-risk section |
497
+ | `src/scripts/runBench.ts` | Cross-domain bench runner with in-memory seed data |
498
+ | `bench/corpus/cross-domain/` | **New** — bench corpus + expected.json |
499
+ | `bench/baselines/baseline.json` | Add cross-domain analyzer baseline |
500
+ | `src/__tests__/bench.test.ts` | Updated to 10 analyzers |
501
+
502
+ ## [3.2.0] — 2026-07-23
503
+
504
+ ### Spec-21: Language-Neutral Detection — Provenance-Based DB Detection
505
+
506
+ Provenance-based detection replaces English name-list matching (`dbReceiverNames`) as the primary mechanism for identifying database handles. Instead of asking "is this variable named `db`?", the system asks "where did this variable's value come from?" An identifier is DB-provenanced if it came from: a known DB package import (`better-sqlite3`, `drizzle-orm`, `@prisma/client`, `pg`, `mysql2`, etc.), a `.prepare()`/`.exec()` chain on a provenanced receiver, a `D1Database`-annotated type, or an `env.DB` binding. Provenance propagates through assignment, destructuring, and cross-file export/import.
507
+
508
+ This makes detection work for any language — a Portuguese `banco`, Russian `база`, or German `datenbank` identifier is detected as long as it traces back to a known DB package import. The English name lists remain as fallbacks for codebases whose provenance is invisible (dynamic requires, injected globals).
509
+
510
+ #### R1: Provenance Resolver
511
+
512
+ - **New module `src/analyzers/provenance.ts`**: Shared detection utility consumed by both the schema and data-access analyzers.
513
+ - **`isDBProvenanced()`**: Given a call-expression AST node, determines if its callee is DB-provenanced via import tracing, binding detection, type annotation, or propagation.
514
+ - **`extractDBProvenancedImports()`**: Extracts all DB-provenanced identifiers from a file's imports by matching import specifiers against `DB_PACKAGES`.
515
+ - **`propagateProvenance()`**: Propagates provenance through assignment (`const x = drizzle(env.DB)`), destructuring, class field initialization, default parameters, and type annotations.
516
+ - **`ProvenanceContext`**: Built once per file, cached for all analyzer calls on that file. Holds the resolved set of DB-provenanced and validator-provenanced identifiers with evidence chains.
517
+ - **`ProvenanceEvidence`**: Records the reason (`package`, `binding`, `type`, `propagation`, `fallback`), source (e.g., "named import from drizzle-orm"), and chain of propagation for each provenanced identifier.
518
+
519
+ #### R2: Conjunctive Inference
520
+
521
+ - **Conjunctive guard**: A variable is DB-provenanced ONLY through provenance-linked evidence. Rules that do NOT qualify: name alone (a variable named `database` without provenance → NO), method alone (`.first()` without DB-provenanced receiver → NO), Map named `database` with `.first()` calls → zero violations.
522
+ - **`inferReceivers()`**: During full sync, finds call expressions where the method name matches `DB_CALL_METHODS` AND the receiver traces to a provenanced source through assignment chains. Adds intermediate identifiers to the inferred set.
523
+ - **`config detection`**: New CLI command showing the resolved provenance set with per-entry evidence, including `reason` and `chain` fields. Visible fallback entries (`reason: 'fallback'`) signal "caught by name, not provenance."
524
+ - **Cross-file provenance**: Stored in `metadata_json` column of the `functions` table during sync. Scoped runs (hook path) consume stored provenance; full-sync runs may use on-demand reads. Hook-latency measurement (`provenanceResolutionMs`) tracked on every scoped run per Spec 14 R6.2 precedent.
525
+
526
+ #### R3: Detection Modes
527
+
528
+ A single shared `detection.mode` config key replaces the planned per-analyzer mode configs:
529
+
530
+ | Mode | Behavior |
531
+ |------|----------|
532
+ | `hybrid` (default) | Provenance-primary + conjunctive name-fallback. Provenance resolves first; unresolved identifiers matching `dbReceiverNames` or `dbBindingNames` get `reason: 'fallback'`. |
533
+ | `provenance` | Strict provenance only. Never consults name lists. For codebases with fully visible provenance chains. |
534
+ | `names` | Legacy English-only name matching. Opt-in escape hatch for users who need the old behavior unchanged. |
535
+
536
+ #### R4: Validator Provenance
537
+
538
+ - **`VALIDATOR_PACKAGES`**: `zod`, `joi`, `ajv`, `valibot`, `yup`, `superstruct`, `arktype`, `@sinclair/typebox`, `class-validator`.
539
+ - **`extractValidatorProvenancedImports()`**: Same pattern as DB provenance extraction but for validator packages.
540
+ - **Infrastructure ready for Spec 15**: Validator provenance is computed and stored; the `validate*`/`assert*` name heuristic is defined for the validator-bypass detector in Spec 15.
541
+ - **Config**: `validatorPackageList` in `defaults.ts` (shipped list, user-extensible). Detection mode is the shared `detection.mode` key.
542
+
543
+ #### R5: Unicode Identifier Correctness
544
+
545
+ - **QueryParser camelCase splitting** (line 554): `/(?=[A-Z])/` → `/(?=\p{Lu})/u` — handles all Unicode uppercase.
546
+ - **QueryParser token matching** (line 286): `\w+` → `[\p{L}\p{N}_]+` — matches non-Latin characters.
547
+ - **codeIndexDB-enhanced camelCase breakdown** (line 583): `/([A-Z])/g` → `/(\p{Lu})/gu`.
548
+ - **ruleEngine exported symbol extraction** (lines 489-514): `\w` → `[\p{L}\p{N}_]` with `u` flag in all three regex patterns.
549
+ - **Non-Latin unclassifiable guard**: The naming analyzer treats identifiers containing characters outside `[\p{Script=Latin}\p{N}_$]` as unclassifiable — returns zero violations instead of flagging what it cannot parse.
550
+
551
+ #### R6: Fixtures and Spec 11 Amendment
552
+
553
+ - **7 new fixtures** in `src/__tests__/fixtures/spec-21/`:
554
+ - `banco-provenance.ts` — Portuguese identifier, provenance-only detection
555
+ - `cyrillic-ids.ts` — Cyrillic identifier "база", Unicode correctness end-to-end
556
+ - `map-named-database.ts` — conjunctive guard (Map named `database` → zero violations)
557
+ - `fallback-global.ts` — injected global caught under hybrid mode via name fallback
558
+ - `validator-zod-portuguese.ts` — validator recognized via provenance
559
+ - `cyrillic-naming.ts` — Cyrillic exports → unclassifiable → zero naming violations
560
+ - `cross-file-provenance/provider.ts` + `consumer.ts` — export/import provenance chain
561
+ - **Spec 11 amendment**: Bench corpus gains a non-English-identifier fixture project (mixed Portuguese/German/Japanese identifiers, DB access via provenance only). Per-rule precision/recall is reported on it alongside the English corpora. Detection gap between the two is a release-blocking finding.
562
+
563
+ ### Changed Files
564
+
565
+ | File | Change |
566
+ |------|--------|
567
+ | `src/analyzers/provenance.ts` | **New** — core provenance module (package lists, extraction, propagation, inference) |
568
+ | `src/analyzers/universal/UniversalDataAccessAnalyzer.ts` | Replace `isDBCallee()`, `isDbCallNode()`, `isOrmPattern()` with provenance-based detection |
569
+ | `src/analyzers/universal/UniversalSchemaAnalyzer.ts` | Replace `passesFileGate()`, `isDbMemberCall()` with provenance calls |
570
+ | `src/config/defaults.ts` | Add `detection: { mode: 'hybrid' }` default; add `validatorPackageList` default |
571
+ | `src/auditRunner.ts` | Wire provenance context and detection config into analyzer config |
572
+ | `src/types.ts` | `ProvenanceEvidence`, `DetectionConfig` interfaces |
573
+ | `src/cli.ts` | `config detection` command |
574
+ | `src/codeIndexDB.ts` | Add `provenance` field to metadata_json |
575
+ | `src/search/QueryParser.ts` | Unicode-aware regexes (R5) |
576
+ | `src/codeIndexDB-enhanced.ts` | Unicode-aware camelCase breakdown (R5) |
577
+ | `src/invariants/ruleEngine.ts` | Unicode-aware regex + non-Latin unclassifiable guard (R5) |
578
+ | `src/__tests__/fixtures/spec-21/` | **New** — 7 fixture files |
579
+ | `src/__tests__/provenance.test.ts` | **New** — unit + integration tests |
580
+
5
581
  ## [3.1.0] — 2026-07-20
6
582
 
7
583
  ### Spec-17: Signal Hotfix — Noise Reduction Across All Analyzers
8
584
 
9
- Large-scale noise reduction targeting all 6 analyzers based on a real-corpus diagnostic report (3,871 files, 6,159 functions, 26,119 findings — ~96% noise). Every noise class in the diagnostic is addressed at the defect level.
585
+ Large-scale noise reduction targeting all 6 analyzers based on a real-corpus diagnostic report (3,871 files, 6,159 functions, 26,119 findings — ~96% noise). Every noise class in the diagnostic is addressed at the defect level. **R1 diagnosis**: The `sql-injection` rule in the schema analyzer used regex-based string-pattern matching across all source files, producing ~15,000 findings in the self-audit. Only a handful of those involved actual SQL-context string concatenation; the vast majority flagged template-literal interpolations inside non-SQL string expressions (logging, URLs, error messages). This was the single largest noise source in the corpus.
10
586
 
11
587
  #### R1: Documentation Analyzer
12
588
 
@@ -243,3 +819,150 @@ Complete re-architecture. The entire Spec 01–09 arc ships as a single breaking
243
819
  ### Mid-series note
244
820
 
245
821
  The internal version increments spec-architected for individual specs (2.7.0, 3.0.0–4.0.1) were never published to npm. The last published version before this release was 2.6.2. This 3.0.0 release absorbs the entire nine-spec arc into a single breaking release per Amendment A1.
822
+
823
+ ## [3.1.1] — 2026-07-20
824
+
825
+ ### Spec 11: Analyzer Quality Evaluation
826
+
827
+ Empirical measurement of every built-in rule's precision on real code. Four phases across three corpora (code-auditor self-audit, Gin web framework, Excalidraw whiteboard).
828
+
829
+ #### R1: Findings Ledger
830
+
831
+ - **`src/ledger/`**: Per-corpus, per-run, per-rule precision/recall/F1 ledger stored in the code index database. Every audit run records which rules fired, how many findings each produced, and (once triaged) how many were true/false/TBU.
832
+ - **Delta tracking**: Between-run diffs show which rules gained or lost precision. Used to detect regressions from rule changes.
833
+
834
+ #### R2: Benchmark Corpus and Harness
835
+
836
+ - **`bench/corpus/`**: 26 fixture projects (one per analyzer rule), each with an `expected.json` ground-truth file. Fixtures are hand-crafted to exercise exactly one rule's detection logic.
837
+ - **`bench/runBench.ts`**: Harness computing per-rule precision, recall, and F1 against ground truth. Outputs `bench/results/latest.json`.
838
+ - **`bench/baseline.json`**: Frozen precision/recall/F1 snapshot. A regression gate (`bench/regression.test.ts`) fails the build if any rule's F1 drops more than 0.02 below baseline.
839
+ - **Non-English corpus**: Mixed Portuguese/German/Japanese identifiers testing provenance-based detection. Detection gaps between English and non-English corpora are release-blocking (Spec 21 amendment).
840
+
841
+ #### R3: Empirical Threshold Tuning
842
+
843
+ - **Threshold sweeps**: Each numeric threshold (`maxFunctionLength`, `maxParameters`, `classMethodsThreshold`, `maxMethodComplexity`, `classAggregateComplexity`) swept across 5–8 values on the self-audit corpus. Per-value precision and yield recorded.
844
+ - **`bench/results/sweep-report.md`**: Sweep results with recommended values. Applied to `DEFAULT_ANALYZER_CONFIGS` where precision improves without substantial yield loss.
845
+ - **`very-complex-method.ts`**: Added to the SOLID bench corpus to close a detection gap at the `classAggregateComplexity` threshold.
846
+
847
+ #### R4: Real-Corpus Triage
848
+
849
+ - **Three-corpus triage**: 691 self-audit findings, 205 gin findings, 1,747 excalidraw findings classified as true / false / true-but-useless with one-sentence rationales.
850
+ - **Classification principles**: Test fixtures are false positives by definition. Domain mismatch (SaaS rules on CLI tools) is false. TBU covers JSDoc-on-everything, internal-tool N+1, time-correlated git signals.
851
+ - **`bench/results/triage-report.md`**: Per-analyzer, per-rule precision and judged-true rates with root-cause analysis.
852
+ - **`bench/results/triage-classified.json`**: 691 classified findings with verdict and rationale.
853
+
854
+ #### R5: Mechanical Recalibration
855
+
856
+ Binding recalibration rules applied to the self-audit triage results:
857
+
858
+ | Condition | Action |
859
+ |-----------|--------|
860
+ | precision ≥ 0.95 AND judged-true ≥ 0.90 | Promote one severity tier |
861
+ | judged-true < 0.50 | Disable by default (`off`) |
862
+ | n < 10 judged findings (T+F) | Exempt (insufficient sample) |
863
+
864
+ **6 rules disabled** (`missing-org-filter`, `unknown-table`, `sql-injection-risk`, `loop-query`, `unfiltered-query`, `direct-sql`): Domain mismatch (SaaS tenant isolation on a CLI tool), dogfooding artifacts (the tool's own SQL-pattern constants detected as queries), or findings confined to test fixtures.
865
+
866
+ **3 rules promoted**: `single-responsibility` (warning → critical, precision 0.98), `solid/class-size` (suggestion → warning, precision 1.00), `dependency-inversion` (suggestion → warning, precision 1.00).
867
+
868
+ **Guard rails**: Minimum 10 judged findings before recalibration applies. One-tier promotion only (no suggestion → critical in a single step). Rules exempt from recalibration remain at their current severity with a note that the sample is too small.
869
+
870
+ **Implementation**: `severityOverrides` on the default `AuditConfig` object. The `UniversalAnalyzer` base class filters `'off'`-severity violations before reporting. Users can override any rule's severity in their own `.codeauditor.json`.
871
+
872
+ #### R6: Honest Documentation
873
+
874
+ - **Deterministic vs advisory split**: README now documents which rules are structural facts and which are heuristic signals. Every disabled rule names the corpus where it *would* be useful.
875
+ - **Recalibration disclosure**: README names the three measurement corpora, the recalibration rules, and the re-enable path (`severityOverrides`).
876
+ - **`'off'` severity**: Documented as the opt-out mechanism. Setting a rule to `"off"` removes it from audit output entirely.
877
+ - **`severityOverrides` on `AuditConfig`**: New top-level config field for global per-rule severity overrides. Applied before per-file path profile caps.
878
+
879
+ ### Changed Files
880
+
881
+ | File | Change |
882
+ |------|--------|
883
+ | `src/ledger/findingsLedger.ts` | **New** — per-run, per-rule precision ledger |
884
+ | `src/ledger/delta.ts` | **New** — between-run delta computation |
885
+ | `bench/corpus/` | **New** — 26 per-analyzer fixture projects with `expected.json` |
886
+ | `bench/runBench.ts` | **New** — harness computing precision/recall/F1 |
887
+ | `bench/results/` | **New** — triage reports, recalibration table, sweep report |
888
+ | `src/types.ts` | `Severity` extended with `'off'`; `severityOverrides` added to `AuditConfig` |
889
+ | `src/languages/UniversalAnalyzer.ts` | Filter `'off'`-severity violations; preserve `errors` field |
890
+ | `src/config/defaults.ts` | `severityOverrides` in `getDefaultConfig()` with recalibration values |
891
+ | `src/analyzers/analyzerUtils.ts` | Severity maps include `off: 0` |
892
+ | `src/reporting/` (html, csv) | Severity maps include `off: 0` |
893
+ | `README.md` | Deterministic/advisory split; recalibration disclosure; re-enable path |
894
+ | `CHANGELOG.md` | Spec 11 entry (this section) |
895
+
896
+ ## [3.1.1] — 2026-07-20
897
+
898
+ ### Spec-18 R1/R6 follow-up: Baseline Fingerprint Scheme & Per-Analyzer Symbol Fixes
899
+
900
+ #### Baseline schemaVersion bump (v1 → v2)
901
+
902
+ - **schemaVersion 2**: Baseline fingerprint scheme revised for collision-resistant per-analyzer symbols.
903
+ - **Forward-compatibility**: v1 baselines are rejected with a clear message directing users to re-snapshot (`code-audit baseline`).
904
+ - **`missing-schemas`**: Single-fire config gate → `top-level:missing-schemas`.
905
+
906
+ #### Schema analyzer symbol overhaul
907
+
908
+ All three schema rules now use enclosing-function + ordinal symbols, matching the data-access analyzer scheme:
909
+
910
+ - **`sql-injection`**: Per-call-site regex detection with global matching; each match gets `{enclosingFn}:sql-injection` symbol (with ordinal for multiple matches in the same function).
911
+ - **`n-plus-one`**: `.map()`, `.forEach()`, and `for(...)` loop context detection around `.query()`/`.execute()` call sites; each gets `{enclosingFn}:n-plus-one` symbol with ordinal disambiguation.
912
+ - **`missing-schemas`**: Gate violation uses `top-level:missing-schemas` symbol.
913
+
914
+ Helpers added to `UniversalSchemaAnalyzer`:
915
+ - `findClosestNodeAt(root, location, adapter)` — finds deepest AST node containing a source position
916
+ - `findEnclosingFunctionName(node, adapter)` — walks parent chain to find enclosing function/method name
917
+ - `getNodeName(node, adapter)` — extracts human-readable name from AST node
918
+
919
+ #### Cross-surface fingerprint consistency
920
+
921
+ - **`projectTasks.ts`** (`from_audit`): Replaced divergent inline symbol extraction with canonical `extractSymbol()` from `symbols.ts`. The previous inline chain used a different priority order (`className` before `functionName`) and was missing `methodName` and `name` fields.
922
+ - **Cross-surface test** (`baseline.test.ts`): Replaced tautology test (comparing `fingerprint()` with itself) with proper cross-surface verification — creates Violation objects with diverse symbol-field configurations and verifies `extractSymbol()` + `fingerprint()` produce identical, stable hashes through all three pathways (baseline matching, from_audit task creation, SARIF output).
923
+
924
+ #### Spec 20 stray files removed
925
+
926
+ Stray Spec 20 files (`profileResolver.ts`, `profile.test.ts`, spec doc) removed — they imported nonexistent types from `types.ts` and had no git history. Spec 20 will be implemented under its own proper plan review.
927
+
928
+ ### Spec-19 Corrective Batch — July Close-Out
929
+
930
+ #### Item 1: Real Oracle Fixtures
931
+
932
+ Replaced the generic `oracle-rerun.test.ts` suite with 27 standalone fixture files, each structurally equivalent to the cited recall-corpus code. The 30-test suite (27 item tests + 3 extras) passes with the documented split: 13 fire, 17 silent (including 2 retired rules).
933
+
934
+ #### Item 2: method-complexity R1 Diagnosis
935
+
936
+ The per-node-shape complexity measurement (Spec-19 R1) fixed the class of false positives where complexity-1 functions containing `.map()` callbacks and SQL-query patterns were miscomputed as high complexity, including the "hero-repo.ts:83" repository-method shape — a single `db.query()` + `.map()` normalizer that the old walker over-counted by descending into callback AST subtrees. The Σ(lines/10) heuristic theory floated in the first close-out summary was wrong: that heuristic had already been replaced by Spec-17 R5 before the 3.1.1 triage that caught these findings — it cannot have caused complexity-1 findings observed on 3.1.1. Spec-19 R1's callback-descending walker fix is the correct diagnosis.
937
+
938
+ #### Item 3: n-plus-one / loop-query Rule Consolidation
939
+
940
+ The schema analyzer's regex-based `n-plus-one` rule and the data-access analyzer's AST-based `loop-query` rule both detected the same defect (N+1 database queries inside loops/map callbacks). Consolidated to a single emitter: the data-access analyzer's `loop-query` rule, which uses tree-sitter AST traversal for accurate loop-detection rather than 500-character text-window heuristics. The schema analyzer's `checkNPlusOne()` method and the `n-plus-one` rule ID have been retired. `data-access/loop-query` is now the canonical rule for N+1 query detection.
941
+
942
+ **Migration note**: Previously-baselined `n-plus-one` findings will churn to "fixed" / "new: `loop-query`" on the next audit run after upgrading — one-time noise. Users with `severityOverrides['n-plus-one']` must rename the key to `loop-query`:
943
+
944
+ ```json
945
+ // Before (schema analyzer, retired):
946
+ { "analyzerConfigs": { "schema": { "severityOverrides": { "n-plus-one": "critical" } } } }
947
+
948
+ // After (data-access analyzer, canonical):
949
+ { "analyzerConfigs": { "data-access": { "severityOverrides": { "loop-query": "critical" } } } }
950
+ ```
951
+
952
+ #### Item 4: Structural Similarity Contract
953
+
954
+ Structural similarity detection (`dry/structural-similarity`) remains **default-off** (`checkStructuralSimilarity: false`). The oracle suite confirms this contract: item 26 (CRUD handlers) produces 0 violations with defaults; item 27 (API version routers) fires at `suggestion` severity when enabled — confirming the strategist-manager shape is correctly detected when the user opts in. Both pass at HEAD.
955
+
956
+ #### Item 5: Hook-Script Transcripts from Foreign cwd
957
+
958
+ All three hook adapters verified as correctly forwarding the project root when invoked from a foreign cwd (a directory different from the project being audited):
959
+
960
+ - **`hook-audit.sh`** (Claude Code PostToolUse): Passes `-p "${CLAUDE_PROJECT_DIR}"` — the Claude Code runtime forwards `CLAUDE_PROJECT_DIR` on every hook invocation. Transcript confirms `projectRoot` resolves to the project, not the hook launch cwd.
961
+ - **`cursor.ts`** (`code-audit cursor-hook`): Priority chain `event.cwd` → `CLAUDE_PROJECT_DIR` → `process.cwd()`. Native Cursor supplies the correct `cwd` in the stdin event; Claude Code compat mode supplies `CLAUDE_PROJECT_DIR`. `workspace_roots` from the Cursor common schema is available but `event.cwd` (the hook-specific working directory) is the correct primary source — it points to the project root in single-root workspaces. Covered by 3 test cases in `cursor.spec.ts`.
962
+ - **`codex.ts`** (`code-audit codex-hook`): **Defect fixed** — was using `CLAUDE_PROJECT_DIR → process.cwd()` fallback, which is wrong for Codex-native invocations because Codex hooks don't set `CLAUDE_PROJECT_DIR`. Codex's common payload carries `cwd` (learn.chatgpt.com/docs/hooks). Resolution order is now `event.cwd → CLAUDE_PROJECT_DIR → process.cwd()` — matching the cursor.ts payload-first pattern. Refactored to export `processCodexEvent()` and `formatCodexFeedback()` for testability. New `codex.spec.ts` with 17 tests covering empty stdin, invalid JSON, no file path, critical → exit 2, warning → advisory, audit-throw → never-wedge, foreign cwd (`CLAUDE_PROJECT_DIR`), cwd fallback, `tool_input.path` fallback, payload-first resolution (`event.cwd`), env fallback when no `event.cwd`, and process.cwd() last resort. All 42 hook tests pass (25 cursor + 17 codex).
963
+
964
+ Real-payload transcripts with `event.cwd` in the Codex payload (no `CLAUDE_PROJECT_DIR` set) confirm all three hooks load the correct project root, code index, and config.
965
+
966
+ #### Item 6: Version Reconciliation
967
+
968
+ All corrective batch items (1–6) were developed on version 3.1.1 (the post-Spec-17 release baseline) on the `main` branch. No version discrepancy exists between `package.json` (3.1.1) and the CHANGELOG. Spec files reference planned ship versions (spec-04: v3.2.0, spec-05: v3.3.0, spec-11: v3.2.0) that were planning projections written ahead of implementation — the actual release cadence bundled multiple specs into fewer releases. Specs never touch version fields per the goal doc; the canonical version lives in `package.json` alone. The accumulated close-out changes are staged for the next release which should bump to at least 3.2.0 given the rule-ID consolidation (`n-plus-one` → `loop-query`), fingerprint-scheme changes, and hook-adapter refactoring included in this batch.