@runhalo/engine 0.4.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 (64) hide show
  1. package/dist/ast-engine.d.ts +60 -0
  2. package/dist/ast-engine.js +653 -0
  3. package/dist/ast-engine.js.map +1 -0
  4. package/dist/context-analyzer.d.ts +209 -0
  5. package/dist/context-analyzer.js +408 -0
  6. package/dist/context-analyzer.js.map +1 -0
  7. package/dist/data-flow-tracer.d.ts +106 -0
  8. package/dist/data-flow-tracer.js +506 -0
  9. package/dist/data-flow-tracer.js.map +1 -0
  10. package/dist/fp-patterns.d.ts +36 -0
  11. package/dist/fp-patterns.js +426 -0
  12. package/dist/fp-patterns.js.map +1 -0
  13. package/dist/frameworks/angular.d.ts +11 -0
  14. package/dist/frameworks/angular.js +41 -0
  15. package/dist/frameworks/angular.js.map +1 -0
  16. package/dist/frameworks/django.d.ts +11 -0
  17. package/dist/frameworks/django.js +57 -0
  18. package/dist/frameworks/django.js.map +1 -0
  19. package/dist/frameworks/index.d.ts +59 -0
  20. package/dist/frameworks/index.js +99 -0
  21. package/dist/frameworks/index.js.map +1 -0
  22. package/dist/frameworks/nextjs.d.ts +11 -0
  23. package/dist/frameworks/nextjs.js +59 -0
  24. package/dist/frameworks/nextjs.js.map +1 -0
  25. package/dist/frameworks/rails.d.ts +11 -0
  26. package/dist/frameworks/rails.js +58 -0
  27. package/dist/frameworks/rails.js.map +1 -0
  28. package/dist/frameworks/react.d.ts +13 -0
  29. package/dist/frameworks/react.js +36 -0
  30. package/dist/frameworks/react.js.map +1 -0
  31. package/dist/frameworks/types.d.ts +29 -0
  32. package/dist/frameworks/types.js +11 -0
  33. package/dist/frameworks/types.js.map +1 -0
  34. package/dist/frameworks/vue.d.ts +9 -0
  35. package/dist/frameworks/vue.js +39 -0
  36. package/dist/frameworks/vue.js.map +1 -0
  37. package/dist/graduation/fp-verdict-logger.d.ts +81 -0
  38. package/dist/graduation/fp-verdict-logger.js +130 -0
  39. package/dist/graduation/fp-verdict-logger.js.map +1 -0
  40. package/dist/graduation/graduation-codifier.d.ts +37 -0
  41. package/dist/graduation/graduation-codifier.js +205 -0
  42. package/dist/graduation/graduation-codifier.js.map +1 -0
  43. package/dist/graduation/graduation-validator.d.ts +73 -0
  44. package/dist/graduation/graduation-validator.js +204 -0
  45. package/dist/graduation/graduation-validator.js.map +1 -0
  46. package/dist/graduation/index.d.ts +71 -0
  47. package/dist/graduation/index.js +105 -0
  48. package/dist/graduation/index.js.map +1 -0
  49. package/dist/graduation/pattern-aggregator.d.ts +77 -0
  50. package/dist/graduation/pattern-aggregator.js +154 -0
  51. package/dist/graduation/pattern-aggregator.js.map +1 -0
  52. package/dist/index.d.ts +99 -0
  53. package/dist/index.js +718 -61
  54. package/dist/index.js.map +1 -1
  55. package/dist/review-board/two-agent-review.d.ts +152 -0
  56. package/dist/review-board/two-agent-review.js +463 -0
  57. package/dist/review-board/two-agent-review.js.map +1 -0
  58. package/dist/scope-analyzer.d.ts +91 -0
  59. package/dist/scope-analyzer.js +300 -0
  60. package/dist/scope-analyzer.js.map +1 -0
  61. package/package.json +9 -2
  62. package/rules/coppa-tier-1.yaml +17 -10
  63. package/rules/rules.json +2094 -99
  64. package/rules/validation-report.json +58 -0
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ /**
3
+ * Graduation Pipeline — Sprint 13a Week 2
4
+ *
5
+ * Four-stage pipeline that transforms AI Review Board FP verdicts
6
+ * into permanent engine heuristics:
7
+ *
8
+ * Stage 1: COLLECT — Log each verdict to structured JSONL
9
+ * Stage 2: AGGREGATE — Compute per-pattern statistics across scans
10
+ * Stage 3: VALIDATE — Check graduation criteria (dismissals, confidence, precision)
11
+ * Stage 4: CODIFY — Generate engine heuristic code for approved patterns
12
+ *
13
+ * Usage:
14
+ * import { GraduationPipeline } from './graduation';
15
+ * const pipeline = new GraduationPipeline({ logDir: './verdict-logs' });
16
+ * pipeline.logVerdict(verdict); // Stage 1
17
+ * const stats = pipeline.aggregate(); // Stage 2
18
+ * const candidates = pipeline.validate(); // Stage 3
19
+ * const code = pipeline.codify(); // Stage 4
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.GraduationPipeline = exports.formatCodegenReport = exports.generateAllCode = exports.generateCode = exports.MVP_GRADUATION_CRITERIA = exports.DEFAULT_GRADUATION_CRITERIA = exports.formatGraduationReport = exports.validateGraduation = exports.formatAggregationReport = exports.aggregateFromDirectory = exports.aggregatePatterns = exports.FPVerdictLogger = void 0;
23
+ var fp_verdict_logger_1 = require("./fp-verdict-logger");
24
+ Object.defineProperty(exports, "FPVerdictLogger", { enumerable: true, get: function () { return fp_verdict_logger_1.FPVerdictLogger; } });
25
+ var pattern_aggregator_1 = require("./pattern-aggregator");
26
+ Object.defineProperty(exports, "aggregatePatterns", { enumerable: true, get: function () { return pattern_aggregator_1.aggregatePatterns; } });
27
+ Object.defineProperty(exports, "aggregateFromDirectory", { enumerable: true, get: function () { return pattern_aggregator_1.aggregateFromDirectory; } });
28
+ Object.defineProperty(exports, "formatAggregationReport", { enumerable: true, get: function () { return pattern_aggregator_1.formatAggregationReport; } });
29
+ var graduation_validator_1 = require("./graduation-validator");
30
+ Object.defineProperty(exports, "validateGraduation", { enumerable: true, get: function () { return graduation_validator_1.validateGraduation; } });
31
+ Object.defineProperty(exports, "formatGraduationReport", { enumerable: true, get: function () { return graduation_validator_1.formatGraduationReport; } });
32
+ Object.defineProperty(exports, "DEFAULT_GRADUATION_CRITERIA", { enumerable: true, get: function () { return graduation_validator_1.DEFAULT_GRADUATION_CRITERIA; } });
33
+ Object.defineProperty(exports, "MVP_GRADUATION_CRITERIA", { enumerable: true, get: function () { return graduation_validator_1.MVP_GRADUATION_CRITERIA; } });
34
+ var graduation_codifier_1 = require("./graduation-codifier");
35
+ Object.defineProperty(exports, "generateCode", { enumerable: true, get: function () { return graduation_codifier_1.generateCode; } });
36
+ Object.defineProperty(exports, "generateAllCode", { enumerable: true, get: function () { return graduation_codifier_1.generateAllCode; } });
37
+ Object.defineProperty(exports, "formatCodegenReport", { enumerable: true, get: function () { return graduation_codifier_1.formatCodegenReport; } });
38
+ const fp_verdict_logger_2 = require("./fp-verdict-logger");
39
+ const pattern_aggregator_2 = require("./pattern-aggregator");
40
+ const graduation_validator_2 = require("./graduation-validator");
41
+ const graduation_codifier_2 = require("./graduation-codifier");
42
+ class GraduationPipeline {
43
+ constructor(config) {
44
+ this.logger = null;
45
+ this.config = config;
46
+ }
47
+ // ─── Stage 1: Collect ──────────────────────────────────────────────
48
+ /**
49
+ * Initialize logger for a new scan.
50
+ */
51
+ startScan(scanId, promptVersion) {
52
+ this.logger = new fp_verdict_logger_2.FPVerdictLogger({
53
+ logDir: this.config.logDir,
54
+ scanId,
55
+ promptVersion,
56
+ });
57
+ return this.logger;
58
+ }
59
+ /**
60
+ * Log a single verdict (convenience method).
61
+ */
62
+ logVerdict(entry) {
63
+ if (!this.logger) {
64
+ throw new Error('Call startScan() before logging verdicts');
65
+ }
66
+ this.logger.log(entry);
67
+ }
68
+ // ─── Stage 2: Aggregate ────────────────────────────────────────────
69
+ /**
70
+ * Aggregate all verdict logs in the log directory.
71
+ */
72
+ aggregate() {
73
+ const entries = fp_verdict_logger_2.FPVerdictLogger.readAllLogs(this.config.logDir);
74
+ return (0, pattern_aggregator_2.aggregatePatterns)(entries, this.config.knownPatternIds);
75
+ }
76
+ // ─── Stage 3: Validate ─────────────────────────────────────────────
77
+ /**
78
+ * Validate aggregated patterns against graduation criteria.
79
+ */
80
+ validate(aggregation) {
81
+ const agg = aggregation || this.aggregate();
82
+ return (0, graduation_validator_2.validateGraduation)(agg, this.config.criteria || graduation_validator_2.MVP_GRADUATION_CRITERIA, this.config.groundTruthPrecision);
83
+ }
84
+ // ─── Stage 4: Codify ───────────────────────────────────────────────
85
+ /**
86
+ * Generate code for all eligible graduation candidates.
87
+ */
88
+ codify(report) {
89
+ const rep = report || this.validate();
90
+ return (0, graduation_codifier_2.generateAllCode)(rep.eligible);
91
+ }
92
+ // ─── Full Pipeline Run ─────────────────────────────────────────────
93
+ /**
94
+ * Run the full pipeline (stages 2-4) on existing log data.
95
+ * Stage 1 (logging) happens during scans, not here.
96
+ */
97
+ runPipeline() {
98
+ const aggregation = this.aggregate();
99
+ const graduation = this.validate(aggregation);
100
+ const codegen = this.codify(graduation);
101
+ return { aggregation, graduation, codegen };
102
+ }
103
+ }
104
+ exports.GraduationPipeline = GraduationPipeline;
105
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/graduation/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AAEH,yDAAuE;AAA9D,oHAAA,eAAe,OAAA;AACxB,2DAM8B;AAL5B,uHAAA,iBAAiB,OAAA;AACjB,4HAAA,sBAAsB,OAAA;AACtB,6HAAA,uBAAuB,OAAA;AAIzB,+DAQgC;AAP9B,0HAAA,kBAAkB,OAAA;AAClB,8HAAA,sBAAsB,OAAA;AACtB,mIAAA,2BAA2B,OAAA;AAC3B,+HAAA,uBAAuB,OAAA;AAKzB,6DAK+B;AAJ7B,mHAAA,YAAY,OAAA;AACZ,sHAAA,eAAe,OAAA;AACf,0HAAA,mBAAmB,OAAA;AAKrB,2DAAuE;AACvE,6DAA4E;AAC5E,iEAKgC;AAChC,+DAAuE;AAevE,MAAa,kBAAkB;IAI7B,YAAY,MAAgC;QAFpC,WAAM,GAA2B,IAAI,CAAC;QAG5C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,sEAAsE;IAEtE;;OAEG;IACH,SAAS,CAAC,MAAc,EAAE,aAAsB;QAC9C,IAAI,CAAC,MAAM,GAAG,IAAI,mCAAe,CAAC;YAChC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,MAAM;YACN,aAAa;SACd,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,KAAsE;QAC/E,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,sEAAsE;IAEtE;;OAEG;IACH,SAAS;QACP,MAAM,OAAO,GAAG,mCAAe,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChE,OAAO,IAAA,sCAAiB,EAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACjE,CAAC;IAED,sEAAsE;IAEtE;;OAEG;IACH,QAAQ,CAAC,WAA+B;QACtC,MAAM,GAAG,GAAG,WAAW,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5C,OAAO,IAAA,yCAAkB,EACvB,GAAG,EACH,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,8CAAuB,EAC/C,IAAI,CAAC,MAAM,CAAC,oBAAoB,CACjC,CAAC;IACJ,CAAC;IAED,sEAAsE;IAEtE;;OAEG;IACH,MAAM,CAAC,MAAyB;QAC9B,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtC,OAAO,IAAA,qCAAe,EAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,sEAAsE;IAEtE;;;OAGG;IACH,WAAW;QAKT,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAExC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IAC9C,CAAC;CACF;AAnFD,gDAmFC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Sprint 13a Week 2: Pattern Aggregator
3
+ *
4
+ * Stage 2 of the Graduation Pipeline.
5
+ * Reads verdict logs (JSONL) and aggregates FP patterns across scans.
6
+ * Produces statistics per fpPatternId: total dismissals, avg confidence,
7
+ * false confirmation rate, affected rules and file paths.
8
+ *
9
+ * This is the bridge between raw verdict data and graduation decisions.
10
+ */
11
+ import { VerdictLogEntry } from './fp-verdict-logger';
12
+ export interface PatternStats {
13
+ /** The FP pattern ID (from fp-patterns.ts library) */
14
+ fpPatternId: string;
15
+ /** Human-readable pattern name */
16
+ fpReason: string;
17
+ /** Total times this pattern was used to dismiss a violation */
18
+ totalDismissals: number;
19
+ /** Average confidence of dismissals (1-10) */
20
+ avgConfidence: number;
21
+ /** Min confidence seen */
22
+ minConfidence: number;
23
+ /** Max confidence seen */
24
+ maxConfidence: number;
25
+ /** Number of times this pattern's verdict was later contradicted (false dismissal) */
26
+ falseConfirmations: number;
27
+ /** Rules this pattern applies to */
28
+ affectedRules: string[];
29
+ /** Sample file paths (up to 5) */
30
+ samplePaths: string[];
31
+ /** Number of unique scans this pattern appeared in */
32
+ uniqueScans: number;
33
+ /** First seen timestamp */
34
+ firstSeen: string;
35
+ /** Last seen timestamp */
36
+ lastSeen: string;
37
+ /** Whether this pattern is in the static FP pattern library */
38
+ inLibrary: boolean;
39
+ }
40
+ export interface AggregationResult {
41
+ /** When the aggregation was run */
42
+ aggregatedAt: string;
43
+ /** Total verdict entries processed */
44
+ totalEntries: number;
45
+ /** Total dismissed entries */
46
+ totalDismissed: number;
47
+ /** Total confirmed/escalated entries */
48
+ totalConfirmed: number;
49
+ /** Number of unique scans */
50
+ uniqueScans: number;
51
+ /** Per-pattern statistics */
52
+ patterns: PatternStats[];
53
+ /** Patterns without fpPatternId (novel FP patterns from AI) */
54
+ unclassifiedDismissals: number;
55
+ /** Rules with highest FP rates */
56
+ highFPRules: Array<{
57
+ ruleId: string;
58
+ total: number;
59
+ dismissed: number;
60
+ fpRate: number;
61
+ }>;
62
+ }
63
+ /**
64
+ * Aggregate verdict log entries into per-pattern statistics.
65
+ *
66
+ * @param entries - All verdict log entries to aggregate
67
+ * @param knownPatternIds - Set of pattern IDs from the static FP library (for inLibrary flag)
68
+ */
69
+ export declare function aggregatePatterns(entries: VerdictLogEntry[], knownPatternIds?: Set<string>): AggregationResult;
70
+ /**
71
+ * Convenience: aggregate from a log directory.
72
+ */
73
+ export declare function aggregateFromDirectory(logDir: string, knownPatternIds?: Set<string>): AggregationResult;
74
+ /**
75
+ * Format aggregation result as a readable report.
76
+ */
77
+ export declare function formatAggregationReport(result: AggregationResult): string;
@@ -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
@@ -7,7 +7,10 @@
7
7
  * Sprint 1 Fixes: Added tree-sitter for AST analysis, YAML rule loading
