tryassay 0.29.0 → 0.30.1

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 (79) hide show
  1. package/dist/cli.js +10 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/generate.js +1 -0
  4. package/dist/commands/generate.js.map +1 -1
  5. package/dist/commands/harvest.d.ts +9 -0
  6. package/dist/commands/harvest.js +76 -0
  7. package/dist/commands/harvest.js.map +1 -0
  8. package/dist/lib/__tests__/learned-rules.test.d.ts +1 -0
  9. package/dist/lib/__tests__/learned-rules.test.js +260 -0
  10. package/dist/lib/__tests__/learned-rules.test.js.map +1 -0
  11. package/dist/lib/__tests__/pr-harvester-types.test.d.ts +1 -0
  12. package/dist/lib/__tests__/pr-harvester-types.test.js +43 -0
  13. package/dist/lib/__tests__/pr-harvester-types.test.js.map +1 -0
  14. package/dist/lib/__tests__/pr-harvester.test.d.ts +1 -0
  15. package/dist/lib/__tests__/pr-harvester.test.js +341 -0
  16. package/dist/lib/__tests__/pr-harvester.test.js.map +1 -0
  17. package/dist/lib/__tests__/rule-harvester.test.d.ts +1 -0
  18. package/dist/lib/__tests__/rule-harvester.test.js +526 -0
  19. package/dist/lib/__tests__/rule-harvester.test.js.map +1 -0
  20. package/dist/lib/learned-rules/category-map.d.ts +28 -0
  21. package/dist/lib/learned-rules/category-map.js +110 -0
  22. package/dist/lib/learned-rules/category-map.js.map +1 -0
  23. package/dist/lib/learned-rules/index.d.ts +105 -0
  24. package/dist/lib/learned-rules/index.js +198 -0
  25. package/dist/lib/learned-rules/index.js.map +1 -0
  26. package/dist/lib/learned-rules/learned-catalog.d.ts +62 -0
  27. package/dist/lib/learned-rules/learned-catalog.js +161 -0
  28. package/dist/lib/learned-rules/learned-catalog.js.map +1 -0
  29. package/dist/lib/learned-rules/pattern-extractor.d.ts +25 -0
  30. package/dist/lib/learned-rules/pattern-extractor.js +351 -0
  31. package/dist/lib/learned-rules/pattern-extractor.js.map +1 -0
  32. package/dist/lib/learned-rules/rule-codifier.d.ts +41 -0
  33. package/dist/lib/learned-rules/rule-codifier.js +138 -0
  34. package/dist/lib/learned-rules/rule-codifier.js.map +1 -0
  35. package/dist/lib/learned-rules/starter-catalog.d.ts +16 -0
  36. package/dist/lib/learned-rules/starter-catalog.js +402 -0
  37. package/dist/lib/learned-rules/starter-catalog.js.map +1 -0
  38. package/dist/lib/learned-rules/types.d.ts +196 -0
  39. package/dist/lib/learned-rules/types.js +9 -0
  40. package/dist/lib/learned-rules/types.js.map +1 -0
  41. package/dist/lib/learned-rules/validation-harness.d.ts +26 -0
  42. package/dist/lib/learned-rules/validation-harness.js +260 -0
  43. package/dist/lib/learned-rules/validation-harness.js.map +1 -0
  44. package/dist/lib/rule-harvester/diff-parser.d.ts +9 -0
  45. package/dist/lib/rule-harvester/diff-parser.js +77 -0
  46. package/dist/lib/rule-harvester/diff-parser.js.map +1 -0
  47. package/dist/lib/rule-harvester/file-selector.d.ts +10 -0
  48. package/dist/lib/rule-harvester/file-selector.js +59 -0
  49. package/dist/lib/rule-harvester/file-selector.js.map +1 -0
  50. package/dist/lib/rule-harvester/ground-truth.d.ts +19 -0
  51. package/dist/lib/rule-harvester/ground-truth.js +156 -0
  52. package/dist/lib/rule-harvester/ground-truth.js.map +1 -0
  53. package/dist/lib/rule-harvester/harvest.d.ts +26 -0
  54. package/dist/lib/rule-harvester/harvest.js +307 -0
  55. package/dist/lib/rule-harvester/harvest.js.map +1 -0
  56. package/dist/lib/rule-harvester/pr-discovery.d.ts +49 -0
  57. package/dist/lib/rule-harvester/pr-discovery.js +168 -0
  58. package/dist/lib/rule-harvester/pr-discovery.js.map +1 -0
  59. package/dist/lib/rule-harvester/pr-harvest.d.ts +53 -0
  60. package/dist/lib/rule-harvester/pr-harvest.js +326 -0
  61. package/dist/lib/rule-harvester/pr-harvest.js.map +1 -0
  62. package/dist/lib/rule-harvester/progress.d.ts +13 -0
  63. package/dist/lib/rule-harvester/progress.js +50 -0
  64. package/dist/lib/rule-harvester/progress.js.map +1 -0
  65. package/dist/lib/rule-harvester/reporter.d.ts +35 -0
  66. package/dist/lib/rule-harvester/reporter.js +46 -0
  67. package/dist/lib/rule-harvester/reporter.js.map +1 -0
  68. package/dist/lib/rule-harvester/rule-generalizer.d.ts +25 -0
  69. package/dist/lib/rule-harvester/rule-generalizer.js +135 -0
  70. package/dist/lib/rule-harvester/rule-generalizer.js.map +1 -0
  71. package/dist/lib/rule-harvester/scanner.d.ts +20 -0
  72. package/dist/lib/rule-harvester/scanner.js +37 -0
  73. package/dist/lib/rule-harvester/scanner.js.map +1 -0
  74. package/dist/sdk/forward-verify.d.ts +3 -1
  75. package/dist/sdk/forward-verify.js +68 -5
  76. package/dist/sdk/forward-verify.js.map +1 -1
  77. package/dist/sdk/index.d.ts +1 -1
  78. package/dist/sdk/types.d.ts +21 -0
  79. package/package.json +1 -1
