@mmnto/totem 1.18.2 → 1.19.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.
@@ -0,0 +1,355 @@
1
+ /**
2
+ * ADR-091 Stage 4 Verify-Against-Codebase verifier (mmnto-ai/totem#1682).
3
+ *
4
+ * Runs a compiled rule deterministically (zero LLM) against the consumer's
5
+ * existing codebase before promoting it to Active status. Catches the class
6
+ * of false positive that Layer 3 (ADR-088) cannot — Layer 3 verifies the
7
+ * pattern matches the lesson's authored `badExample` (internal consistency);
8
+ * Stage 4 verifies the pattern doesn't accidentally fire on legitimate code
9
+ * (global false-positive safety).
10
+ *
11
+ * Four outcomes per ADR-091 §"Stage 4: Verify-Against-Codebase":
12
+ *
13
+ * - **No matches** (`outcome: 'no-matches'`) — the verifier ran, found zero
14
+ * hits in the codebase. Caller sets `status: 'untested-against-codebase'`;
15
+ * subsequent compile cycles in a populated repo can re-run Stage 4 and
16
+ * promote.
17
+ * - **Out-of-scope baseline match** (`outcome: 'out-of-scope'`) — the rule
18
+ * fired on at least one file in the verification baseline (test files,
19
+ * fixture directories, or files outside the rule's `fileGlobs` scope).
20
+ * The pattern is over-broad. Caller archives the rule with
21
+ * `reasonCode: 'stage4-out-of-scope-match'` and the offending paths.
22
+ * - **In-scope `badExample`-shape match** (`outcome: 'in-scope-bad-example'`)
23
+ * — the rule fired only on in-scope files AND every in-scope match line is
24
+ * structurally equivalent to the rule's `badExample`. The rule fires on
25
+ * real code in the exact authored shape. Caller sets `status: 'active'`
26
+ * with `confidence: 'high'`.
27
+ * - **Candidate Debt** (`outcome: 'candidate-debt'`) — the rule fired only
28
+ * on in-scope files but at least one match line differs from the
29
+ * `badExample` shape. The rule may be catching real debt, or producing
30
+ * false positives the LLM-generated pattern overshoots into. Caller
31
+ * accepts as `status: 'active'` and forces `severity: 'warning'` so it
32
+ * never breaks CI on first run; `totem doctor` (mmnto-ai/totem#1685)
33
+ * surfaces the candidate-debt sites for human confirmation.
34
+ *
35
+ * Bootstrap modes: T1 ships local-compile fully (the verifier runs against
36
+ * the consumer's working tree before `totem lesson compile` serializes the
37
+ * rule). Pack install→lint promotion lands in T3 (mmnto-ai/totem#1684).
38
+ * Consumer baseline overrides land in T2 (mmnto-ai/totem#1683). Perf
39
+ * optimizations (single-pass, file-tree caching, streaming short-circuit)
40
+ * land in T5 (mmnto-ai/totem#1686). T1 walks per-rule, no caching.
41
+ *
42
+ * Architecture: callback-based filesystem. The verifier accepts `listFiles`
43
+ * + `readFile` callbacks instead of touching `fs` directly so core stays
44
+ * orchestration-only. CLI implementations back the callbacks with `git
45
+ * ls-files` and `fs.readFile`; tests stub them with synthetic file maps.
46
+ */
47
+ import { applyAstRulesToAdditions, applyRulesToAdditions } from './rule-engine.js';
48
+ // ─── Default baseline ───────────────────────────────
49
+ /**
50
+ * Glob shapes the test-contract scope classifier (mmnto-ai/totem#1626 /
51
+ * mmnto-ai/totem#1652) promotes-to-test-inclusive when emitting LLM scope.
52
+ * Stage 4 mirrors them as the default baseline so any rule that fires on a
53
+ * test or fixture file is treated as out-of-scope by default. T2
54
+ * (mmnto-ai/totem#1683) lets consumers `exclude` from this list when their
55
+ * project legitimately treats `tests/` as production.
56
+ */
57
+ export const DEFAULT_BASELINE_GLOBS = [
58
+ '**/*.test.*',
59
+ '**/*.spec.*',
60
+ '**/__tests__/**',
61
+ '**/tests/**',
62
+ '**/__fixtures__/**',
63
+ '**/fixtures/**',
64
+ ];
65
+ export function getDefaultBaseline() {
66
+ // T1: the default baseline is rule-independent (every rule gets the same
67
+ // test/fixture exclusion). T2 (mmnto-ai/totem#1683) introduces per-config
68
+ // `extend`/`exclude` overrides; the function signature accepts a rule
69
+ // parameter then so per-rule baseline derivation can layer on top.
70
+ return { excludeFileGlobs: DEFAULT_BASELINE_GLOBS };
71
+ }
72
+ // ─── Glob matching (matches rule-engine semantics) ─
73
+ function matchesGlob(filePath, glob) {
74
+ // Normalize Windows backslashes to forward slashes — globs use forward
75
+ // slashes universally, repo paths come back from git-ls-files in either
76
+ // shape on Windows depending on core.autocrlf.
77
+ const normalized = filePath.replace(/\\/g, '/');
78
+ // Exact glob match — escape regex metacharacters except `*`, `?`, and
79
+ // brace groups, then expand `**` to `.*`, `*` to `[^/]*`, `?` to `.`.
80
+ if (glob.includes('*') || glob.includes('?') || glob.includes('{')) {
81
+ const regexPattern = globToRegex(glob);
82
+ return new RegExp(`^${regexPattern}$`).test(normalized);
83
+ }
84
+ // Literal filename match (e.g., "Dockerfile")
85
+ return normalized === glob || normalized.endsWith('/' + glob);
86
+ }
87
+ function globToRegex(glob) {
88
+ let result = '';
89
+ let i = 0;
90
+ while (i < glob.length) {
91
+ const ch = glob[i];
92
+ if (ch === '*') {
93
+ if (glob[i + 1] === '*') {
94
+ result += '.*';
95
+ i += 2;
96
+ // Consume trailing `/` if present so `**/foo` becomes `.*foo`
97
+ if (glob[i] === '/')
98
+ i++;
99
+ continue;
100
+ }
101
+ result += '[^/]*';
102
+ }
103
+ else if (ch === '?') {
104
+ result += '[^/]';
105
+ }
106
+ else if (ch === '{') {
107
+ const end = glob.indexOf('}', i);
108
+ if (end === -1) {
109
+ result += '\\{';
110
+ }
111
+ else {
112
+ const alts = glob.slice(i + 1, end).split(',');
113
+ result += '(?:' + alts.map(escapeRegex).join('|') + ')';
114
+ i = end + 1;
115
+ continue;
116
+ }
117
+ }
118
+ else if ('.+()[]^$|\\'.includes(ch)) {
119
+ result += '\\' + ch;
120
+ }
121
+ else {
122
+ result += ch;
123
+ }
124
+ i++;
125
+ }
126
+ return result;
127
+ }
128
+ function escapeRegex(s) {
129
+ return s.replace(/[.+()[\]^$|\\*?{}]/g, '\\$&');
130
+ }
131
+ function fileMatchesAnyGlob(filePath, globs) {
132
+ return globs.some((g) => matchesGlob(filePath, g));
133
+ }
134
+ /**
135
+ * A file is "in scope" for Stage 4 verification when it matches the rule's
136
+ * declared `fileGlobs` (or has none, meaning the rule applies everywhere)
137
+ * AND is not in the baseline-excluded set. A baseline-excluded test file
138
+ * inside `**\/*.ts` scope counts as baseline, not in-scope, because the
139
+ * verifier's job is to detect over-broad firing — including on tests the
140
+ * rule is supposed to skip.
141
+ */
142
+ function classifyFile(filePath, ruleFileGlobs, baseline) {
143
+ // Rule has explicit fileGlobs and this file doesn't match → baseline (out-of-scope).
144
+ if (ruleFileGlobs && ruleFileGlobs.length > 0) {
145
+ const positive = ruleFileGlobs.filter((g) => !g.startsWith('!'));
146
+ const negative = ruleFileGlobs.filter((g) => g.startsWith('!')).map((g) => g.slice(1));
147
+ const matchesPositive = positive.length === 0 || fileMatchesAnyGlob(filePath, positive);
148
+ const matchesNegative = fileMatchesAnyGlob(filePath, negative);
149
+ if (!matchesPositive || matchesNegative)
150
+ return 'baseline';
151
+ }
152
+ // File matches rule scope (or rule has no scope). Now check baseline overrides.
153
+ if (fileMatchesAnyGlob(filePath, baseline.excludeFileGlobs))
154
+ return 'baseline';
155
+ return 'in-scope';
156
+ }
157
+ // ─── Synthetic DiffAddition production ─────────────
158
+ /**
159
+ * Convert raw file content into the `DiffAddition[]` shape the rule engine
160
+ * expects. One addition per line. `precedingLine` carries the prior line
161
+ * verbatim so suppression directives (`// totem-ignore-next-line`) work
162
+ * inside the verifier the same way they do in lint. `astContext` is left
163
+ * undefined — the engine treats undefined as "code", which is exactly the
164
+ * Stage 4 contract: detect over-broad firing on any source line, not just
165
+ * lines a Tree-sitter classifier labels as code.
166
+ */
167
+ function fileToAdditions(file, content) {
168
+ // CR mmnto-ai/totem#1757 R3: don't synthesize a trailing blank line.
169
+ // `''.split(/\r?\n/)` returns `['']` and `'foo\n'.split(/\r?\n/)`
170
+ // returns `['foo', '']`, both of which would inject a non-existent
171
+ // blank addition. A pattern like `^$` (blank-line detector) would
172
+ // then falsely fire on every newline-terminated file in the
173
+ // codebase, flipping rules into out-of-scope or candidate-debt for
174
+ // the wrong reason.
175
+ if (content.length === 0)
176
+ return [];
177
+ const lines = content.split(/\r?\n/);
178
+ if (/\r?\n$/.test(content)) {
179
+ lines.pop();
180
+ }
181
+ const additions = [];
182
+ for (let i = 0; i < lines.length; i++) {
183
+ const line = lines[i] ?? '';
184
+ additions.push({
185
+ file,
186
+ line,
187
+ lineNumber: i + 1,
188
+ precedingLine: i > 0 ? (lines[i - 1] ?? null) : null,
189
+ });
190
+ }
191
+ return additions;
192
+ }
193
+ // ─── Rule execution ────────────────────────────────
194
+ const NOOP_LOGGER = { warn: () => undefined };
195
+ function defaultRuleCtx() {
196
+ return {
197
+ logger: NOOP_LOGGER,
198
+ state: { hasWarnedShieldContext: false },
199
+ };
200
+ }
201
+ /**
202
+ * Run the rule against the entire codebase, with `fileGlobs` stripped so
203
+ * the rule fires on every file (in-scope AND baseline). Stage 4 partitions
204
+ * the resulting violations by file classification afterward. Without the
205
+ * strip, `applyRulesToAdditions` would skip baseline files internally and
206
+ * the verifier would see zero out-of-scope hits even when the pattern is
207
+ * obviously over-broad.
208
+ */
209
+ async function runRuleAgainstAllFiles(rule, additions, ctx, workingDirectory) {
210
+ const ruleNoScope = { ...rule, fileGlobs: undefined };
211
+ if (rule.engine === 'regex' || !rule.engine) {
212
+ return applyRulesToAdditions(ctx, [ruleNoScope], [...additions]);
213
+ }
214
+ // ast / ast-grep — requires a working directory for file resolution.
215
+ // Fail loud when absent so Stage 4 cannot silently misclassify the run
216
+ // as `'no-matches'`. T1's CLI integration always passes a
217
+ // workingDirectory; tests that hit this path must pass one too.
218
+ // (CR mmnto-ai/totem#1757 R1 — earlier `return []` short-circuit
219
+ // hid the missing-input case as a clean result.)
220
+ if (!workingDirectory) {
221
+ const msg = `[Totem Error] Stage 4 verifier requires deps.workingDirectory for ${rule.engine} rules.`;
222
+ throw new Error(msg);
223
+ }
224
+ return applyAstRulesToAdditions(ctx, [ruleNoScope], [...additions], workingDirectory);
225
+ }
226
+ // ─── Structural equivalence ────────────────────────
227
+ /**
228
+ * T1 uses byte-equal trimmed comparison: a violation line is `badExample`-
229
+ * shape iff `line.trim()` equals `badExample.trim()`. Stricter equivalence
230
+ * (full subtree match for ast-grep, normalized whitespace for regex) is
231
+ * deferred to T5 (mmnto-ai/totem#1686) when the perf-pass adds AST-aware
232
+ * comparison.
233
+ *
234
+ * `badExample` may carry multiple lines (Pipeline 3 reuses Bad snippets
235
+ * verbatim). The function compares against ANY trimmed line of the
236
+ * `badExample` block — a violation matches if the line equals any one of
237
+ * the badExample's component lines.
238
+ */
239
+ function lineMatchesBadExample(line, badExample) {
240
+ if (badExample === undefined)
241
+ return false;
242
+ const trimmedLine = line.trim();
243
+ if (trimmedLine.length === 0)
244
+ return false;
245
+ for (const candidate of badExample.split(/\r?\n/)) {
246
+ if (candidate.trim() === trimmedLine)
247
+ return true;
248
+ }
249
+ return false;
250
+ }
251
+ // ─── Public API ────────────────────────────────────
252
+ /**
253
+ * Run Stage 4 verification for a single compiled rule against the consumer's
254
+ * codebase. Caller decides what to do with the returned outcome:
255
+ *
256
+ * - `'no-matches'` → set rule.status = 'untested-against-codebase'
257
+ * - `'out-of-scope'` → archive rule with reasonCode 'stage4-out-of-scope-match'
258
+ * - `'in-scope-bad-example'` → set rule.status = 'active', confidence = 'high'
259
+ * - `'candidate-debt'` → set rule.status = 'active', force severity = 'warning'
260
+ *
261
+ * The verifier itself does NOT mutate the rule. Mutation happens at the
262
+ * compileLesson integration site so the trace event and lifecycle field
263
+ * preservation remain centralized.
264
+ *
265
+ * For Pipeline 1 manual rules, the integration site bypasses Stage 4
266
+ * entirely — those rules are human-authored and Stage 4 is a safety net
267
+ * for LLM-generated patterns. The verifier itself is engine-agnostic and
268
+ * will run on any rule it's handed.
269
+ */
270
+ export async function verifyAgainstCodebase(rule, baseline, deps) {
271
+ const files = await deps.listFiles();
272
+ const ctx = deps.ruleCtx ?? defaultRuleCtx();
273
+ // Build all additions across all files. T5 (mmnto-ai/totem#1686) will
274
+ // batch this across rules per compile cycle; T1 walks per-rule.
275
+ const additions = [];
276
+ for (const file of files) {
277
+ let content;
278
+ try {
279
+ content = await deps.readFile(file);
280
+ }
281
+ catch (err) {
282
+ // Fail loud per Tenet 4. The file showed up in listFiles() so its
283
+ // absence here is a real environment problem (race with deletion,
284
+ // permission change, broken symlink). The operator needs to see
285
+ // exactly which file failed; preserving `cause` keeps the original
286
+ // stack/context intact (CR mmnto-ai/totem#1757 R2 — the prior
287
+ // `${err.message}` concat flattened the original exception).
288
+ throw new Error(`Stage 4 verifier could not read ${file}.`, { cause: err });
289
+ }
290
+ additions.push(...fileToAdditions(file, content));
291
+ }
292
+ if (additions.length === 0) {
293
+ return {
294
+ outcome: 'no-matches',
295
+ baselineMatches: [],
296
+ inScopeMatches: [],
297
+ candidateDebtLines: [],
298
+ };
299
+ }
300
+ const violations = await runRuleAgainstAllFiles(rule, additions, ctx, deps.workingDirectory);
301
+ if (violations.length === 0) {
302
+ return {
303
+ outcome: 'no-matches',
304
+ baselineMatches: [],
305
+ inScopeMatches: [],
306
+ candidateDebtLines: [],
307
+ };
308
+ }
309
+ // Partition violations by file classification.
310
+ const baselineMatchSet = new Set();
311
+ const inScopeMatchSet = new Set();
312
+ const candidateDebtLines = [];
313
+ for (const violation of violations) {
314
+ const classification = classifyFile(violation.file, rule.fileGlobs, baseline);
315
+ if (classification === 'baseline') {
316
+ baselineMatchSet.add(violation.file);
317
+ }
318
+ else {
319
+ inScopeMatchSet.add(violation.file);
320
+ if (!lineMatchesBadExample(violation.line, rule.badExample)) {
321
+ candidateDebtLines.push(violation.line);
322
+ }
323
+ }
324
+ }
325
+ // Out-of-scope wins precedence over in-scope outcomes — even one baseline
326
+ // match means the pattern is over-broad and gets archived. ADR-091
327
+ // §"Stage 4: Verify-Against-Codebase" is explicit on this ordering.
328
+ if (baselineMatchSet.size > 0) {
329
+ return {
330
+ outcome: 'out-of-scope',
331
+ baselineMatches: [...baselineMatchSet].sort(),
332
+ inScopeMatches: [...inScopeMatchSet].sort(),
333
+ candidateDebtLines: [],
334
+ };
335
+ }
336
+ // All violations are in-scope. Distinguish bad-example shape from
337
+ // candidate debt by whether ANY violation line failed to match the
338
+ // badExample. A single mismatch flips the outcome to candidate-debt;
339
+ // the rule ships at warning severity until a human confirms the hits.
340
+ if (candidateDebtLines.length === 0) {
341
+ return {
342
+ outcome: 'in-scope-bad-example',
343
+ baselineMatches: [],
344
+ inScopeMatches: [...inScopeMatchSet].sort(),
345
+ candidateDebtLines: [],
346
+ };
347
+ }
348
+ return {
349
+ outcome: 'candidate-debt',
350
+ baselineMatches: [],
351
+ inScopeMatches: [...inScopeMatchSet].sort(),
352
+ candidateDebtLines,
353
+ };
354
+ }
355
+ //# sourceMappingURL=stage4-verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage4-verifier.js","sourceRoot":"","sources":["../src/stage4-verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stage4-verifier.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage4-verifier.test.d.ts","sourceRoot":"","sources":["../src/stage4-verifier.test.ts"],"names":[],"mappings":""}