8
8
  */
9
9
  import Parser from 'tree-sitter';
10
+ import { ConfidenceResult, ConfidenceSignals, ConfidenceInterpretation, ViolationInput } from './context-analyzer';
11
+ export type { ConfidenceResult, ConfidenceSignals, ConfidenceInterpretation, ViolationInput };
10
12
  export type Severity = 'critical' | 'high' | 'medium' | 'low';
13
+ export type ASTVerdict = 'confirmed' | 'suppressed' | 'regex_only';
11
14
  export type Fixability = 'auto' | 'guided' | 'flag-only';
12
15
  export interface RemediationSpec {
13
16
  fixability: Fixability;
@@ -34,6 +37,40 @@ export interface Violation {
34
37
  matchType?: 'regex' | 'ast' | 'hybrid';
35
38
  fixability?: Fixability;
36
39
  remediation?: RemediationSpec;
40
+ /** AST analysis verdict: confirmed, suppressed, or regex_only */
41
+ astVerdict?: ASTVerdict;
42
+ /** AST analysis confidence: 0.0 to 1.0 */
43
+ astConfidence?: number;
44
+ /** Reason for AST verdict */
45
+ astReason?: string;
46
+ /** Whether this violation was suppressed by framework profile */
47
+ frameworkSuppressed?: boolean;
48
+ /** ContextAnalyzer confidence score (0.0-1.0) */
49
+ confidence?: number;
50
+ /** ContextAnalyzer interpretation */
51
+ confidenceInterpretation?: ConfidenceInterpretation;
52
+ /** ContextAnalyzer reason string */
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
+ };
37
74
  }
