@kevinrabun/judges 3.43.0 → 3.45.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/CHANGELOG.md +24 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +112 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/burndown.d.ts +27 -0
- package/dist/commands/burndown.d.ts.map +1 -0
- package/dist/commands/burndown.js +180 -0
- package/dist/commands/burndown.js.map +1 -0
- package/dist/commands/compare-runs.d.ts +38 -0
- package/dist/commands/compare-runs.d.ts.map +1 -0
- package/dist/commands/compare-runs.js +229 -0
- package/dist/commands/compare-runs.js.map +1 -0
- package/dist/commands/correlate.d.ts +28 -0
- package/dist/commands/correlate.d.ts.map +1 -0
- package/dist/commands/correlate.js +242 -0
- package/dist/commands/correlate.js.map +1 -0
- package/dist/commands/digest.d.ts +20 -0
- package/dist/commands/digest.d.ts.map +1 -0
- package/dist/commands/digest.js +222 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/explain-finding.d.ts +8 -0
- package/dist/commands/explain-finding.d.ts.map +1 -0
- package/dist/commands/explain-finding.js +279 -0
- package/dist/commands/explain-finding.js.map +1 -0
- package/dist/commands/judge-reputation.d.ts +29 -0
- package/dist/commands/judge-reputation.d.ts.map +1 -0
- package/dist/commands/judge-reputation.js +199 -0
- package/dist/commands/judge-reputation.js.map +1 -0
- package/dist/commands/kb.d.ts +41 -0
- package/dist/commands/kb.d.ts.map +1 -0
- package/dist/commands/kb.js +231 -0
- package/dist/commands/kb.js.map +1 -0
- package/dist/commands/noise-advisor.d.ts +30 -0
- package/dist/commands/noise-advisor.d.ts.map +1 -0
- package/dist/commands/noise-advisor.js +171 -0
- package/dist/commands/noise-advisor.js.map +1 -0
- package/dist/commands/query.d.ts +20 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +230 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/recommend.d.ts +21 -0
- package/dist/commands/recommend.d.ts.map +1 -0
- package/dist/commands/recommend.js +283 -0
- package/dist/commands/recommend.js.map +1 -0
- package/dist/commands/report-template.d.ts +17 -0
- package/dist/commands/report-template.d.ts.map +1 -0
- package/dist/commands/report-template.js +291 -0
- package/dist/commands/report-template.js.map +1 -0
- package/dist/commands/review-queue.d.ts +34 -0
- package/dist/commands/review-queue.d.ts.map +1 -0
- package/dist/commands/review-queue.js +226 -0
- package/dist/commands/review-queue.js.map +1 -0
- package/dist/commands/rule-owner.d.ts +31 -0
- package/dist/commands/rule-owner.d.ts.map +1 -0
- package/dist/commands/rule-owner.js +182 -0
- package/dist/commands/rule-owner.js.map +1 -0
- package/dist/commands/rule-share.d.ts +35 -0
- package/dist/commands/rule-share.d.ts.map +1 -0
- package/dist/commands/rule-share.js +203 -0
- package/dist/commands/rule-share.js.map +1 -0
- package/dist/commands/suppress.d.ts +40 -0
- package/dist/commands/suppress.d.ts.map +1 -0
- package/dist/commands/suppress.js +209 -0
- package/dist/commands/suppress.js.map +1 -0
- package/dist/commands/vote.d.ts +32 -0
- package/dist/commands/vote.d.ts.map +1 -0
- package/dist/commands/vote.js +201 -0
- package/dist/commands/vote.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team knowledge base — store team decisions about rules, exceptions,
|
|
3
|
+
* known patterns, and contextual knowledge that informs evaluations.
|
|
4
|
+
*
|
|
5
|
+
* Stored locally in .judges-kb.json.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
8
|
+
const KB_FILE = ".judges-kb.json";
|
|
9
|
+
// ─── Core ───────────────────────────────────────────────────────────────────
|
|
10
|
+
function loadDb(file = KB_FILE) {
|
|
11
|
+
if (!existsSync(file))
|
|
12
|
+
return { entries: [] };
|
|
13
|
+
return JSON.parse(readFileSync(file, "utf-8"));
|
|
14
|
+
}
|
|
15
|
+
function saveDb(db, file = KB_FILE) {
|
|
16
|
+
writeFileSync(file, JSON.stringify(db, null, 2));
|
|
17
|
+
}
|
|
18
|
+
function genId() {
|
|
19
|
+
return `kb-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
20
|
+
}
|
|
21
|
+
export function addKbEntry(opts) {
|
|
22
|
+
const db = loadDb();
|
|
23
|
+
const entry = {
|
|
24
|
+
id: genId(),
|
|
25
|
+
rulePattern: opts.rulePattern,
|
|
26
|
+
decision: opts.decision,
|
|
27
|
+
reason: opts.reason,
|
|
28
|
+
approvedBy: opts.approvedBy,
|
|
29
|
+
createdIso: new Date().toISOString(),
|
|
30
|
+
scope: opts.scope,
|
|
31
|
+
tags: opts.tags,
|
|
32
|
+
active: true,
|
|
33
|
+
};
|
|
34
|
+
if (opts.expiresIn) {
|
|
35
|
+
const exp = new Date();
|
|
36
|
+
exp.setDate(exp.getDate() + opts.expiresIn);
|
|
37
|
+
entry.expiresIso = exp.toISOString();
|
|
38
|
+
}
|
|
39
|
+
db.entries.push(entry);
|
|
40
|
+
saveDb(db);
|
|
41
|
+
return entry;
|
|
42
|
+
}
|
|
43
|
+
export function archiveKbEntry(id) {
|
|
44
|
+
const db = loadDb();
|
|
45
|
+
const entry = db.entries.find((e) => e.id === id);
|
|
46
|
+
if (!entry)
|
|
47
|
+
return false;
|
|
48
|
+
entry.active = false;
|
|
49
|
+
saveDb(db);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
export function searchKb(query) {
|
|
53
|
+
const db = loadDb();
|
|
54
|
+
const q = query.toLowerCase();
|
|
55
|
+
return db.entries.filter((e) => e.active &&
|
|
56
|
+
(e.rulePattern.toLowerCase().includes(q) ||
|
|
57
|
+
e.reason.toLowerCase().includes(q) ||
|
|
58
|
+
e.decision.includes(q) ||
|
|
59
|
+
e.tags?.some((t) => t.toLowerCase().includes(q))));
|
|
60
|
+
}
|
|
61
|
+
export function getApplicableEntries(ruleId) {
|
|
62
|
+
const db = loadDb();
|
|
63
|
+
const now = Date.now();
|
|
64
|
+
return db.entries.filter((e) => {
|
|
65
|
+
if (!e.active)
|
|
66
|
+
return false;
|
|
67
|
+
if (e.expiresIso && new Date(e.expiresIso).getTime() < now)
|
|
68
|
+
return false;
|
|
69
|
+
return ruleId === e.rulePattern || ruleId.startsWith(e.rulePattern);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
73
|
+
export function runKnowledgeBase(argv) {
|
|
74
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
75
|
+
console.log(`
|
|
76
|
+
judges kb — Team knowledge base for rule decisions and exceptions
|
|
77
|
+
|
|
78
|
+
Usage:
|
|
79
|
+
judges kb --add --rule AUTH-003 --decision not-applicable --reason "Stateless microservices" --approved-by "Team Lead"
|
|
80
|
+
judges kb --search AUTH Search knowledge base
|
|
81
|
+
judges kb --check SEC-001 Check if rule has KB entries
|
|
82
|
+
judges kb --list List all active entries
|
|
83
|
+
judges kb --archive <id> Archive an entry
|
|
84
|
+
judges kb --stats Show KB statistics
|
|
85
|
+
|
|
86
|
+
Options:
|
|
87
|
+
--add Add new KB entry
|
|
88
|
+
--rule <pattern> Rule ID or prefix
|
|
89
|
+
--decision <type> not-applicable | accepted-risk | deferred | exception | custom-guidance
|
|
90
|
+
--reason <text> Reason for decision
|
|
91
|
+
--approved-by <name> Who approved
|
|
92
|
+
--scope <glob> File scope
|
|
93
|
+
--tags <list> Comma-separated tags
|
|
94
|
+
--expires-in <days> Auto-expire after N days
|
|
95
|
+
--search <query> Search KB
|
|
96
|
+
--check <rule-id> Check for KB entries on a rule
|
|
97
|
+
--list List all active entries
|
|
98
|
+
--archive <id> Archive an entry
|
|
99
|
+
--stats Show statistics
|
|
100
|
+
--format json JSON output
|
|
101
|
+
--help, -h Show this help
|
|
102
|
+
`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
106
|
+
// Add entry
|
|
107
|
+
if (argv.includes("--add")) {
|
|
108
|
+
const rulePattern = argv.find((_a, i) => argv[i - 1] === "--rule");
|
|
109
|
+
const decision = argv.find((_a, i) => argv[i - 1] === "--decision");
|
|
110
|
+
const reason = argv.find((_a, i) => argv[i - 1] === "--reason");
|
|
111
|
+
const approvedBy = argv.find((_a, i) => argv[i - 1] === "--approved-by") ||
|
|
112
|
+
process.env.USER ||
|
|
113
|
+
process.env.USERNAME ||
|
|
114
|
+
"unknown";
|
|
115
|
+
const scope = argv.find((_a, i) => argv[i - 1] === "--scope");
|
|
116
|
+
const tagsStr = argv.find((_a, i) => argv[i - 1] === "--tags");
|
|
117
|
+
const expiresStr = argv.find((_a, i) => argv[i - 1] === "--expires-in");
|
|
118
|
+
if (!rulePattern || !decision || !reason) {
|
|
119
|
+
console.error("Error: --rule, --decision, and --reason required");
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
const entry = addKbEntry({
|
|
123
|
+
rulePattern,
|
|
124
|
+
decision,
|
|
125
|
+
reason,
|
|
126
|
+
approvedBy,
|
|
127
|
+
scope,
|
|
128
|
+
tags: tagsStr ? tagsStr.split(",").map((s) => s.trim()) : undefined,
|
|
129
|
+
expiresIn: expiresStr ? parseInt(expiresStr, 10) : undefined,
|
|
130
|
+
});
|
|
131
|
+
if (format === "json") {
|
|
132
|
+
console.log(JSON.stringify(entry, null, 2));
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
console.log(` ✅ KB entry created: ${entry.id}`);
|
|
136
|
+
console.log(` ${entry.rulePattern}: ${entry.decision} — ${entry.reason}`);
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// Search
|
|
141
|
+
const searchQuery = argv.find((_a, i) => argv[i - 1] === "--search");
|
|
142
|
+
if (searchQuery) {
|
|
143
|
+
const results = searchKb(searchQuery);
|
|
144
|
+
if (format === "json") {
|
|
145
|
+
console.log(JSON.stringify(results, null, 2));
|
|
146
|
+
}
|
|
147
|
+
else if (results.length === 0) {
|
|
148
|
+
console.log(`\n No KB entries matching "${searchQuery}".\n`);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.log(`\n ${results.length} KB entry(ies) matching "${searchQuery}"\n ──────────────────`);
|
|
152
|
+
for (const e of results) {
|
|
153
|
+
console.log(` ${e.rulePattern.padEnd(15)} ${e.decision.padEnd(18)} ${e.reason}`);
|
|
154
|
+
console.log(` Approved by ${e.approvedBy} on ${e.createdIso.split("T")[0]}`);
|
|
155
|
+
}
|
|
156
|
+
console.log("");
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// Check specific rule
|
|
161
|
+
const checkRule = argv.find((_a, i) => argv[i - 1] === "--check");
|
|
162
|
+
if (checkRule) {
|
|
163
|
+
const entries = getApplicableEntries(checkRule);
|
|
164
|
+
if (format === "json") {
|
|
165
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
166
|
+
}
|
|
167
|
+
else if (entries.length === 0) {
|
|
168
|
+
console.log(`\n No KB entries for ${checkRule}.\n`);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log(`\n KB entries for ${checkRule}:`);
|
|
172
|
+
for (const e of entries) {
|
|
173
|
+
console.log(` ${e.decision}: ${e.reason} (${e.approvedBy})`);
|
|
174
|
+
}
|
|
175
|
+
console.log("");
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// Archive
|
|
180
|
+
const archiveId = argv.find((_a, i) => argv[i - 1] === "--archive");
|
|
181
|
+
if (archiveId) {
|
|
182
|
+
if (archiveKbEntry(archiveId)) {
|
|
183
|
+
console.log(` Archived: ${archiveId}`);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
console.error(` Not found: ${archiveId}`);
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// Stats
|
|
191
|
+
if (argv.includes("--stats")) {
|
|
192
|
+
const db = loadDb();
|
|
193
|
+
const active = db.entries.filter((e) => e.active);
|
|
194
|
+
const byDecision = {};
|
|
195
|
+
for (const e of active) {
|
|
196
|
+
byDecision[e.decision] = (byDecision[e.decision] || 0) + 1;
|
|
197
|
+
}
|
|
198
|
+
if (format === "json") {
|
|
199
|
+
console.log(JSON.stringify({ total: db.entries.length, active: active.length, byDecision }, null, 2));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log(`\n Knowledge Base\n ──────────────`);
|
|
203
|
+
console.log(` Total: ${db.entries.length} (${active.length} active)\n`);
|
|
204
|
+
for (const [d, c] of Object.entries(byDecision)) {
|
|
205
|
+
console.log(` ${d.padEnd(20)} ${c}`);
|
|
206
|
+
}
|
|
207
|
+
console.log("");
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
// Default: list all
|
|
212
|
+
const db = loadDb();
|
|
213
|
+
const active = db.entries.filter((e) => e.active);
|
|
214
|
+
if (active.length === 0) {
|
|
215
|
+
console.log("\n Knowledge base is empty. Use --add to create an entry.\n");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (format === "json") {
|
|
219
|
+
console.log(JSON.stringify(active, null, 2));
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
console.log(`\n Team Knowledge Base (${active.length} active)\n ──────────────────────`);
|
|
223
|
+
for (const e of active) {
|
|
224
|
+
const exp = e.expiresIso ? ` (expires ${e.expiresIso.split("T")[0]})` : "";
|
|
225
|
+
console.log(` ${e.id} ${e.rulePattern.padEnd(15)} ${e.decision}${exp}`);
|
|
226
|
+
console.log(` ${e.reason} — ${e.approvedBy}`);
|
|
227
|
+
}
|
|
228
|
+
console.log("");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=kb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kb.js","sourceRoot":"","sources":["../../src/commands/kb.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Noise advisor — analyze finding feedback history and rule performance
|
|
3
|
+
* to recommend tuning actions (disable rules, adjust severity, etc.).
|
|
4
|
+
*
|
|
5
|
+
* Uses local false-negative and suppression data — no external services.
|
|
6
|
+
*/
|
|
7
|
+
export interface RuleStats {
|
|
8
|
+
ruleId: string;
|
|
9
|
+
totalFindings: number;
|
|
10
|
+
suppressedCount: number;
|
|
11
|
+
falseNegativeCount: number;
|
|
12
|
+
fpRate: number;
|
|
13
|
+
avgConfidence: number;
|
|
14
|
+
}
|
|
15
|
+
export interface NoiseRecommendation {
|
|
16
|
+
ruleId: string;
|
|
17
|
+
action: "disable" | "raise-threshold" | "lower-severity" | "keep" | "investigate";
|
|
18
|
+
reason: string;
|
|
19
|
+
fpRate: number;
|
|
20
|
+
findingCount: number;
|
|
21
|
+
confidence: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function analyzeNoise(opts?: {
|
|
24
|
+
resultsPath?: string;
|
|
25
|
+
triagePath?: string;
|
|
26
|
+
fnPath?: string;
|
|
27
|
+
suppressionPath?: string;
|
|
28
|
+
}): NoiseRecommendation[];
|
|
29
|
+
export declare function runNoiseAdvisor(argv: string[]): void;
|
|
30
|
+
//# sourceMappingURL=noise-advisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noise-advisor.d.ts","sourceRoot":"","sources":["../../src/commands/noise-advisor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,MAAM,GAAG,aAAa,CAAC;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAgCD,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,mBAAmB,EAAE,CAwGxB;AAID,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAkEpD"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Noise advisor — analyze finding feedback history and rule performance
|
|
3
|
+
* to recommend tuning actions (disable rules, adjust severity, etc.).
|
|
4
|
+
*
|
|
5
|
+
* Uses local false-negative and suppression data — no external services.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, existsSync } from "fs";
|
|
8
|
+
// ─── Analysis ───────────────────────────────────────────────────────────────
|
|
9
|
+
function loadJsonSafe(path) {
|
|
10
|
+
if (!existsSync(path))
|
|
11
|
+
return null;
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function analyzeNoise(opts) {
|
|
20
|
+
const resultsPath = opts?.resultsPath;
|
|
21
|
+
const fnPath = opts?.fnPath || ".judges-false-negatives.json";
|
|
22
|
+
const suppressionPath = opts?.suppressionPath || ".judges-suppressions.json";
|
|
23
|
+
// Gather findings from results
|
|
24
|
+
const ruleMap = new Map();
|
|
25
|
+
if (resultsPath && existsSync(resultsPath)) {
|
|
26
|
+
const data = JSON.parse(readFileSync(resultsPath, "utf-8"));
|
|
27
|
+
const findings = data.evaluations
|
|
28
|
+
? data.evaluations.flatMap((e) => e.findings || [])
|
|
29
|
+
: data.findings || [];
|
|
30
|
+
for (const f of findings) {
|
|
31
|
+
const existing = ruleMap.get(f.ruleId) || { total: 0, confidences: [], severities: [] };
|
|
32
|
+
existing.total++;
|
|
33
|
+
if (f.confidence !== undefined)
|
|
34
|
+
existing.confidences.push(f.confidence);
|
|
35
|
+
existing.severities.push(f.severity);
|
|
36
|
+
ruleMap.set(f.ruleId, existing);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Count suppressed findings per rule
|
|
40
|
+
const suppressedByRule = new Map();
|
|
41
|
+
const suppressionDb = loadJsonSafe(suppressionPath);
|
|
42
|
+
if (suppressionDb?.rules) {
|
|
43
|
+
for (const r of suppressionDb.rules) {
|
|
44
|
+
if (!r.active)
|
|
45
|
+
continue;
|
|
46
|
+
if (r.ruleIds) {
|
|
47
|
+
for (const id of r.ruleIds) {
|
|
48
|
+
suppressedByRule.set(id, (suppressedByRule.get(id) || 0) + 1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (r.rulePrefix) {
|
|
52
|
+
// Count as affecting all matching rules
|
|
53
|
+
for (const ruleId of ruleMap.keys()) {
|
|
54
|
+
if (ruleId.startsWith(r.rulePrefix)) {
|
|
55
|
+
suppressedByRule.set(ruleId, (suppressedByRule.get(ruleId) || 0) + 1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Count false negatives
|
|
62
|
+
const fnByRule = new Map();
|
|
63
|
+
const fnDb = loadJsonSafe(fnPath);
|
|
64
|
+
if (fnDb?.entries) {
|
|
65
|
+
for (const e of fnDb.entries) {
|
|
66
|
+
const key = e.ruleId || e.category || "unknown";
|
|
67
|
+
fnByRule.set(key, (fnByRule.get(key) || 0) + 1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Generate recommendations
|
|
71
|
+
const recommendations = [];
|
|
72
|
+
for (const [ruleId, stats] of ruleMap) {
|
|
73
|
+
const suppressed = suppressedByRule.get(ruleId) || 0;
|
|
74
|
+
const fnCount = fnByRule.get(ruleId) || 0;
|
|
75
|
+
const total = stats.total + suppressed;
|
|
76
|
+
const fpRate = total > 0 ? suppressed / total : 0;
|
|
77
|
+
const avgConf = stats.confidences.length > 0 ? stats.confidences.reduce((a, b) => a + b, 0) / stats.confidences.length : 0.5;
|
|
78
|
+
let action = "keep";
|
|
79
|
+
let reason = "Rule performs within acceptable parameters.";
|
|
80
|
+
if (fpRate > 0.6 && total >= 3) {
|
|
81
|
+
action = "disable";
|
|
82
|
+
reason = `${(fpRate * 100).toFixed(0)}% false-positive rate across ${total} findings. Consider disabling.`;
|
|
83
|
+
}
|
|
84
|
+
else if (fpRate > 0.4 && total >= 3) {
|
|
85
|
+
action = "raise-threshold";
|
|
86
|
+
reason = `${(fpRate * 100).toFixed(0)}% FP rate. Raise confidence threshold to reduce noise.`;
|
|
87
|
+
}
|
|
88
|
+
else if (avgConf < 0.4 && stats.total >= 3) {
|
|
89
|
+
action = "lower-severity";
|
|
90
|
+
reason = `Average confidence ${(avgConf * 100).toFixed(0)}%. Lower severity or add to review queue.`;
|
|
91
|
+
}
|
|
92
|
+
else if (fnCount > 0 && suppressed > 0) {
|
|
93
|
+
action = "investigate";
|
|
94
|
+
reason = `Rule has both false negatives (${fnCount}) and suppressions (${suppressed}). Needs calibration review.`;
|
|
95
|
+
}
|
|
96
|
+
recommendations.push({
|
|
97
|
+
ruleId,
|
|
98
|
+
action,
|
|
99
|
+
reason,
|
|
100
|
+
fpRate: Math.round(fpRate * 1000) / 1000,
|
|
101
|
+
findingCount: total,
|
|
102
|
+
confidence: Math.round(avgConf * 1000) / 1000,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
// Sort by actionability (disable first, then raise-threshold, etc.)
|
|
106
|
+
const actionOrder = {
|
|
107
|
+
disable: 0,
|
|
108
|
+
"raise-threshold": 1,
|
|
109
|
+
"lower-severity": 2,
|
|
110
|
+
investigate: 3,
|
|
111
|
+
keep: 4,
|
|
112
|
+
};
|
|
113
|
+
recommendations.sort((a, b) => (actionOrder[a.action] ?? 5) - (actionOrder[b.action] ?? 5));
|
|
114
|
+
return recommendations;
|
|
115
|
+
}
|
|
116
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
117
|
+
export function runNoiseAdvisor(argv) {
|
|
118
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
119
|
+
console.log(`
|
|
120
|
+
judges noise-advisor — Analyze rule performance and recommend tuning
|
|
121
|
+
|
|
122
|
+
Usage:
|
|
123
|
+
judges noise-advisor --input results.json
|
|
124
|
+
judges noise-advisor --input results.json --format json
|
|
125
|
+
|
|
126
|
+
Analyzes findings, suppressions, and false-negative feedback to recommend:
|
|
127
|
+
- Rules to disable (high FP rate)
|
|
128
|
+
- Rules needing threshold adjustment
|
|
129
|
+
- Rules requiring calibration review
|
|
130
|
+
|
|
131
|
+
Options:
|
|
132
|
+
--input <path> Results JSON file
|
|
133
|
+
--format json JSON output
|
|
134
|
+
--help, -h Show this help
|
|
135
|
+
`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
139
|
+
const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
|
|
140
|
+
const recs = analyzeNoise({ resultsPath: inputPath || undefined });
|
|
141
|
+
if (recs.length === 0) {
|
|
142
|
+
console.log("\n No data to analyze. Run an evaluation first or provide --input.\n");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (format === "json") {
|
|
146
|
+
console.log(JSON.stringify(recs, null, 2));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const actionable = recs.filter((r) => r.action !== "keep");
|
|
150
|
+
const keep = recs.filter((r) => r.action === "keep");
|
|
151
|
+
console.log(`\n Noise Analysis — ${recs.length} rules analyzed, ${actionable.length} need attention\n ─────────────────`);
|
|
152
|
+
if (actionable.length > 0) {
|
|
153
|
+
console.log("\n Recommendations:");
|
|
154
|
+
for (const r of actionable) {
|
|
155
|
+
const icon = r.action === "disable"
|
|
156
|
+
? "🔴"
|
|
157
|
+
: r.action === "raise-threshold"
|
|
158
|
+
? "🟡"
|
|
159
|
+
: r.action === "lower-severity"
|
|
160
|
+
? "🟠"
|
|
161
|
+
: "🔍";
|
|
162
|
+
console.log(` ${icon} ${r.ruleId.padEnd(15)} ${r.action.padEnd(18)} FP: ${(r.fpRate * 100).toFixed(0)}% (${r.findingCount} total)`);
|
|
163
|
+
console.log(` ${r.reason}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (keep.length > 0) {
|
|
167
|
+
console.log(`\n ${keep.length} rule(s) performing well — no changes needed.`);
|
|
168
|
+
}
|
|
169
|
+
console.log("");
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=noise-advisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noise-advisor.js","sourceRoot":"","sources":["../../src/commands/noise-advisor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced finding search/filter — complex queries across evaluation results.
|
|
3
|
+
*
|
|
4
|
+
* Reads local .judges-results.json files for searching.
|
|
5
|
+
*/
|
|
6
|
+
import type { Finding } from "../types.js";
|
|
7
|
+
interface FindingRecord extends Finding {
|
|
8
|
+
source?: string;
|
|
9
|
+
timestamp?: string;
|
|
10
|
+
}
|
|
11
|
+
interface QueryResult {
|
|
12
|
+
matches: FindingRecord[];
|
|
13
|
+
total: number;
|
|
14
|
+
query: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function queryFindings(queryStr: string, findings?: FindingRecord[]): QueryResult;
|
|
17
|
+
export declare function aggregateFindings(findings: FindingRecord[], groupBy: string): Record<string, number>;
|
|
18
|
+
export declare function runQuery(argv: string[]): void;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,UAAU,aAAc,SAAQ,OAAO;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAmED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,EAAE,GAAG,WAAW,CAkCvF;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBpG;AAID,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAuF7C"}
|