@vyuhlabs/dxkit 2.4.6 → 2.4.8

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 (357) hide show
  1. package/CHANGELOG.md +1076 -0
  2. package/README.md +132 -27
  3. package/dist/analysis-result.d.ts +112 -0
  4. package/dist/analysis-result.d.ts.map +1 -0
  5. package/dist/analysis-result.js +52 -0
  6. package/dist/analysis-result.js.map +1 -0
  7. package/dist/analyzers/bom/detailed.d.ts.map +1 -1
  8. package/dist/analyzers/bom/detailed.js +19 -0
  9. package/dist/analyzers/bom/detailed.js.map +1 -1
  10. package/dist/analyzers/bom/gather.d.ts +27 -26
  11. package/dist/analyzers/bom/gather.d.ts.map +1 -1
  12. package/dist/analyzers/bom/gather.js +26 -87
  13. package/dist/analyzers/bom/gather.js.map +1 -1
  14. package/dist/analyzers/bom/index.d.ts +0 -7
  15. package/dist/analyzers/bom/index.d.ts.map +1 -1
  16. package/dist/analyzers/bom/index.js +98 -48
  17. package/dist/analyzers/bom/index.js.map +1 -1
  18. package/dist/analyzers/bom/types.d.ts +11 -13
  19. package/dist/analyzers/bom/types.d.ts.map +1 -1
  20. package/dist/analyzers/cache.d.ts +95 -0
  21. package/dist/analyzers/cache.d.ts.map +1 -0
  22. package/dist/analyzers/cache.js +309 -0
  23. package/dist/analyzers/cache.js.map +1 -0
  24. package/dist/analyzers/coverage-runner.d.ts +56 -0
  25. package/dist/analyzers/coverage-runner.d.ts.map +1 -0
  26. package/dist/analyzers/coverage-runner.js +72 -0
  27. package/dist/analyzers/coverage-runner.js.map +1 -0
  28. package/dist/analyzers/dashboard/index.d.ts +24 -0
  29. package/dist/analyzers/dashboard/index.d.ts.map +1 -0
  30. package/dist/analyzers/dashboard/index.js +667 -0
  31. package/dist/analyzers/dashboard/index.js.map +1 -0
  32. package/dist/analyzers/developer/gather.d.ts.map +1 -1
  33. package/dist/analyzers/developer/gather.js +205 -37
  34. package/dist/analyzers/developer/gather.js.map +1 -1
  35. package/dist/analyzers/developer/index.d.ts +1 -1
  36. package/dist/analyzers/developer/index.d.ts.map +1 -1
  37. package/dist/analyzers/developer/index.js +21 -9
  38. package/dist/analyzers/developer/index.js.map +1 -1
  39. package/dist/analyzers/dispatcher.d.ts +52 -0
  40. package/dist/analyzers/dispatcher.d.ts.map +1 -1
  41. package/dist/analyzers/dispatcher.js +92 -9
  42. package/dist/analyzers/dispatcher.js.map +1 -1
  43. package/dist/analyzers/docs/shallow.d.ts +17 -5
  44. package/dist/analyzers/docs/shallow.d.ts.map +1 -1
  45. package/dist/analyzers/docs/shallow.js +65 -2
  46. package/dist/analyzers/docs/shallow.js.map +1 -1
  47. package/dist/analyzers/dx/shallow.d.ts +17 -5
  48. package/dist/analyzers/dx/shallow.d.ts.map +1 -1
  49. package/dist/analyzers/dx/shallow.js +66 -2
  50. package/dist/analyzers/dx/shallow.js.map +1 -1
  51. package/dist/analyzers/health/actions.d.ts +1 -1
  52. package/dist/analyzers/health/actions.d.ts.map +1 -1
  53. package/dist/analyzers/health/actions.js +27 -9
  54. package/dist/analyzers/health/actions.js.map +1 -1
  55. package/dist/analyzers/health/detailed.d.ts +2 -1
  56. package/dist/analyzers/health/detailed.d.ts.map +1 -1
  57. package/dist/analyzers/health/detailed.js +11 -7
  58. package/dist/analyzers/health/detailed.js.map +1 -1
  59. package/dist/analyzers/health.d.ts +27 -0
  60. package/dist/analyzers/health.d.ts.map +1 -1
  61. package/dist/analyzers/health.js +282 -34
  62. package/dist/analyzers/health.js.map +1 -1
  63. package/dist/analyzers/licenses/gather.d.ts +35 -8
  64. package/dist/analyzers/licenses/gather.d.ts.map +1 -1
  65. package/dist/analyzers/licenses/gather.js +86 -13
  66. package/dist/analyzers/licenses/gather.js.map +1 -1
  67. package/dist/analyzers/licenses/index.d.ts +1 -1
  68. package/dist/analyzers/licenses/index.d.ts.map +1 -1
  69. package/dist/analyzers/licenses/index.js +52 -11
  70. package/dist/analyzers/licenses/index.js.map +1 -1
  71. package/dist/analyzers/licenses/types.d.ts +15 -0
  72. package/dist/analyzers/licenses/types.d.ts.map +1 -1
  73. package/dist/analyzers/maintainability/shallow.d.ts +17 -5
  74. package/dist/analyzers/maintainability/shallow.d.ts.map +1 -1
  75. package/dist/analyzers/maintainability/shallow.js +80 -2
  76. package/dist/analyzers/maintainability/shallow.js.map +1 -1
  77. package/dist/analyzers/quality/detailed.d.ts.map +1 -1
  78. package/dist/analyzers/quality/detailed.js +4 -6
  79. package/dist/analyzers/quality/detailed.js.map +1 -1
  80. package/dist/analyzers/quality/gather.d.ts +1 -14
  81. package/dist/analyzers/quality/gather.d.ts.map +1 -1
  82. package/dist/analyzers/quality/gather.js +48 -137
  83. package/dist/analyzers/quality/gather.js.map +1 -1
  84. package/dist/analyzers/quality/index.d.ts +9 -2
  85. package/dist/analyzers/quality/index.d.ts.map +1 -1
  86. package/dist/analyzers/quality/index.js +197 -117
  87. package/dist/analyzers/quality/index.js.map +1 -1
  88. package/dist/analyzers/quality/shallow.d.ts +50 -5
  89. package/dist/analyzers/quality/shallow.d.ts.map +1 -1
  90. package/dist/analyzers/quality/shallow.js +155 -2
  91. package/dist/analyzers/quality/shallow.js.map +1 -1
  92. package/dist/analyzers/quality/types.d.ts +14 -0
  93. package/dist/analyzers/quality/types.d.ts.map +1 -1
  94. package/dist/analyzers/security/actions.d.ts +11 -4
  95. package/dist/analyzers/security/actions.d.ts.map +1 -1
  96. package/dist/analyzers/security/actions.js +87 -37
  97. package/dist/analyzers/security/actions.js.map +1 -1
  98. package/dist/analyzers/security/aggregator.d.ts +236 -0
  99. package/dist/analyzers/security/aggregator.d.ts.map +1 -0
  100. package/dist/analyzers/security/aggregator.js +349 -0
  101. package/dist/analyzers/security/aggregator.js.map +1 -0
  102. package/dist/analyzers/security/detailed.d.ts +2 -2
  103. package/dist/analyzers/security/detailed.d.ts.map +1 -1
  104. package/dist/analyzers/security/detailed.js +10 -9
  105. package/dist/analyzers/security/detailed.js.map +1 -1
  106. package/dist/analyzers/security/gather.d.ts +104 -1
  107. package/dist/analyzers/security/gather.d.ts.map +1 -1
  108. package/dist/analyzers/security/gather.js +299 -9
  109. package/dist/analyzers/security/gather.js.map +1 -1
  110. package/dist/analyzers/security/index.d.ts +15 -0
  111. package/dist/analyzers/security/index.d.ts.map +1 -1
  112. package/dist/analyzers/security/index.js +463 -50
  113. package/dist/analyzers/security/index.js.map +1 -1
  114. package/dist/analyzers/security/shallow.d.ts +50 -6
  115. package/dist/analyzers/security/shallow.d.ts.map +1 -1
  116. package/dist/analyzers/security/shallow.js +154 -2
  117. package/dist/analyzers/security/shallow.js.map +1 -1
  118. package/dist/analyzers/security/types.d.ts +51 -0
  119. package/dist/analyzers/security/types.d.ts.map +1 -1
  120. package/dist/analyzers/tests/detailed.d.ts.map +1 -1
  121. package/dist/analyzers/tests/detailed.js +2 -3
  122. package/dist/analyzers/tests/detailed.js.map +1 -1
  123. package/dist/analyzers/tests/gather.d.ts +2 -1
  124. package/dist/analyzers/tests/gather.d.ts.map +1 -1
  125. package/dist/analyzers/tests/gather.js +98 -69
  126. package/dist/analyzers/tests/gather.js.map +1 -1
  127. package/dist/analyzers/tests/index.d.ts +11 -2
  128. package/dist/analyzers/tests/index.d.ts.map +1 -1
  129. package/dist/analyzers/tests/index.js +83 -18
  130. package/dist/analyzers/tests/index.js.map +1 -1
  131. package/dist/analyzers/tests/shallow.d.ts +19 -5
  132. package/dist/analyzers/tests/shallow.d.ts.map +1 -1
  133. package/dist/analyzers/tests/shallow.js +89 -2
  134. package/dist/analyzers/tests/shallow.js.map +1 -1
  135. package/dist/analyzers/tests/types.d.ts +41 -1
  136. package/dist/analyzers/tests/types.d.ts.map +1 -1
  137. package/dist/analyzers/tools/autogen-header.d.ts +8 -0
  138. package/dist/analyzers/tools/autogen-header.d.ts.map +1 -0
  139. package/dist/analyzers/tools/autogen-header.js +107 -0
  140. package/dist/analyzers/tools/autogen-header.js.map +1 -0
  141. package/dist/analyzers/tools/cloc.d.ts.map +1 -1
  142. package/dist/analyzers/tools/cloc.js +36 -5
  143. package/dist/analyzers/tools/cloc.js.map +1 -1
  144. package/dist/analyzers/tools/deadline.d.ts +67 -0
  145. package/dist/analyzers/tools/deadline.d.ts.map +1 -0
  146. package/dist/analyzers/tools/deadline.js +81 -0
  147. package/dist/analyzers/tools/deadline.js.map +1 -0
  148. package/dist/analyzers/tools/debug-statements.d.ts +17 -0
  149. package/dist/analyzers/tools/debug-statements.d.ts.map +1 -0
  150. package/dist/analyzers/tools/debug-statements.js +58 -0
  151. package/dist/analyzers/tools/debug-statements.js.map +1 -0
  152. package/dist/analyzers/tools/default-exclusions.gitignore +28 -0
  153. package/dist/analyzers/tools/exclusions.d.ts +33 -6
  154. package/dist/analyzers/tools/exclusions.d.ts.map +1 -1
  155. package/dist/analyzers/tools/exclusions.js +95 -26
  156. package/dist/analyzers/tools/exclusions.js.map +1 -1
  157. package/dist/analyzers/tools/generic.d.ts +17 -2
  158. package/dist/analyzers/tools/generic.d.ts.map +1 -1
  159. package/dist/analyzers/tools/generic.js +206 -109
  160. package/dist/analyzers/tools/generic.js.map +1 -1
  161. package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
  162. package/dist/analyzers/tools/gitleaks.js +48 -1
  163. package/dist/analyzers/tools/gitleaks.js.map +1 -1
  164. package/dist/analyzers/tools/graphify.d.ts +30 -2
  165. package/dist/analyzers/tools/graphify.d.ts.map +1 -1
  166. package/dist/analyzers/tools/graphify.js +131 -15
  167. package/dist/analyzers/tools/graphify.js.map +1 -1
  168. package/dist/analyzers/tools/jscpd.d.ts +12 -2
  169. package/dist/analyzers/tools/jscpd.d.ts.map +1 -1
  170. package/dist/analyzers/tools/jscpd.js +129 -6
  171. package/dist/analyzers/tools/jscpd.js.map +1 -1
  172. package/dist/analyzers/tools/lint-label.d.ts +29 -0
  173. package/dist/analyzers/tools/lint-label.d.ts.map +1 -0
  174. package/dist/analyzers/tools/lint-label.js +23 -0
  175. package/dist/analyzers/tools/lint-label.js.map +1 -0
  176. package/dist/analyzers/tools/minified-detection.d.ts +9 -0
  177. package/dist/analyzers/tools/minified-detection.d.ts.map +1 -0
  178. package/dist/analyzers/tools/minified-detection.js +147 -0
  179. package/dist/analyzers/tools/minified-detection.js.map +1 -0
  180. package/dist/analyzers/tools/nuget-package-reference.d.ts +133 -0
  181. package/dist/analyzers/tools/nuget-package-reference.d.ts.map +1 -0
  182. package/dist/analyzers/tools/nuget-package-reference.js +177 -0
  183. package/dist/analyzers/tools/nuget-package-reference.js.map +1 -0
  184. package/dist/analyzers/tools/osv-scanner-deps.d.ts +3 -2
  185. package/dist/analyzers/tools/osv-scanner-deps.d.ts.map +1 -1
  186. package/dist/analyzers/tools/osv-scanner-deps.js +32 -14
  187. package/dist/analyzers/tools/osv-scanner-deps.js.map +1 -1
  188. package/dist/analyzers/tools/osv.d.ts +36 -0
  189. package/dist/analyzers/tools/osv.d.ts.map +1 -1
  190. package/dist/analyzers/tools/osv.js +26 -0
  191. package/dist/analyzers/tools/osv.js.map +1 -1
  192. package/dist/analyzers/tools/parallel.d.ts +1 -1
  193. package/dist/analyzers/tools/parallel.d.ts.map +1 -1
  194. package/dist/analyzers/tools/parallel.js +2 -2
  195. package/dist/analyzers/tools/parallel.js.map +1 -1
  196. package/dist/analyzers/tools/report-date.d.ts +17 -0
  197. package/dist/analyzers/tools/report-date.d.ts.map +1 -0
  198. package/dist/analyzers/tools/report-date.js +26 -0
  199. package/dist/analyzers/tools/report-date.js.map +1 -0
  200. package/dist/analyzers/tools/risk-score.d.ts +7 -0
  201. package/dist/analyzers/tools/risk-score.d.ts.map +1 -1
  202. package/dist/analyzers/tools/risk-score.js +9 -2
  203. package/dist/analyzers/tools/risk-score.js.map +1 -1
  204. package/dist/analyzers/tools/run-tests-helper.d.ts +43 -0
  205. package/dist/analyzers/tools/run-tests-helper.d.ts.map +1 -0
  206. package/dist/analyzers/tools/run-tests-helper.js +156 -0
  207. package/dist/analyzers/tools/run-tests-helper.js.map +1 -0
  208. package/dist/analyzers/tools/runner.d.ts.map +1 -1
  209. package/dist/analyzers/tools/runner.js +75 -12
  210. package/dist/analyzers/tools/runner.js.map +1 -1
  211. package/dist/analyzers/tools/semgrep.d.ts +39 -2
  212. package/dist/analyzers/tools/semgrep.d.ts.map +1 -1
  213. package/dist/analyzers/tools/semgrep.js +131 -9
  214. package/dist/analyzers/tools/semgrep.js.map +1 -1
  215. package/dist/analyzers/tools/timing.d.ts +17 -3
  216. package/dist/analyzers/tools/timing.d.ts.map +1 -1
  217. package/dist/analyzers/tools/timing.js +36 -14
  218. package/dist/analyzers/tools/timing.js.map +1 -1
  219. package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
  220. package/dist/analyzers/tools/tool-registry.js +11 -1
  221. package/dist/analyzers/tools/tool-registry.js.map +1 -1
  222. package/dist/analyzers/tools/tools-unavailable-prose.d.ts +18 -0
  223. package/dist/analyzers/tools/tools-unavailable-prose.d.ts.map +1 -0
  224. package/dist/analyzers/tools/tools-unavailable-prose.js +69 -0
  225. package/dist/analyzers/tools/tools-unavailable-prose.js.map +1 -0
  226. package/dist/analyzers/tools/upgrade-plan-resolver.d.ts.map +1 -1
  227. package/dist/analyzers/tools/upgrade-plan-resolver.js +7 -0
  228. package/dist/analyzers/tools/upgrade-plan-resolver.js.map +1 -1
  229. package/dist/analyzers/tools/vendored-advisor.d.ts +43 -0
  230. package/dist/analyzers/tools/vendored-advisor.d.ts.map +1 -0
  231. package/dist/analyzers/tools/vendored-advisor.js +107 -0
  232. package/dist/analyzers/tools/vendored-advisor.js.map +1 -0
  233. package/dist/analyzers/tools/walk-paths.d.ts +78 -0
  234. package/dist/analyzers/tools/walk-paths.d.ts.map +1 -0
  235. package/dist/analyzers/tools/walk-paths.js +150 -0
  236. package/dist/analyzers/tools/walk-paths.js.map +1 -0
  237. package/dist/analyzers/tools/walk-source-files.d.ts +70 -0
  238. package/dist/analyzers/tools/walk-source-files.d.ts.map +1 -0
  239. package/dist/analyzers/tools/walk-source-files.js +369 -0
  240. package/dist/analyzers/tools/walk-source-files.js.map +1 -0
  241. package/dist/analyzers/types.d.ts +204 -4
  242. package/dist/analyzers/types.d.ts.map +1 -1
  243. package/dist/analyzers/xlsx/bom.d.ts.map +1 -1
  244. package/dist/analyzers/xlsx/bom.js +8 -1
  245. package/dist/analyzers/xlsx/bom.js.map +1 -1
  246. package/dist/cli.d.ts.map +1 -1
  247. package/dist/cli.js +581 -189
  248. package/dist/cli.js.map +1 -1
  249. package/dist/detect.d.ts.map +1 -1
  250. package/dist/detect.js +24 -7
  251. package/dist/detect.js.map +1 -1
  252. package/dist/doctor.d.ts.map +1 -1
  253. package/dist/doctor.js +103 -53
  254. package/dist/doctor.js.map +1 -1
  255. package/dist/languages/capabilities/provider.d.ts +130 -1
  256. package/dist/languages/capabilities/provider.d.ts.map +1 -1
  257. package/dist/languages/capabilities/types.d.ts +68 -7
  258. package/dist/languages/capabilities/types.d.ts.map +1 -1
  259. package/dist/languages/csharp.d.ts +15 -1
  260. package/dist/languages/csharp.d.ts.map +1 -1
  261. package/dist/languages/csharp.js +624 -146
  262. package/dist/languages/csharp.js.map +1 -1
  263. package/dist/languages/go.d.ts.map +1 -1
  264. package/dist/languages/go.js +89 -11
  265. package/dist/languages/go.js.map +1 -1
  266. package/dist/languages/index.d.ts +132 -2
  267. package/dist/languages/index.d.ts.map +1 -1
  268. package/dist/languages/index.js +207 -0
  269. package/dist/languages/index.js.map +1 -1
  270. package/dist/languages/java.d.ts.map +1 -1
  271. package/dist/languages/java.js +113 -26
  272. package/dist/languages/java.js.map +1 -1
  273. package/dist/languages/kotlin.d.ts.map +1 -1
  274. package/dist/languages/kotlin.js +132 -26
  275. package/dist/languages/kotlin.js.map +1 -1
  276. package/dist/languages/python.d.ts.map +1 -1
  277. package/dist/languages/python.js +149 -44
  278. package/dist/languages/python.js.map +1 -1
  279. package/dist/languages/ruby.d.ts +39 -1
  280. package/dist/languages/ruby.d.ts.map +1 -1
  281. package/dist/languages/ruby.js +178 -44
  282. package/dist/languages/ruby.js.map +1 -1
  283. package/dist/languages/rust.d.ts.map +1 -1
  284. package/dist/languages/rust.js +103 -16
  285. package/dist/languages/rust.js.map +1 -1
  286. package/dist/languages/types.d.ts +228 -5
  287. package/dist/languages/types.d.ts.map +1 -1
  288. package/dist/languages/typescript.d.ts.map +1 -1
  289. package/dist/languages/typescript.js +201 -14
  290. package/dist/languages/typescript.js.map +1 -1
  291. package/dist/scoring/dimensions/documentation.d.ts +53 -0
  292. package/dist/scoring/dimensions/documentation.d.ts.map +1 -0
  293. package/dist/scoring/dimensions/documentation.js +106 -0
  294. package/dist/scoring/dimensions/documentation.js.map +1 -0
  295. package/dist/scoring/dimensions/dx.d.ts +53 -0
  296. package/dist/scoring/dimensions/dx.d.ts.map +1 -0
  297. package/dist/scoring/dimensions/dx.js +105 -0
  298. package/dist/scoring/dimensions/dx.js.map +1 -0
  299. package/dist/scoring/dimensions/maintainability.d.ts +53 -0
  300. package/dist/scoring/dimensions/maintainability.d.ts.map +1 -0
  301. package/dist/scoring/dimensions/maintainability.js +101 -0
  302. package/dist/scoring/dimensions/maintainability.js.map +1 -0
  303. package/dist/scoring/dimensions/quality.d.ts +108 -0
  304. package/dist/scoring/dimensions/quality.d.ts.map +1 -0
  305. package/dist/scoring/dimensions/quality.js +174 -0
  306. package/dist/scoring/dimensions/quality.js.map +1 -0
  307. package/dist/scoring/dimensions/security.d.ts +84 -0
  308. package/dist/scoring/dimensions/security.d.ts.map +1 -0
  309. package/dist/scoring/dimensions/security.js +135 -0
  310. package/dist/scoring/dimensions/security.js.map +1 -0
  311. package/dist/scoring/dimensions/testing.d.ts +56 -0
  312. package/dist/scoring/dimensions/testing.d.ts.map +1 -0
  313. package/dist/scoring/dimensions/testing.js +98 -0
  314. package/dist/scoring/dimensions/testing.js.map +1 -0
  315. package/dist/scoring/evaluator.d.ts +27 -0
  316. package/dist/scoring/evaluator.d.ts.map +1 -0
  317. package/dist/scoring/evaluator.js +124 -0
  318. package/dist/scoring/evaluator.js.map +1 -0
  319. package/dist/scoring/format.d.ts +34 -0
  320. package/dist/scoring/format.d.ts.map +1 -0
  321. package/dist/scoring/format.js +63 -0
  322. package/dist/scoring/format.js.map +1 -0
  323. package/dist/scoring/index.d.ts +37 -0
  324. package/dist/scoring/index.d.ts.map +1 -0
  325. package/dist/scoring/index.js +57 -0
  326. package/dist/scoring/index.js.map +1 -0
  327. package/dist/scoring/overall.d.ts +54 -0
  328. package/dist/scoring/overall.d.ts.map +1 -0
  329. package/dist/scoring/overall.js +76 -0
  330. package/dist/scoring/overall.js.map +1 -0
  331. package/dist/scoring/result.d.ts +111 -0
  332. package/dist/scoring/result.d.ts.map +1 -0
  333. package/dist/scoring/result.js +14 -0
  334. package/dist/scoring/result.js.map +1 -0
  335. package/dist/scoring/spec.d.ts +76 -0
  336. package/dist/scoring/spec.d.ts.map +1 -0
  337. package/dist/scoring/spec.js +22 -0
  338. package/dist/scoring/spec.js.map +1 -0
  339. package/dist/scoring/thresholds.d.ts +56 -0
  340. package/dist/scoring/thresholds.d.ts.map +1 -0
  341. package/dist/scoring/thresholds.js +75 -0
  342. package/dist/scoring/thresholds.js.map +1 -0
  343. package/dist/tools-cli.d.ts.map +1 -1
  344. package/dist/tools-cli.js +21 -2
  345. package/dist/tools-cli.js.map +1 -1
  346. package/dist/types.d.ts +16 -0
  347. package/dist/types.d.ts.map +1 -1
  348. package/package.json +1 -1
  349. package/templates/.claude/commands/dashboard.md +17 -9
  350. package/dist/analyzers/scoring.d.ts +0 -49
  351. package/dist/analyzers/scoring.d.ts.map +0 -1
  352. package/dist/analyzers/scoring.js +0 -422
  353. package/dist/analyzers/scoring.js.map +0 -1
  354. package/dist/analyzers/security/scoring.d.ts +0 -29
  355. package/dist/analyzers/security/scoring.d.ts.map +0 -1
  356. package/dist/analyzers/security/scoring.js +0 -40
  357. package/dist/analyzers/security/scoring.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,1082 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.4.8] - 2026-05-18
