@kevinrabun/judges 3.115.4 → 3.117.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.
Files changed (114) hide show
  1. package/agents/accessibility.judge.md +7 -0
  2. package/agents/agent-instructions.judge.md +7 -0
  3. package/agents/ai-code-safety.judge.md +7 -0
  4. package/agents/api-contract.judge.md +7 -0
  5. package/agents/api-design.judge.md +7 -0
  6. package/agents/authentication.judge.md +7 -0
  7. package/agents/backwards-compatibility.judge.md +7 -0
  8. package/agents/caching.judge.md +7 -0
  9. package/agents/ci-cd.judge.md +7 -0
  10. package/agents/cloud-readiness.judge.md +7 -0
  11. package/agents/concurrency.judge.md +7 -0
  12. package/agents/configuration-management.judge.md +7 -0
  13. package/agents/cybersecurity.judge.md +7 -0
  14. package/agents/data-security.judge.md +7 -0
  15. package/agents/dependency-health.judge.md +7 -0
  16. package/agents/documentation.judge.md +7 -0
  17. package/agents/error-handling.judge.md +7 -0
  18. package/agents/ethics-bias.judge.md +7 -0
  19. package/agents/false-positive-review.judge.md +12 -0
  20. package/agents/framework-safety.judge.md +7 -0
  21. package/agents/hallucination-detection.judge.md +13 -0
  22. package/agents/iac-security.judge.md +7 -0
  23. package/agents/intent-alignment.judge.md +13 -0
  24. package/agents/logging-privacy.judge.md +7 -0
  25. package/agents/maintainability.judge.md +7 -0
  26. package/agents/multi-turn-coherence.judge.md +7 -0
  27. package/agents/observability.judge.md +7 -0
  28. package/agents/portability.judge.md +7 -0
  29. package/agents/rate-limiting.judge.md +7 -0
  30. package/agents/reliability.judge.md +7 -0
  31. package/agents/security.judge.md +13 -0
  32. package/agents/testing.judge.md +7 -0
  33. package/agents/ux.judge.md +7 -0
  34. package/dist/a2a-protocol.d.ts +136 -0
  35. package/dist/a2a-protocol.js +218 -0
  36. package/dist/api.d.ts +21 -3
  37. package/dist/api.js +21 -1
  38. package/dist/audit-trail.d.ts +245 -0
  39. package/dist/audit-trail.js +257 -0
  40. package/dist/commands/benchmark-advanced.js +51 -51
  41. package/dist/commands/benchmark-ai-agents.js +16 -16
  42. package/dist/commands/benchmark-compliance-ethics.js +12 -12
  43. package/dist/commands/benchmark-expanded-2.js +2 -2
  44. package/dist/commands/benchmark-expanded.js +2 -2
  45. package/dist/commands/benchmark-infrastructure.js +12 -12
  46. package/dist/commands/benchmark-languages.js +11 -11
  47. package/dist/commands/benchmark-quality-ops.js +7 -7
  48. package/dist/commands/benchmark-security-deep.js +9 -9
  49. package/dist/commands/benchmark.js +1 -1
  50. package/dist/commands/llm-benchmark-optimizer.d.ts +78 -0
  51. package/dist/commands/llm-benchmark-optimizer.js +241 -0
  52. package/dist/commands/llm-benchmark.d.ts +4 -2
  53. package/dist/commands/llm-benchmark.js +40 -12
  54. package/dist/escalation.d.ts +100 -0
  55. package/dist/escalation.js +292 -0
  56. package/dist/evaluation-session.d.ts +74 -0
  57. package/dist/evaluation-session.js +152 -0
  58. package/dist/evaluators/index.d.ts +23 -1
  59. package/dist/evaluators/index.js +192 -3
  60. package/dist/evaluators/judge-selector.d.ts +19 -0
  61. package/dist/evaluators/judge-selector.js +141 -0
  62. package/dist/evaluators/recall-boost.d.ts +27 -0
  63. package/dist/evaluators/recall-boost.js +409 -0
  64. package/dist/feedback-loop.d.ts +62 -0
  65. package/dist/feedback-loop.js +179 -0
  66. package/dist/index.js +2 -0
  67. package/dist/judges/accessibility.js +7 -0
  68. package/dist/judges/agent-instructions.js +7 -0
  69. package/dist/judges/ai-code-safety.js +7 -0
  70. package/dist/judges/api-contract.js +7 -0
  71. package/dist/judges/api-design.js +7 -0
  72. package/dist/judges/authentication.js +7 -0
  73. package/dist/judges/backwards-compatibility.js +7 -0
  74. package/dist/judges/caching.js +7 -0
  75. package/dist/judges/ci-cd.js +7 -0
  76. package/dist/judges/cloud-readiness.js +7 -0
  77. package/dist/judges/concurrency.js +7 -0
  78. package/dist/judges/configuration-management.js +7 -0
  79. package/dist/judges/cybersecurity.js +7 -0
  80. package/dist/judges/data-security.js +7 -0
  81. package/dist/judges/dependency-health.js +7 -0
  82. package/dist/judges/documentation.js +7 -0
  83. package/dist/judges/error-handling.js +7 -0
  84. package/dist/judges/ethics-bias.js +7 -0
  85. package/dist/judges/false-positive-review.js +13 -1
  86. package/dist/judges/framework-safety.js +7 -0
  87. package/dist/judges/hallucination-detection.js +14 -1
  88. package/dist/judges/iac-security.js +7 -0
  89. package/dist/judges/intent-alignment.js +14 -1
  90. package/dist/judges/logging-privacy.js +7 -0
  91. package/dist/judges/maintainability.js +7 -0
  92. package/dist/judges/multi-turn-coherence.js +7 -0
  93. package/dist/judges/observability.js +7 -0
  94. package/dist/judges/portability.js +7 -0
  95. package/dist/judges/rate-limiting.js +7 -0
  96. package/dist/judges/reliability.js +7 -0
  97. package/dist/judges/security.js +14 -1
  98. package/dist/judges/testing.js +7 -0
  99. package/dist/judges/ux.js +7 -0
  100. package/dist/review-conversation.d.ts +87 -0
  101. package/dist/review-conversation.js +307 -0
  102. package/dist/sast-integration.d.ts +112 -0
  103. package/dist/sast-integration.js +215 -0
  104. package/dist/tools/register-evaluation.js +208 -8
  105. package/dist/tools/register-fix.js +24 -1
  106. package/dist/tools/register-resources.d.ts +6 -0
  107. package/dist/tools/register-resources.js +177 -0
  108. package/dist/tools/register-review.js +26 -1
  109. package/dist/tools/register-workflow.js +384 -11
  110. package/dist/tools/validation.d.ts +13 -0
  111. package/dist/tools/validation.js +77 -0
  112. package/dist/types.d.ts +122 -0
  113. package/package.json +25 -12
  114. package/server.json +2 -2
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Immutable Audit Trail
3
+ *
4
+ * Records every code review action as an append-only event log for
5
+ * compliance-sensitive environments (SOX, HIPAA, PCI DSS, SOC 2).
6
+ *
7
+ * Each event captures:
8
+ * - What was reviewed (file, commit, PR)
9
+ * - What was found (findings and their severities)
10
+ * - What was suppressed and why
11
+ * - What was escalated to humans
12
+ * - Who overrode findings and the justification
13
+ * - Review decisions and confidence scores
14
+ *
15
+ * The log is append-only — events are never modified or deleted.
16
+ * File: .judges-audit.jsonl (JSON Lines format for efficient append)
17
+ */
18
+ import type { Finding, Severity, ReviewDecision } from "./types.js";
19
+ export type AuditEventType = "evaluation-started" | "evaluation-completed" | "finding-detected" | "finding-suppressed" | "finding-overridden" | "finding-escalated" | "escalation-resolved" | "review-decision" | "triage-action" | "config-change" | "calibration-applied";
20
+ export interface AuditEvent {
21
+ /** Monotonically increasing event ID */
22
+ eventId: string;
23
+ /** Event type */
24
+ type: AuditEventType;
25
+ /** ISO 8601 timestamp */
26
+ timestamp: string;
27
+ /** Session identifier for grouping related events */
28
+ sessionId: string;
29
+ /** File being reviewed (if applicable) */
30
+ filePath?: string;
31
+ /** Git commit SHA (if available) */
32
+ commitSha?: string;
33
+ /** PR number (if available) */
34
+ prNumber?: number;
35
+ /** Actor (user, system, or judge ID) */
36
+ actor: string;
37
+ /** Event payload (varies by type) */
38
+ payload: AuditPayload;
39
+ /** Integrity hash of this event + previous event hash (chain) */
40
+ integrityHash: string;
41
+ }
42
+ export type AuditPayload = EvaluationStartedPayload | EvaluationCompletedPayload | FindingDetectedPayload | FindingSuppressedPayload | FindingOverriddenPayload | FindingEscalatedPayload | EscalationResolvedPayload | ReviewDecisionPayload | TriageActionPayload | ConfigChangePayload | CalibrationAppliedPayload;
43
+ export interface EvaluationStartedPayload {
44
+ kind: "evaluation-started";
45
+ language: string;
46
+ judgeCount: number;
47
+ preset?: string;
48
+ configHash?: string;
49
+ }
50
+ export interface EvaluationCompletedPayload {
51
+ kind: "evaluation-completed";
52
+ findingCount: number;
53
+ suppressedCount: number;
54
+ escalatedCount: number;
55
+ verdict: string;
56
+ score: number;
57
+ durationMs: number;
58
+ }
59
+ export interface FindingDetectedPayload {
60
+ kind: "finding-detected";
61
+ ruleId: string;
62
+ severity: Severity;
63
+ title: string;
64
+ confidence: number;
65
+ lineNumbers?: number[];
66
+ provenance?: string;
67
+ }
68
+ export interface FindingSuppressedPayload {
69
+ kind: "finding-suppressed";
70
+ ruleId: string;
71
+ severity: Severity;
72
+ reason: string;
73
+ suppressionType: "inline-comment" | "config-rule" | "false-positive-filter" | "calibration" | "confidence-threshold";
74
+ }
75
+ export interface FindingOverriddenPayload {
76
+ kind: "finding-overridden";
77
+ ruleId: string;
78
+ severity: Severity;
79
+ overriddenBy: string;
80
+ justification: string;
81
+ previousStatus: string;
82
+ newStatus: string;
83
+ }
84
+ export interface FindingEscalatedPayload {
85
+ kind: "finding-escalated";
86
+ ruleId: string;
87
+ severity: Severity;
88
+ escalationReasons: string[];
89
+ routingTarget: string;
90
+ }
91
+ export interface EscalationResolvedPayload {
92
+ kind: "escalation-resolved";
93
+ escalationId: string;
94
+ resolvedBy: string;
95
+ resolution: "confirmed" | "dismissed" | "modified";
96
+ notes?: string;
97
+ }
98
+ export interface ReviewDecisionPayload {
99
+ kind: "review-decision";
100
+ action: string;
101
+ criticalCount: number;
102
+ highCount: number;
103
+ totalFindings: number;
104
+ mustFixTriggered: boolean;
105
+ escalationsPending: number;
106
+ }
107
+ export interface TriageActionPayload {
108
+ kind: "triage-action";
109
+ findingFingerprint: string;
110
+ ruleId: string;
111
+ action: string;
112
+ reason?: string;
113
+ triagedBy: string;
114
+ }
115
+ export interface ConfigChangePayload {
116
+ kind: "config-change";
117
+ field: string;
118
+ oldValue: string;
119
+ newValue: string;
120
+ changedBy: string;
121
+ }
122
+ export interface CalibrationAppliedPayload {
123
+ kind: "calibration-applied";
124
+ findingsAdjusted: number;
125
+ avgConfidenceShift: number;
126
+ modelId?: string;
127
+ }
128
+ /**
129
+ * Append a single audit event to the log file.
130
+ * Uses JSONL (one JSON object per line) for efficient append.
131
+ */
132
+ export declare function appendAuditEvent(event: AuditEvent, baseDir?: string): void;
133
+ /**
134
+ * Read all audit events from the log file.
135
+ * Returns events in chronological order.
136
+ */
137
+ export declare function readAuditTrail(baseDir?: string): AuditEvent[];
138
+ /**
139
+ * Verify the integrity chain of the audit trail.
140
+ * Returns true if no tampering detected, false if chain is broken.
141
+ */
142
+ export declare function verifyAuditIntegrity(events: AuditEvent[]): {
143
+ valid: boolean;
144
+ brokenAt?: number;
145
+ details?: string;
146
+ };
147
+ /**
148
+ * Record the start of an evaluation session.
149
+ */
150
+ export declare function recordEvaluationStart(sessionId: string, language: string, judgeCount: number, options?: {
151
+ preset?: string;
152
+ filePath?: string;
153
+ commitSha?: string;
154
+ baseDir?: string;
155
+ }): void;
156
+ /**
157
+ * Record the completion of an evaluation.
158
+ */
159
+ export declare function recordEvaluationComplete(sessionId: string, stats: {
160
+ findingCount: number;
161
+ suppressedCount: number;
162
+ escalatedCount: number;
163
+ verdict: string;
164
+ score: number;
165
+ durationMs: number;
166
+ }, options?: {
167
+ filePath?: string;
168
+ commitSha?: string;
169
+ baseDir?: string;
170
+ }): void;
171
+ /**
172
+ * Record individual findings detected during evaluation.
173
+ */
174
+ export declare function recordFindings(sessionId: string, findings: Finding[], options?: {
175
+ filePath?: string;
176
+ baseDir?: string;
177
+ }): void;
178
+ /**
179
+ * Record a finding suppression (inline comment, config, FP filter, etc.).
180
+ */
181
+ export declare function recordSuppression(sessionId: string, ruleId: string, severity: Severity, reason: string, suppressionType: FindingSuppressedPayload["suppressionType"], options?: {
182
+ filePath?: string;
183
+ baseDir?: string;
184
+ }): void;
185
+ /**
186
+ * Record a human override of a finding.
187
+ */
188
+ export declare function recordOverride(sessionId: string, ruleId: string, severity: Severity, overriddenBy: string, justification: string, previousStatus: string, newStatus: string, options?: {
189
+ filePath?: string;
190
+ baseDir?: string;
191
+ }): void;
192
+ /**
193
+ * Record a finding escalation to human review.
194
+ */
195
+ export declare function recordEscalation(sessionId: string, ruleId: string, severity: Severity, escalationReasons: string[], routingTarget: string, options?: {
196
+ filePath?: string;
197
+ baseDir?: string;
198
+ }): void;
199
+ /**
200
+ * Record the review decision for a file/PR.
201
+ */
202
+ export declare function recordReviewDecision(sessionId: string, decision: ReviewDecision, options?: {
203
+ filePath?: string;
204
+ commitSha?: string;
205
+ prNumber?: number;
206
+ baseDir?: string;
207
+ }): void;
208
+ /**
209
+ * Record a triage action on a tracked finding.
210
+ */
211
+ export declare function recordTriageAction(sessionId: string, findingFingerprint: string, ruleId: string, action: string, triagedBy: string, options?: {
212
+ reason?: string;
213
+ filePath?: string;
214
+ baseDir?: string;
215
+ }): void;
216
+ export interface AuditSummary {
217
+ totalEvents: number;
218
+ evaluations: number;
219
+ findingsDetected: number;
220
+ findingsSuppressed: number;
221
+ findingsEscalated: number;
222
+ findingsOverridden: number;
223
+ reviewDecisions: number;
224
+ triageActions: number;
225
+ integrityValid: boolean;
226
+ timeRange: {
227
+ from: string;
228
+ to: string;
229
+ } | null;
230
+ }
231
+ /**
232
+ * Compute a summary of the audit trail for compliance reporting.
233
+ */
234
+ export declare function computeAuditSummary(events: AuditEvent[]): AuditSummary;
235
+ /**
236
+ * Filter audit events by session, time range, type, or file.
237
+ */
238
+ export declare function queryAuditTrail(events: AuditEvent[], filters: {
239
+ sessionId?: string;
240
+ types?: AuditEventType[];
241
+ filePath?: string;
242
+ from?: string;
243
+ to?: string;
244
+ actor?: string;
245
+ }): AuditEvent[];
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Immutable Audit Trail
3
+ *
4
+ * Records every code review action as an append-only event log for
5
+ * compliance-sensitive environments (SOX, HIPAA, PCI DSS, SOC 2).
6
+ *
7
+ * Each event captures:
8
+ * - What was reviewed (file, commit, PR)
9
+ * - What was found (findings and their severities)
10
+ * - What was suppressed and why
11
+ * - What was escalated to humans
12
+ * - Who overrode findings and the justification
13
+ * - Review decisions and confidence scores
14
+ *
15
+ * The log is append-only — events are never modified or deleted.
16
+ * File: .judges-audit.jsonl (JSON Lines format for efficient append)
17
+ */
18
+ import { appendFileSync, readFileSync, existsSync } from "fs";
19
+ import { resolve } from "path";
20
+ // ─── Audit Trail I/O ─────────────────────────────────────────────────────────
21
+ const AUDIT_FILE = ".judges-audit.jsonl";
22
+ let lastHash = "";
23
+ let eventCounter = 0;
24
+ /**
25
+ * Simple hash for integrity chaining. Uses FNV-1a for speed.
26
+ * This is for tamper detection, not cryptographic security.
27
+ */
28
+ function fnv1aHash(data) {
29
+ let hash = 0x811c9dc5;
30
+ for (let i = 0; i < data.length; i++) {
31
+ hash ^= data.charCodeAt(i);
32
+ hash = (hash * 0x01000193) >>> 0;
33
+ }
34
+ return hash.toString(16).padStart(8, "0");
35
+ }
36
+ function generateEventId() {
37
+ eventCounter++;
38
+ const ts = Date.now().toString(36);
39
+ const seq = eventCounter.toString(36).padStart(4, "0");
40
+ return `evt_${ts}_${seq}`;
41
+ }
42
+ function buildEvent(type, sessionId, actor, payload, context) {
43
+ const event = {
44
+ eventId: generateEventId(),
45
+ type,
46
+ timestamp: new Date().toISOString(),
47
+ sessionId,
48
+ actor,
49
+ payload,
50
+ ...context,
51
+ };
52
+ // Chain hash: hash of (previous hash + this event's content)
53
+ const content = JSON.stringify(event);
54
+ const integrityHash = fnv1aHash(lastHash + content);
55
+ lastHash = integrityHash;
56
+ return { ...event, integrityHash };
57
+ }
58
+ /**
59
+ * Append a single audit event to the log file.
60
+ * Uses JSONL (one JSON object per line) for efficient append.
61
+ */
62
+ export function appendAuditEvent(event, baseDir) {
63
+ const dir = baseDir || process.cwd();
64
+ const filePath = resolve(dir, AUDIT_FILE);
65
+ const line = JSON.stringify(event) + "\n";
66
+ appendFileSync(filePath, line, "utf-8");
67
+ }
68
+ /**
69
+ * Read all audit events from the log file.
70
+ * Returns events in chronological order.
71
+ */
72
+ export function readAuditTrail(baseDir) {
73
+ const dir = baseDir || process.cwd();
74
+ const filePath = resolve(dir, AUDIT_FILE);
75
+ if (!existsSync(filePath))
76
+ return [];
77
+ const content = readFileSync(filePath, "utf-8");
78
+ const events = [];
79
+ for (const line of content.split("\n")) {
80
+ const trimmed = line.trim();
81
+ if (!trimmed)
82
+ continue;
83
+ try {
84
+ events.push(JSON.parse(trimmed));
85
+ }
86
+ catch {
87
+ // Skip malformed lines — don't crash on corrupted entries
88
+ }
89
+ }
90
+ return events;
91
+ }
92
+ /**
93
+ * Verify the integrity chain of the audit trail.
94
+ * Returns true if no tampering detected, false if chain is broken.
95
+ */
96
+ export function verifyAuditIntegrity(events) {
97
+ let prevHash = "";
98
+ for (let i = 0; i < events.length; i++) {
99
+ const event = events[i];
100
+ const { integrityHash, ...rest } = event;
101
+ const content = JSON.stringify(rest);
102
+ const expectedHash = fnv1aHash(prevHash + content);
103
+ if (expectedHash !== integrityHash) {
104
+ return {
105
+ valid: false,
106
+ brokenAt: i,
107
+ details: `Event ${event.eventId} at index ${i}: expected hash ${expectedHash}, got ${integrityHash}`,
108
+ };
109
+ }
110
+ prevHash = integrityHash;
111
+ }
112
+ return { valid: true };
113
+ }
114
+ // ─── Convenience Recording Functions ─────────────────────────────────────────
115
+ /**
116
+ * Record the start of an evaluation session.
117
+ */
118
+ export function recordEvaluationStart(sessionId, language, judgeCount, options) {
119
+ const event = buildEvent("evaluation-started", sessionId, "system", {
120
+ kind: "evaluation-started",
121
+ language,
122
+ judgeCount,
123
+ preset: options?.preset,
124
+ }, { filePath: options?.filePath, commitSha: options?.commitSha });
125
+ appendAuditEvent(event, options?.baseDir);
126
+ }
127
+ /**
128
+ * Record the completion of an evaluation.
129
+ */
130
+ export function recordEvaluationComplete(sessionId, stats, options) {
131
+ const event = buildEvent("evaluation-completed", sessionId, "system", { kind: "evaluation-completed", ...stats }, { filePath: options?.filePath, commitSha: options?.commitSha });
132
+ appendAuditEvent(event, options?.baseDir);
133
+ }
134
+ /**
135
+ * Record individual findings detected during evaluation.
136
+ */
137
+ export function recordFindings(sessionId, findings, options) {
138
+ for (const f of findings) {
139
+ const event = buildEvent("finding-detected", sessionId, f.ruleId.split("-")[0] || "evaluator", {
140
+ kind: "finding-detected",
141
+ ruleId: f.ruleId,
142
+ severity: f.severity,
143
+ title: f.title,
144
+ confidence: f.confidence ?? 0.5,
145
+ lineNumbers: f.lineNumbers,
146
+ provenance: f.provenance,
147
+ }, { filePath: options?.filePath });
148
+ appendAuditEvent(event, options?.baseDir);
149
+ }
150
+ }
151
+ /**
152
+ * Record a finding suppression (inline comment, config, FP filter, etc.).
153
+ */
154
+ export function recordSuppression(sessionId, ruleId, severity, reason, suppressionType, options) {
155
+ const event = buildEvent("finding-suppressed", sessionId, "system", { kind: "finding-suppressed", ruleId, severity, reason, suppressionType }, { filePath: options?.filePath });
156
+ appendAuditEvent(event, options?.baseDir);
157
+ }
158
+ /**
159
+ * Record a human override of a finding.
160
+ */
161
+ export function recordOverride(sessionId, ruleId, severity, overriddenBy, justification, previousStatus, newStatus, options) {
162
+ const event = buildEvent("finding-overridden", sessionId, overriddenBy, { kind: "finding-overridden", ruleId, severity, overriddenBy, justification, previousStatus, newStatus }, { filePath: options?.filePath });
163
+ appendAuditEvent(event, options?.baseDir);
164
+ }
165
+ /**
166
+ * Record a finding escalation to human review.
167
+ */
168
+ export function recordEscalation(sessionId, ruleId, severity, escalationReasons, routingTarget, options) {
169
+ const event = buildEvent("finding-escalated", sessionId, "escalation-engine", { kind: "finding-escalated", ruleId, severity, escalationReasons, routingTarget }, { filePath: options?.filePath });
170
+ appendAuditEvent(event, options?.baseDir);
171
+ }
172
+ /**
173
+ * Record the review decision for a file/PR.
174
+ */
175
+ export function recordReviewDecision(sessionId, decision, options) {
176
+ const event = buildEvent("review-decision", sessionId, "tribunal", {
177
+ kind: "review-decision",
178
+ action: decision.action,
179
+ criticalCount: decision.severityCounts.critical,
180
+ highCount: decision.severityCounts.high,
181
+ totalFindings: decision.totalFindings,
182
+ mustFixTriggered: decision.blockingIssues.length > 0,
183
+ escalationsPending: 0,
184
+ }, { filePath: options?.filePath, commitSha: options?.commitSha, prNumber: options?.prNumber });
185
+ appendAuditEvent(event, options?.baseDir);
186
+ }
187
+ /**
188
+ * Record a triage action on a tracked finding.
189
+ */
190
+ export function recordTriageAction(sessionId, findingFingerprint, ruleId, action, triagedBy, options) {
191
+ const event = buildEvent("triage-action", sessionId, triagedBy, { kind: "triage-action", findingFingerprint, ruleId, action, triagedBy, reason: options?.reason }, { filePath: options?.filePath });
192
+ appendAuditEvent(event, options?.baseDir);
193
+ }
194
+ /**
195
+ * Compute a summary of the audit trail for compliance reporting.
196
+ */
197
+ export function computeAuditSummary(events) {
198
+ const integrity = verifyAuditIntegrity(events);
199
+ const summary = {
200
+ totalEvents: events.length,
201
+ evaluations: 0,
202
+ findingsDetected: 0,
203
+ findingsSuppressed: 0,
204
+ findingsEscalated: 0,
205
+ findingsOverridden: 0,
206
+ reviewDecisions: 0,
207
+ triageActions: 0,
208
+ integrityValid: integrity.valid,
209
+ timeRange: events.length > 0 ? { from: events[0].timestamp, to: events[events.length - 1].timestamp } : null,
210
+ };
211
+ for (const event of events) {
212
+ switch (event.type) {
213
+ case "evaluation-completed":
214
+ summary.evaluations++;
215
+ break;
216
+ case "finding-detected":
217
+ summary.findingsDetected++;
218
+ break;
219
+ case "finding-suppressed":
220
+ summary.findingsSuppressed++;
221
+ break;
222
+ case "finding-escalated":
223
+ summary.findingsEscalated++;
224
+ break;
225
+ case "finding-overridden":
226
+ summary.findingsOverridden++;
227
+ break;
228
+ case "review-decision":
229
+ summary.reviewDecisions++;
230
+ break;
231
+ case "triage-action":
232
+ summary.triageActions++;
233
+ break;
234
+ }
235
+ }
236
+ return summary;
237
+ }
238
+ /**
239
+ * Filter audit events by session, time range, type, or file.
240
+ */
241
+ export function queryAuditTrail(events, filters) {
242
+ return events.filter((e) => {
243
+ if (filters.sessionId && e.sessionId !== filters.sessionId)
244
+ return false;
245
+ if (filters.types && !filters.types.includes(e.type))
246
+ return false;
247
+ if (filters.filePath && e.filePath !== filters.filePath)
248
+ return false;
249
+ if (filters.from && e.timestamp < filters.from)
250
+ return false;
251
+ if (filters.to && e.timestamp > filters.to)
252
+ return false;
253
+ if (filters.actor && e.actor !== filters.actor)
254
+ return false;
255
+ return true;
256
+ });
257
+ }