@@ -0,0 +1,526 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { confirmByGrep, parseConfirmation } from '../rule-harvester/ground-truth.js';
3
+ import { buildScanResult } from '../rule-harvester/scanner.js';
4
+ import { mkdtemp, rm, readFile } from 'node:fs/promises';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ import { selectFiles } from '../rule-harvester/file-selector.js';
8
+ import { loadProgress, saveProgress, getFileState, setFileState, getRepoStatus, initRepo, } from '../rule-harvester/progress.js';
9
+ import { createRunReport, saveRunReport } from '../rule-harvester/reporter.js';
10
+ describe('selectFiles', () => {
11
+ it('prioritizes API route files', () => {
12
+ const candidates = [
13
+ { path: 'src/lib/utils.ts', lineCount: 50 },
14
+ { path: 'src/api/users.ts', lineCount: 50 },
15
+ { path: 'src/routes/auth.ts', lineCount: 50 },
16
+ ];
17
+ const result = selectFiles(candidates);
18
+ expect(result[0].priority).toBe(1);
19
+ expect(result[0].path).toMatch(/\/(api|routes)\//);
20
+ });
21
+ it('skips test files', () => {
22
+ const candidates = [
23
+ { path: 'src/lib/utils.test.ts', lineCount: 50 },
24
+ { path: 'src/lib/utils.spec.ts', lineCount: 50 },
25
+ { path: 'src/__tests__/foo.ts', lineCount: 50 },
26
+ { path: 'src/lib/utils.ts', lineCount: 50 },
27
+ ];
28
+ const result = selectFiles(candidates);
29
+ expect(result).toHaveLength(1);
30
+ expect(result[0].path).toBe('src/lib/utils.ts');
31
+ });
32
+ it('skips .d.ts files', () => {
33
+ const candidates = [
34
+ { path: 'src/types/foo.d.ts', lineCount: 50 },
35
+ { path: 'src/lib/utils.ts', lineCount: 50 },
36
+ ];
37
+ const result = selectFiles(candidates);
38
+ expect(result).toHaveLength(1);
39
+ expect(result[0].path).toBe('src/lib/utils.ts');
40
+ });
41
+ it('skips files over 800 lines', () => {
42
+ const candidates = [
43
+ { path: 'src/api/huge.ts', lineCount: 801 },
44
+ { path: 'src/api/normal.ts', lineCount: 800 },
45
+ { path: 'src/api/small.ts', lineCount: 100 },
46
+ ];
47
+ const result = selectFiles(candidates);
48
+ const paths = result.map((f) => f.path);
49
+ expect(paths).not.toContain('src/api/huge.ts');
50
+ expect(paths).toContain('src/api/normal.ts');
51
+ expect(paths).toContain('src/api/small.ts');
52
+ });
53
+ it('limits to 20 files', () => {
54
+ const candidates = Array.from({ length: 50 }, (_, i) => ({
55
+ path: `src/lib/file${i}.ts`,
56
+ lineCount: 10,
57
+ }));
58
+ const result = selectFiles(candidates);
59
+ expect(result).toHaveLength(20);
60
+ });
61
+ it('assigns priority reasons', () => {
62
+ const candidates = [
63
+ { path: 'src/api/users.ts', lineCount: 50 },
64
+ { path: 'src/auth/login.ts', lineCount: 50 },
65
+ { path: 'src/db/schema.ts', lineCount: 50 },
66
+ { path: 'src/services/email.ts', lineCount: 50 },
67
+ { path: 'src/lib/helpers.ts', lineCount: 50 },
68
+ { path: 'src/components/button.tsx', lineCount: 50 },
69
+ { path: 'src/misc/other.js', lineCount: 50 },
70
+ ];
71
+ const result = selectFiles(candidates);
72
+ const byPath = Object.fromEntries(result.map((f) => [f.path, f]));
73
+ expect(byPath['src/api/users.ts'].reason).toMatch(/api|route|middleware/i);
74
+ expect(byPath['src/auth/login.ts'].reason).toMatch(/auth/i);
75
+ expect(byPath['src/db/schema.ts'].reason).toMatch(/database|model/i);
76
+ expect(byPath['src/services/email.ts'].reason).toMatch(/service|handler|controller/i);
77
+ expect(byPath['src/lib/helpers.ts'].reason).toMatch(/library|utility|helper/i);
78
+ expect(byPath['src/components/button.tsx'].reason).toMatch(/react/i);
79
+ expect(byPath['src/misc/other.js'].reason).toMatch(/other/i);
80
+ });
81
+ it('skips config and generated files', () => {
82
+ const candidates = [
83
+ { path: 'tailwind.config.ts', lineCount: 20 },
84
+ { path: 'next.config.js', lineCount: 20 },
85
+ { path: 'vite.config.ts', lineCount: 20 },
86
+ { path: 'jest.config.js', lineCount: 20 },
87
+ { path: 'vitest.config.ts', lineCount: 20 },
88
+ { path: 'eslint.config.js', lineCount: 20 },
89
+ { path: 'prettier.config.js', lineCount: 20 },
90
+ { path: 'tsconfig.json', lineCount: 20 },
91
+ { path: 'package.json', lineCount: 20 },
92
+ { path: 'src/generated/schema.ts', lineCount: 20 },
93
+ { path: 'src/lib/real.ts', lineCount: 20 },
94
+ ];
95
+ const result = selectFiles(candidates);
96
+ expect(result).toHaveLength(1);
97
+ expect(result[0].path).toBe('src/lib/real.ts');
98
+ });
99
+ it('prioritizes auth-related paths at priority 2', () => {
100
+ const candidates = [
101
+ { path: 'src/auth/session.ts', lineCount: 50 },
102
+ { path: 'src/db/users.ts', lineCount: 50 },
103
+ ];
104
+ const result = selectFiles(candidates);
105
+ expect(result[0].path).toBe('src/auth/session.ts');
106
+ expect(result[0].priority).toBe(2);
107
+ expect(result[1].priority).toBe(3);
108
+ });
109
+ it('prioritizes database paths at priority 3', () => {
110
+ const candidates = [
111
+ { path: 'src/services/payment.ts', lineCount: 50 },
112
+ { path: 'src/models/user.ts', lineCount: 50 },
113
+ { path: 'src/database/migrate.ts', lineCount: 50 },
114
+ { path: 'src/entities/order.ts', lineCount: 50 },
115
+ ];
116
+ const result = selectFiles(candidates);
117
+ const dbFiles = result.filter((f) => f.priority === 3);
118
+ expect(dbFiles.length).toBeGreaterThan(0);
119
+ const serviceFiles = result.filter((f) => f.priority === 4);
120
+ expect(serviceFiles.length).toBeGreaterThan(0);
121
+ // All db files should rank above service files
122
+ const minDbPriority = Math.min(...dbFiles.map((f) => f.priority));
123
+ const maxServicePriority = Math.max(...serviceFiles.map((f) => f.priority));
124
+ expect(minDbPriority).toBeLessThan(maxServicePriority);
125
+ });
126
+ });
127
+ describe('Progress Tracker', () => {
128
+ it('returns empty progress when no file exists', async () => {
129
+ const dir = await mkdtemp(join(tmpdir(), 'assay-progress-test-'));
130
+ try {
131
+ const progress = await loadProgress(dir);
132
+ expect(progress).toEqual({});
133
+ }
134
+ finally {
135
+ await rm(dir, { recursive: true });
136
+ }
137
+ });
138
+ it('saves and loads progress roundtrip', async () => {
139
+ const dir = await mkdtemp(join(tmpdir(), 'assay-progress-test-'));
140
+ try {
141
+ const progress = {
142
+ 'owner/repo': {
143
+ status: 'in_progress',
144
+ startedAt: '2026-01-01T00:00:00.000Z',
145
+ files: {
146
+ 'src/lib/foo.ts': 'scanned',
147
+ 'src/lib/bar.ts': 'learned',
148
+ },
149
+ },
150
+ };
151
+ await saveProgress(dir, progress);
152
+ const loaded = await loadProgress(dir);
153
+ expect(loaded).toEqual(progress);
154
+ }
155
+ finally {
156
+ await rm(dir, { recursive: true });
157
+ }
158
+ });
159
+ it('gets file state when present', () => {
160
+ const progress = {
161
+ 'owner/repo': {
162
+ status: 'in_progress',
163
+ startedAt: '2026-01-01T00:00:00.000Z',
164
+ files: { 'src/lib/foo.ts': 'scanned' },
165
+ },
166
+ };
167
+ expect(getFileState(progress, 'owner/repo', 'src/lib/foo.ts')).toBe('scanned');
168
+ });
169
+ it('returns pending when file not found', () => {
170
+ const progress = {};
171
+ expect(getFileState(progress, 'owner/repo', 'src/lib/missing.ts')).toBe('pending');
172
+ });
173
+ it('sets file state immutably (original unchanged)', () => {
174
+ const original = {};
175
+ const updated = setFileState(original, 'owner/repo', 'src/lib/foo.ts', 'scanned');
176
+ expect(original).toEqual({});
177
+ expect(updated['owner/repo'].files['src/lib/foo.ts']).toBe('scanned');
178
+ });
179
+ it('auto-creates repo entry on first setFileState', () => {
180
+ const progress = {};
181
+ const updated = setFileState(progress, 'owner/repo', 'src/lib/foo.ts', 'scanned');
182
+ expect(updated['owner/repo']).toBeDefined();
183
+ expect(updated['owner/repo'].startedAt).toBeTruthy();
184
+ expect(updated['owner/repo'].status).toBe('in_progress');
185
+ });
186
+ it('computes repo status: all learned = complete', () => {
187
+ expect(getRepoStatus({ 'a.ts': 'learned', 'b.ts': 'learned' })).toBe('complete');
188
+ });
189
+ it('computes repo status: mixed = in_progress', () => {
190
+ expect(getRepoStatus({ 'a.ts': 'learned', 'b.ts': 'scanned' })).toBe('in_progress');
191
+ });
192
+ it('computes repo status: all pending = pending', () => {
193
+ expect(getRepoStatus({ 'a.ts': 'pending', 'b.ts': 'pending' })).toBe('pending');
194
+ });
195
+ it('computes repo status: empty = pending', () => {
196
+ expect(getRepoStatus({})).toBe('pending');
197
+ });
198
+ it('computes repo status: confirmed + learned = in_progress', () => {
199
+ expect(getRepoStatus({ 'a.ts': 'confirmed', 'b.ts': 'learned' })).toBe('in_progress');
200
+ });
201
+ it('computes repo status: all confirmed = in_progress', () => {
202
+ expect(getRepoStatus({ 'a.ts': 'confirmed', 'b.ts': 'confirmed' })).toBe('in_progress');
203
+ });
204
+ it('initRepo creates entry only if absent', () => {
205
+ const empty = {};
206
+ const created = initRepo(empty, 'owner/repo');
207
+ expect(created['owner/repo']).toBeDefined();
208
+ expect(created['owner/repo'].status).toBe('pending');
209
+ expect(created['owner/repo'].files).toEqual({});
210
+ // Does not overwrite existing
211
+ const existing = {
212
+ 'owner/repo': {
213
+ status: 'in_progress',
214
+ startedAt: '2026-01-01T00:00:00.000Z',
215
+ files: { 'a.ts': 'scanned' },
216
+ },
217
+ };
218
+ const unchanged = initRepo(existing, 'owner/repo');
219
+ expect(unchanged).toBe(existing); // same reference
220
+ });
221
+ });
222
+ describe('Reporter', () => {
223
+ const catalogSize = { total: 10, promoted: 7, rejected: 3 };
224
+ const makeFileResult = (overrides = {}) => ({
225
+ repo: 'owner/repo',
226
+ filePath: 'src/lib/foo.ts',
227
+ claimsExtracted: 5,
228
+ confirmed: 2,
229
+ rulesLearned: 1,
230
+ rulesRejected: 0,
231
+ rulesDuplicate: 0,
232
+ unmatchedCategories: [],
233
+ durationMs: 3000,
234
+ ...overrides,
235
+ });
236
+ it('aggregates file results into a run report', () => {
237
+ const fileResults = [
238
+ makeFileResult({ filePath: 'src/lib/foo.ts', claimsExtracted: 4, confirmed: 2, rulesLearned: 1, rulesRejected: 0, rulesDuplicate: 0, durationMs: 2000 }),
239
+ makeFileResult({ filePath: 'src/lib/bar.ts', claimsExtracted: 6, confirmed: 3, rulesLearned: 2, rulesRejected: 1, rulesDuplicate: 1, durationMs: 4000 }),
240
+ ];
241
+ const report = createRunReport(fileResults, 'claude-3-5-sonnet', catalogSize);
242
+ expect(report.reposScanned).toBe(1);
243
+ expect(report.filesScanned).toBe(2);
244
+ expect(report.claimsExtracted).toBe(10);
245
+ expect(report.findingsConfirmed).toBe(5);
246
+ expect(report.rulesLearned).toBe(3);
247
+ expect(report.rulesRejected).toBe(1);
248
+ expect(report.rulesDuplicate).toBe(1);
249
+ expect(report.model).toBe('claude-3-5-sonnet');
250
+ expect(report.catalogSize).toEqual(catalogSize);
251
+ expect(report.durationMinutes).toBeCloseTo((2000 + 4000) / 60_000);
252
+ });
253
+ it('saves run report to a timestamped JSON file', async () => {
254
+ const dir = await mkdtemp(join(tmpdir(), 'assay-reporter-test-'));
255
+ try {
256
+ const report = createRunReport([makeFileResult()], 'claude-3-5-sonnet', catalogSize);
257
+ const filePath = await saveRunReport(dir, report);
258
+ // File should exist and be parseable JSON
259
+ const raw = await readFile(filePath, 'utf-8');
260
+ const parsed = JSON.parse(raw);
261
+ expect(parsed.model).toBe('claude-3-5-sonnet');
262
+ expect(parsed.filesScanned).toBe(1);
263
+ expect(parsed.timestamp).toBe(report.timestamp);
264
+ // Filename should not contain : or .
265
+ const filename = filePath.split('/').pop();
266
+ expect(filename).not.toContain(':');
267
+ expect(filename).toMatch(/\.json$/);
268
+ }
269
+ finally {
270
+ await rm(dir, { recursive: true });
271
+ }
272
+ });
273
+ it('aggregates unmatchedCategories counts across multiple files', () => {
274
+ const fileResults = [
275
+ makeFileResult({ unmatchedCategories: ['security', 'performance'] }),
276
+ makeFileResult({ unmatchedCategories: ['security', 'correctness'] }),
277
+ ];
278
+ const report = createRunReport(fileResults, 'claude-3-5-sonnet', catalogSize);
279
+ expect(report.unmatchedCategories['security']).toBe(2);
280
+ expect(report.unmatchedCategories['performance']).toBe(1);
281
+ expect(report.unmatchedCategories['correctness']).toBe(1);
282
+ });
283
+ it('handles empty file results gracefully', () => {
284
+ const report = createRunReport([], 'claude-3-5-sonnet', catalogSize);
285
+ expect(report.reposScanned).toBe(0);
286
+ expect(report.filesScanned).toBe(0);
287
+ expect(report.claimsExtracted).toBe(0);
288
+ expect(report.findingsConfirmed).toBe(0);
289
+ expect(report.rulesLearned).toBe(0);
290
+ expect(report.rulesRejected).toBe(0);
291
+ expect(report.rulesDuplicate).toBe(0);
292
+ expect(report.unmatchedCategories).toEqual({});
293
+ expect(report.durationMinutes).toBe(0);
294
+ });
295
+ });
296
+ describe('Ground Truth Validator', () => {
297
+ const makeClaim = (overrides = {}) => ({
298
+ claimId: 'claim-001',
299
+ category: 'error-handling',
300
+ description: 'Missing try/catch around async call',
301
+ verdict: 'FAIL',
302
+ ...overrides,
303
+ });
304
+ it('confirms missing error handling (await without try/catch)', () => {
305
+ const code = `
306
+ async function fetchData() {
307
+ const result = await fetch('https://example.com/api');
308
+ return result.json();
309
+ }
310
+ `;
311
+ const claim = makeClaim();
312
+ const result = confirmByGrep(code, claim);
313
+ expect(result.confirmed).toBe(true);
314
+ expect(result.method).toBe('grep');
315
+ expect(result.evidence).toMatch(/await without try\/catch/);
316
+ });
317
+ it('rejects error handling claim when try/catch exists', () => {
318
+ const code = `
319
+ async function fetchData() {
320
+ try {
321
+ const result = await fetch('https://example.com/api');
322
+ return result.json();
323
+ } catch (err) {
324
+ console.error(err);
325
+ }
326
+ }
327
+ `;
328
+ const claim = makeClaim();
329
+ const result = confirmByGrep(code, claim);
330
+ expect(result.confirmed).toBe(false);
331
+ expect(result.method).toBe('grep');
332
+ });
333
+ it('confirms SQL injection (template literal with ${})', () => {
334
+ const code = `
335
+ async function getUser(id: string) {
336
+ const query = \`SELECT * FROM users WHERE id = \${id}\`;
337
+ return db.query(query);
338
+ }
339
+ `;
340
+ const claim = makeClaim({
341
+ claimId: 'claim-002',
342
+ category: 'security',
343
+ description: 'SQL injection via template literal query construction',
344
+ verdict: 'FAIL',
345
+ });
346
+ const result = confirmByGrep(code, claim);
347
+ expect(result.confirmed).toBe(true);
348
+ expect(result.method).toBe('grep');
349
+ expect(result.evidence).toMatch(/SQL template literal/);
350
+ });
351
+ it('confirms missing null check (nested access without ?.)', () => {
352
+ const code = `
353
+ function getCity(user: any) {
354
+ return user.address.city.name;
355
+ }
356
+ `;
357
+ const claim = makeClaim({
358
+ claimId: 'claim-003',
359
+ category: 'edge-case',
360
+ description: 'Missing null check on nested property access',
361
+ verdict: 'FAIL',
362
+ });
363
+ const result = confirmByGrep(code, claim);
364
+ expect(result.confirmed).toBe(true);
365
+ expect(result.method).toBe('grep');
366
+ expect(result.evidence).toMatch(/optional chaining/i);
367
+ });
368
+ it('returns not-confirmed for unknown categories', () => {
369
+ const code = `const x = 42;`;
370
+ const claim = makeClaim({
371
+ claimId: 'claim-004',
372
+ category: 'performance',
373
+ description: 'Inefficient algorithm in hot path',
374
+ verdict: 'FAIL',
375
+ });
376
+ const result = confirmByGrep(code, claim);
377
+ expect(result.confirmed).toBe(false);
378
+ expect(result.method).toBe('grep');
379
+ expect(result.evidence).toMatch(/No grep strategy for category "performance"/);
380
+ });
381
+ it('confirms hardcoded secret pattern', () => {
382
+ const code = `
383
+ const API_KEY = "sk-abc123def456ghi789jkl";
384
+ const client = new Client(API_KEY);
385
+ `;
386
+ const claim = makeClaim({
387
+ claimId: 'claim-005',
388
+ category: 'hardcoded secret',
389
+ description: 'Hardcoded API key in source code',
390
+ verdict: 'FAIL',
391
+ });
392
+ const result = confirmByGrep(code, claim);
393
+ expect(result.confirmed).toBe(true);
394
+ expect(result.method).toBe('grep');
395
+ expect(result.evidence).toMatch(/hardcoded secret/i);
396
+ });
397
+ it('rejects hardcoded secret when no pattern match', () => {
398
+ const code = `
399
+ const apiKey = process.env.API_KEY;
400
+ const client = new Client(apiKey);
401
+ `;
402
+ const claim = makeClaim({
403
+ claimId: 'claim-006',
404
+ category: 'hardcoded secret',
405
+ description: 'Hardcoded API key in source code',
406
+ verdict: 'FAIL',
407
+ });
408
+ const result = confirmByGrep(code, claim);
409
+ expect(result.confirmed).toBe(false);
410
+ expect(result.method).toBe('grep');
411
+ });
412
+ it('uses compiler method when tsc reports error in file for type-safety claim', () => {
413
+ const code = `const x: string = 42;`;
414
+ const claim = makeClaim({
415
+ claimId: 'claim-007',
416
+ category: 'type-safety',
417
+ description: 'Type mismatch',
418
+ verdict: 'FAIL',
419
+ });
420
+ const tscOutput = `src/lib/foo.ts(1,7): error TS2322: Type 'number' is not assignable to type 'string'.`;
421
+ const result = parseConfirmation(code, claim, tscOutput, 'src/lib/foo.ts');
422
+ expect(result.confirmed).toBe(true);
423
+ expect(result.method).toBe('compiler');
424
+ expect(result.evidence).toMatch(/tsc reported error/);
425
+ });
426
+ it('falls through to grep when tscOutput is null', () => {
427
+ const code = `
428
+ async function load() {
429
+ const data = await getData();
430
+ return data;
431
+ }
432
+ `;
433
+ const claim = makeClaim({
434
+ claimId: 'claim-008',
435
+ category: 'error-handling',
436
+ description: 'Missing try/catch',
437
+ verdict: 'FAIL',
438
+ });
439
+ const result = parseConfirmation(code, claim, null, 'src/lib/foo.ts');
440
+ expect(result.method).toBe('grep');
441
+ expect(result.confirmed).toBe(true);
442
+ });
443
+ });
444
+ describe('Scanner', () => {
445
+ const makeClaim = (overrides = {}) => ({
446
+ id: 'claim-001',
447
+ category: 'error-handling',
448
+ severity: 'high',
449
+ description: 'Missing error handling around async call',
450
+ assertion: 'All async calls must be wrapped in try/catch',
451
+ ...overrides,
452
+ });
453
+ const makeVerification = (overrides = {}) => ({
454
+ claimId: 'claim-001',
455
+ verdict: 'FAIL',
456
+ reasoning: 'No try/catch found around async call',
457
+ method: 'llm',
458
+ ...overrides,
459
+ });
460
+ it('builds scan result from claims and verifications (3 claims, 2 FAIL, 1 PASS → 2 failures)', () => {
461
+ const claims = [
462
+ makeClaim({ id: 'c1', category: 'error-handling', severity: 'high' }),
463
+ makeClaim({ id: 'c2', category: 'security', severity: 'critical' }),
464
+ makeClaim({ id: 'c3', category: 'type-safety', severity: 'medium' }),
465
+ ];
466
+ const verifications = [
467
+ makeVerification({ claimId: 'c1', verdict: 'FAIL' }),
468
+ makeVerification({ claimId: 'c2', verdict: 'PASS', reasoning: 'Input is validated' }),
469
+ makeVerification({ claimId: 'c3', verdict: 'FAIL', reasoning: 'Type mismatch detected' }),
470
+ ];
471
+ const result = buildScanResult(claims, verifications);
472
+ expect(result.totalClaims).toBe(3);
473
+ expect(result.failures).toHaveLength(2);
474
+ expect(result.failures.map((f) => f.claimId)).toEqual(expect.arrayContaining(['c1', 'c3']));
475
+ });
476
+ it('extracts failure metadata for learning pipeline (all fields populated correctly)', () => {
477
+ const claims = [
478
+ makeClaim({
479
+ id: 'c1',
480
+ category: 'security',
481
+ severity: 'critical',
482
+ description: 'SQL injection vulnerability',
483
+ assertion: 'User input must never be interpolated into SQL',
484
+ }),
485
+ ];
486
+ const verifications = [
487
+ makeVerification({
488
+ claimId: 'c1',
489
+ verdict: 'FAIL',
490
+ reasoning: 'Template literal used with user input in query',
491
+ method: 'formal',
492
+ }),
493
+ ];
494
+ const result = buildScanResult(claims, verifications);
495
+ expect(result.failures).toHaveLength(1);
496
+ const failure = result.failures[0];
497
+ expect(failure.claimId).toBe('c1');
498
+ expect(failure.category).toBe('security');
499
+ expect(failure.severity).toBe('critical');
500
+ expect(failure.description).toBe('SQL injection vulnerability');
501
+ expect(failure.assertion).toBe('User input must never be interpolated into SQL');
502
+ expect(failure.reasoning).toBe('Template literal used with user input in query');
503
+ expect(failure.method).toBe('formal');
504
+ });
505
+ it('handles empty verifications (0 claims → 0 failures)', () => {
506
+ const result = buildScanResult([], []);
507
+ expect(result.totalClaims).toBe(0);
508
+ expect(result.failures).toHaveLength(0);
509
+ });
510
+ it('filters PARTIAL verdicts into failures too', () => {
511
+ const claims = [
512
+ makeClaim({ id: 'c1', category: 'error-handling', severity: 'medium' }),
513
+ makeClaim({ id: 'c2', category: 'performance', severity: 'low' }),
514
+ ];
515
+ const verifications = [
516
+ makeVerification({ claimId: 'c1', verdict: 'PARTIAL', reasoning: 'Error partially handled' }),
517
+ makeVerification({ claimId: 'c2', verdict: 'PASS', reasoning: 'Performance acceptable' }),
518
+ ];
519
+ const result = buildScanResult(claims, verifications);
520
+ expect(result.totalClaims).toBe(2);
521
+ expect(result.failures).toHaveLength(1);
522
+ expect(result.failures[0].claimId).toBe('c1');
523
+ expect(result.failures[0].reasoning).toBe('Error partially handled');
524
+ });
525
+ });
526
+ //# sourceMappingURL=rule-harvester.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-harvester.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/rule-harvester.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Canonical Category Map — normalizes the fragmented claim categories
3
+ * (37 variants) down to ~12 canonical categories.
4
+ *
5
+ * Used in two places:
6
+ * 1. Rule creation (harvester + pattern extractor) — new rules get canonical categories
7
+ * 2. Rule loading (catalog) — existing rules get mapped at load time
8
+ */
9
+ /**
10
+ * The canonical set of claim categories for all learned rules.
11
+ */
12
+ export declare const CANONICAL_CATEGORIES: readonly ["security", "error-handling", "data-validation", "async", "resource-management", "api-contract", "state-management", "i18n", "performance", "type-safety", "ui-logic", "code-quality"];
13
+ export type CanonicalCategory = (typeof CANONICAL_CATEGORIES)[number];
14
+ /**
15
+ * Maps every known raw category string to its canonical form.
16
+ *
17
+ * When adding new mappings, keep the keys lowercase and hyphenated.
18
+ */
19
+ export declare const CATEGORY_MAP: Readonly<Record<string, CanonicalCategory>>;
20
+ /**
21
+ * Normalize a raw category string to its canonical form.
22
+ *
23
+ * Lookup order:
24
+ * 1. Exact match in CATEGORY_MAP
25
+ * 2. Lowercase + trim exact match
26
+ * 3. Fallback to 'code-quality' (the broadest bucket)
27
+ */
28
+ export declare function normalizeCategory(raw: string): CanonicalCategory;