@xenos1996/usa 2.0.0
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/LICENSE +21 -0
- package/README.md +335 -0
- package/USA.md +597 -0
- package/dist/bootstrap/catalog.d.ts +46 -0
- package/dist/bootstrap/catalog.d.ts.map +1 -0
- package/dist/bootstrap/catalog.js +312 -0
- package/dist/bootstrap/catalog.js.map +1 -0
- package/dist/bootstrap/index.d.ts +36 -0
- package/dist/bootstrap/index.d.ts.map +1 -0
- package/dist/bootstrap/index.js +177 -0
- package/dist/bootstrap/index.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +706 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +88 -0
- package/dist/config.js.map +1 -0
- package/dist/detect/index.d.ts +58 -0
- package/dist/detect/index.d.ts.map +1 -0
- package/dist/detect/index.js +329 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/engine/audit.d.ts +32 -0
- package/dist/engine/audit.d.ts.map +1 -0
- package/dist/engine/audit.js +366 -0
- package/dist/engine/audit.js.map +1 -0
- package/dist/engine/diff.d.ts +24 -0
- package/dist/engine/diff.d.ts.map +1 -0
- package/dist/engine/diff.js +136 -0
- package/dist/engine/diff.js.map +1 -0
- package/dist/engine/evaluate.d.ts +19 -0
- package/dist/engine/evaluate.d.ts.map +1 -0
- package/dist/engine/evaluate.js +377 -0
- package/dist/engine/evaluate.js.map +1 -0
- package/dist/engine/gate.d.ts +19 -0
- package/dist/engine/gate.d.ts.map +1 -0
- package/dist/engine/gate.js +47 -0
- package/dist/engine/gate.js.map +1 -0
- package/dist/engine/loader.d.ts +37 -0
- package/dist/engine/loader.d.ts.map +1 -0
- package/dist/engine/loader.js +388 -0
- package/dist/engine/loader.js.map +1 -0
- package/dist/engine/maturity.d.ts +20 -0
- package/dist/engine/maturity.d.ts.map +1 -0
- package/dist/engine/maturity.js +157 -0
- package/dist/engine/maturity.js.map +1 -0
- package/dist/engine/score.d.ts +19 -0
- package/dist/engine/score.d.ts.map +1 -0
- package/dist/engine/score.js +141 -0
- package/dist/engine/score.js.map +1 -0
- package/dist/engine/sections.d.ts +14 -0
- package/dist/engine/sections.d.ts.map +1 -0
- package/dist/engine/sections.js +50 -0
- package/dist/engine/sections.js.map +1 -0
- package/dist/evolution/benchmark.d.ts +12 -0
- package/dist/evolution/benchmark.d.ts.map +1 -0
- package/dist/evolution/benchmark.js +107 -0
- package/dist/evolution/benchmark.js.map +1 -0
- package/dist/evolution/capability.d.ts +22 -0
- package/dist/evolution/capability.d.ts.map +1 -0
- package/dist/evolution/capability.js +69 -0
- package/dist/evolution/capability.js.map +1 -0
- package/dist/evolution/coverage.d.ts +15 -0
- package/dist/evolution/coverage.d.ts.map +1 -0
- package/dist/evolution/coverage.js +65 -0
- package/dist/evolution/coverage.js.map +1 -0
- package/dist/evolution/gap.d.ts +10 -0
- package/dist/evolution/gap.d.ts.map +1 -0
- package/dist/evolution/gap.js +52 -0
- package/dist/evolution/gap.js.map +1 -0
- package/dist/evolution/propose.d.ts +50 -0
- package/dist/evolution/propose.d.ts.map +1 -0
- package/dist/evolution/propose.js +188 -0
- package/dist/evolution/propose.js.map +1 -0
- package/dist/evolution/queue.d.ts +64 -0
- package/dist/evolution/queue.d.ts.map +1 -0
- package/dist/evolution/queue.js +192 -0
- package/dist/evolution/queue.js.map +1 -0
- package/dist/evolution/release.d.ts +11 -0
- package/dist/evolution/release.d.ts.map +1 -0
- package/dist/evolution/release.js +55 -0
- package/dist/evolution/release.js.map +1 -0
- package/dist/evolution/run.d.ts +88 -0
- package/dist/evolution/run.d.ts.map +1 -0
- package/dist/evolution/run.js +258 -0
- package/dist/evolution/run.js.map +1 -0
- package/dist/evolution/schedule.d.ts +59 -0
- package/dist/evolution/schedule.d.ts.map +1 -0
- package/dist/evolution/schedule.js +77 -0
- package/dist/evolution/schedule.js.map +1 -0
- package/dist/evolution/types.d.ts +174 -0
- package/dist/evolution/types.d.ts.map +1 -0
- package/dist/evolution/types.js +8 -0
- package/dist/evolution/types.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/learn/index.d.ts +27 -0
- package/dist/learn/index.d.ts.map +1 -0
- package/dist/learn/index.js +196 -0
- package/dist/learn/index.js.map +1 -0
- package/dist/report/markdown.d.ts +16 -0
- package/dist/report/markdown.d.ts.map +1 -0
- package/dist/report/markdown.js +488 -0
- package/dist/report/markdown.js.map +1 -0
- package/dist/snapshot/index.d.ts +55 -0
- package/dist/snapshot/index.d.ts.map +1 -0
- package/dist/snapshot/index.js +76 -0
- package/dist/snapshot/index.js.map +1 -0
- package/dist/store/index.d.ts +31 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +69 -0
- package/dist/store/index.js.map +1 -0
- package/dist/types.d.ts +287 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/util/glob.d.ts +11 -0
- package/dist/util/glob.d.ts.map +1 -0
- package/dist/util/glob.js +86 -0
- package/dist/util/glob.js.map +1 -0
- package/dist/util/project.d.ts +90 -0
- package/dist/util/project.d.ts.map +1 -0
- package/dist/util/project.js +636 -0
- package/dist/util/project.js.map +1 -0
- package/dist/util/yaml.d.ts +28 -0
- package/dist/util/yaml.d.ts.map +1 -0
- package/dist/util/yaml.js +48 -0
- package/dist/util/yaml.js.map +1 -0
- package/package.json +94 -0
- package/rules/core/architecture.yaml +190 -0
- package/rules/core/cicd.yaml +212 -0
- package/rules/core/code-quality.yaml +261 -0
- package/rules/core/dependencies.yaml +132 -0
- package/rules/core/documentation.yaml +119 -0
- package/rules/core/future-readiness.yaml +91 -0
- package/rules/core/release.yaml +131 -0
- package/rules/core/repo.yaml +313 -0
- package/rules/core/security.yaml +496 -0
- package/rules/core/supply-chain.yaml +357 -0
- package/rules/core/testing.yaml +266 -0
- package/rules/detectors.yaml +2028 -0
- package/rules/index.yaml +42 -0
- package/rules/profiles/maturity.yaml +135 -0
- package/rules/stacks/ai-era.yaml +193 -0
- package/rules/stacks/api-backend.yaml +121 -0
- package/rules/stacks/cli.yaml +105 -0
- package/rules/stacks/compliance.yaml +157 -0
- package/rules/stacks/containers.yaml +124 -0
- package/rules/stacks/data.yaml +165 -0
- package/rules/stacks/go.yaml +134 -0
- package/rules/stacks/iac.yaml +128 -0
- package/rules/stacks/jvm.yaml +150 -0
- package/rules/stacks/ml-ai.yaml +140 -0
- package/rules/stacks/mobile.yaml +121 -0
- package/rules/stacks/node-typescript.yaml +166 -0
- package/rules/stacks/python.yaml +175 -0
- package/rules/stacks/rust.yaml +129 -0
- package/rules/stacks/solidity.yaml +139 -0
- package/rules/stacks/swift.yaml +100 -0
- package/rules/stacks/web-frontend.yaml +159 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { ruleWeight } from './evaluate.js';
|
|
2
|
+
/** How much credit a rule earns for a given outcome. */
|
|
3
|
+
const CREDIT = {
|
|
4
|
+
PASS: 1,
|
|
5
|
+
EXPERIMENTAL: 0.5,
|
|
6
|
+
DEPRECATED: 0.4,
|
|
7
|
+
WRONG: 0.15,
|
|
8
|
+
MISSING: 0,
|
|
9
|
+
FAIL: 0,
|
|
10
|
+
// Not counted: unresolved judgement or deliberately skipped.
|
|
11
|
+
UNKNOWN: 0,
|
|
12
|
+
NOT_APPLICABLE: 0,
|
|
13
|
+
};
|
|
14
|
+
const EMPTY_COUNTS = () => ({
|
|
15
|
+
PASS: 0,
|
|
16
|
+
FAIL: 0,
|
|
17
|
+
WRONG: 0,
|
|
18
|
+
MISSING: 0,
|
|
19
|
+
DEPRECATED: 0,
|
|
20
|
+
EXPERIMENTAL: 0,
|
|
21
|
+
UNKNOWN: 0,
|
|
22
|
+
NOT_APPLICABLE: 0,
|
|
23
|
+
});
|
|
24
|
+
const EMPTY_SEVERITY = () => ({
|
|
25
|
+
CRITICAL: 0,
|
|
26
|
+
HIGH: 0,
|
|
27
|
+
MEDIUM: 0,
|
|
28
|
+
LOW: 0,
|
|
29
|
+
FUTURE: 0,
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Deterministic, reproducible scoring.
|
|
33
|
+
*
|
|
34
|
+
* credit_i = weight_i × CREDIT[status_i]
|
|
35
|
+
* section = 10 × Σcredit_i / Σweight_i (resolved applicable rules)
|
|
36
|
+
* overall = 100 × Σ(credit_i × sectionWeight) / Σ(weight_i × sectionWeight)
|
|
37
|
+
*
|
|
38
|
+
* Rule-level weighting (rather than averaging section scores) means a section
|
|
39
|
+
* with three rules cannot swing the total as hard as one with thirty.
|
|
40
|
+
*/
|
|
41
|
+
export function score(evaluated, sections, profile) {
|
|
42
|
+
const counts = EMPTY_COUNTS();
|
|
43
|
+
const severityCounts = EMPTY_SEVERITY();
|
|
44
|
+
const sectionMap = new Map(sections.map((s) => [s.id, s]));
|
|
45
|
+
const acc = {
|
|
46
|
+
bySection: new Map(),
|
|
47
|
+
counts,
|
|
48
|
+
severityCounts,
|
|
49
|
+
totalW: 0,
|
|
50
|
+
totalCredit: 0,
|
|
51
|
+
applicableAll: 0,
|
|
52
|
+
resolvedAll: 0,
|
|
53
|
+
};
|
|
54
|
+
for (const { rule, finding } of evaluated) {
|
|
55
|
+
accumulateScoredRule(acc, sectionMap, rule, finding);
|
|
56
|
+
}
|
|
57
|
+
const sectionScores = sections
|
|
58
|
+
.filter((s) => acc.bySection.has(s.id))
|
|
59
|
+
.map((s) => buildSectionScore(s, acc.bySection.get(s.id)));
|
|
60
|
+
return {
|
|
61
|
+
overall: acc.totalW > 0 ? round1((100 * acc.totalCredit) / acc.totalW) : 0,
|
|
62
|
+
sections: sectionScores,
|
|
63
|
+
counts,
|
|
64
|
+
severityCounts,
|
|
65
|
+
automationCoverage: acc.applicableAll > 0 ? round1((100 * acc.resolvedAll) / acc.applicableAll) : 0,
|
|
66
|
+
expectedBand: profile.expectedBand,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function emptyBucket() {
|
|
70
|
+
return { w: 0, credit: 0, applicable: 0, resolved: 0, passed: 0, failed: 0, unknown: 0 };
|
|
71
|
+
}
|
|
72
|
+
function bucketFor(bySection, id) {
|
|
73
|
+
let bucket = bySection.get(id);
|
|
74
|
+
if (!bucket) {
|
|
75
|
+
bucket = emptyBucket();
|
|
76
|
+
bySection.set(id, bucket);
|
|
77
|
+
}
|
|
78
|
+
return bucket;
|
|
79
|
+
}
|
|
80
|
+
function accumulateScoredRule(acc, sectionMap, rule, finding) {
|
|
81
|
+
if (finding.status === 'NOT_APPLICABLE')
|
|
82
|
+
return;
|
|
83
|
+
const sec = sectionMap.get(finding.section) ?? {
|
|
84
|
+
id: finding.section,
|
|
85
|
+
title: finding.sectionTitle,
|
|
86
|
+
weight: 1,
|
|
87
|
+
};
|
|
88
|
+
const bucket = bucketFor(acc.bySection, sec.id);
|
|
89
|
+
bucket.applicable++;
|
|
90
|
+
acc.applicableAll++;
|
|
91
|
+
// Suppressed findings live under Accepted Risk only: counting them as open
|
|
92
|
+
// once produced "HIGH: 1" next to "No CRITICAL or HIGH findings. Nice."
|
|
93
|
+
// in the same report. Unsuppressed UNKNOWN still counts — the report
|
|
94
|
+
// narrative ("N checks need a human") is driven by counts.UNKNOWN.
|
|
95
|
+
if (finding.suppressedReason) {
|
|
96
|
+
if (finding.status === 'UNKNOWN')
|
|
97
|
+
bucket.unknown++;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
acc.counts[finding.status]++;
|
|
101
|
+
if (finding.status !== 'PASS' && finding.status !== 'UNKNOWN') {
|
|
102
|
+
acc.severityCounts[finding.severity]++;
|
|
103
|
+
}
|
|
104
|
+
if (finding.status === 'UNKNOWN') {
|
|
105
|
+
bucket.unknown++;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
applyRuleCredit(acc, bucket, rule, finding, sec.weight);
|
|
109
|
+
}
|
|
110
|
+
function applyRuleCredit(acc, bucket, rule, finding, sectionWeight) {
|
|
111
|
+
const w = ruleWeight(rule) * sectionWeight;
|
|
112
|
+
const credit = w * CREDIT[finding.status];
|
|
113
|
+
bucket.w += w;
|
|
114
|
+
bucket.credit += credit;
|
|
115
|
+
bucket.resolved++;
|
|
116
|
+
acc.resolvedAll++;
|
|
117
|
+
if (finding.status === 'PASS')
|
|
118
|
+
bucket.passed++;
|
|
119
|
+
else
|
|
120
|
+
bucket.failed++;
|
|
121
|
+
acc.totalW += w;
|
|
122
|
+
acc.totalCredit += credit;
|
|
123
|
+
}
|
|
124
|
+
function buildSectionScore(s, b) {
|
|
125
|
+
return {
|
|
126
|
+
id: s.id,
|
|
127
|
+
title: s.title,
|
|
128
|
+
score: b.w > 0 ? round1((10 * b.credit) / b.w) : null,
|
|
129
|
+
weight: s.weight,
|
|
130
|
+
applicable: b.applicable,
|
|
131
|
+
resolved: b.resolved,
|
|
132
|
+
passed: b.passed,
|
|
133
|
+
failed: b.failed,
|
|
134
|
+
unknown: b.unknown,
|
|
135
|
+
confidence: b.applicable > 0 ? round1((100 * b.resolved) / b.applicable) : 100,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function round1(n) {
|
|
139
|
+
return Math.round(n * 10) / 10;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/engine/score.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SectionDef {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
/** Multiplier applied to every rule in the section when computing the total. */
|
|
5
|
+
weight: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Section registry. Security, supply chain and testing carry the heaviest
|
|
9
|
+
* multipliers: a repo that fails an auth control is worse than one with a
|
|
10
|
+
* slightly untidy README, and the score should say so.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_SECTIONS: SectionDef[];
|
|
13
|
+
export declare function loadSections(rulesDir: string): SectionDef[];
|
|
14
|
+
//# sourceMappingURL=sections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sections.d.ts","sourceRoot":"","sources":["../../src/engine/sections.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,UAAU,EAiBxC,CAAC;AAEF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAkB3D"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { parse as parseYaml } from 'yaml';
|
|
2
|
+
import { asMap, isMap, list, num, str } from '../util/yaml.js';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
/**
|
|
6
|
+
* Section registry. Security, supply chain and testing carry the heaviest
|
|
7
|
+
* multipliers: a repo that fails an auth control is worse than one with a
|
|
8
|
+
* slightly untidy README, and the score should say so.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_SECTIONS = [
|
|
11
|
+
{ id: 'S1', title: 'Repository & Project Structure', weight: 0.7 },
|
|
12
|
+
{ id: 'S2', title: 'Security', weight: 1.7 },
|
|
13
|
+
{ id: 'S3', title: 'Supply Chain & Build Provenance', weight: 1.3 },
|
|
14
|
+
{ id: 'S4', title: 'Architecture & Design', weight: 1.0 },
|
|
15
|
+
{ id: 'S5', title: 'Code Quality', weight: 1.0 },
|
|
16
|
+
{ id: 'S6', title: 'Data & Database', weight: 1.0 },
|
|
17
|
+
{ id: 'S7', title: 'Testing & Quality Assurance', weight: 1.3 },
|
|
18
|
+
{ id: 'S8', title: 'CI/CD, Infrastructure & Observability', weight: 1.0 },
|
|
19
|
+
{ id: 'S9', title: 'Release & Change Management', weight: 0.7 },
|
|
20
|
+
{ id: 'S10', title: 'Dependencies & Third-Party', weight: 1.2 },
|
|
21
|
+
{ id: 'S11', title: 'Performance & Resilience', weight: 0.8 },
|
|
22
|
+
{ id: 'S12', title: 'Documentation & Knowledge', weight: 0.7 },
|
|
23
|
+
{ id: 'S13', title: 'Accessibility, i18n & Compliance', weight: 0.9 },
|
|
24
|
+
{ id: 'S14', title: 'AI / LLM-Era Risks', weight: 1.1 },
|
|
25
|
+
{ id: 'S15', title: 'Platform-Specific', weight: 1.0 },
|
|
26
|
+
{ id: 'S16', title: 'Future Readiness', weight: 0.4 },
|
|
27
|
+
];
|
|
28
|
+
export function loadSections(rulesDir) {
|
|
29
|
+
const file = path.join(rulesDir, 'sections.yaml');
|
|
30
|
+
if (!fs.existsSync(file))
|
|
31
|
+
return DEFAULT_SECTIONS;
|
|
32
|
+
try {
|
|
33
|
+
const doc = asMap(parseYaml(fs.readFileSync(file, 'utf8')));
|
|
34
|
+
const raw = list(doc.sections);
|
|
35
|
+
if (!raw)
|
|
36
|
+
return DEFAULT_SECTIONS;
|
|
37
|
+
const parsed = raw.filter(isMap).map((s) => ({
|
|
38
|
+
id: str(s.id) ?? 'S0',
|
|
39
|
+
title: str(s.title) ?? str(s.id) ?? 'Untitled',
|
|
40
|
+
weight: num(s.weight) ?? 1,
|
|
41
|
+
}));
|
|
42
|
+
// Keep defaults for any section the override file omits.
|
|
43
|
+
const ids = new Set(parsed.map((s) => s.id));
|
|
44
|
+
return [...parsed, ...DEFAULT_SECTIONS.filter((s) => !ids.has(s.id))];
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return DEFAULT_SECTIONS;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=sections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../../src/engine/sections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BenchmarkCase, BenchmarkResult, Capability } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Run a candidate capability against a set of flees and measure TP/TN/FP/FN,
|
|
4
|
+
* precision/recall, and the one thing that matters most: whether the candidate
|
|
5
|
+
* changed the verdict of any *existing* rule (a regression).
|
|
6
|
+
*
|
|
7
|
+
* A baseline audit (without the candidate) and a candidate audit (with it) are
|
|
8
|
+
* both run on each fixture; the candidate's own rules are excluded from the
|
|
9
|
+
* regression comparison so only collateral damage counts.
|
|
10
|
+
*/
|
|
11
|
+
export declare function runBenchmark(candidate: Capability, cases: BenchmarkCase[], rulesDir?: string, engineVersion?: string): BenchmarkResult;
|
|
12
|
+
//# sourceMappingURL=benchmark.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"benchmark.d.ts","sourceRoot":"","sources":["../../src/evolution/benchmark.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAuB,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAkBlG;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,aAAa,EAAE,EACtB,QAAQ,CAAC,EAAE,MAAM,EACjB,aAAa,SAAU,GACtB,eAAe,CAyCjB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { runAudit } from '../engine/audit.js';
|
|
5
|
+
const OPEN = new Set(['FAIL', 'WRONG', 'MISSING', 'DEPRECATED', 'EXPERIMENTAL']);
|
|
6
|
+
function statusOf(report, ruleId) {
|
|
7
|
+
return report.findings.find((f) => f.ruleId === ruleId)?.status ?? 'NOT_APPLICABLE';
|
|
8
|
+
}
|
|
9
|
+
function materialize(files) {
|
|
10
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'usa-bench-'));
|
|
11
|
+
for (const [rel, content] of Object.entries(files)) {
|
|
12
|
+
const abs = path.join(root, rel);
|
|
13
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
14
|
+
fs.writeFileSync(abs, content, 'utf8');
|
|
15
|
+
}
|
|
16
|
+
return root;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Run a candidate capability against a set of flees and measure TP/TN/FP/FN,
|
|
20
|
+
* precision/recall, and the one thing that matters most: whether the candidate
|
|
21
|
+
* changed the verdict of any *existing* rule (a regression).
|
|
22
|
+
*
|
|
23
|
+
* A baseline audit (without the candidate) and a candidate audit (with it) are
|
|
24
|
+
* both run on each fixture; the candidate's own rules are excluded from the
|
|
25
|
+
* regression comparison so only collateral damage counts.
|
|
26
|
+
*/
|
|
27
|
+
export function runBenchmark(candidate, cases, rulesDir, engineVersion = 'bench') {
|
|
28
|
+
const caseResults = [];
|
|
29
|
+
for (const c of cases) {
|
|
30
|
+
const started = Date.now();
|
|
31
|
+
const root = materialize(c.fixture);
|
|
32
|
+
try {
|
|
33
|
+
const baseline = runAudit({ target: root, rulesDir, usaVersion: engineVersion });
|
|
34
|
+
const withCap = runAudit({
|
|
35
|
+
target: root,
|
|
36
|
+
rulesDir,
|
|
37
|
+
usaVersion: engineVersion,
|
|
38
|
+
extraPacks: candidate.pack ? [candidate.pack] : undefined,
|
|
39
|
+
});
|
|
40
|
+
caseResults.push(evaluateCase(c, candidate, baseline.report, withCap.report, Date.now() - started));
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const summary = caseResults.reduce((acc, r) => ({
|
|
47
|
+
tp: acc.tp + r.tp,
|
|
48
|
+
tn: acc.tn + r.tn,
|
|
49
|
+
fp: acc.fp + r.fp,
|
|
50
|
+
fn: acc.fn + r.fn,
|
|
51
|
+
regressions: acc.regressions + r.regressions.length,
|
|
52
|
+
precision: 0,
|
|
53
|
+
recall: 0,
|
|
54
|
+
}), { tp: 0, tn: 0, fp: 0, fn: 0, precision: 0, recall: 0, regressions: 0 });
|
|
55
|
+
summary.precision = summary.tp + summary.fp > 0 ? summary.tp / (summary.tp + summary.fp) : 1;
|
|
56
|
+
summary.recall = summary.tp + summary.fn > 0 ? summary.tp / (summary.tp + summary.fn) : 1;
|
|
57
|
+
return {
|
|
58
|
+
capability: { id: candidate.id, version: candidate.version },
|
|
59
|
+
cases: caseResults,
|
|
60
|
+
summary,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function evaluateCase(c, candidate, baseline, withCap, elapsedMs) {
|
|
64
|
+
const acc = classify(c.expected, withCap);
|
|
65
|
+
const regressions = collectRegressions(baseline, withCap, candidate.pack?.rules.map((r) => r.id) ?? []);
|
|
66
|
+
const precision = acc.tp + acc.fp > 0 ? acc.tp / (acc.tp + acc.fp) : 1;
|
|
67
|
+
const recall = acc.tp + acc.fn > 0 ? acc.tp / (acc.tp + acc.fn) : 1;
|
|
68
|
+
return { caseId: c.id, kind: c.kind, ...acc, precision, recall, regressions, elapsedMs };
|
|
69
|
+
}
|
|
70
|
+
function classify(expected, withCap) {
|
|
71
|
+
let tp = 0;
|
|
72
|
+
let tn = 0;
|
|
73
|
+
let fp = 0;
|
|
74
|
+
let fn = 0;
|
|
75
|
+
for (const exp of expected) {
|
|
76
|
+
const expectedOpen = OPEN.has(exp.status);
|
|
77
|
+
const actualOpen = OPEN.has(statusOf(withCap, exp.ruleId));
|
|
78
|
+
if (expectedOpen && actualOpen)
|
|
79
|
+
tp++;
|
|
80
|
+
else if (expectedOpen)
|
|
81
|
+
fn++;
|
|
82
|
+
else if (actualOpen)
|
|
83
|
+
fp++;
|
|
84
|
+
else
|
|
85
|
+
tn++;
|
|
86
|
+
}
|
|
87
|
+
return { tp, tn, fp, fn };
|
|
88
|
+
}
|
|
89
|
+
function collectRegressions(baseline, withCap, candidateRules) {
|
|
90
|
+
const excluded = new Set(candidateRules);
|
|
91
|
+
const ids = new Set();
|
|
92
|
+
for (const f of baseline.findings)
|
|
93
|
+
ids.add(f.ruleId);
|
|
94
|
+
for (const f of withCap.findings)
|
|
95
|
+
ids.add(f.ruleId);
|
|
96
|
+
const regressions = [];
|
|
97
|
+
for (const id of [...ids].sort()) {
|
|
98
|
+
if (excluded.has(id))
|
|
99
|
+
continue;
|
|
100
|
+
const a = statusOf(baseline, id);
|
|
101
|
+
const b = statusOf(withCap, id);
|
|
102
|
+
if (a !== b)
|
|
103
|
+
regressions.push(`${id}: ${a} -> ${b}`);
|
|
104
|
+
}
|
|
105
|
+
return regressions;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=benchmark.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"benchmark.js","sourceRoot":"","sources":["../../src/evolution/benchmark.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAI9C,MAAM,IAAI,GAAgB,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;AAE9F,SAAS,QAAQ,CAAC,MAAmB,EAAE,MAAc;IACnD,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,IAAI,gBAAgB,CAAC;AACtF,CAAC;AAED,SAAS,WAAW,CAAC,KAA6B;IAChD,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;IAClE,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACjC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC1B,SAAqB,EACrB,KAAsB,EACtB,QAAiB,EACjB,aAAa,GAAG,OAAO;IAEvB,MAAM,WAAW,GAA0B,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC;YACjF,MAAM,OAAO,GAAG,QAAQ,CAAC;gBACvB,MAAM,EAAE,IAAI;gBACZ,QAAQ;gBACR,UAAU,EAAE,aAAa;gBACzB,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;aAC1D,CAAC,CAAC;YACH,WAAW,CAAC,IAAI,CACd,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAClF,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAChC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE;QACjB,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE;QACjB,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE;QACjB,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE;QACjB,WAAW,EAAE,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM;QACnD,SAAS,EAAE,CAAC;QACZ,MAAM,EAAE,CAAC;KACV,CAAC,EACF,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CACxE,CAAC;IACF,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7F,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1F,OAAO;QACL,UAAU,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE;QAC5D,KAAK,EAAE,WAAW;QAClB,OAAO;KACR,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,CAAgB,EAChB,SAAqB,EACrB,QAAqB,EACrB,OAAoB,EACpB,SAAiB;IAEjB,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,kBAAkB,CACpC,QAAQ,EACR,OAAO,EACP,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAC7C,CAAC;IACF,MAAM,SAAS,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;AAC3F,CAAC;AAED,SAAS,QAAQ,CACf,QAAmC,EACnC,OAAoB;IAEpB,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3D,IAAI,YAAY,IAAI,UAAU;YAAE,EAAE,EAAE,CAAC;aAChC,IAAI,YAAY;YAAE,EAAE,EAAE,CAAC;aACvB,IAAI,UAAU;YAAE,EAAE,EAAE,CAAC;;YACrB,EAAE,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,kBAAkB,CACzB,QAAqB,EACrB,OAAoB,EACpB,cAAwB;IAExB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ;QAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ;QAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACjC,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC/B,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,CAAC;YAAE,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { RulePack } from '../types.js';
|
|
2
|
+
import type { Capability } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Capability-set resolution.
|
|
5
|
+
*
|
|
6
|
+
* The resolved set is an immutable value, hashed once at the start of a run.
|
|
7
|
+
* It depends on: engine version, the base pack ids in the on-disk registry, and
|
|
8
|
+
* any released capabilities injected for this run. A model bundle would become
|
|
9
|
+
* part of this boundary once models exist — until then it is recorded as absent.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveCapabilitySetId(basePackIds: string[], extraCapabilities: Capability[], engineVersion: string): string;
|
|
12
|
+
/** Pack ids present in the on-disk registry (the source of truth). */
|
|
13
|
+
export declare function basePackIds(rulesDir: string): string[];
|
|
14
|
+
/** Wrap a candidate rule pack as a `data` capability. */
|
|
15
|
+
export declare function capabilityFromPack(pack: RulePack, opts?: {
|
|
16
|
+
version?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
createdBy?: string;
|
|
19
|
+
createdAt?: string;
|
|
20
|
+
languages?: string[];
|
|
21
|
+
}): Capability;
|
|
22
|
+
//# sourceMappingURL=capability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/evolution/capability.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EAAE,EACrB,iBAAiB,EAAE,UAAU,EAAE,EAC/B,aAAa,EAAE,MAAM,GACpB,MAAM,CAOR;AAED,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAGtD;AAED,yDAAyD;AACzD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EACd,IAAI,GAAE;IACJ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,GACL,UAAU,CAcZ"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { loadRulePacks } from '../engine/loader.js';
|
|
2
|
+
import { hashText } from '../snapshot/index.js';
|
|
3
|
+
import { canonicalJson } from '../snapshot/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Capability-set resolution.
|
|
6
|
+
*
|
|
7
|
+
* The resolved set is an immutable value, hashed once at the start of a run.
|
|
8
|
+
* It depends on: engine version, the base pack ids in the on-disk registry, and
|
|
9
|
+
* any released capabilities injected for this run. A model bundle would become
|
|
10
|
+
* part of this boundary once models exist — until then it is recorded as absent.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveCapabilitySetId(basePackIds, extraCapabilities, engineVersion) {
|
|
13
|
+
const payload = canonicalJson({
|
|
14
|
+
engineVersion,
|
|
15
|
+
basePacks: [...basePackIds].sort(),
|
|
16
|
+
extraCapabilities: extraCapabilities.map((c) => `${c.id}@${c.version}`).sort(),
|
|
17
|
+
});
|
|
18
|
+
return hashText(payload);
|
|
19
|
+
}
|
|
20
|
+
/** Pack ids present in the on-disk registry (the source of truth). */
|
|
21
|
+
export function basePackIds(rulesDir) {
|
|
22
|
+
const { packs } = loadRulePacks(rulesDir);
|
|
23
|
+
return packs.map((p) => p.id).sort();
|
|
24
|
+
}
|
|
25
|
+
/** Wrap a candidate rule pack as a `data` capability. */
|
|
26
|
+
export function capabilityFromPack(pack, opts = {}) {
|
|
27
|
+
return {
|
|
28
|
+
id: pack.id,
|
|
29
|
+
version: opts.version ?? pack.version ?? '0.1.0',
|
|
30
|
+
kind: 'data',
|
|
31
|
+
description: opts.description ?? pack.description ?? pack.title,
|
|
32
|
+
pack,
|
|
33
|
+
languages: opts.languages ?? inferLanguages(pack),
|
|
34
|
+
status: 'stable',
|
|
35
|
+
provenance: {
|
|
36
|
+
createdAt: opts.createdAt ?? new Date().toISOString(),
|
|
37
|
+
createdBy: opts.createdBy ?? 'evolution',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Infer which languages a pack analyzes from its declared applicability
|
|
43
|
+
* (`skip_when` / per-rule `applies_when` `lang:*` facts). A capability should
|
|
44
|
+
* declare what it covers so coverage accounting stays honest and automatic.
|
|
45
|
+
*/
|
|
46
|
+
function inferLanguages(pack) {
|
|
47
|
+
const langs = new Set();
|
|
48
|
+
collectLangFacts(pack.skipWhen, langs);
|
|
49
|
+
for (const rule of pack.rules)
|
|
50
|
+
collectLangFacts(rule.appliesWhen, langs);
|
|
51
|
+
const out = [...langs].sort();
|
|
52
|
+
return out.length > 0 ? out : [];
|
|
53
|
+
}
|
|
54
|
+
function collectLangFacts(p, out) {
|
|
55
|
+
if (!p)
|
|
56
|
+
return;
|
|
57
|
+
const q = p;
|
|
58
|
+
for (const key of ['all', 'any']) {
|
|
59
|
+
if (Array.isArray(q[key]))
|
|
60
|
+
for (const x of q[key])
|
|
61
|
+
collectLangFacts(x, out);
|
|
62
|
+
}
|
|
63
|
+
if (q.not !== undefined && q.not !== null)
|
|
64
|
+
collectLangFacts(q.not, out);
|
|
65
|
+
const fact = q.fact;
|
|
66
|
+
if (typeof fact === 'string' && fact.startsWith('lang:'))
|
|
67
|
+
out.add(fact.slice('lang:'.length));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../../src/evolution/capability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AuditReport, Facts } from '../types.js';
|
|
2
|
+
import type { CoverageModel } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Coverage is tied to what the audit *actually resolved* — never to a registry
|
|
5
|
+
* that merely contains a capability. A detected language with a shipped pack, or
|
|
6
|
+
* one released and injected for this run (`extraCoveredLangs`), is "covered";
|
|
7
|
+
* anything else is "unsupported".
|
|
8
|
+
*
|
|
9
|
+
* `extraCoveredLangs` comes from the capabilities actually executed in this run
|
|
10
|
+
* (each released capability declares the languages it analyzes). The static
|
|
11
|
+
* `COVERED_LANGS` map is the base set of shipped packs; the bootstrap knowledge
|
|
12
|
+
* remains the single source of truth for "does a bootstrap proposal exist".
|
|
13
|
+
*/
|
|
14
|
+
export declare function computeCoverage(report: AuditReport, facts: Facts, extraCoveredLangs?: string[]): CoverageModel;
|
|
15
|
+
//# sourceMappingURL=coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/evolution/coverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,KAAK,EACZ,iBAAiB,GAAE,MAAM,EAAO,GAC/B,aAAa,CAwDf"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { bootstrapPacks } from '../bootstrap/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Coverage is tied to what the audit *actually resolved* — never to a registry
|
|
4
|
+
* that merely contains a capability. A detected language with a shipped pack, or
|
|
5
|
+
* one released and injected for this run (`extraCoveredLangs`), is "covered";
|
|
6
|
+
* anything else is "unsupported".
|
|
7
|
+
*
|
|
8
|
+
* `extraCoveredLangs` comes from the capabilities actually executed in this run
|
|
9
|
+
* (each released capability declares the languages it analyzes). The static
|
|
10
|
+
* `COVERED_LANGS` map is the base set of shipped packs; the bootstrap knowledge
|
|
11
|
+
* remains the single source of truth for "does a bootstrap proposal exist".
|
|
12
|
+
*/
|
|
13
|
+
export function computeCoverage(report, facts, extraCoveredLangs = []) {
|
|
14
|
+
const boot = bootstrapPacks(facts);
|
|
15
|
+
const langs = [...facts.flags]
|
|
16
|
+
.filter((f) => f.startsWith('lang:'))
|
|
17
|
+
.map((f) => f.slice('lang:'.length))
|
|
18
|
+
.sort();
|
|
19
|
+
const coveredSet = new Set([...boot.coveredLangs, ...extraCoveredLangs]);
|
|
20
|
+
const partialSet = new Set(boot.generatedLangs);
|
|
21
|
+
const blindSpots = [];
|
|
22
|
+
const coveredLanguages = [];
|
|
23
|
+
const unsupportedLanguages = [];
|
|
24
|
+
for (const lang of langs) {
|
|
25
|
+
if (coveredSet.has(lang)) {
|
|
26
|
+
coveredLanguages.push(lang);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
unsupportedLanguages.push(lang);
|
|
30
|
+
const hint = partialSet.has(lang)
|
|
31
|
+
? ' (a bootstrap proposal exists, but it is not a shipped capability)'
|
|
32
|
+
: ' (no coverage at all)';
|
|
33
|
+
blindSpots.push({
|
|
34
|
+
kind: 'unsupported-language',
|
|
35
|
+
id: `lang:${lang}`,
|
|
36
|
+
detail: `No production capability analyzes ${lang}${hint}.`,
|
|
37
|
+
evidence: `detected fact "lang:${lang}"; packs loaded: ${report.options.packsLoaded.join(', ') || 'none'}`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const unverifiableSections = [];
|
|
42
|
+
for (const s of report.score.sections) {
|
|
43
|
+
if (s.score === null) {
|
|
44
|
+
unverifiableSections.push(s.id);
|
|
45
|
+
blindSpots.push({
|
|
46
|
+
kind: 'unverifiable-section',
|
|
47
|
+
id: `section:${s.id}`,
|
|
48
|
+
detail: `Section ${s.id} (${s.title}) could not be verified automatically.`,
|
|
49
|
+
evidence: `${s.applicable} applicable rule(s), ${s.unknown} unresolved by the engine`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const languageCoverage = langs.length > 0 ? Math.round((100 * coveredLanguages.length) / langs.length) : 100;
|
|
54
|
+
return {
|
|
55
|
+
automationCoverage: report.score.automationCoverage,
|
|
56
|
+
languageCoverage,
|
|
57
|
+
detectedLanguages: langs,
|
|
58
|
+
coveredLanguages,
|
|
59
|
+
unsupportedLanguages,
|
|
60
|
+
unverifiableSections,
|
|
61
|
+
unknownFindings: report.score.counts.UNKNOWN,
|
|
62
|
+
blindSpots,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/evolution/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CapabilityGap, CoverageModel } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Turn a coverage model's blind spots into evidence-backed capability gaps.
|
|
4
|
+
*
|
|
5
|
+
* Every gap cites the audit run and snapshot that produced it, plus the
|
|
6
|
+
* observed fact/pack-list evidence — a gap is a conclusion from recorded
|
|
7
|
+
* evidence, never free-floating intuition.
|
|
8
|
+
*/
|
|
9
|
+
export declare function deriveGaps(coverage: CoverageModel, auditRunId: string, snapshotId: string, now?: string): CapabilityGap[];
|
|
10
|
+
//# sourceMappingURL=gap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gap.d.ts","sourceRoot":"","sources":["../../src/evolution/gap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,GAAG,SAA2B,GAC7B,aAAa,EAAE,CAYjB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn a coverage model's blind spots into evidence-backed capability gaps.
|
|
3
|
+
*
|
|
4
|
+
* Every gap cites the audit run and snapshot that produced it, plus the
|
|
5
|
+
* observed fact/pack-list evidence — a gap is a conclusion from recorded
|
|
6
|
+
* evidence, never free-floating intuition.
|
|
7
|
+
*/
|
|
8
|
+
export function deriveGaps(coverage, auditRunId, snapshotId, now = new Date().toISOString()) {
|
|
9
|
+
const gaps = [];
|
|
10
|
+
for (const spot of coverage.blindSpots) {
|
|
11
|
+
gaps.push(spot.kind === 'unsupported-language' ? languageGap(spot) : sectionGap(spot));
|
|
12
|
+
}
|
|
13
|
+
for (const gap of gaps) {
|
|
14
|
+
gap.auditRunId = auditRunId;
|
|
15
|
+
gap.snapshotId = snapshotId;
|
|
16
|
+
gap.createdAt = now;
|
|
17
|
+
gap.evidence.push(`auditRun:${auditRunId}`, `snapshot:${snapshotId}`);
|
|
18
|
+
}
|
|
19
|
+
return gaps;
|
|
20
|
+
}
|
|
21
|
+
function languageGap(spot) {
|
|
22
|
+
const lang = spot.id.startsWith('lang:') ? spot.id.slice('lang:'.length) : spot.id;
|
|
23
|
+
return {
|
|
24
|
+
id: `unsupported-technology:${lang}`,
|
|
25
|
+
kind: 'unsupported-technology',
|
|
26
|
+
target: lang,
|
|
27
|
+
problem: `USA cannot analyze ${lang} repositories — no capability covers this language.`,
|
|
28
|
+
evidence: [spot.evidence],
|
|
29
|
+
requiredCapability: `stacks/${lang}`,
|
|
30
|
+
priority: 'high',
|
|
31
|
+
auditRunId: '',
|
|
32
|
+
snapshotId: '',
|
|
33
|
+
createdAt: '',
|
|
34
|
+
state: 'open',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function sectionGap(spot) {
|
|
38
|
+
return {
|
|
39
|
+
id: `unverifiable-property:${spot.id}`,
|
|
40
|
+
kind: 'unverifiable-property',
|
|
41
|
+
target: spot.id,
|
|
42
|
+
problem: spot.detail,
|
|
43
|
+
evidence: [spot.evidence],
|
|
44
|
+
requiredCapability: spot.id,
|
|
45
|
+
priority: 'medium',
|
|
46
|
+
auditRunId: '',
|
|
47
|
+
snapshotId: '',
|
|
48
|
+
createdAt: '',
|
|
49
|
+
state: 'open',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=gap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gap.js","sourceRoot":"","sources":["../../src/evolution/gap.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACxB,QAAuB,EACvB,UAAkB,EAClB,UAAkB,EAClB,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;IAE9B,MAAM,IAAI,GAAoB,EAAE,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,sBAAsB,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IACzF,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,GAAG,CAAC,UAAU,GAAG,UAAU,CAAC;QAC5B,GAAG,CAAC,UAAU,GAAG,UAAU,CAAC;QAC5B,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;QACpB,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,UAAU,EAAE,EAAE,YAAY,UAAU,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,IAAsD;IACzE,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IACnF,OAAO;QACL,EAAE,EAAE,0BAA0B,IAAI,EAAE;QACpC,IAAI,EAAE,wBAAwB;QAC9B,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,sBAAsB,IAAI,qDAAqD;QACxF,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;QACzB,kBAAkB,EAAE,UAAU,IAAI,EAAE;QACpC,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,EAAE;QACd,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,MAAM;KACd,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,IAAsD;IACxE,OAAO;QACL,EAAE,EAAE,yBAAyB,IAAI,CAAC,EAAE,EAAE;QACtC,IAAI,EAAE,uBAAuB;QAC7B,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,OAAO,EAAE,IAAI,CAAC,MAAM;QACpB,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;QACzB,kBAAkB,EAAE,IAAI,CAAC,EAAE;QAC3B,QAAQ,EAAE,QAAQ;QAClB,UAAU,EAAE,EAAE;QACd,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,MAAM;KACd,CAAC;AACJ,CAAC"}
|