@runhalo/engine 0.5.0 → 0.6.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 (40) hide show
  1. package/dist/context-analyzer.js +38 -31
  2. package/dist/context-analyzer.js.map +1 -1
  3. package/dist/fp-patterns.d.ts +36 -0
  4. package/dist/fp-patterns.js +426 -0
  5. package/dist/fp-patterns.js.map +1 -0
  6. package/dist/frameworks/angular.d.ts +11 -0
  7. package/dist/frameworks/angular.js +41 -0
  8. package/dist/frameworks/angular.js.map +1 -0
  9. package/dist/frameworks/index.js +6 -0
  10. package/dist/frameworks/index.js.map +1 -1
  11. package/dist/frameworks/react.d.ts +13 -0
  12. package/dist/frameworks/react.js +36 -0
  13. package/dist/frameworks/react.js.map +1 -0
  14. package/dist/frameworks/vue.d.ts +9 -0
  15. package/dist/frameworks/vue.js +39 -0
  16. package/dist/frameworks/vue.js.map +1 -0
  17. package/dist/graduation/fp-verdict-logger.d.ts +81 -0
  18. package/dist/graduation/fp-verdict-logger.js +130 -0
  19. package/dist/graduation/fp-verdict-logger.js.map +1 -0
  20. package/dist/graduation/graduation-codifier.d.ts +37 -0
  21. package/dist/graduation/graduation-codifier.js +205 -0
  22. package/dist/graduation/graduation-codifier.js.map +1 -0
  23. package/dist/graduation/graduation-validator.d.ts +73 -0
  24. package/dist/graduation/graduation-validator.js +204 -0
  25. package/dist/graduation/graduation-validator.js.map +1 -0
  26. package/dist/graduation/index.d.ts +71 -0
  27. package/dist/graduation/index.js +105 -0
  28. package/dist/graduation/index.js.map +1 -0
  29. package/dist/graduation/pattern-aggregator.d.ts +77 -0
  30. package/dist/graduation/pattern-aggregator.js +154 -0
  31. package/dist/graduation/pattern-aggregator.js.map +1 -0
  32. package/dist/index.d.ts +75 -0
  33. package/dist/index.js +632 -73
  34. package/dist/index.js.map +1 -1
  35. package/dist/review-board/two-agent-review.d.ts +152 -0
  36. package/dist/review-board/two-agent-review.js +463 -0
  37. package/dist/review-board/two-agent-review.js.map +1 -0
  38. package/package.json +5 -2
  39. package/rules/coppa-tier-1.yaml +17 -10
  40. package/rules/rules.json +408 -40
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ /**
3
+ * Sprint 13a Week 2: Pattern Aggregator
4
+ *
5
+ * Stage 2 of the Graduation Pipeline.
6
+ * Reads verdict logs (JSONL) and aggregates FP patterns across scans.
7
+ * Produces statistics per fpPatternId: total dismissals, avg confidence,
8
+ * false confirmation rate, affected rules and file paths.
9
+ *
10
+ * This is the bridge between raw verdict data and graduation decisions.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.aggregatePatterns = aggregatePatterns;
14
+ exports.aggregateFromDirectory = aggregateFromDirectory;
15
+ exports.formatAggregationReport = formatAggregationReport;
16
+ const fp_verdict_logger_1 = require("./fp-verdict-logger");
17
+ // ─── Aggregator ─────────────────────────────────────────────────────────────
18
+ /**
19
+ * Aggregate verdict log entries into per-pattern statistics.
20
+ *
21
+ * @param entries - All verdict log entries to aggregate
22
+ * @param knownPatternIds - Set of pattern IDs from the static FP library (for inLibrary flag)
23
+ */
24
+ function aggregatePatterns(entries, knownPatternIds) {
25
+ const patternMap = new Map();
26
+ const ruleStats = new Map();
27
+ let totalDismissed = 0;
28
+ let totalConfirmed = 0;
29
+ let unclassifiedDismissals = 0;
30
+ const allScans = new Set();
31
+ for (const entry of entries) {
32
+ allScans.add(entry.scanId);
33
+ // Track rule-level stats
34
+ const ruleStat = ruleStats.get(entry.ruleId) || { total: 0, dismissed: 0 };
35
+ ruleStat.total++;
36
+ if (entry.verdict === 'dismissed') {
37
+ totalDismissed++;
38
+ ruleStat.dismissed++;
39
+ if (entry.fpPatternId) {
40
+ let patternData = patternMap.get(entry.fpPatternId);
41
+ if (!patternData) {
42
+ patternData = {
43
+ dismissals: [],
44
+ fpReasons: new Set(),
45
+ rules: new Set(),
46
+ scans: new Set(),
47
+ paths: new Set(),
48
+ };
49
+ patternMap.set(entry.fpPatternId, patternData);
50
+ }
51
+ patternData.dismissals.push(entry);
52
+ if (entry.fpReason)
53
+ patternData.fpReasons.add(entry.fpReason);
54
+ patternData.rules.add(entry.ruleId);
55
+ patternData.scans.add(entry.scanId);
56
+ patternData.paths.add(entry.filePath);
57
+ }
58
+ else {
59
+ unclassifiedDismissals++;
60
+ }
61
+ }
62
+ else if (entry.verdict === 'confirmed' || entry.verdict === 'escalated') {
63
+ totalConfirmed++;
64
+ }
65
+ ruleStats.set(entry.ruleId, ruleStat);
66
+ }
67
+ // Build pattern stats
68
+ const patterns = [];
69
+ for (const [patternId, data] of patternMap) {
70
+ const confidences = data.dismissals
71
+ .map(d => d.confidence)
72
+ .filter((c) => typeof c === 'number');
73
+ const timestamps = data.dismissals
74
+ .map(d => d.timestamp)
75
+ .sort();
76
+ patterns.push({
77
+ fpPatternId: patternId,
78
+ fpReason: [...data.fpReasons].join('; ') || patternId,
79
+ totalDismissals: data.dismissals.length,
80
+ avgConfidence: confidences.length > 0
81
+ ? Math.round((confidences.reduce((a, b) => a + b, 0) / confidences.length) * 10) / 10
82
+ : 0,
83
+ minConfidence: confidences.length > 0 ? Math.min(...confidences) : 0,
84
+ maxConfidence: confidences.length > 0 ? Math.max(...confidences) : 0,
85
+ falseConfirmations: 0, // Populated by graduation-validator with ground truth
86
+ affectedRules: [...data.rules],
87
+ samplePaths: [...data.paths].slice(0, 5),
88
+ uniqueScans: data.scans.size,
89
+ firstSeen: timestamps[0] || '',
90
+ lastSeen: timestamps[timestamps.length - 1] || '',
91
+ inLibrary: knownPatternIds ? knownPatternIds.has(patternId) : false,
92
+ });
93
+ }
94
+ // Sort by total dismissals (most common first)
95
+ patterns.sort((a, b) => b.totalDismissals - a.totalDismissals);
96
+ // High FP rate rules
97
+ const highFPRules = [...ruleStats.entries()]
98
+ .map(([ruleId, stats]) => ({
99
+ ruleId,
100
+ total: stats.total,
101
+ dismissed: stats.dismissed,
102
+ fpRate: stats.total > 0 ? Math.round((stats.dismissed / stats.total) * 1000) / 10 : 0,
103
+ }))
104
+ .filter(r => r.fpRate > 30) // Only show rules with >30% FP rate
105
+ .sort((a, b) => b.fpRate - a.fpRate);
106
+ return {
107
+ aggregatedAt: new Date().toISOString(),
108
+ totalEntries: entries.length,
109
+ totalDismissed,
110
+ totalConfirmed,
111
+ uniqueScans: allScans.size,
112
+ patterns,
113
+ unclassifiedDismissals,
114
+ highFPRules,
115
+ };
116
+ }
117
+ /**
118
+ * Convenience: aggregate from a log directory.
119
+ */
120
+ function aggregateFromDirectory(logDir, knownPatternIds) {
121
+ const entries = fp_verdict_logger_1.FPVerdictLogger.readAllLogs(logDir);
122
+ return aggregatePatterns(entries, knownPatternIds);
123
+ }
124
+ /**
125
+ * Format aggregation result as a readable report.
126
+ */
127
+ function formatAggregationReport(result) {
128
+ const lines = [
129
+ '═══ FP Pattern Aggregation Report ═══',
130
+ '',
131
+ `Aggregated at: ${result.aggregatedAt}`,
132
+ `Total entries: ${result.totalEntries}`,
133
+ `Dismissed: ${result.totalDismissed} (${result.totalEntries > 0 ? Math.round(result.totalDismissed / result.totalEntries * 100) : 0}%)`,
134
+ `Confirmed: ${result.totalConfirmed}`,
135
+ `Unique scans: ${result.uniqueScans}`,
136
+ `Unclassified dismissals: ${result.unclassifiedDismissals}`,
137
+ '',
138
+ '── Top FP Patterns ──',
139
+ ];
140
+ for (const p of result.patterns.slice(0, 15)) {
141
+ const libraryTag = p.inLibrary ? '' : ' [NEW]';
142
+ lines.push(` ${p.fpPatternId.padEnd(30)} ${p.totalDismissals} dismissals, avg conf ${p.avgConfidence}, ${p.uniqueScans} scans${libraryTag}`);
143
+ lines.push(` Rules: ${p.affectedRules.join(', ')}`);
144
+ }
145
+ if (result.highFPRules.length > 0) {
146
+ lines.push('');
147
+ lines.push('── High FP Rate Rules ──');
148
+ for (const r of result.highFPRules) {
149
+ lines.push(` ${r.ruleId.padEnd(25)} ${r.dismissed}/${r.total} (${r.fpRate}% FP rate)`);
150
+ }
151
+ }
152
+ return lines.join('\n');
153
+ }
154
+ //# sourceMappingURL=pattern-aggregator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern-aggregator.js","sourceRoot":"","sources":["../../src/graduation/pattern-aggregator.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -51,6 +51,26 @@ export interface Violation {
51
51
  confidenceInterpretation?: ConfidenceInterpretation;
