@vyuhlabs/dxkit 2.4.6 → 2.4.7

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 (345) hide show
  1. package/CHANGELOG.md +885 -0
  2. package/README.md +131 -26
  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 +666 -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 +19 -8
  38. package/dist/analyzers/developer/index.js.map +1 -1
  39. package/dist/analyzers/dispatcher.d.ts +37 -0
  40. package/dist/analyzers/dispatcher.d.ts.map +1 -1
  41. package/dist/analyzers/dispatcher.js +56 -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 +271 -33
  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 +70 -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 +189 -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 +347 -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 +103 -1
  107. package/dist/analyzers/security/gather.d.ts.map +1 -1
  108. package/dist/analyzers/security/gather.js +281 -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/debug-statements.d.ts +17 -0
  145. package/dist/analyzers/tools/debug-statements.d.ts.map +1 -0
  146. package/dist/analyzers/tools/debug-statements.js +58 -0
  147. package/dist/analyzers/tools/debug-statements.js.map +1 -0
  148. package/dist/analyzers/tools/default-exclusions.gitignore +28 -0
  149. package/dist/analyzers/tools/exclusions.d.ts +33 -6
  150. package/dist/analyzers/tools/exclusions.d.ts.map +1 -1
  151. package/dist/analyzers/tools/exclusions.js +95 -26
  152. package/dist/analyzers/tools/exclusions.js.map +1 -1
  153. package/dist/analyzers/tools/generic.d.ts +17 -2
  154. package/dist/analyzers/tools/generic.d.ts.map +1 -1
  155. package/dist/analyzers/tools/generic.js +206 -109
  156. package/dist/analyzers/tools/generic.js.map +1 -1
  157. package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
  158. package/dist/analyzers/tools/gitleaks.js +48 -1
  159. package/dist/analyzers/tools/gitleaks.js.map +1 -1
  160. package/dist/analyzers/tools/graphify.d.ts +30 -2
  161. package/dist/analyzers/tools/graphify.d.ts.map +1 -1
  162. package/dist/analyzers/tools/graphify.js +131 -15
  163. package/dist/analyzers/tools/graphify.js.map +1 -1
  164. package/dist/analyzers/tools/jscpd.d.ts +12 -2
  165. package/dist/analyzers/tools/jscpd.d.ts.map +1 -1
  166. package/dist/analyzers/tools/jscpd.js +129 -6
  167. package/dist/analyzers/tools/jscpd.js.map +1 -1
  168. package/dist/analyzers/tools/minified-detection.d.ts +9 -0
  169. package/dist/analyzers/tools/minified-detection.d.ts.map +1 -0
  170. package/dist/analyzers/tools/minified-detection.js +147 -0
  171. package/dist/analyzers/tools/minified-detection.js.map +1 -0
  172. package/dist/analyzers/tools/nuget-package-reference.d.ts +131 -0
  173. package/dist/analyzers/tools/nuget-package-reference.d.ts.map +1 -0
  174. package/dist/analyzers/tools/nuget-package-reference.js +175 -0
  175. package/dist/analyzers/tools/nuget-package-reference.js.map +1 -0
  176. package/dist/analyzers/tools/osv-scanner-deps.d.ts +3 -2
  177. package/dist/analyzers/tools/osv-scanner-deps.d.ts.map +1 -1
  178. package/dist/analyzers/tools/osv-scanner-deps.js +32 -14
  179. package/dist/analyzers/tools/osv-scanner-deps.js.map +1 -1
  180. package/dist/analyzers/tools/osv.d.ts +36 -0
  181. package/dist/analyzers/tools/osv.d.ts.map +1 -1
  182. package/dist/analyzers/tools/osv.js +26 -0
  183. package/dist/analyzers/tools/osv.js.map +1 -1
  184. package/dist/analyzers/tools/parallel.d.ts +1 -1
  185. package/dist/analyzers/tools/parallel.d.ts.map +1 -1
  186. package/dist/analyzers/tools/parallel.js +2 -2
  187. package/dist/analyzers/tools/parallel.js.map +1 -1
  188. package/dist/analyzers/tools/risk-score.d.ts +7 -0
  189. package/dist/analyzers/tools/risk-score.d.ts.map +1 -1
  190. package/dist/analyzers/tools/risk-score.js +9 -2
  191. package/dist/analyzers/tools/risk-score.js.map +1 -1
  192. package/dist/analyzers/tools/run-tests-helper.d.ts +43 -0
  193. package/dist/analyzers/tools/run-tests-helper.d.ts.map +1 -0
  194. package/dist/analyzers/tools/run-tests-helper.js +156 -0
  195. package/dist/analyzers/tools/run-tests-helper.js.map +1 -0
  196. package/dist/analyzers/tools/runner.d.ts.map +1 -1
  197. package/dist/analyzers/tools/runner.js +75 -12
  198. package/dist/analyzers/tools/runner.js.map +1 -1
  199. package/dist/analyzers/tools/semgrep.d.ts +39 -2
  200. package/dist/analyzers/tools/semgrep.d.ts.map +1 -1
  201. package/dist/analyzers/tools/semgrep.js +131 -9
  202. package/dist/analyzers/tools/semgrep.js.map +1 -1
  203. package/dist/analyzers/tools/timing.d.ts +17 -3
  204. package/dist/analyzers/tools/timing.d.ts.map +1 -1
  205. package/dist/analyzers/tools/timing.js +36 -14
  206. package/dist/analyzers/tools/timing.js.map +1 -1
  207. package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
  208. package/dist/analyzers/tools/tool-registry.js +11 -1
  209. package/dist/analyzers/tools/tool-registry.js.map +1 -1
  210. package/dist/analyzers/tools/tools-unavailable-prose.d.ts +18 -0
  211. package/dist/analyzers/tools/tools-unavailable-prose.d.ts.map +1 -0
  212. package/dist/analyzers/tools/tools-unavailable-prose.js +69 -0
  213. package/dist/analyzers/tools/tools-unavailable-prose.js.map +1 -0
  214. package/dist/analyzers/tools/upgrade-plan-resolver.d.ts.map +1 -1
  215. package/dist/analyzers/tools/upgrade-plan-resolver.js +7 -0
  216. package/dist/analyzers/tools/upgrade-plan-resolver.js.map +1 -1
  217. package/dist/analyzers/tools/vendored-advisor.d.ts +43 -0
  218. package/dist/analyzers/tools/vendored-advisor.d.ts.map +1 -0
  219. package/dist/analyzers/tools/vendored-advisor.js +107 -0
  220. package/dist/analyzers/tools/vendored-advisor.js.map +1 -0
  221. package/dist/analyzers/tools/walk-paths.d.ts +78 -0
  222. package/dist/analyzers/tools/walk-paths.d.ts.map +1 -0
  223. package/dist/analyzers/tools/walk-paths.js +150 -0
  224. package/dist/analyzers/tools/walk-paths.js.map +1 -0
  225. package/dist/analyzers/tools/walk-source-files.d.ts +70 -0
  226. package/dist/analyzers/tools/walk-source-files.d.ts.map +1 -0
  227. package/dist/analyzers/tools/walk-source-files.js +369 -0
  228. package/dist/analyzers/tools/walk-source-files.js.map +1 -0
  229. package/dist/analyzers/types.d.ts +204 -4
  230. package/dist/analyzers/types.d.ts.map +1 -1
  231. package/dist/analyzers/xlsx/bom.d.ts.map +1 -1
  232. package/dist/analyzers/xlsx/bom.js +8 -1
  233. package/dist/analyzers/xlsx/bom.js.map +1 -1
  234. package/dist/cli.d.ts.map +1 -1
  235. package/dist/cli.js +557 -189
  236. package/dist/cli.js.map +1 -1
  237. package/dist/detect.d.ts.map +1 -1
  238. package/dist/detect.js +24 -7
  239. package/dist/detect.js.map +1 -1
  240. package/dist/doctor.d.ts.map +1 -1
  241. package/dist/doctor.js +103 -53
  242. package/dist/doctor.js.map +1 -1
  243. package/dist/languages/capabilities/provider.d.ts +130 -1
  244. package/dist/languages/capabilities/provider.d.ts.map +1 -1
  245. package/dist/languages/capabilities/types.d.ts +68 -7
  246. package/dist/languages/capabilities/types.d.ts.map +1 -1
  247. package/dist/languages/csharp.d.ts +15 -1
  248. package/dist/languages/csharp.d.ts.map +1 -1
  249. package/dist/languages/csharp.js +624 -146
  250. package/dist/languages/csharp.js.map +1 -1
  251. package/dist/languages/go.d.ts.map +1 -1
  252. package/dist/languages/go.js +89 -11
  253. package/dist/languages/go.js.map +1 -1
  254. package/dist/languages/index.d.ts +131 -2
  255. package/dist/languages/index.d.ts.map +1 -1
  256. package/dist/languages/index.js +206 -0
  257. package/dist/languages/index.js.map +1 -1
  258. package/dist/languages/java.d.ts.map +1 -1
  259. package/dist/languages/java.js +113 -26
  260. package/dist/languages/java.js.map +1 -1
  261. package/dist/languages/kotlin.d.ts.map +1 -1
  262. package/dist/languages/kotlin.js +132 -26
  263. package/dist/languages/kotlin.js.map +1 -1
  264. package/dist/languages/python.d.ts.map +1 -1
  265. package/dist/languages/python.js +149 -44
  266. package/dist/languages/python.js.map +1 -1
  267. package/dist/languages/ruby.d.ts +39 -1
  268. package/dist/languages/ruby.d.ts.map +1 -1
  269. package/dist/languages/ruby.js +178 -44
  270. package/dist/languages/ruby.js.map +1 -1
  271. package/dist/languages/rust.d.ts.map +1 -1
  272. package/dist/languages/rust.js +103 -16
  273. package/dist/languages/rust.js.map +1 -1
  274. package/dist/languages/types.d.ts +228 -5
  275. package/dist/languages/types.d.ts.map +1 -1
  276. package/dist/languages/typescript.d.ts.map +1 -1
  277. package/dist/languages/typescript.js +201 -14
  278. package/dist/languages/typescript.js.map +1 -1
  279. package/dist/scoring/dimensions/documentation.d.ts +53 -0
  280. package/dist/scoring/dimensions/documentation.d.ts.map +1 -0
  281. package/dist/scoring/dimensions/documentation.js +106 -0
  282. package/dist/scoring/dimensions/documentation.js.map +1 -0
  283. package/dist/scoring/dimensions/dx.d.ts +53 -0
  284. package/dist/scoring/dimensions/dx.d.ts.map +1 -0
  285. package/dist/scoring/dimensions/dx.js +105 -0
  286. package/dist/scoring/dimensions/dx.js.map +1 -0
  287. package/dist/scoring/dimensions/maintainability.d.ts +53 -0
  288. package/dist/scoring/dimensions/maintainability.d.ts.map +1 -0
  289. package/dist/scoring/dimensions/maintainability.js +101 -0
  290. package/dist/scoring/dimensions/maintainability.js.map +1 -0
  291. package/dist/scoring/dimensions/quality.d.ts +108 -0
  292. package/dist/scoring/dimensions/quality.d.ts.map +1 -0
  293. package/dist/scoring/dimensions/quality.js +174 -0
  294. package/dist/scoring/dimensions/quality.js.map +1 -0
  295. package/dist/scoring/dimensions/security.d.ts +84 -0
  296. package/dist/scoring/dimensions/security.d.ts.map +1 -0
  297. package/dist/scoring/dimensions/security.js +135 -0
  298. package/dist/scoring/dimensions/security.js.map +1 -0
  299. package/dist/scoring/dimensions/testing.d.ts +56 -0
  300. package/dist/scoring/dimensions/testing.d.ts.map +1 -0
  301. package/dist/scoring/dimensions/testing.js +98 -0
  302. package/dist/scoring/dimensions/testing.js.map +1 -0
  303. package/dist/scoring/evaluator.d.ts +27 -0
  304. package/dist/scoring/evaluator.d.ts.map +1 -0
  305. package/dist/scoring/evaluator.js +124 -0
  306. package/dist/scoring/evaluator.js.map +1 -0
  307. package/dist/scoring/format.d.ts +34 -0
  308. package/dist/scoring/format.d.ts.map +1 -0
  309. package/dist/scoring/format.js +63 -0
  310. package/dist/scoring/format.js.map +1 -0
  311. package/dist/scoring/index.d.ts +37 -0
  312. package/dist/scoring/index.d.ts.map +1 -0
  313. package/dist/scoring/index.js +57 -0
  314. package/dist/scoring/index.js.map +1 -0
  315. package/dist/scoring/overall.d.ts +54 -0
  316. package/dist/scoring/overall.d.ts.map +1 -0
  317. package/dist/scoring/overall.js +76 -0
  318. package/dist/scoring/overall.js.map +1 -0
  319. package/dist/scoring/result.d.ts +111 -0
  320. package/dist/scoring/result.d.ts.map +1 -0
  321. package/dist/scoring/result.js +14 -0
  322. package/dist/scoring/result.js.map +1 -0
  323. package/dist/scoring/spec.d.ts +76 -0
  324. package/dist/scoring/spec.d.ts.map +1 -0
  325. package/dist/scoring/spec.js +22 -0
  326. package/dist/scoring/spec.js.map +1 -0
  327. package/dist/scoring/thresholds.d.ts +56 -0
  328. package/dist/scoring/thresholds.d.ts.map +1 -0
  329. package/dist/scoring/thresholds.js +75 -0
  330. package/dist/scoring/thresholds.js.map +1 -0
  331. package/dist/tools-cli.d.ts.map +1 -1
  332. package/dist/tools-cli.js +21 -2
  333. package/dist/tools-cli.js.map +1 -1
  334. package/dist/types.d.ts +16 -0
  335. package/dist/types.d.ts.map +1 -1
  336. package/package.json +1 -1
  337. package/templates/.claude/commands/dashboard.md +17 -9
  338. package/dist/analyzers/scoring.d.ts +0 -49
  339. package/dist/analyzers/scoring.d.ts.map +0 -1
  340. package/dist/analyzers/scoring.js +0 -422
  341. package/dist/analyzers/scoring.js.map +0 -1
  342. package/dist/analyzers/security/scoring.d.ts +0 -29
  343. package/dist/analyzers/security/scoring.d.ts.map +0 -1
  344. package/dist/analyzers/security/scoring.js +0 -40
  345. package/dist/analyzers/security/scoring.js.map +0 -1
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Security dimension — declarative scoring spec.
3
+ *
4
+ * Methodology: severity-dominant rating per ISO/IEC 5055 (automated
5
+ * source code quality measures, CISQ-driven) layered with CVSS v4
6
+ * (FIRST.org) for vulnerability severity bands. The spec encodes:
7
+ *
8
+ * - Penalty deductions for secrets, private keys, `.env` in git,
9
+ * code-pattern findings (semgrep et al), and dependency
10
+ * vulnerabilities. Each penalty surfaces as a discrete Deduction
11
+ * with a human-readable reason.
12
+ * - Cap rules that bound the rating when specific blocker classes
13
+ * are present (see `src/scoring/STANDARDS.md` for the cap
14
+ * taxonomy):
15
+ * trust-broken (40) — committed credentials
16
+ * uncertainty (65) — dep-vuln scanner did not run
17
+ * fixable-finding (79) — open HIGH/CRITICAL code finding
18
+ *
19
+ * The evaluator (`evaluateSpec`) consumes this spec + a
20
+ * `SecurityScoreInput` and produces the canonical `ScoreResult`. Both
21
+ * the health audit's Security dimension and the standalone
22
+ * vulnerability scan call the same path — same input ⇒ same number
23
+ * by construction.
24
+ *
25
+ * Adapters that build `SecurityScoreInput` from their domain data:
26
+ *
27
+ * - Health side: `src/analyzers/security/shallow.ts:toSecurityScoreInput`
28
+ * reads from `ScoreInput { metrics, capabilities }`. Falls back
29
+ * to grep-based HealthMetrics counts when `capabilities.codePatterns`
30
+ * is absent (semgrep unavailable).
31
+ * - Standalone side: `src/analyzers/security/actions.ts:countsFromReport`
32
+ * reads from `SecurityReport.findings` by partitioning on rule +
33
+ * category.
34
+ *
35
+ * Both adapters land on this same `SecurityScoreInput` shape; both
36
+ * dispatch through the same spec; both observe identical scores.
37
+ */
38
+ import type { DimensionScoringSpec } from '../spec';
39
+ /** Severity counts shape, kept inline for clarity at call sites. */
40
+ interface SeverityCounts {
41
+ critical: number;
42
+ high: number;
43
+ medium: number;
44
+ low: number;
45
+ }
46
+ /**
47
+ * Clean partition of the security signal universe. Each finding the
48
+ * gather code emits maps to exactly one field — no double-counting,
49
+ * no missed contributions. Both health-side and standalone-side
50
+ * adapters produce this shape.
51
+ */
52
+ export interface SecurityScoreInput {
53
+ /** Gitleaks-detected secrets (hardcoded credentials, API keys). */
54
+ secretFindings: number;
55
+ /** Private key / cert files on disk (*.key, *.pem). */
56
+ privateKeyFiles: number;
57
+ /** .env files tracked in git. */
58
+ envFilesInGit: number;
59
+ /**
60
+ * Semgrep code-pattern findings by severity. Includes eval/exec,
61
+ * TLS verification disabled, SQL injection, XSS, CORS, SSRF, and
62
+ * every other static-analysis pattern the active language packs'
63
+ * rulesets cover.
64
+ */
65
+ codeFindings: SeverityCounts;
66
+ /** Dependency-vulnerability counts unioned across active packs. */
67
+ depVulns: SeverityCounts;
68
+ /**
69
+ * True if at least one active pack's depVulns gather reached
70
+ * success OR cleanly reported `no-manifest`; false if any pack
71
+ * returned `unavailable` (tool absent / no output / parse fail).
72
+ *
73
+ * When false, the `dep-vulns-unavailable` cap fires and bounds
74
+ * the score at the uncertainty tier ceiling regardless of other
75
+ * signals — dxkit can't honestly claim a top-tier score when it
76
+ * couldn't actually scan the deps.
77
+ *
78
+ * Adapters MUST populate this from `DepVulnSummary.available`.
79
+ */
80
+ depVulnsAvailable: boolean;
81
+ }
82
+ export declare const SECURITY_SCORING_SPEC: DimensionScoringSpec<SecurityScoreInput>;
83
+ export {};
84
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../src/scoring/dimensions/security.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,oEAAoE;AACpE,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC;IACvB,uDAAuD;IACvD,eAAe,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,YAAY,EAAE,cAAc,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,EAAE,cAAc,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAUD,eAAO,MAAM,qBAAqB,EAAE,oBAAoB,CAAC,kBAAkB,CAoF1E,CAAC"}
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ /**
3
+ * Security dimension — declarative scoring spec.
4
+ *
5
+ * Methodology: severity-dominant rating per ISO/IEC 5055 (automated
6
+ * source code quality measures, CISQ-driven) layered with CVSS v4
7
+ * (FIRST.org) for vulnerability severity bands. The spec encodes:
8
+ *
9
+ * - Penalty deductions for secrets, private keys, `.env` in git,
10
+ * code-pattern findings (semgrep et al), and dependency
11
+ * vulnerabilities. Each penalty surfaces as a discrete Deduction
12
+ * with a human-readable reason.
13
+ * - Cap rules that bound the rating when specific blocker classes
14
+ * are present (see `src/scoring/STANDARDS.md` for the cap
15
+ * taxonomy):
16
+ * trust-broken (40) — committed credentials
17
+ * uncertainty (65) — dep-vuln scanner did not run
18
+ * fixable-finding (79) — open HIGH/CRITICAL code finding
19
+ *
20
+ * The evaluator (`evaluateSpec`) consumes this spec + a
21
+ * `SecurityScoreInput` and produces the canonical `ScoreResult`. Both
22
+ * the health audit's Security dimension and the standalone
23
+ * vulnerability scan call the same path — same input ⇒ same number
24
+ * by construction.
25
+ *
26
+ * Adapters that build `SecurityScoreInput` from their domain data:
27
+ *
28
+ * - Health side: `src/analyzers/security/shallow.ts:toSecurityScoreInput`
29
+ * reads from `ScoreInput { metrics, capabilities }`. Falls back
30
+ * to grep-based HealthMetrics counts when `capabilities.codePatterns`
31
+ * is absent (semgrep unavailable).
32
+ * - Standalone side: `src/analyzers/security/actions.ts:countsFromReport`
33
+ * reads from `SecurityReport.findings` by partitioning on rule +
34
+ * category.
35
+ *
36
+ * Both adapters land on this same `SecurityScoreInput` shape; both
37
+ * dispatch through the same spec; both observe identical scores.
38
+ */
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.SECURITY_SCORING_SPEC = void 0;
41
+ /**
42
+ * Helper: render a count phrase with proper plural ("1 secret" /
43
+ * "5 secrets"). Used by penalty + cap reason builders.
44
+ */
45
+ function plural(n, singular, plural) {
46
+ return `${n} ${n === 1 ? singular : (plural ?? `${singular}s`)}`;
47
+ }
48
+ exports.SECURITY_SCORING_SPEC = {
49
+ dimension: 'security',
50
+ methodology: 'iso-iec-5055-severity-dominant',
51
+ baseline: 100,
52
+ penalties: [
53
+ {
54
+ id: 'secrets-present',
55
+ describe: (i) => `${plural(i.secretFindings, 'hardcoded secret')} detected`,
56
+ applies: (i) => i.secretFindings > 0,
57
+ delta: (i) => (i.secretFindings > 10 ? -25 : i.secretFindings > 5 ? -20 : -15),
58
+ },
59
+ {
60
+ id: 'private-key-files',
61
+ describe: (i) => `${plural(i.privateKeyFiles, 'private key / cert file')} on disk`,
62
+ applies: (i) => i.privateKeyFiles > 0,
63
+ delta: () => -20,
64
+ },
65
+ {
66
+ id: 'env-files-in-git',
67
+ describe: (i) => `${plural(i.envFilesInGit, '.env file')} tracked in git`,
68
+ applies: (i) => i.envFilesInGit > 0,
69
+ delta: () => -10,
70
+ },
71
+ {
72
+ id: 'code-findings-critical',
73
+ describe: (i) => `${plural(i.codeFindings.critical, 'CRITICAL code finding')} (static analysis)`,
74
+ applies: (i) => i.codeFindings.critical > 0,
75
+ delta: (i) => (i.codeFindings.critical > 10 ? -25 : i.codeFindings.critical > 5 ? -20 : -15),
76
+ },
77
+ {
78
+ id: 'code-findings-high',
79
+ describe: (i) => `${plural(i.codeFindings.high, 'HIGH code finding')} (static analysis)`,
80
+ applies: (i) => i.codeFindings.high > 0,
81
+ delta: (i) => (i.codeFindings.high > 5 ? -10 : -5),
82
+ },
83
+ {
84
+ id: 'code-findings-medium',
85
+ describe: (i) => `${plural(i.codeFindings.medium, 'MEDIUM code finding')} (static analysis)`,
86
+ applies: (i) => i.codeFindings.medium > 10,
87
+ delta: () => -5,
88
+ },
89
+ {
90
+ id: 'dep-vulns-critical',
91
+ describe: (i) => `${plural(i.depVulns.critical, 'CRITICAL dependency vulnerability')}`,
92
+ applies: (i) => i.depVulns.critical > 0,
93
+ delta: () => -15,
94
+ },
95
+ {
96
+ id: 'dep-vulns-high',
97
+ describe: (i) => `${plural(i.depVulns.high, 'HIGH dependency vulnerability')}`,
98
+ applies: (i) => i.depVulns.high > 0,
99
+ delta: (i) => (i.depVulns.high > 5 ? -10 : -5),
100
+ },
101
+ ],
102
+ caps: [
103
+ {
104
+ id: 'secrets-present',
105
+ tier: 'trust-broken',
106
+ describe: (i) => {
107
+ const parts = [];
108
+ if (i.secretFindings > 0)
109
+ parts.push(plural(i.secretFindings, 'hardcoded secret'));
110
+ if (i.privateKeyFiles > 0)
111
+ parts.push(plural(i.privateKeyFiles, 'private key file'));
112
+ if (i.envFilesInGit > 0)
113
+ parts.push(plural(i.envFilesInGit, '.env in git'));
114
+ return `committed credentials present: ${parts.join(' + ')}`;
115
+ },
116
+ applies: (i) => i.secretFindings > 0 || i.privateKeyFiles > 0 || i.envFilesInGit > 0,
117
+ },
118
+ {
119
+ id: 'dep-vulns-unavailable',
120
+ tier: 'uncertainty',
121
+ describe: () => `dependency vulnerability scan did not run`,
122
+ applies: (i) => !i.depVulnsAvailable,
123
+ },
124
+ {
125
+ id: 'high-plus-code-open',
126
+ tier: 'fixable-finding',
127
+ describe: (i) => {
128
+ const total = i.codeFindings.critical + i.codeFindings.high;
129
+ return `${plural(total, 'open HIGH+ code finding')}`;
130
+ },
131
+ applies: (i) => i.codeFindings.critical > 0 || i.codeFindings.high > 0,
132
+ },
133
+ ],
134
+ };
135
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../../src/scoring/dimensions/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Testing dimension — declarative scoring spec.
3
+ *
4
+ * Methodology: additive checklist over test-discipline signals (test
5
+ * ratio, coverage-config presence, runner exit code, line-coverage
6
+ * thresholds) gated on test-file presence, plus a hygiene penalty
7
+ * for source that's predominantly commented-out code.
8
+ *
9
+ * Industry-conventional coverage thresholds: 60% (adequate), 80%
10
+ * (excellent). Sources: CodeClimate default config, SonarQube's
11
+ * Coverage on New Code quality-gate condition (default 80%), Google
12
+ * Testing on the Toilet recommendations. These thresholds are the
13
+ * de-facto convention; dxkit adopts them.
14
+ *
15
+ * Cap rule encodes the Label Contract: when coverage data is absent
16
+ * the dimension can't honestly claim a top-tier rating regardless of
17
+ * how many test files exist — file presence + a green exit code
18
+ * without line-coverage measurement is failing the most basic
19
+ * testing-discipline check.
20
+ *
21
+ * unmeasured (35) no coverage data available
22
+ *
23
+ * Source signal flow: the adapter (`src/analyzers/tests/shallow.ts`)
24
+ * builds `TestingScoreInput` from the health-side ScoreInput
25
+ * (HealthMetrics + CapabilityReport) and dispatches through
26
+ * `evaluateSpec`. The standalone test-gaps subcommand uses its own
27
+ * separate analyzer; this dimension only feeds the health rollup.
28
+ */
29
+ import type { DimensionScoringSpec } from '../spec';
30
+ /**
31
+ * Partition of every signal the Testing scorer reads. The adapter
32
+ * builds this shape; the spec stays consumer-agnostic.
33
+ */
34
+ export interface TestingScoreInput {
35
+ /** Total source files (the denominator for test-ratio). */
36
+ sourceFiles: number;
37
+ /** Test files (discovered by name patterns per active language pack). */
38
+ testFiles: number;
39
+ /** True when at least one coverage config file is present
40
+ * (jest.config + collectCoverage, vitest.config + coverage,
41
+ * pytest.ini + --cov, etc.). */
42
+ coverageConfigExists: boolean;
43
+ /** Runner exit code: true=green, false=red, null=not invoked. */
44
+ testsPass: boolean | null;
45
+ /** Line-coverage percent (rounded integer). Null when no coverage
46
+ * artifact was found — the most-conservative interpretation is
47
+ * "we don't know" and triggers the unmeasured cap. */
48
+ coveragePercent: number | null;
49
+ /** From graphify: ratio of commented-out code in source files
50
+ * (0.0–1.0). Beyond 0.5 the file is more dead/commented than
51
+ * active code — a hygiene red flag worth penalizing. Null when
52
+ * graphify didn't run. */
53
+ commentedCodeRatio: number | null;
54
+ }
55
+ export declare const TESTING_SCORING_SPEC: DimensionScoringSpec<TestingScoreInput>;
56
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../src/scoring/dimensions/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB;;qCAEiC;IACjC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,iEAAiE;IACjE,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B;;2DAEuD;IACvD,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;+BAG2B;IAC3B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,oBAAoB,EAAE,oBAAoB,CAAC,iBAAiB,CAqExE,CAAC"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * Testing dimension — declarative scoring spec.
4
+ *
5
+ * Methodology: additive checklist over test-discipline signals (test
6
+ * ratio, coverage-config presence, runner exit code, line-coverage
7
+ * thresholds) gated on test-file presence, plus a hygiene penalty
8
+ * for source that's predominantly commented-out code.
9
+ *
10
+ * Industry-conventional coverage thresholds: 60% (adequate), 80%
11
+ * (excellent). Sources: CodeClimate default config, SonarQube's
12
+ * Coverage on New Code quality-gate condition (default 80%), Google
13
+ * Testing on the Toilet recommendations. These thresholds are the
14
+ * de-facto convention; dxkit adopts them.
15
+ *
16
+ * Cap rule encodes the Label Contract: when coverage data is absent
17
+ * the dimension can't honestly claim a top-tier rating regardless of
18
+ * how many test files exist — file presence + a green exit code
19
+ * without line-coverage measurement is failing the most basic
20
+ * testing-discipline check.
21
+ *
22
+ * unmeasured (35) no coverage data available
23
+ *
24
+ * Source signal flow: the adapter (`src/analyzers/tests/shallow.ts`)
25
+ * builds `TestingScoreInput` from the health-side ScoreInput
26
+ * (HealthMetrics + CapabilityReport) and dispatches through
27
+ * `evaluateSpec`. The standalone test-gaps subcommand uses its own
28
+ * separate analyzer; this dimension only feeds the health rollup.
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.TESTING_SCORING_SPEC = void 0;
32
+ exports.TESTING_SCORING_SPEC = {
33
+ dimension: 'testing',
34
+ methodology: 'industry-coverage-thresholds',
35
+ // Additive baseline: every positive-delta signal contributes
36
+ // points; the zero-tests deduction surfaces the most-actionable
37
+ // customer case (no tests at all) with a real Top Action.
38
+ baseline: 0,
39
+ penalties: [
40
+ {
41
+ id: 'no-tests-found',
42
+ describe: (i) => `no test files found across ${i.sourceFiles} source files (start with the highest-risk untested files — see test-gaps)`,
43
+ applies: (i) => i.testFiles === 0,
44
+ // -60 mirrors the max bonus the test-ratio rule could grant at
45
+ // a healthy ratio. The score floors at 0 (E) either way, but
46
+ // surfacing the deduction makes the dimension actionable: the
47
+ // renderer shows "+60 — would lift rating E → C" and the
48
+ // severe-debt disclosure fires.
49
+ delta: () => -60,
50
+ },
51
+ {
52
+ id: 'test-ratio',
53
+ describe: (i) => `${i.testFiles} test files for ${i.sourceFiles} source files ` +
54
+ `(${((i.testFiles / Math.max(i.sourceFiles, 1)) * 100).toFixed(1)}% ratio)`,
55
+ applies: (i) => i.testFiles > 0,
56
+ delta: (i) => Math.min((i.testFiles / Math.max(i.sourceFiles, 1)) * 200, 60),
57
+ },
58
+ {
59
+ id: 'coverage-config-present',
60
+ describe: () => `coverage config detected`,
61
+ applies: (i) => i.testFiles > 0 && i.coverageConfigExists,
62
+ delta: () => 10,
63
+ },
64
+ {
65
+ id: 'tests-passing',
66
+ describe: () => `test runner reports green`,
67
+ applies: (i) => i.testFiles > 0 && i.testsPass === true,
68
+ delta: () => 15,
69
+ },
70
+ {
71
+ id: 'coverage-adequate',
72
+ describe: (i) => `line coverage ${i.coveragePercent}% (≥ 60% threshold met)`,
73
+ applies: (i) => i.testFiles > 0 && i.coveragePercent !== null && i.coveragePercent >= 60, // scoring-spec-ok: industry coverage threshold, not a rating boundary
74
+ delta: () => 10,
75
+ },
76
+ {
77
+ id: 'coverage-excellent',
78
+ describe: (i) => `line coverage ${i.coveragePercent}% (≥ 80% threshold met)`,
79
+ applies: (i) => i.testFiles > 0 && i.coveragePercent !== null && i.coveragePercent >= 80, // scoring-spec-ok: industry coverage threshold, not a rating boundary
80
+ delta: () => 5,
81
+ },
82
+ {
83
+ id: 'commented-code-density',
84
+ describe: (i) => `${((i.commentedCodeRatio ?? 0) * 100).toFixed(0)}% of source is commented-out code`,
85
+ applies: (i) => i.commentedCodeRatio !== null && i.commentedCodeRatio > 0.5,
86
+ delta: () => -15,
87
+ },
88
+ ],
89
+ caps: [
90
+ {
91
+ id: 'coverage-unmeasured',
92
+ tier: 'unmeasured',
93
+ describe: () => `no coverage data available — test runner did not produce a coverage artifact`,
94
+ applies: (i) => i.coveragePercent === null,
95
+ },
96
+ ],
97
+ };
98
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../../../src/scoring/dimensions/testing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Pure-function spec evaluator. The single code path every dimension's
3
+ * score travels through.
4
+ *
5
+ * Same spec + same input → same `ScoreResult`, every time. No I/O, no
6
+ * clock, no randomness. This is the determinism property dxkit's
7
+ * scoring depends on for cross-process consistency and for agents to
8
+ * verify expected score deltas after applying a fix.
9
+ *
10
+ * Algorithm:
11
+ * 1. Apply each penalty whose `applies(input)` is true; accumulate
12
+ * deductions and a running score from `spec.baseline`.
13
+ * 2. Clamp the raw score to [0, 100].
14
+ * 3. Determine which caps apply; sort by ceiling ascending; the
15
+ * first (lowest-ceiling) cap that binds (i.e. final > ceiling)
16
+ * lowers the final score to that ceiling.
17
+ * 4. Compute uplift for each surfaced action:
18
+ * - For deductions: bounded by the current cap (0 if a cap binds).
19
+ * - For the binding cap: distance to the next-applicable ceiling
20
+ * OR the post-clamp rawScore, whichever is lower.
21
+ * 5. Build `topActions` by sorting deductions + cap by uplift desc.
22
+ * Annotate any action whose uplift crosses a rating boundary.
23
+ */
24
+ import type { DimensionScoringSpec } from './spec';
25
+ import type { ScoreResult } from './result';
26
+ export declare function evaluateSpec<TInput>(spec: DimensionScoringSpec<TInput>, input: TInput): ScoreResult;
27
+ //# sourceMappingURL=evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../src/scoring/evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAEnD,OAAO,KAAK,EAAyB,WAAW,EAAa,MAAM,UAAU,CAAC;AAE9E,wBAAgB,YAAY,CAAC,MAAM,EACjC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,EAClC,KAAK,EAAE,MAAM,GACZ,WAAW,CAwGb"}
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ /**
3
+ * Pure-function spec evaluator. The single code path every dimension's
4
+ * score travels through.
5
+ *
6
+ * Same spec + same input → same `ScoreResult`, every time. No I/O, no
7
+ * clock, no randomness. This is the determinism property dxkit's
8
+ * scoring depends on for cross-process consistency and for agents to
9
+ * verify expected score deltas after applying a fix.
10
+ *
11
+ * Algorithm:
12
+ * 1. Apply each penalty whose `applies(input)` is true; accumulate
13
+ * deductions and a running score from `spec.baseline`.
14
+ * 2. Clamp the raw score to [0, 100].
15
+ * 3. Determine which caps apply; sort by ceiling ascending; the
16
+ * first (lowest-ceiling) cap that binds (i.e. final > ceiling)
17
+ * lowers the final score to that ceiling.
18
+ * 4. Compute uplift for each surfaced action:
19
+ * - For deductions: bounded by the current cap (0 if a cap binds).
20
+ * - For the binding cap: distance to the next-applicable ceiling
21
+ * OR the post-clamp rawScore, whichever is lower.
22
+ * 5. Build `topActions` by sorting deductions + cap by uplift desc.
23
+ * Annotate any action whose uplift crosses a rating boundary.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.evaluateSpec = evaluateSpec;
27
+ const thresholds_1 = require("./thresholds");
28
+ function evaluateSpec(spec, input) {
29
+ const deductions = [];
30
+ let runningScore = spec.baseline;
31
+ for (const rule of spec.penalties) {
32
+ if (!rule.applies(input))
33
+ continue;
34
+ const delta = rule.delta(input);
35
+ runningScore += delta;
36
+ const upliftIfFixed = rule.upliftIfFixed ? rule.upliftIfFixed(input) : Math.abs(delta);
37
+ deductions.push({
38
+ id: rule.id,
39
+ reason: rule.describe(input),
40
+ delta,
41
+ upliftIfFixed,
42
+ });
43
+ }
44
+ const rawScore = runningScore;
45
+ const rawPenalty = rawScore - spec.baseline;
46
+ const scoreAfterClamp = Math.round(Math.max(0, Math.min(100, rawScore)));
47
+ const applicableCaps = spec.caps
48
+ .filter((cap) => cap.applies(input))
49
+ .map((cap) => ({ cap, ceiling: thresholds_1.CAP_TIERS[cap.tier] }))
50
+ .sort((a, b) => a.ceiling - b.ceiling);
51
+ let finalScore = scoreAfterClamp;
52
+ let bindingCap = null;
53
+ for (let i = 0; i < applicableCaps.length; i++) {
54
+ const { cap, ceiling } = applicableCaps[i];
55
+ if (finalScore <= ceiling)
56
+ continue;
57
+ // Uplift if THIS cap were lifted: next-most-aggressive cap takes
58
+ // over, or the unclamped post-penalty score (capped at 100) bounds
59
+ // if no other cap applies.
60
+ const nextCap = applicableCaps[i + 1];
61
+ const ceilingIfRemoved = nextCap ? Math.min(scoreAfterClamp, nextCap.ceiling) : scoreAfterClamp;
62
+ bindingCap = {
63
+ id: cap.id,
64
+ tier: cap.tier,
65
+ ceiling,
66
+ reason: cap.describe(input),
67
+ upliftIfRemoved: ceilingIfRemoved - ceiling,
68
+ };
69
+ finalScore = ceiling;
70
+ break;
71
+ }
72
+ const capsApplied = bindingCap ? [bindingCap] : [];
73
+ // Compute effective uplift for each deduction. When a cap binds,
74
+ // fixing a non-cap deduction can't raise the score past the ceiling,
75
+ // so uplift reads as 0 — surfaces the cap as the real top action.
76
+ const effectiveDeductionUplift = (d) => {
77
+ if (bindingCap)
78
+ return 0;
79
+ const headroom = 100 - finalScore;
80
+ return Math.max(0, Math.min(d.upliftIfFixed, headroom));
81
+ };
82
+ const currentRating = (0, thresholds_1.ratingFromScore)(finalScore);
83
+ const projectRating = (uplift) => (0, thresholds_1.ratingFromScore)(Math.min(100, finalScore + uplift));
84
+ const buildTopActions = () => {
85
+ const actions = [];
86
+ for (const d of deductions) {
87
+ const uplift = effectiveDeductionUplift(d);
88
+ if (uplift <= 0)
89
+ continue;
90
+ const projected = projectRating(uplift);
91
+ actions.push({
92
+ source: 'deduction',
93
+ id: d.id,
94
+ reason: d.reason,
95
+ upliftIfFixed: uplift,
96
+ ratingTransition: projected !== currentRating ? { from: currentRating, to: projected } : undefined,
97
+ });
98
+ }
99
+ if (bindingCap && bindingCap.upliftIfRemoved > 0) {
100
+ const projected = projectRating(bindingCap.upliftIfRemoved);
101
+ actions.push({
102
+ source: 'cap',
103
+ id: bindingCap.id,
104
+ reason: bindingCap.reason,
105
+ upliftIfFixed: bindingCap.upliftIfRemoved,
106
+ ratingTransition: projected !== currentRating ? { from: currentRating, to: projected } : undefined,
107
+ });
108
+ }
109
+ actions.sort((a, b) => b.upliftIfFixed - a.upliftIfFixed);
110
+ return actions;
111
+ };
112
+ return {
113
+ dimension: spec.dimension,
114
+ methodology: spec.methodology,
115
+ rating: currentRating,
116
+ score: finalScore,
117
+ rawScore,
118
+ rawPenalty,
119
+ deductions,
120
+ capsApplied,
121
+ topActions: buildTopActions(),
122
+ };
123
+ }
124
+ //# sourceMappingURL=evaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../../src/scoring/evaluator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Renderer helpers — turn a `ScoreResult`'s structured provenance
3
+ * into markdown the customer can act on.
4
+ *
5
+ * These functions don't know which dimension they're rendering; they
6
+ * read `topActions[]` + `capsApplied[]` from any spec output and
7
+ * produce consistent prose. Per-dimension renderers (the analyzer
8
+ * subdirs) call into here so the "Top Actions" surface looks the
9
+ * same across every dimension's report.
10
+ */
11
+ import type { CapApplied, ScoreResult, TopAction } from './result';
12
+ /**
13
+ * Subset of `DimensionScore` the formatters need. Lets the health-side
14
+ * `DimensionScore` and any future direct `ScoreResult` consumer share
15
+ * the same renderer without coupling on the full health type.
16
+ */
17
+ export interface ScoreResultLike {
18
+ readonly score: number;
19
+ readonly rating: ScoreResult['rating'];
20
+ readonly rawScore?: number;
21
+ readonly rawPenalty?: number;
22
+ readonly capsApplied?: readonly CapApplied[];
23
+ readonly topActions?: readonly TopAction[];
24
+ }
25
+ /** One-line top-action summary, suitable for table cells / CLI grids. */
26
+ export declare function formatTopActionLine(score: ScoreResultLike): string;
27
+ /**
28
+ * Markdown block listing the top N actions for a dimension. Returns
29
+ * an empty array (no lines) when the dimension has no actionable
30
+ * items — caller decides whether to suppress the section header in
31
+ * that case.
32
+ */
33
+ export declare function formatTopActionsBlock(score: ScoreResultLike, limit?: number): string[];
34
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/scoring/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;CAC5C;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAQlE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE,CAmCjF"}