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