52
52
  /** ContextAnalyzer reason string */
53
53
  confidenceReason?: string;
54
+ /** Whether this violation is from a vendored/third-party library path */
55
+ vendorPath?: boolean;
56
+ /** Lines surrounding the match (5 before + 5 after) */
57
+ surroundingCode?: string;
58
+ /** File-level metadata flags computed during scan */
59
+ fileMetadata?: {
60
+ language: string;
61
+ isVendor: boolean;
62
+ isTest: boolean;
63
+ isAdmin: boolean;
64
+ isConsent: boolean;
65
+ isDocGenerator: boolean;
66
+ detectedFramework?: string;
67
+ isMock?: boolean;
68
+ isFixture?: boolean;
69
+ isCIConfig?: boolean;
70
+ isBuildOutput?: boolean;
71
+ isTypeDefinition?: boolean;
72
+ isStorybook?: boolean;
73
+ };
54
74
  }
55
75
  export interface Rule {
56
76
  id: string;
@@ -62,7 +82,51 @@ export interface Rule {
62
82
  penalty: string;
63
83
  languages: string[];
64
84
  remediation?: RemediationSpec;
85
+ is_active?: boolean;
86
+ }
87
+ export interface FileClassification {
88
+ /** How this classification was determined */
89
+ method: 'heuristic' | 'classifier';
90
+ /** Detected programming language */
91
+ language: string;
92
+ /** Whether the file is in a vendored/third-party directory */
93
+ isVendor: boolean;
94
+ /** Whether the file is a test/spec/fixture file */
95
+ isTest: boolean;
96
+ /** Whether the file is a consent/privacy compliance implementation */
97
+ isConsent: boolean;
98
+ /** Whether the file is in an admin/instructor/staff backend path */
99
+ isAdmin: boolean;
100
+ /** Whether the file is documentation generator output */
101
+ isDocGenerator: boolean;
102
+ /** Whether the file is a Django migration */
103
+ isDjangoMigration: boolean;
104
+ /** Whether the file is a Rails fixture or seed file */
105
+ isFixtureOrSeed: boolean;
106
+ /** Whether the file is a mock/factory file */
107
+ isMockOrFactory: boolean;
108
+ /** Whether the file is a CI/CD config file */
109
+ isCIConfig: boolean;
110
+ /** Whether the file is build output */
111
+ isBuildOutput: boolean;
112
+ /** Whether the file is a type definition only (no runtime code) */
113
+ isTypeDefinition: boolean;
114
+ /** Whether the file is a Storybook story */
115
+ isStorybook: boolean;
116
+ /** Whether the file should be completely skipped (combined signal) */
117
+ shouldSkip: boolean;
118
+ /** Category for why the file should be skipped (if shouldSkip is true) */
119
+ skipReason?: string;
65
120
  }
121
+ /**
122
+ * Sprint 13a: Classify a file using deterministic heuristics.
123
+ * Returns a FileClassification object that the scan loop uses to skip
124
+ * files or suppress specific rules.
125
+ *
126
+ * @param filePath — normalized file path (forward slashes)
127
+ * @param contentPrefix — first 3000 chars of file content (for decorator/annotation detection)
128
+ */
129
+ export declare function classifyFile(filePath: string, contentPrefix?: string): FileClassification;
66
130
  export interface SuppressionConfig {
67
131
  enabled: boolean;
68
132
  commentPattern: string;
@@ -154,6 +218,17 @@ export interface IgnoreConfig {
154
218
  * src/auth.ts:coppa-auth-001 — suppress rule in specific file
155
219
  */
156
220
  export declare function parseHaloignore(content: string): IgnoreConfig;
221
+ /**
222
+ * Sprint 10: Check if a file path is in a vendored/third-party library directory.
223
+ * Vendor files are auto-suppressed to eliminate false positives from code the project doesn't control.
224
+ */
225
+ export declare function isVendorPath(filePath: string): boolean;
226
+ /**
227
+ * Sprint 11a: Check if a file path is in a documentation generator output directory.
228
+ * Doc generator templates and output contain external links, code examples, etc. that are
229
+ * developer-facing, not child-facing content. Flagging these is a false positive.
230
+ */
231
+ export declare function isDocGeneratorPath(filePath: string): boolean;
157
232
  /**
158
233
  * Check if a file should be ignored based on .haloignore config
159
234
  */