11
+
12
+ ### Summary
13
+
14
+ Focused patch release closing the regressions surfaced by a
15
+ post-2.4.7 user-simulation evaluation across the three external
16
+ audit repos. The biggest item is the structural follow-up to
17
+ D134 — the silent-health failure root-caused in 2.4.7 was a
18
+ real abandoned-Promise inside `runDetached`, but the underlying
19
+ class (unbounded await chain at the dispatcher level) had a
20
+ second failure mode that the 2.4.7 fix didn't reach. 2.4.8
21
+ closes it structurally. Plus: a date-rollover false-failure on
22
+ long runs, a Tools-used footer attribution drift, a cascade
23
+ warning when the analysis cache can't be built, and a README
24
+ upgrade-advisory correction. Tests: 1265 / 0 (up from 1241 at
25
+ the 2.4.7 baseline).
26
+
27
+ #### Per-provider deadline closes a second silent-health failure mode (D141)
28
+
29
+ D134 in 2.4.7 added a `settle()` guard plus a safety deadline
30
+ **inside** `runDetached` so that exit / error / safety-deadline
31
+ each force the subprocess Promise to resolve. That closed the
32
+ shape where a `runDetached` Promise itself stayed pending. But
33
+ a post-ship user-simulation reproduced the same silent-rc=0
34
+ behavior on a JS-heavy customer frontend audit — and this time
35
+ the runDetached safety deadline did not fire, because the
36
+ abandoned Promise was not inside `runDetached` at all. It was
37
+ inside the capability dispatcher's `Promise.allSettled` over
38
+ nine providers: one of those providers' `gatherOutcome` chains
39
+ contained a Promise that never settled, `Promise.allSettled`
40
+ cannot collapse an unsettled Promise, the whole
41
+ `gatherCapabilityReport` stayed pending forever, Node's event
42
+ loop emptied and the parent saw a clean rc=0 with no markdown
43
+ written.
44
+
45
+ Fix (commit `611321d`):
46
+
47
+ - New `src/analyzers/tools/deadline.ts` with a
48
+ `withDeadline(promise, deadlineMs)` helper that races any
49
+ Promise against a timer.
50
+ - The dispatcher (`src/analyzers/dispatcher.ts`) wraps every
51
+ provider's `gather` / `gatherOutcome` call in a 720-second
52
+ deadline (`DEFAULT_PROVIDER_DEADLINE_MS`). A stalled provider
53
+ is materialised as a skipped source with reason
54
+ `"stalled at >Ns (deadline)"` that flows through the existing
55
+ availability machinery into the `Tools unavailable` surface.
56
+ A stderr line names the stalled capability + source so the
57
+ abandoned-Promise location is visible in `--verbose` and CI
58
+ logs.
59
+ - The two non-dispatcher gathers
60
+ (`gatherDepVulnsWithAvailability` and
61
+ `gatherLicensesWithAvailability`) iterate active packs
62
+ themselves; both apply the same per-pack deadline pattern.
63
+ - New `DispatcherOptions` fields (`providerDeadlineMs`,
64
+ `onProviderStall`) so tests can wrap deadlines around 50-ms
65
+ stubs without polluting test output. Default `onProviderStall`
66
+ emits the stderr notification.
67
+ - New regression test
68
+ (`test/dispatcher-deadline.test.ts`, 7 cases) exercises the
69
+ helper directly, the dispatcher with one hung + one good
70
+ provider, the all-hung case, the bounded wall-clock claim,
71
+ and confirms thrown-provider rejections still route through
72
+ `onProviderError` (not `onProviderStall`).
73
+
74
+ Verification on the failure repo:
75
+
76
+ - Pre-fix (2.4.7 user-sim): `report` exited 1 after ~1428 s;
77
+ Health step hung in the capabilities Promise.all and never
78
+ wrote `health-audit-*.md`; orchestrator's 2.4.7
79
+ defense-in-depth guard surfaced the ✗ but the underlying
80
+ hang remained.
81
+ - Post-fix: `report` exited 0 in 1264.5 s; all 8 steps wrote
82
+ their reports; one stderr line attributed the stall to the
83
+ typescript-pack licenses provider walking a deep
84
+ `node_modules` tree — the reproducible offender behind the
85
+ intermittent hang. The Licenses report's framing notice
86
+ reads `typescript: stalled at >720s (deadline)` so the
87
+ customer sees what to act on.
88
+
89
+ The class is now closed by construction: a never-settling
90
+ provider can no longer keep `Promise.allSettled` pending
91
+ forever; the worst-case behaviour is one capability surfacing
92
+ as unavailable with the deadline reason visible to the user.
93
+
94
+ #### Orchestrator date snapshot survives UTC-midnight rollover (D140)
95
+
96
+ Long `vyuh-dxkit report` runs that crossed UTC midnight
97
+ produced false failures. Files written before midnight got the
98
+ old date suffix; files written after got the new one; the
99
+ orchestrator's post-step file-existence check compared against
100
+ the date snapshot it captured at startup. Several reports were
101
+ on disk under the new date but the orchestrator reported them
102
+ as missing.
103
+
104
+ Fix (commit `cc1f146`):
105
+
106
+ - New `src/analyzers/tools/report-date.ts` exposes
107
+ `getReportDate()`, which honors the optional
108
+ `DXKIT_REPORT_DATE=YYYY-MM-DD` env var (validated) and falls
109
+ back to today's UTC date.
110
+ - The orchestrator captures the date once at startup and
111
+ threads it to every child subcommand via the env var, so
112
+ every report filename in a single run shares the same date.
113
+ - All 10 internal date-stamping call sites in
114
+ `src/cli.ts` + dashboard + dev-report routed through the
115
+ helper.
116
+ - 6 new tests in `test/report-date.test.ts`, including a
117
+ `Date.now` jump that emulates the orchestrator-snapshot
118
+ surviving a midnight rollover.
119
+
120
+ #### Tools-used footer reads cleanly when one pack's lint skipped (D138 follow-up)
121
+
122
+ The 2.4.7 D138 work landed honesty-prose in the dedicated
123
+ `⚠ Lint coverage gap` row when one active language pack's
124
+ linter didn't run. But the `Tools used:` footer at the bottom
125
+ of every report was still rendering the augmented label
126
+ verbatim — so on a polyglot repo it read
127
+ `..., ruff (not run: typescript — config error), ...`, which
128
+ parses as "ruff did not run because of typescript" (false;
129
+ ruff ran fine on Python files; the parenthetical describes
130
+ eslint's fate, not ruff's). Internal commas inside the
131
+ parenthetical also broke the comma-split that fanned the
132
+ footer string into individual tool names.
133
+
134
+ Fix (commit `98ea153`):
135
+
136
+ - New `src/analyzers/tools/lint-label.ts` centralises the
137
+ parse (regex + `stripNotRunSuffix` helper).
138
+ - `splitToolNames` in `health.ts` and the `toolsUsed` push in
139
+ `quality/index.ts` both strip the `(not run: ...)` suffix
140
+ before emitting into the footer.
141
+ - The dedicated `⚠ Lint coverage gap` row keeps its own
142
+ augmented-label parse — that row is exactly where the
143
+ per-pack skip belongs.
144
+ - 11 tests in `test/lint-label.test.ts` cover single-pack,
145
+ multi-pack with internal commas, and malformed input.
146
+
147
+ #### Cascade warning when health fails before the analysis cache builds (related to D141)
148
+
149
+ When the Health step fails before the cross-process
150
+ `AnalysisResult` cache is built, every downstream report
151
+ (Vulnerabilities, BoM, Licenses, Test gaps, Quality,
152
+ Developer) re-runs detection + Layer 0 + Layer 2 gather from
153
+ scratch — measurably slower than the cache-hit path. On a
154
+ heavy polyglot repo this can add hundreds of seconds across
155
+ the run. The structural fix (build the cache from the
156
+ gather output even when the markdown write fails) is the
157
+ larger piece; this release surfaces the symptom honestly so
158
+ the user understands why the remaining steps feel slower.
159
+
160
+ Fix (commit `fa019f8`):
161
+
162
+ - When Health fails before the cache is built, the
163
+ orchestrator logs:
164
+ `Health failed before the analysis cache could be built.
165
+ The remaining steps will re-detect the stack and re-gather
166
+ shared metrics from scratch (expect each to be measurably
167
+ slower than usual).`
168
+ - No new tests — the warning is exercised end-to-end via
169
+ the orchestrator's existing integration coverage.
170
+
171
+ #### README upgrade advisory now matches the observed behavior of modern npm (related to F3 audit finding)
172
+
173
+ The 2.4.7 README's "Already installed dxkit globally?" callout
174
+ claimed `npx @vyuhlabs/dxkit@<version>` falls through to a
175
+ stale `vyuh-dxkit` global on PATH. Tested under npm 11.6.0
176
+ with a stale 2.4.2 global installed, `npx @vyuhlabs/dxkit@2.4.7
177
+ --version` correctly returned `2.4.7` — modern npm/npx does
178
+ not fall through. A reader following the advisory might
179
+ uninstall a working global install on advice that doesn't
180
+ match their environment.
181
+
182
+ Fix (commit `6d8363b`): rewrites the callout to keep the
183
+ genuinely useful upgrade hint (globals don't auto-update;
184
+ either upgrade them or remove them and rely on `npx`) without
185
+ the inaccurate npx-behaviour assertion. Also drops the
186
+ 2.4.7-specific fix-mention which would have gone stale after
187
+ this release.
188
+
189
+ ### Test posture
190
+
191
+ - `npm run test:run` — **1265 / 0** (up from 1241).
192
+ - `+6` tests for D140 (`test/report-date.test.ts`).
193
+ - `+11` tests for D138 follow-up (`test/lint-label.test.ts`).
194
+ - `+7` tests for D141 (`test/dispatcher-deadline.test.ts`),
195
+ including the D138-class regression that simulates a
196
+ never-settling provider and asserts the dispatcher returns
197
+ within the deadline window with the stalled source in
198
+ `skipped` + `skipReasons`.
199
+ - arch / slop / lint / format / typecheck — all clean.
200
+
201
+ ## [2.4.7] - 2026-05-17
202
+
203
+ ### Summary
204
+
205
+ 2.4.7 is the largest release since the language-pack architecture
206
+ landed. It bundles three distinct architectural deliverables
207
+ (actionable scoring foundation, per-stack architectural shape,
208
+ canonical security aggregator), customer-visible UX rework
209
+ (security top-5 actions, .env-in-git callout, lint-skip prose
210
+ honesty, tools-unavailable renderer split), one ship-blocker
211
+ root-cause fix (silent health failure under concurrent subprocess
212
+ load), and the project's OSS hygiene baseline. 17 defect IDs
213
+ closed in this version. Scoring methodology now anchored to
214
+ ISO/IEC 25010, ISO/IEC 5055, SQALE, CVSS v4, CWE, OWASP, and
215
+ OpenSSF Scorecard. Tests: 1241 / 0 (up from 1175 at the 2.4.6
216
+ baseline). No runtime regressions across the cross-ecosystem
217
+ matrix.
218
+
219
+ Customer-visible numeric impact: scores on some repos will shift
220
+ between 2.4.6 and 2.4.7 because the underlying methodology
221
+ changed (see the "Actionable scoring foundation" section below
222
+ and its "Customer-visible score changes" subsection), not because
223
+ of bugs. Migration notes at
224
+ [`docs/MIGRATING-TO-2.4.7-SCORING.md`](docs/MIGRATING-TO-2.4.7-SCORING.md).
225
+
226
+ ### Phase C11 — OSS hygiene baseline (2026-05-17)
227
+
228
+ Adds the standard set of OSS community files so the project
229
+ satisfies the OpenSSF Scorecard `Security-Policy`,
230
+ `Code-of-Conduct`, and `Contributors` checks and gives external
231
+ contributors a clear on-ramp.
232
+
233
+ - `SECURITY.md` — supported-versions table, response SLAs, explicit
234
+ scope, and a pointer to GitHub's [private vulnerability
235
+ reporting](https://github.com/vyuh-labs/dxkit/security/advisories/new)
236
+ (no public email; routes directly to maintainers).
237
+ - `CODE_OF_CONDUCT.md` — adopts the [Contributor Covenant
238
+ 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/)
239
+ by canonical URL reference. Reports route through the same
240
+ private channel as security disclosures.
241
+ - `.github/PULL_REQUEST_TEMPLATE.md` — summary + motivation +
242
+ verification checklist + an architectural-rules pointer section
243
+ nudging contributors at the relevant CLAUDE.md rules before
244
+ touching scoring / language packs / exclusions / tool invocation.
245
+ - `.github/ISSUE_TEMPLATE/bug.yml` — issue form: repro steps,
246
+ versions (dxkit + Node), OS, repo stack, logs. Confirmations
247
+ block routes security reports to private disclosure.
248
+ - `.github/ISSUE_TEMPLATE/feature.yml` — issue form: problem
249
+ framing, proposal, alternatives considered, scope dropdown.
250
+ - `.github/ISSUE_TEMPLATE/question.yml` — light triage form that
251
+ redirects bug / feature / security reports to the right channel
252
+ and surfaces existing docs (README, SCORING.md, CLAUDE.md).
253
+ - `docs/ARCHITECTURE.md` — short tour of the analyzer data flow,
254
+ the three core patterns (language packs, scoring specs,
255
+ centralized exclusions + tool registry), the `runDetached`
256
+ subprocess discipline, the `AnalysisResult` cache, and the
257
+ release flow. Entry-point doc; defers to CLAUDE.md as the
258
+ authoritative rule set.
259
+
260
+ No runtime code changes. Commits: `93a1790`.
261
+
262
+ ### Phase C10.25 — Audit-residue closures + silent-failure root-cause (2026-05-17)
263
+
264
+ The earlier phases of 2.4.7 brought enough new code into the
265
+ analyzer that a pre-ship convergence audit on the three external
266
+ customer repos surfaced one HIGH-severity defect — the report
267
+ orchestrator's health step intermittently exiting `rc=0` with no
268
+ `health-audit-*.md` written on the heaviest polyglot repo — plus a
269
+ batch of MEDIUM residue items. This phase closes all of them.
270
+ Pairs with the per-stack architectural-shape work below to leave
271
+ 2.4.7 with zero outstanding ship blockers.
272
+
273
+ #### Silent health-failure root-cause (D134)
274
+
275
+ The report orchestrator's health step on a heavy polyglot repo
276
+ (13k+ graphify function nodes, ~700 source files, large
277
+ `node_modules`) intermittently exited `rc=0` with no
278
+ `health-audit-*.md` written. The dashboard then read "no health
279
+ data" while the orchestrator itself printed `✓ Health`.
280
+ Investigation via a `spawnSync` reproducer plus targeted
281
+ diagnostic instrumentation captured the failure shape:
282
+
283
+ ```
284
+ [beforeExit] code=0 reachedWrite=false writeComplete=false
285
+ [exit] code=0 reachedWrite=false writeComplete=false
286
+ ```
287
+
288
+ No `uncaughtException`, no `unhandledRejection` — classic
289
+ abandoned-Promise. Under concurrent subprocess load (semgrep +
290
+ jscpd + graphify all spawning grandchildren), one `runDetached`
291
+ invocation's `exit` and `error` events both failed to fire. The
292
+ Promise stayed permanently pending, the capabilities `Promise.all`
293
+ hung, `analyzeHealthInternal`'s `await` never returned, Node's
294
+ event loop emptied and the process exited cleanly with the main
295
+ task still suspended.
296
+
297
+ Fix in `src/analyzers/tools/runner.ts` (commit `55ce0d6`):
298
+
299
+ - **Single-resolve `settle()` guard** — `exit` / `error` /
300
+ safety-deadline, first wins; subsequent events are no-ops.
301
+ - **Error listener registered BEFORE other setup** to close the
302
+ spawn-time-emission race window.
303
+ - **Safety deadline at `timeoutMs + 30_000`** — the Promise
304
+ mathematically must settle within that window even if every
305
+ event source fails.
306
+
307
+ Verification on the failure repo:
308
+
309
+ - Pre-fix: 795-800 s, `rc=0`, **no** health markdown on disk.
310
+ - Post-fix: 662.8 s, `rc=0`, full health markdown on disk.
311
+
312
+ Defense-in-depth (commit `5b6e360`): the `report` orchestrator
313
+ now asserts each step wrote its expected markdown post-step. A
314
+ future regression that re-introduces the hang surfaces a per-step
315
+ `✗` instead of a silent `✓`.
316
+
317
+ #### jscpd OOM class-fix — centralized exclusions plumbed into `--ignore` (D139)
318
+
319
+ jscpd was invoked with `--gitignore` + the autogen-pattern list but
320
+ NOT dxkit's bundled `default-exclusions.gitignore` / `.dxkit-ignore`
321
+ union — the same exclusion set every in-process walker (cloc, grep,
322
+ semgrep, graphify's Python filter) honors. Repos committing vendored
323
+ bundles outside `.gitignore` (e.g. minified library copies under a
324
+ `public/` tree) led jscpd to descend in, tokenize multi-thousand-line
325
+ minified bundles, exhaust heap, and OOM-kill before flushing its
326
+ JSON report. The quality report would then read
327
+ "Duplication unavailable" on the densest repos — exactly the repos
328
+ where the metric mattered most.
329
+
330
+ Fix (commit `2afc097`):
331
+
332
+ - New `getJscpdIgnorePatterns(cwd)` helper in
333
+ `src/analyzers/tools/exclusions.ts` returns the centralized
334
+ exclusion set as `**/<pattern>`-style globs.
335
+ - `gatherJscpdResult` unions it with the autogen patterns and
336
+ passes the union to jscpd's `--ignore`.
337
+ - `jscpdProvider` gains a `gatherOutcome` method so the
338
+ dispatcher captures jscpd's actual failure reason
339
+ ("not installed" / "timed out at 600s" / "exit code N
340
+ (stderr: ...)" / "no output" / "parse error") instead of
341
+ dropping it at the gather / `null` boundary.
342
+
343
+ CLAUDE.md Rule 4 ("Exclusions come from `exclusions.ts`") was
344
+ honored at the in-process walker layer but not at the
345
+ subprocess-tool argument-builder layer. This closes that drift
346
+ for jscpd and lays the pattern for any future subprocess tool
347
+ that walks the repo.
348
+
349
+ Verification on the worst-case repo:
350
+
351
+ - **Standalone smoke**: 569 s OOM → 17 s success, **7.26 %**
352
+ duplication, 444 clones, 7 423 duplicated lines.
353
+ - **End-to-end via `vyuh-dxkit quality`**: capabilities-gather
354
+ 770 s → 272 s (jscpd no longer the long pole; eslint also
355
+ surfaces its real findings as a side-effect, contributing
356
+ 10 496 errors + 2 787 warnings that were previously masked).
357
+
358
+ #### Tools-unavailable renderer prose-honesty (D138)
359
+
360
+ The dispatcher's `skipReasons` channel already carried the real
361
+ per-source failure reason for every attempted-but-failed tool, but
362
+ `availabilityFromOutcome` in `src/analyzers/health.ts` collapsed
363
+ every case to a generic "attempted but produced no output (likely
364
+ killed by resource limits — try running dxkit on this repo alone)"
365
+ prose. The renderer then printed `**Tools unavailable:** jscpd
366
+ (...)` — a reader reasonably concluded the binary needed
367
+ installing, when in fact the binary was fine and the run had
368
+ OOM'd at runtime. Same misleading-label class as D113 / D128
369
+ (lint-skip prose) and D135 (cache-level availability envelope) —
370
+ this fix extends the honesty pattern one layer up to the renderer
371
+ header label.
372
+
373
+ Fix (commit `425d0ef`):
374
+
375
+ - `semgrepProvider` + `graphifyProvider` gain `gatherOutcome`
376
+ (jscpdProvider's method came with the companion D139 commit).
377
+ The dispatcher now captures the real per-source reason into
378
+ `DispatchOutcome.skipReasons`.
379
+ - `availabilityFromOutcome` prefers `skipReasons[<source>]` when
380
+ present; falls back to the generic prose for legacy providers
381
+ without `gatherOutcome`.
382
+ - New `splitToolsUnavailable` / `renderToolsUnavailableLines`
383
+ helpers in `src/analyzers/tools/tools-unavailable-prose.ts`
384
+ route entries into two honest categories:
385
+ - `**Tools not installed:**` — action: install
386
+ - `**Tools that failed at runtime:**` — action: investigate
387
+ - 9 markdown renderer call-sites (`cli.ts`, tests / security /
388
+ quality / health / bom analyzer surfaces, each with their
389
+ `index.ts` and `detailed.ts` formatter pair) + the xlsx BoM
390
+ (two worksheet rows) all share the canonical helper.
391
+
392
+ #### Other audit-residue closures
393
+
394
+ | ID(s) | Description | Closing commit |
395
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
396
+ | D124 / D100 / D118 | Vendored-source exclusion class-fix — top-largest-file metric on all 3 customer repos now first-party (or correctly flagged by the per-file advisor). Generic `largest_files` walk routes through canonical exclusions. | `72ec70a` |
397
+ | D113 / D128 | Per-pack lint-skip reasons plumbed end-to-end. Tools row reads `ruff (not run: typescript — config error)` instead of dropping the skip silently. | `b878553` |
398
+ | D118-residue | Graphify enumeration honors file-glob + content-minified exclusions. Webpack-hash bundles no longer rank as the densest file on customer reports (the JS-heavy customer frontend: 4 606 fn artifact → 228 fn real first-party densest). | `0da08bd` |
399
+ | D135 / D136 (interim) | Vendored-advisor token list extended for SAP B1 OData proxy classes, map-library, proto-gen conventions. Customers with heavy-autogen .NET ERP integrations now see actionable `.dxkit-ignore` guidance. | `d9f0c31` |
400
+
401
+ Tests at this phase close: 1241 / 0 (+15 new unit tests for
402
+ `getJscpdIgnorePatterns`, `splitToolsUnavailable`,
403
+ `renderToolsUnavailableLines`). Architecture gate clean.
404
+
405
+ ### Phase C8 — Per-stack architectural shape (2026-05-17)
406
+
407
+ Before this phase, the analyzers carried hardcoded Node-backend-
408
+ centric path patterns (`'/controllers/'`, `'/services/'`,
409
+ `'/models/'`) and a closed `SourceFile.type` union (`'controller'
410
+ | 'service' | 'model' | ...`). A pure React frontend or a .NET
411
+ WinForms desktop app matched none of the defaults and reported
412
+ `0/0/0` across test-gap CRITICAL / HIGH / MEDIUM buckets — the
413
+ kind of metric that reads as a bug to a frontend or desktop
414
+ developer scanning the report.
415
+
416
+ This phase replaces the hardcoded vocabulary with a per-pack
417
+ `architecturalShape` capability on `LanguageSupport`. Each pack
418
+ declares its own primary-component paths, route-handler paths,
419
+ data-model paths, prose vocabulary, and per-bucket test-gap
420
+ priority taxonomy. Cross-cutting analyzer code unions across
421
+ active packs at runtime — so a polyglot repo's metrics correctly
422
+ span TypeScript's `/controllers/` + `/components/` alongside
423
+ C#'s `Forms/`, and adding a new language pack auto-extends every
424
+ consumer.
425
+
426
+ #### What landed
427
+
428
+ - New `architecturalShape?: ArchitecturalShape` field on
429
+ `LanguageSupport` (commit `9a6c48d`).
430
+ - 7 packs contribute concrete shapes (commit `c313744`). E.g.
431
+ the csharp pack declares `Forms/`, `ViewModels/`, `Services/`;
432
+ the typescript pack declares `/controllers/`, `/services/`,
433
+ `/models/`, `/components/`, `/hooks/`; the python pack
434
+ declares `/views/`, `/viewsets/`, `/models/`, `/serializers/`.
435
+ Two packs (rust, go) intentionally omit `architecturalShape`
436
+ — they don't have a canonical convention strong enough to
437
+ declare without overfitting.
438
+ - Five consumer migrations onto the new helpers (commit
439
+ `6ab2712`): `analyzers/tools/generic.ts` (largest-file +
440
+ source-walk classification), `analyzers/maintainability/shallow.ts`
441
+ (vocabulary prose), `analyzers/security/actions.ts`
442
+ (route-handler attribution), `analyzers/tests/index.ts`
443
+ (test-gap priority taxonomy), `analyzers/health.ts`
444
+ (route-handler files count).
445
+ - Cross-cutting registry helpers in `src/languages/index.ts`:
446
+ `allPrimaryComponentPaths(flags)`, `allRoutePaths(flags)`,
447
+ `allModelPaths(flags)`, `allTestGapPriorityPaths(flags)`,
448
+ `dominantVocabulary(flags)` — every consumer reads from the
449
+ active-pack union.
450
+ - `dominantVocabulary` weighted by cloc line count (commit
451
+ `7147f3f`) so a polyglot repo's vocabulary prose matches the
452
+ dominant stack. A 106k-line-TS / 1.2k-line-Python monorepo
453
+ correctly renders as "controllers + components", not
454
+ "views + viewsets".
455
+ - Two new arch-gate rules (commit `c4f9c20`) in
456
+ `scripts/check-architecture.sh`:
457
+ - No quoted path-style framework literals (`'/controllers/'`,
458
+ `'/services/'`, etc.) inside `src/analyzers/` — they belong
459
+ in `LanguageSupport.architecturalShape`.
460
+ - No bare singular role-name string literals (`'controller'`,
461
+ `'service'`, `'handler'`, `'interceptor'`, `'repository'`,
462
+ `'viewmodel'`, `'viewset'`, `'router'`) — the pre-extension
463
+ closed enum is replaced by free string labels derived from
464
+ `patternToLabel(matched architectural-shape pattern)`.
465
+ - Synthetic 6th-pack injection assertion in
466
+ `test/recipe-playbook.test.ts` — confirms an
467
+ `architecturalShape` contribution from a brand-new pack flows
468
+ through test-gap taxonomy and Maintainability prose without
469
+ cross-cutting edits.
470
+ - CLAUDE.md gains Rule 8 documenting the new architecture.
471
+
472
+ #### Customer-visible effects (verified post-fix)
473
+
474
+ - **platform** (TS / Node backend): test-gap MEDIUM 207;
475
+ Maintainability prose reads "controllers / components"
476
+ (typescript wins cloc weight on a 106k-line monorepo).
477
+ - **the JS-heavy customer frontend** (React frontend): test-gap MEDIUM 499 → 379
478
+ (-120) because the vendored-exclusion class-fix in the
479
+ audit-residue phase above also excludes lexical-playground
480
+ subtrees from primary-component matching. Honest count.
481
+ - **the .NET WinForms benchmark** (.NET WinForms): Maintainability vocabulary
482
+ reads "Forms / Services"; test-gap classification correctly
483
+ picks up the WinForms project structure.
484
+
485
+ #### Defects closed
486
+
487
+ | ID | Description | Closing commit(s) |
488
+ | ---- | ------------------------------------------------------------------------------------------ | -------------------- |
489
+ | D119 | Test-gap priority taxonomy backend-centric (HIGH; misleading on non-Node-backend stacks) | this phase, above |
490
+ | D101 | React / csharp Maintainability vocabulary | this phase, above |
491
+ | D065 | API-docs gate on `routeHandlerFiles` | this phase, above |
492
+
493
+ ### Phase C7 — Actionable scoring foundation (2026-05-17)
494
+
495
+ Reframes dxkit's six-dimension scoring from descriptive ("Code
496
+ Quality: 75/100, Good") to actionable ("Code Quality: 75/100, B —
497
+ top action: fix 11 lint errors for +10, would lift rating to A").
498
+ The numeric scores stay on the same 0-100 scale; every dimension
499
+ now also produces structured provenance that tells the customer
500
+ what to fix and how much the score would lift.
501
+
502
+ dxkit's scoring is now **deterministic** (same repo + same dxkit
503
+ version → identical score, every machine), **anchored** (cites
504
+ underlying open standards: ISO/IEC 25010, ISO/IEC 5055, SQALE
505
+ method, CVSS v4, CWE, OWASP, OpenSSF Scorecard), and **actionable**
506
+ (every score paired with structured `deductions`, `capsApplied`,
507
+ `topActions`).
508
+
509
+ See [`docs/SCORING.md`](docs/SCORING.md) for the full methodology
510
+ and [`docs/MIGRATING-TO-2.4.7-SCORING.md`](docs/MIGRATING-TO-2.4.7-SCORING.md)
511
+ for JSON-consumer migration.
512
+
513
+ #### Architecture
514
+
515
+ - **Single home for dimension scoring** at `src/scoring/`,
516
+ mirroring the per-language pattern from CLAUDE.md Rule 6. Each
517
+ of the six dimensions (Security, Code Quality, Tests,
518
+ Documentation, Maintainability, Developer Experience) declares
519
+ a `DimensionScoringSpec<T>` artifact under
520
+ `src/scoring/dimensions/<id>.ts` consumed by a shared
521
+ pure-function evaluator. Adding a new dimension is a recipe
522
+ documented in CONTRIBUTING.md.
523
+ - **Cap-tier taxonomy** named by severity: `trust-broken` (40,
524
+ catastrophic), `unmeasured` (35, no signal), `uncertainty` (65,
525
+ key tool missing), `partial-uncertainty` (75, partial gap),
526
+ `fixable-finding` (79, concrete bounded finding open). Caps
527
+ enforce the Label Contract: "A" means "no known blockers."
528
+ - **Zero scoring code remains in `src/analyzers/`**. Files deleted
529
+ in full: `src/analyzers/scoring.ts`, `src/analyzers/security/scoring.ts`,
530
+ `src/analyzers/quality/scoring.ts`. CLAUDE.md gains Rule 7
531
+ documenting the new architecture; three new arch-gate rules in
532
+ `scripts/check-architecture.sh` prevent regression.
533
+ - **Scoring playbook test** (`test/scoring-playbook.test.ts`)
534
+ injects a synthetic 7th-dimension spec to confirm the registry
535
+ + evaluator + format helpers stay spec-driven.
536
+
537
+ #### Customer-visible score changes
538
+
539
+ - **D131 closure — Security HIGH+ open caps at 79 (B)**. Pre-2.4.7
540
+ a single open HIGH-severity code finding (e.g. a TLS-validation
541
+ bypass) left the Security dimension at 95/100 ("Excellent") —
542
+ the headline contradicted the unfixed finding. Now repos with at
543
+ least one open HIGH or CRITICAL code finding cap at 79 (B grade)
544
+ with the cap explicit in the rendered report:
545
+ `Rating cap: 1 open HIGH+ code finding — bounded at 79/100`.
546
+ Repos with zero open HIGH+ are unaffected.
547
+ - **D129 closure — severe-debt disclosure**. Pre-2.4.7, "Code
548
+ Quality 0/100" rendered identically whether the penalty stack
549
+ totalled -5 (barely below the floor) or -85 (catastrophic). The
550
+ Top Actions block now surfaces the rawPenalty when the score
551
+ floors at 0: `Severe: raw penalty -85 (deductions exceed the
552
+ floor).`
553
+ - **Maintainability — SQALE baseline shift**. Methodology
554
+ migrated to ISO/IEC 25010 + SQALE-inspired step thresholds.
555
+ Baseline shifts from 70 to 100 (matches every other subtractive
556
+ dimension); the small-codebase bonus is removed as overfit.
557
+ Clean repos see Maintainability scores rise by ~30 points.
558
+ Documented behavior change.
559
+ - **Testing — cap-then-penalty ordering**. When `commentedCodeRatio
560
+ > 0.5` AND coverage data missing, the final score is now 35 (cap
561
+ binds as the ceiling). Pre-2.4.7 it was 20 (cap then sub-cap
562
+ subtraction). The new semantic is cleaner — caps are ceilings,
563
+ not floors-and-then-keep-subtracting. Affects a narrow edge case.
564
+ - **No-tests-found surfaces as a Top Action**. Repos with zero
565
+ test files now show a dedicated deduction +60 with severe-debt
566
+ disclosure, pointing at test-gaps for the ranked critical files.
567
+ Pre-2.4.7 these repos had a 0/E Tests score with no actionable
568
+ signal in the dimension's Top Actions block.
569
+ - **`DimensionScore.status` → `rating`**. The descriptive enum
570
+ (`'excellent' | 'good' | 'fair' | 'poor' | 'critical'`) is
571
+ replaced by a uniform letter rating (`'A' | 'B' | 'C' | 'D' |
572
+ 'E'`). The overall summary's `grade` field renames to `rating`
573
+ with the same `F` → `E` enum unification.
574
+ - **Documentation + Developer Experience specs inverted from
575
+ additive to subtractive**. Numeric scores preserved by
576
+ construction; the `deductions[]` list now reads as
577
+ actions-to-take ("README missing") rather than bonuses already
578
+ earned ("README present").
579
+
580
+ #### Renderer + JSON
581
+
582
+ - CLI grid prints a top-action continuation under each dimension
583
+ line: `→ 11 lint errors +10 (B → A)`.
584
+ - Health detailed markdown gains a `Top actions (sorted by score
585
+ uplift)` block per dimension with rating-transition annotations.
586
+ - Dashboard hero now reads `Rating D` instead of `Grade D`.
587
+ - Health-detailed JSON schema bumps `11` → `12` for the new
588
+ provenance fields on `DimensionScore` (`rawScore`,
589
+ `rawPenalty`, `methodology`, `deductions`, `capsApplied`,
590
+ `topActions`). All optional — pre-2.4.7 consumers continue to
591
+ work.
592
+
593
+ Two-phase release. **Phase A** (audit-driven hot-patches, originally
594
+ shipped 2026-05-13) closed a 17-defect cascade surfaced by a critical
595
+ post-shipment audit on the .NET WinForms benchmark (enterprise C# / 1500+ files / 68
596
+ sub-projects / 1.6M lines of cloc-counted JSON), plus the long-deferred
597
+ D021 (coverage workflow). **Phase B** (class-fix release, 2026-05-14)
598
+ pivoted from patch shipping to architectural class-fix shipping after
599
+ pre-ship audits on platform and the JS-heavy customer frontend surfaced 12 NEW defects
600
+ (D074–D085), 9 of which were repeated instances of the same disease
601
+ class fixed at different sites.
602
+
603
+ ### Phase C2 — Security UX rework (2026-05-14)
604
+
605
+ Builds on Phase C1's typed canonical aggregator with the user-facing
606
+ UX changes the 2026-05-14 critical-perspective audit demanded. C1
607
+ closed the architectural drift class; C2 closes the labeling,
608
+ scoring-credibility, and prioritization gaps that remained.
609
+
610
+ - **C2.1 — Vuln-scan section split** (commit `e637911`). The pre-C2
611
+ executive summary had ONE "Code Findings" table that combined
612
+ codeBySeverity + secretsBySeverity under a label that meant
613
+ code-only to health-side prose. Readers (and AI agents) saw
614
+ apparent drift between health "10H code findings" and vuln-scan
615
+ "Code Findings: 16H." Both numbers were correct for their scopes,
616
+ but the labels obscured this. C2.1 splits the executive summary
617
+ into three labeled tables — **Code Findings** (code-pattern only,
618
+ matches health), **Secret & Config Findings** (gitleaks +
619
+ private-key + .env), **Dependency Vulnerabilities** (unchanged).
620
+ `SecurityReport.summary` grows `codeOnly` and `secretsOnly`
621
+ siblings of `findings`; renderer reads them by name.
622
+
623
+ - **C2.2 / D098 — `SECRETS_PRESENT_CAP = 40`** (commit `243fa86`).
624
+ Pre-C2 baseline: the JS-heavy customer frontend scored Security 60/100 "Good" despite
625
+ 4 hardcoded API keys + 1 .env in git. Credentials in source-control
626
+ history are presumed compromised even after rotation, and a "Good"
627
+ score reads as deprioritizable. C2.2 caps the Security dimension at
628
+ ≤ 40 ("Fair" or worse) whenever `secretFindings > 0 ||
629
+ privateKeyFiles > 0 || envFilesInGit > 0`. Applied as a ceiling
630
+ AFTER all per-signal penalties and the dep-availability cap, so
631
+ it composes monotonically with everything else.
632
+ - Validated: the JS-heavy customer frontend 60 → 40 "Fair" (✓ cap fires);
633
+ platform 45 → 40 "Fair" (✓); the .NET WinForms benchmark 90 → 90 (✓ cap
634
+ correctly does NOT fire — no committed credentials).
635
+
636
+ - **C2.3 / D099 — `.env`-in-git callout block** (commit `7f43dfc`).
637
+ Pre-C2 a `.env` finding appeared as a plain HIGH entry in the
638
+ Configuration Issues section with no actionable command. C2.3
639
+ adds a dedicated `## 🚨 .env files tracked in git` block between
640
+ the executive summary and the per-category sections. Contents:
641
+ rotation caveat ("presumed compromised even after deletion"),
642
+ working-tree bash block (`git rm --cached <file>` per file +
643
+ `.gitignore` + commit), and history-rewrite block
644
+ (`git filter-repo` preferred + BFG alternative + "every
645
+ collaborator must re-clone" coordination caveat).
646
+
647
+ - **C2.4 / D105 — Top 5 priority actions** (commit `6fe45fa`).
648
+ Pre-C2 reports listed every finding by severity within category;
649
+ no prioritization surface. A reader scanning the report had to
650
+ skim dozens of medium findings to spot the one KEV-listed dep
651
+ upgrade that actually mattered this week. C2.4 adds a
652
+ `## 🎯 Top 5 Priority Actions` markdown table at the top of the
653
+ findings sections. Priority order codifies the triage rubric:
654
+ KEV deps → hardcoded secrets → .env in git → private-key files →
655
+ non-KEV deps by risk-score tier → HIGH/CRITICAL code findings.
656
+ Capped at 5 — anything below the cap shows up in the per-category
657
+ sections below.
658
+
659
+ - **D108 — Top 5 sparse-tier fallback** (commit `c09ba87`). C2.5
660
+ audit surfaced D108: the .NET WinForms benchmark's Top 5 had only 1 entry despite
661
+ 2 unpatched dep vulns (MongoDB.Driver risk 19 + SharpCompress
662
+ risk 15). The original C2.4 dep filter required `riskScore >= 25`
663
+ which excluded the "watch" tier (10-25 per risk-score.ts), leaving
664
+ the table sparse. Fix: tier-iterate dep risk-score buckets
665
+ (`≥ 50 → 25-50 → 10-25 → ≥ 0`) and stop only when Top 5 is full.
666
+ Findings without scored risk surface in the lowest tier so
667
+ nothing is silently dropped.
668
+
669
+ ### Phase C2 — Verification audit (C2.5)
670
+
671
+ Cross-report parity audit on three customer repos (`platform`,
672
+ the .NET WinForms benchmark, the JS-heavy customer frontend). All vuln-scan + health pairs verified:
673
+
674
+ - **D086 / D087 / D091 closures from C1 remain intact** across
675
+ all 3 repos. Cross-report parity holds.
676
+ - **D098 secrets-cap fires correctly**: the JS-heavy customer frontend + platform both
677
+ drop to 40 "Fair"; the .NET WinForms benchmark (no secrets) stays at 90.
678
+ - **D099 .env callout renders correctly on the JS-heavy customer frontend** (the only
679
+ repo with a tracked .env).
680
+ - **D105 Top 5 surfaces actionable rows on every repo**, post-D108
681
+ including the sparse-repo case.
682
+
683
+ ### D109 investigation — non-defect
684
+
685
+ C2.5 also surfaced a candidate drift: platform vuln-scan code-only
686
+ `10H 7M` vs health `10H 10M`. HIGH agreed; MEDIUM differed by 3.
687
+ Investigation via an in-process probe (`tmp/d109-probe.js` runs
688
+ both analyzers sequentially in ONE node process, sharing the
689
+ dispatcher cache) showed identical aggregates: `{ high: 10,
690
+ medium: 20 }` on both sides. **D109 is NOT a real defect** — the
691
+ architecture is sound. The observed drift across separate
692
+ processes was semgrep tool-runtime variance (MEDIUM count varied
693
+ 7 → 10 → 20 across runs while HIGH stayed stable at 10). Future
694
+ docs follow-up: note semgrep's non-determinism as a known
695
+ limitation.
696
+
697
+ ### Phase C1 — Canonical security aggregator (2026-05-14)
698
+
699
+ Three customer-facing aggregation-drift defects (D086, D087, D091)
700
+ shared one root: **multiple consumers re-counting severity from raw
701
+ envelope arrays with different inclusion rules**. Phase B closed
702
+ this class at the GATHER layer (canonical `walkSourceFiles`); Phase
703
+ C1 closes it at the AGGREGATION layer with the same class-fix
704
+ discipline plus two newly-surfaced defects (D107 BoM vs vuln-scan
705
+ disagreement, D091-boundary neighbor-bucket miss) caught during the
706
+ pre-release audit and fixed before ship.
707
+
708
+ - **Canonical `SecurityAggregate`** (commit `a3942f4`). New
709
+ `src/analyzers/security/aggregator.ts` exporting
710
+ `buildSecurityAggregate(envelopes) → SecurityAggregate`. The typed
711
+ contract carries three separately-named severity buckets
712
+ (`codeBySeverity`, `depBySeverity`, `secretsBySeverity`), two
713
+ distinct dep-count fields (`dependencyAdvisoryUniqueCount`
714
+ canonical user-facing + `dependencyFindingsRawCount` for audit),
715
+ fingerprint-stamped `CodeFinding[]` per category, dedup audit
716
+ trail, and per-source provenance. Renderers cannot accidentally
717
+ sum cross-axis or pick the wrong number — both defects become
718
+ impossible by the typed shape.
719
+
720
+ - **Six consumers migrated** onto the aggregate (4 user-facing + 2
721
+ internal):
722
+ - `security/index.ts` standalone vuln-scan (commit `f3bd69f`, D087
723
+ closure — Subtotal now matches "N advisories" by reading
724
+ `dependencyAdvisoryUniqueCount` by name)
725
+ - `security/shallow.ts` health-side scorer (commit `c73c7ca`, D086
726
+ closure — code-finding prose reads `codeBySeverity` from the same
727
+ field vuln-scan reads)
728
+ - `dashboard/index.ts` (commit `9fb0220` — reads severity buckets
729
+ from `vulns.summary.findings + dependencies` instead of re-summing
730
+ finding arrays)
731
+ - BoM (commit `4ae69ed` C1.8, D107 closure — see below)
732
+ - C# pack (commit `14b02a7` C1.9, G_v4_9 — see below)
733
+ - Action planner + legacy fallback (`actions.ts`, `shallow.ts`)
734
+ annotated `// aggregator-ok` for the two legitimate exceptions
735
+ (rebuilding `SecurityScoreInput` from a `SecurityReport`; legacy
736
+ ScoreInput fixtures predating the aggregator field).
737
+
738
+ - **D107 — BoM vs vuln-scan disagreement (NEW, surfaced in C1.7
739
+ audit)** (commit `4ae69ed`). the .NET WinForms benchmark: vuln-scan reported 2 dep
740
+ advisories (MongoDB.Driver HIGH + SharpCompress MEDIUM via
741
+ osv-scanner-nuget-direct) while BoM reported 0. Root cause: BoM
742
+ walks per-sub-root project directories and called `gatherDepVulns`
743
+ at each sub-root, hitting the csharp pack's cwd-sensitive routing
744
+ (at sub-root with stale `obj/project.assets.json`, dotnet returned
745
+ 0; at repo-root with no `.csproj`, the fallback fired). Fix: BoM
746
+ now gathers dep-vulns ONCE at the repo root and passes the result
747
+ to every per-sub-root entry builder via a new `depVulnsOverride`
748
+ option. License-side stays per-sub-root (legitimately
749
+ per-project). Post-fix: the .NET WinForms benchmark BoM 2 ≡ vuln-scan 2.
750
+
751
+ - **G_v4_9 — csharp pack cwd-invariant** (commit `14b02a7`). The
752
+ pack-contract defect underneath D107: `gatherCsharpDepVulnsResult`
753
+ produced different fingerprint sets depending on where `cwd`
754
+ pointed within the repo. Fix: always run BOTH `dotnet list package
755
+ --vulnerable` (when applicable) AND
756
+ `osv-scanner-nuget-direct` (the direct PackageReference parse)
757
+ in parallel, merge findings by `(package, installedVersion, id)`
758
+ fingerprint at the pack layer. Envelope counts recomputed from the
759
+ merged set; `tool` field joins what ran. Result: same fingerprint
760
+ set regardless of cwd. Any future multi-cwd caller now inherits
761
+ consistency.
762
+
763
+ - **D091 boundary case (NEW, surfaced in C1.7 audit)** (commit
764
+ `c7b72e2`). The JS-heavy customer frontend `SetupConfigForm.js:43` (semgrep MEDIUM
765
+ `bypass-tls-verification`) and `:45` (registry HIGH
766
+ `tls-validation-disabled`) — same root, 2 lines apart, same
767
+ canonical rule — failed to collapse because the
768
+ `Math.floor(line/3)*3` bucketing put them in different buckets
769
+ (42 and 45, straddling a multiple-of-3). Documented as a known
770
+ edge case in the C1.1 commit; biting in production was the trigger
771
+ to fix it. Fix: after the natural-bucket lookup misses, check
772
+ neighbor buckets at `(canonicalRule, file, line ± 3)`. Two
773
+ MEDIUMs absorbed into HIGHs on the JS-heavy customer frontend, reducing apparent
774
+ code-finding count from 13 → 11 in the right direction.
775
+
776
+ - **G_v4_8 architectural gate** (commit `6e89131`) in
777
+ `scripts/check-architecture.sh`. Blocks the smoking-gun pattern
778
+ (`[<var>.severity]++` accumulator bump, or
779
+ `function countBySeverity(`) outside the canonical aggregator.
780
+ Static lookup maps (`SEV_RANK`, `SEV_LABEL`) and type-decl fields
781
+ inside interfaces don't match — only the actual aggregation shape.
782
+ BoM's per-package `[e.maxSeverity]++` naturally falls outside the
783
+ pattern (different attribute name) so BoM's legitimate per-package
784
+ aggregation is unaffected.
785
+
786
+ - **Recipe codification (G_v4_8 + G_v4_9 in
787
+ `tmp/recipe-v4-working-doc.md`)**. Two recipe-playbook
788
+ synthetic-pack assertions in `test/recipe-playbook.test.ts`
789
+ (synthetic depVuln finding flows into `depBySeverity` +
790
+ `dependencyAdvisoryUniqueCount`; cross-tool TLS-bypass collapses
791
+ regardless of pack identity). Future language packs feeding
792
+ security data through standard capability descriptors
793
+ automatically inherit drift prevention.
794
+
795
+ ### Phase C1 — Defect closures
796
+
797
+ | ID | Status | Closing commit(s) |
798
+ | --- | --- | --- |
799
+ | D086 | CLOSED (architectural) | `a3942f4` + `c73c7ca` — both surfaces read `aggregate.codeBySeverity` |
800
+ | D087 | CLOSED | `a3942f4` + `f3bd69f` — `dependencyAdvisoryUniqueCount` field forces the canonical count |
801
+ | D091 | CLOSED | `a3942f4` (canonical-rule registry + line-window) + `c7b72e2` (neighbor-bucket lookup for boundary case) |
802
+ | D107 | CLOSED (NEW, two layers) | `4ae69ed` (BoM single-source) + `14b02a7` (G_v4_9 csharp cwd-invariant) |
803
+
804
+ ### Phase C1 — Empirical validation
805
+
806
+ Cross-report parity audit on three customer repos (all numbers
807
+ post-Phase-C1):
808
+
809
+ - **platform** (1500+ TS/Node files, 2 project roots):
810
+ - vuln-scan Subtotal **81** ≡ "**81** advisories" ≡ "Showing 50 of
811
+ **81**" ≡ BoM `totalAdvisories` **81** ✓
812
+ - 5 cross-tool TLS-bypass collisions deduped (MEDIUM bucket
813
+ 14 → 9)
814
+ - **the .NET WinForms benchmark** (C#, 3 nested project roots):
815
+ - vuln-scan **2** ≡ BoM **2** ≡ health **2** (dep) ✓
816
+ - health code findings **1** ≡ vuln-scan code findings **1** ✓
817
+ - **the JS-heavy customer frontend** (JS-heavy, large repo with degraded license info):
818
+ - dep advisories **31** ≡ **31** ≡ **31** ✓
819
+ - D091-boundary case on `SetupConfigForm.js:43+:45` collapses (the
820
+ C1.10 fix)
821
+ - 2 MEDIUMs absorbed into HIGHs via neighbor-bucket lookup
822
+
823
+ Tests: **1178 passed / 8 skipped** (1175 pre-Phase-C + 1 + 2 + 1 new
824
+ unit/synthetic-pack assertions). Architecture gate clean. No
825
+ regressions across the cross-ecosystem matrix.
826
+
827
+ Open and deferred to Phase C2-C8 (still inside 2.4.7 per the
828
+ 2026-05-14 reprioritization):
829
+
830
+ - C2: Security UX rework — split vuln-scan "Code Findings" section
831
+ into code-only + secret/config (closes the perception-level D086
832
+ drift even though architectural drift is gone), security rubric
833
+ weights secrets/.env heavily (D098), Top 5 actions in short
834
+ reports (D105), .env-in-git callout (D099)
835
+ - C3: D094 CWE truncation (`**CWE:** C` still on 2 platform
836
+ semgrep findings), D090 Remediation Commands split
837
+ - C4: D100 vendor-path exclusions
838
+ - C5: D093 word-boundary truncation, D096 densest-file
839
+ clarification
840
+ - C6: D106 agent rewrites
841
+ - C7: Final pre-release validation
842
+ - C8: PR → main → tag v2.4.7 → SLSA publish
843
+
844
+ ### Phase B — Class-fix release (2026-05-14)
845
+
846
+ Two architectural deliverables backed by 4 consumer-site migrations
847
+ and a permanent gate:
848
+
849
+ - **G_v4_7 — `walkSourceFiles` + `countLineMatches`** (new canonical
850
+ helpers in `src/analyzers/tools/walk-source-files.ts`). Pure JS,
851
+ no shell. The the JS-heavy customer frontend D082/D083 silent-zero cascade was caused
852
+ by `grep -rEf <pat> --include=*.js .` producing 67MB of stdout on
853
+ minified files, overflowing `run()`'s 64MB ceiling, and returning
854
+ empty. The walker prunes excluded files at the directory boundary,
855
+ so grep is never asked to walk `public/build/*.min.js` in the
856
+ first place. Bumping `maxBuffer` is a moving target — the right
857
+ answer is "don't pass excluded files to the scanner at all."
858
+
859
+ - **Consumer migrations onto canonical helpers** (4 sites):
860
+ - `tools/generic.ts` (commits `3275e1e` + `226a56a`)
861
+ - `quality/gather.ts` (commit `82e0e75`)
862
+ - `tests/gather.ts` (commit `753a412`)
863
+ - `security/gather.ts` TLS-bypass walk (commit `099e844`)
864
+ Each migration is behavior-preserving by default (e.g. `includeTests: true`
865
+ preserves pre-migration semantics where the legacy grep matched in
866
+ test files too).
867
+
868
+ - **`gatherDebugStatements` shared helper** (commit `e7a8821`).
869
+ Replaces the two divergent implementations in `health.consoleLogCount`
870
+ (sum of JS console + Python print + Go fmt.Print across language-
871
+ scoped walks) and `quality.consoleLogCount` (single console.* pattern
872
+ across all extensions). After: both reports route through one
873
+ function — they cannot drift.
874
+
875
+ - **Architectural gate** (commit `32574e0`) in
876
+ `scripts/check-architecture.sh`. Blocks new
877
+ `grep -r{l,n,c,E,f}` calls in production code outside a 4-file
878
+ allowlist. After this release, the D082/D083 class of bug cannot
879
+ recur without explicitly bypassing the canonical helpers — which
880
+ the gate blocks.
881
+
882
+ ### Phase B — Defect closures (D074–D080, D082–D085)
883
+
884
+ | ID | Severity | Closing commit(s) |
885
+ | --- | --- | --- |
886
+ | D074 — commented-out matches inflate counts | HIGH | `3275e1e` + `82e0e75` + `099e844` + `e7a8821` (`skipComments: true` on print-family / anyType / eval / TLS-bypass) |
887
+ | D075 — sourceFiles cross-report drift | HIGH | `0e71683` + `3275e1e` + `753a412` + `e7a8821` (canonical walker + label alignment) |
888
+ | D076 — dep-vuln count drift health vs BoM | HIGH | `06b0cec` (BoM `totalAdvisories` uses unique fingerprint count) |
889
+ | D077 — dashboard tile drift | MED | closes with D075 |
890
+ | D078 — BoM Risk `**0.0**` for missing CVSS | MED | `46b0d6e` (`computeRiskScore` returns `null` for `cvssScore=0`) |
891
+ | D079 — duplicate grep-count implementations | MED | `82e0e75` + `e7a8821` (shared `gatherDebugStatements`) |
892
+ | D080 — lint dispatcher last-wins | MED | `72cd102` (`gatherWithProvenance` exposes attempted+skipped sources; label reads `"ruff (not run: typescript)"`) |
893
+ | D082 — the JS-heavy customer frontend `consoleLogCount = 0` silent zero | CRITICAL | `0e71683` + `3275e1e` + `e7a8821` (walker prunes minified files at directory boundary) |
894
+ | D083 — `run()` maxBuffer overflow on minified-JS | CRITICAL | `0e71683` + `3275e1e` + `099e844` + `32574e0` |
895
+ | D084 — D082 cascade (anyType, eval) | HIGH | closes with D082/D083 |
896
+ | D085 — the JS-heavy customer frontend dep-count drift | HIGH | `06b0cec` |
897
+
898
+ **Deferred to 2.4.8**:
899
+ - D081 (`Dead Imports: 0` suspicious) — investigated; root cause is
900
+ graphify Python script's `dead = imports - calls - module_ids`
901
+ zeroing out module-style imports. Fix requires a new metric
902
+ (`unreachableImportCount`) + synthetic tests + threshold tuning.
903
+ - **G_v4_8 full architectural enforcement** — typed gather-result
904
+ interfaces with explicit field-ownership claims. Narrow D076/D085
905
+ fix shipped (BoM uses fingerprint count); the typed-contract
906
+ prevention layer is preventive hardening, not on the convergence-
907
+ audit gate.
908
+
909
+ ### Phase B — Empirical validation
910
+
911
+ Convergence audit on three customer repos:
912
+
913
+ - **the .NET WinForms benchmark**: 1537 source files consistent across health,
914
+ test-gaps, maintainability dimension; `consoleLogCount=1`,
915
+ `tlsDisabledCount=1` stable.
916
+ - **platform** (the audit's most-troubled repo): `sourceFiles`
917
+ converged 447/438/444 → **444 / 444 / 444**;
918
+ `consoleLogCount` cross-report converged 1578/1555 → **698 / 698**;
919
+ `tlsDisabledCount` 18 reported / 11 active → **11**; lint label
920
+ `"ruff"` → `"ruff (not run: typescript)"`.
921
+ - **the JS-heavy customer frontend**: `consoleLogCount` **0 → 1066** (D082/D083 closure;
922
+ catastrophic silent zero eliminated).
923
+
924
+ ### Phase A — Audit-driven hot-patches (2026-05-13)
925
+
926
+ The earlier portion of the 2.4.7 release. Same content as below —
927
+ preserved for traceability.
928
+
929
+ The cascade taught us that test-green ≠ report-correct: all 1091
930
+ tests passed before the audit. Reinforces
931
+ `feedback_critical_audit_before_shipping.md` — pre-delivery audit on
932
+ real customer reports is the gold standard, not the unit-test suite.
933
+
934
+ ### Added — D021 close (coverage workflow)
935
+
936
+ Four pieces shipped together:
937
+
938
+ - **`coverageFidelity` tier** classifies the `coverageSource` field
939
+ into three trust levels:
940
+ - `line-coverage` — real artifact (istanbul / coverage-py / jacoco /
941
+ simplecov / lcov / cobertura / go). The percent is line-coverage
942
+ truth.
943
+ - `import-graph` — derived from test-file import edges (up to N
944
+ hops). Informed heuristic.
945
+ - `filename-match` — share of source files with a name-matched
946
+ test. Pure heuristic.
947
+ Test-gap reports lead with a ⚠️ / ℹ️ banner when fidelity isn't
948
+ `line-coverage`, so a 0% from a heuristic can't be confused with a
949
+ 0% from a real coverage run.
950
+ - **`--with-coverage` flag** on `health` and `test-gaps`. Materializes
951
+ the coverage artifact via per-pack `runTests()` BEFORE analysis, so
952
+ `loadCoverage()` finds it and the report reads line-coverage truth.
953
+ Shares the same runner the `coverage` command uses.
954
+ - **`vyuh-dxkit report` orchestrator**. Single command that runs
955
+ every analyzer + dashboard in dependency order. `--with-coverage`
956
+ runs the coverage step ONCE upfront rather than per-command, so
957
+ `health` and `test-gaps` share the artifact without re-running the
958
+ test suite per analyzer.
959
+ - **Cross-ecosystem matrix coverage row × 8 packs** in
960
+ `test/integration/cross-ecosystem.test.ts` + per-pack contract
961
+ conformance assertions in `test/languages-contract.test.ts`. Locks
962
+ in the round-trip from "test runner" to "coverageFidelity:
963
+ line-coverage" across python / typescript / go / rust / csharp /
964
+ kotlin / java / ruby.
965
+
966
+ ### Added — language pack contracts
967
+
968
+ - **`LanguageSupport.upgradeCommand?(name, version)`** (G_v4_4) —
969
+ each pack ships its own per-ecosystem package upgrade template
970
+ (`dotnet add package`, `npm install`, `pip install`, `cargo update`,
971
+ `go get`, edit-pom for Maven, edit-Gemfile for Bundler). Replaces
972
+ the hardcoded switch on `tool` in `buildUpgradeCommand`
973
+ (security/index.ts). Dispatch now routes through
974
+ `getLanguage(packId).upgradeCommand()` — no language branching in
975
+ non-pack code (CLAUDE.md rule 6).
976
+ - **`DepVulnFinding.packId`** stamped at every producer site
977
+ (npm-audit / pip-audit / govulncheck / cargo-audit /
978
+ dotnet-vulnerable / osv-scanner-deps via new `packId` parameter on
979
+ `parseOsvScannerFindings` and `gatherOsvScannerDepVulnsResult`). The
980
+ vuln-scan "Remediation Commands" block now ships actual runnable
981
+ commands instead of bare `#` prose for every ecosystem.
982
+ - **`LanguageSupport.clocLanguageNames?`** (D073) — each pack
983
+ declares the names cloc emits in its `--json` output. cloc's
984
+ per-language summary + `totalLines` aggregation now filter to the
985
+ active-pack set, so markup/data formats (JSON / XML / CSV /
986
+ Markdown) stop deflating quality metrics. On the .NET WinForms benchmark: Comment
987
+ Ratio 4.3% → 27.9% (a 1.6M JSON denominator vs C#'s 568K).
988
+
989
+ ### Fixed — Tier 1 (credibility critical)
990
+
991
+ The post-shipment audit's master bug + its direct cascade:
992
+
993
+ - **D055** — `.dxkit-ignore` multi-segment paths flatten to basenames
994
+ in cloc / graphify / grep. `Dev/Addons/VendorAddon/SAPB1/` silently
995
+ became `{Dev, Addons, VendorAddon, SAPB1}` — cloc then excluded every
996
+ directory named `Dev` in the tree, killing 90% of source visibility.
997
+ Fix: `getClocExcludeFlags` emits `--exclude-dir` (basenames) PLUS
998
+ `--fullpath --not-match-d` (Perl regex on full path).
999
+ `getPythonExcludeFilter` emits both a basename set AND a multi-
1000
+ segment path list for graphify's walker. Grep callers post-filter
1001
+ via `isExcludedPath()`.
1002
+ - **D056** — Registry-driven greps (docCommentFiles, tlsBypassFindings)
1003
+ now post-filter through `isExcludedPath()`. Pre-fix the shell pipe
1004
+ only filtered hardcoded `node_modules` + `dist` — every other
1005
+ exclusion was silently ignored.
1006
+ - **D057** — Cloc no longer writes `sourceFiles`. Generic.ts owns
1007
+ the source-file count; cloc owns line counts + language breakdown.
1008
+ Pre-fix `mergeLayer2` blindly overwrote generic's find-based 1537
1009
+ with cloc's broken 141. Class-fix (merger field-ownership claims,
1010
+ G_v4_8) deferred to 2.4.8.
1011
+ - **D072** — Registry-greps now apply the SAME autogen filters
1012
+ (`autogeneratedSourcePatterns` basename glob + `isAutogeneratedByHeader`
1013
+ content marker) that `gatherGenericMetrics` uses for `sourceFiles`.
1014
+ Pre-D072 docCommentFiles counted designer.cs / .g.cs files in the
1015
+ numerator but not in `sourceFiles`'s denominator, producing 104%
1016
+ docRatio on the .NET WinForms benchmark even after D055.
1017
+ - **D062** closure via **G_v4_4** above.
1018
+
1019
+ ### Fixed — Tier 2 (visible UX bugs)
1020
+
1021
+ - **D060** — Weekly velocity fills empty weeks with 0-row entries
1022
+ between first and last week with commits. Pre-fix `W08 2, W09 1,
1023
+ W10 7, W14 1, W16 6, ...` had silent gaps that implied "data
1024
+ missing" when reality was zero commits.
1025
+ - **D061** — Hot Files filters auto-generated files via the existing
1026
+ `autogeneratedSourcePatterns` registry. Pre-fix the .NET WinForms benchmark's hot
1027
+ list included `*.Designer.cs` files (WinForms designer regeneration
1028
+ noise).
1029
+ - **D063** — BoM Risk column rendered to one decimal (`18.5`,
1030
+ `14.8`) in both Triage and Vulnerable Packages tables. Pre-fix
1031
+ `toFixed(0)` rounded 14.8 → 15, making it look like SharpCompress
1032
+ should appear in the ≥15 triage when it was actually 14.8 (below
1033
+ threshold).
1034
+ - **D064** — BoM Reach column three-state: `✓` / `✗` / blank. Pre-
1035
+ fix blank silently merged "checked and not reachable" with "no
1036
+ data."
1037
+ - **D032** — Two-part dashboard-input fix. `analyzeHealthWithMetrics`
1038
+ runs unconditionally (was gated on `--detailed`); every report
1039
+ command writes BOTH `-detailed.json` AND `-detailed.md`
1040
+ unconditionally. `--detailed` flag now only controls the
1041
+ success-log console output. Pre-fix a default `dxkit health . &&
1042
+ dxkit dashboard .` workflow showed stale tile numbers + stale tab
1043
+ content from whatever the last `--detailed` run had left behind.
1044
+
1045
+ ### Fixed — Tier 3 (cosmetic)
1046
+
1047
+ - **D065** — Health "Add API documentation" recommendation no longer
1048
+ fires when `controllers === 0`. Pre-fix it triggered for any 100+
1049
+ source file repo, including desktop apps with no HTTP surface.
1050
+ - **D068** — Dashboard "Critical Issues at a Glance" discloses
1051
+ "(showing N of M)" when the per-surface caps (3 vulns + 3 gaps +
1052
+ 2 bom-triage) drop items. Pre-fix a customer with 20 CRITICAL
1053
+ untested files saw 3 and could reasonably infer "only 3 critical
1054
+ things in the repo."
1055
+ - **D070** — BoM main report collapses the project-roots paragraph
1056
+ to a 5-root preview + count; the full list moves to the detailed
1057
+ report under a dedicated `## Project Roots (N)` section, one root
1058
+ per line for grep / sort.
1059
+
1060
+ ### Recipe v4 status
1061
+
1062
+ - **G_v4_4** (per-pack `upgradeCommand`) — **delivered** (promoted
1063
+ from 2.4.8 because D062 fix was otherwise a switch-statement patch).
1064
+ - Still queued for 2.4.8: G_v4_5 (per-pack
1065
+ `autogeneratedHeaderPatterns`), G_v4_6 (unified TLS bypass count +
1066
+ findings), G_v4_7 (`walkSourceFiles` unified helper, class-fix for
1067
+ D072), G_v4_8 (merger field-ownership claims, class-fix for D057),
1068
+ G_v4_inherited_G2opt2 / _G3 / _G7.
1069
+
1070
+ ### Architecture — class lessons from the cascade
1071
+
1072
+ Two layering insights from D057 and D072, both with concrete class-
1073
+ fix candidates queued for 2.4.8:
1074
+
1075
+ - **Layer ownership** — when two gather functions write the same
1076
+ field (e.g. generic.ts and cloc.ts both writing `sourceFiles`),
1077
+ the merger should reject overlap rather than last-write-wins.
1078
+ Tracked as G_v4_8.
1079
+ - **Source-file definition uniformity** — every metric claiming
1080
+ "files matching X among source files" must share the predicate
1081
+ `sourceFiles` uses (exclusions + autogen-basename + autogen-header).
1082
+ Tracked as G_v4_7 (`walkSourceFiles` shared helper). Until it
1083
+ lands, every grep caller funnels through
1084
+ `isCountedSourceFile(cwd, relPath)` in `tools/generic.ts`.
1085
+
10
1086
  ## [2.4.6] - 2026-05-07
11
1087
 
12
1088
  ### Added — Ruby language pack (Phase 10k.2)