38
75
  export interface Rule {
39
76
  id: string;
@@ -45,7 +82,51 @@ export interface Rule {
45
82
  penalty: string;
46
83
  languages: string[];
47
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;
48
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;
49
130
  export interface SuppressionConfig {
50
131
  enabled: boolean;
51
132
  commentPattern: string;
@@ -137,6 +218,17 @@ export interface IgnoreConfig {
137
218
  * src/auth.ts:coppa-auth-001 — suppress rule in specific file
138
219
  */
139
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;
140
232
  /**
141
233
  * Check if a file should be ignored based on .haloignore config
142
234
  */
@@ -161,8 +253,13 @@ export interface EngineConfig {
161
253
  ethical?: boolean;
162
254
  aiAudit?: boolean;
163
255
  sectorAuSbd?: boolean;
256
+ sectorAuOsa?: boolean;
164
257
  packs?: string[];
165
258
  loadedRules?: Rule[];
259
+ framework?: string;
260
+ astAnalysis?: boolean;
261
+ historicalFPRates?: Record<string, number>;
262
+ suppressionRates?: Record<string, number>;
166
263
  }
167
264
  export interface ScanResult {
168
265
  filePath: string;
@@ -176,6 +273,8 @@ export declare class HaloEngine {
176
273
  private config;
177
274
  private rules;
178
275
  private treeSitter;
276
+ private astEngine;
277
+ private contextAnalyzer;
179
278
  constructor(config?: EngineConfig);
180
279
  /**
181
280
  * Load rules from the bundled rules.json file, filtered by pack IDs.