@mmnto/totem 1.64.1 → 1.65.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 (41) hide show
  1. package/dist/ast-gate.d.ts +9 -0
  2. package/dist/ast-gate.d.ts.map +1 -1
  3. package/dist/ast-gate.js +64 -25
  4. package/dist/ast-gate.js.map +1 -1
  5. package/dist/ast-gate.test.js +47 -0
  6. package/dist/ast-gate.test.js.map +1 -1
  7. package/dist/compiler-schema.d.ts +329 -0
  8. package/dist/compiler-schema.d.ts.map +1 -1
  9. package/dist/compiler-schema.js +136 -1
  10. package/dist/compiler-schema.js.map +1 -1
  11. package/dist/compiler-schema.test.js +136 -1
  12. package/dist/compiler-schema.test.js.map +1 -1
  13. package/dist/compiler.d.ts +2 -2
  14. package/dist/compiler.d.ts.map +1 -1
  15. package/dist/compiler.js +1 -1
  16. package/dist/compiler.js.map +1 -1
  17. package/dist/index.d.ts +6 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +3 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/spine/windtunnel-lock.d.ts +440 -0
  22. package/dist/spine/windtunnel-lock.d.ts.map +1 -0
  23. package/dist/spine/windtunnel-lock.js +115 -0
  24. package/dist/spine/windtunnel-lock.js.map +1 -0
  25. package/dist/spine/windtunnel-lock.test.d.ts +2 -0
  26. package/dist/spine/windtunnel-lock.test.d.ts.map +1 -0
  27. package/dist/spine/windtunnel-lock.test.js +214 -0
  28. package/dist/spine/windtunnel-lock.test.js.map +1 -0
  29. package/dist/spine/windtunnel-parity.test.d.ts +2 -0
  30. package/dist/spine/windtunnel-parity.test.d.ts.map +1 -0
  31. package/dist/spine/windtunnel-parity.test.js +192 -0
  32. package/dist/spine/windtunnel-parity.test.js.map +1 -0
  33. package/dist/spine/windtunnel-scorer.d.ts +70 -0
  34. package/dist/spine/windtunnel-scorer.d.ts.map +1 -0
  35. package/dist/spine/windtunnel-scorer.js +176 -0
  36. package/dist/spine/windtunnel-scorer.js.map +1 -0
  37. package/dist/spine/windtunnel-scorer.test.d.ts +2 -0
  38. package/dist/spine/windtunnel-scorer.test.d.ts.map +1 -0
  39. package/dist/spine/windtunnel-scorer.test.js +354 -0
  40. package/dist/spine/windtunnel-scorer.test.js.map +1 -0
  41. package/package.json +1 -1
@@ -4,6 +4,15 @@ export interface AstGateOptions {
4
4
  cwd?: string;
5
5
  /** Optional callback for non-fatal warnings (e.g., file not readable) */
6
6
  onWarn?: (msg: string) => void;
7
+ /**
8
+ * Optional content injection seam (C1 — wind-tunnel parity).
9
+ * When provided, classifyFile uses this instead of git-show / disk reads,
10
+ * so regex astContext classification sees the same post-image content as
11
+ * the AST engine. Returning null skips classification for that file (same
12
+ * as an unreadable file). Throwing propagates — callers must not silently
13
+ * swallow (C2: missing blob is corpus shrinkage, not a clean no-match).
14
+ */
15
+ readStrategy?: (file: string) => Promise<string | null>;
7
16
  }
8
17
  /**
9
18
  * Enrich diff additions with AST context by parsing the actual files.
@@ -1 +1 @@
1
- {"version":3,"file":"ast-gate.d.ts","sourceRoot":"","sources":["../src/ast-gate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,eAAe,CAAC;AAI9D,MAAM,WAAW,cAAc;IAC7B,sDAAsD;IACtD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAID;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,YAAY,EAAE,EACzB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
1
+ {"version":3,"file":"ast-gate.d.ts","sourceRoot":"","sources":["../src/ast-gate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,eAAe,CAAC;AAI9D,MAAM,WAAW,cAAc;IAC7B,sDAAsD;IACtD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACzD;AAID;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,YAAY,EAAE,EACzB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
package/dist/ast-gate.js CHANGED
@@ -31,11 +31,12 @@ export async function enrichWithAstContext(additions, options = {}) {
31
31
  const lang = extensionToLanguage(ext);
32
32
  if (!lang)
33
33
  continue; // Unsupported language — leave as undefined (fail-open)
34
- promises.push(classifyFile(file, fileAdditions, lang, cwd, options.onWarn));
34
+ promises.push(classifyFile(file, fileAdditions, lang, cwd, options));
35
35
  }
36
36
  await Promise.all(promises);
37
37
  }
38
- async function classifyFile(file, additions, lang, cwd, onWarn) {
38
+ async function classifyFile(file, additions, lang, cwd, options) {
39
+ const onWarn = options.onWarn;
39
40
  const fullPath = path.resolve(cwd, file);
40
41
  // Path containment: skip files that escape the working directory
41
42
  const resolvedCwd = path.resolve(cwd) + path.sep;
@@ -43,37 +44,75 @@ async function classifyFile(file, additions, lang, cwd, onWarn) {
43
44
  onWarn?.(`AST gate: ${file} escapes project root, skipping`);
44
45
  return;
45
46
  }
46
- let content;
47
+ const content = await resolveContent(file, fullPath, cwd, options);
48
+ if (content === null)
49
+ return; // unreadable / readStrategy returned null — skip classification
50
+ const lineNumbers = additions.map((a) => a.lineNumber);
51
+ const classifications = await classifyContent(content, lineNumbers, lang, file, onWarn);
52
+ if (classifications === null)
53
+ return; // parse failed — skip classification (fail-open)
54
+ // Enrich additions with their AST context
55
+ for (const addition of additions) {
56
+ const ctx = classifications.get(addition.lineNumber);
57
+ if (ctx) {
58
+ addition.astContext = ctx;
59
+ }
60
+ }
61
+ }
62
+ /**
63
+ * Resolve the file content to classify. When `options.readStrategy` is set
64
+ * (the wind-tunnel parity seam, mmnto-ai/totem#2188), it is the sole source:
65
+ * a `null` return means "skip" (same as unreadable) and a throw propagates
66
+ * (C2 — a missing post-image blob must not silently no-match). When absent,
67
+ * the established staged (`git show :path`) → disk fallback is used.
68
+ *
69
+ * Returns `null` when the file cannot be read and classification should be
70
+ * skipped (fail-open — AST enrichment is advisory, not a hard sensor).
71
+ */
72
+ async function resolveContent(file, fullPath, cwd, options) {
73
+ if (options.readStrategy) {
74
+ const injected = await options.readStrategy(file);
75
+ if (injected === null) {
76
+ options.onWarn?.(`AST gate: readStrategy returned null for ${file}, skipping classification`);
77
+ }
78
+ return injected;
79
+ }
80
+ // totem-context: intentional fallback — git show :path is the preferred staged read; a non-staged file falls through to the disk read below (advisory AST enrichment, never a hard sensor).
47
81
  try {
48
82
  // Prefer staged content (git show :path) over disk file to match the diff being evaluated.
49
- // Falls back to disk if git is unavailable or file isn't staged.
50
83
  const { safeExec } = await import('./sys/exec.js');
51
- content = safeExec('git', ['show', `:${file}`], { cwd });
84
+ return safeExec('git', ['show', `:${file}`], { cwd });
85
+ // totem-context: intentional fallback — staged read missing → disk read below.
52
86
  }
53
- catch {
54
- try {
55
- content = fs.readFileSync(fullPath, 'utf-8');
56
- }
57
- catch {
58
- onWarn?.(`AST gate: cannot read ${file}, skipping classification`);
59
- return;
60
- }
87
+ catch (gitErr) {
88
+ void gitErr;
61
89
  }
62
- const lineNumbers = additions.map((a) => a.lineNumber);
63
- let classifications;
90
+ // totem-context: intentional fail-open — an unreadable file degrades to skip-classification (advisory AST enrichment, never a hard sensor).
64
91
  try {
65
- classifications = await classifyLines(content, lineNumbers, lang);
92
+ return fs.readFileSync(fullPath, 'utf-8');
93
+ // totem-context: intentional fail-open — unreadable file → skip classification.
66
94
  }
67
- catch {
68
- onWarn?.(`AST gate: parse failed for ${file}, skipping classification`);
69
- return;
95
+ catch (diskErr) {
96
+ void diskErr;
97
+ options.onWarn?.(`AST gate: cannot read ${file}, skipping classification`);
98
+ return null;
70
99
  }
71
- // Enrich additions with their AST context
72
- for (const addition of additions) {
73
- const ctx = classifications.get(addition.lineNumber);
74
- if (ctx) {
75
- addition.astContext = ctx;
76
- }
100
+ }
101
+ /**
102
+ * Classify the given lines of `content`, returning the per-line AST context
103
+ * map. Returns `null` when the parse fails so the caller skips classification
104
+ * (fail-open — AST enrichment is advisory, not a hard sensor).
105
+ */
106
+ async function classifyContent(content, lineNumbers, lang, file, onWarn) {
107
+ // totem-context: intentional fail-open — an unparseable file degrades to skip-classification (advisory AST enrichment, never a hard sensor).
108
+ try {
109
+ return await classifyLines(content, lineNumbers, lang);
110
+ // totem-context: intentional fail-open — unparseable file → skip classification.
111
+ }
112
+ catch (parseErr) {
113
+ void parseErr;
114
+ onWarn?.(`AST gate: parse failed for ${file}, skipping classification`);
115
+ return null;
77
116
  }
78
117
  }
79
118
  //# sourceMappingURL=ast-gate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ast-gate.js","sourceRoot":"","sources":["../src/ast-gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ast-gate.js","sourceRoot":"","sources":["../src/ast-gate.ts"],"names":[],"mappings":"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"}
@@ -91,5 +91,52 @@ describe('enrichWithAstContext', () => {
91
91
  expect(additions[0].astContext).toBeUndefined();
92
92
  expect(warnings.some((w) => w.includes('escapes project root'))).toBe(true);
93
93
  });
94
+ it('uses injected readStrategy content when provided (C1 seam)', async () => {
95
+ // readStrategy returns TypeScript with a comment — should classify as comment
96
+ const tsContent = '// a comment\nconst x = 1;\n';
97
+ const additions = [
98
+ { file: 'src/app.ts', line: '// a comment', lineNumber: 1, precedingLine: null },
99
+ { file: 'src/app.ts', line: 'const x = 1;', lineNumber: 2, precedingLine: '// a comment' },
100
+ ];
101
+ await enrichWithAstContext(additions, {
102
+ cwd: tmpDir,
103
+ readStrategy: async (_file) => tsContent,
104
+ });
105
+ expect(additions[0].astContext).toBe('comment');
106
+ expect(additions[1].astContext).toBe('code');
107
+ });
108
+ it('skips classification and warns when readStrategy returns null', async () => {
109
+ const warnings = [];
110
+ const additions = [
111
+ { file: 'src/app.ts', line: 'const x = 1;', lineNumber: 1, precedingLine: null },
112
+ ];
113
+ await enrichWithAstContext(additions, {
114
+ cwd: tmpDir,
115
+ readStrategy: async (_file) => null,
116
+ onWarn: (msg) => warnings.push(msg),
117
+ });
118
+ expect(additions[0].astContext).toBeUndefined();
119
+ expect(warnings.some((w) => w.includes('readStrategy returned null'))).toBe(true);
120
+ });
121
+ it('propagates readStrategy errors without falling back to disk (C2)', async () => {
122
+ const additions = [
123
+ { file: 'src/app.ts', line: 'const x = 1;', lineNumber: 1, precedingLine: null },
124
+ ];
125
+ await expect(enrichWithAstContext(additions, {
126
+ cwd: tmpDir,
127
+ readStrategy: async (_file) => {
128
+ throw new Error('blob not found in lc clone');
129
+ },
130
+ })).rejects.toThrow('blob not found in lc clone');
131
+ });
132
+ it('preserves existing behavior when no readStrategy is provided', async () => {
133
+ fs.writeFileSync(path.join(tmpDir, 'src', 'no-strategy.ts'), '// comment line\nconst z = 99;\n');
134
+ const additions = [
135
+ { file: 'src/no-strategy.ts', line: '// comment line', lineNumber: 1, precedingLine: null },
136
+ ];
137
+ await enrichWithAstContext(additions, { cwd: tmpDir });
138
+ // Disk fallback reads the file and classifies
139
+ expect(additions[0].astContext).toBe('comment');
140
+ });
94
141
  });
95
142
  //# sourceMappingURL=ast-gate.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ast-gate.test.js","sourceRoot":"","sources":["../src/ast-gate.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ast-gate.test.js","sourceRoot":"","sources":["../src/ast-gate.test.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,111 @@ export declare const AstGrepYamlRuleSchema: z.ZodObject<{
36
36
  rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
37
37
  }, z.ZodTypeAny, "passthrough">>;
38
38
  export type AstGrepYamlRule = NapiConfig;
39
+ /**
40
+ * mmnto-ai/totem#2183 — the §3.1 provenance leg of the ADR-110 Gate-1
41
+ * legitimacy bar: the identity of the merged-PR history a regenerated rule was
42
+ * mined from. Structured and **mechanically validated** (NOT a bare string) so
43
+ * a placeholder cannot masquerade as provenance. Promotion state is NOT carried
44
+ * here — it lives on the owning rule's top-level `unverified` flag (ADR-089
45
+ * zero-trust), the single source of truth `deriveRuleClass` reads. Control
46
+ * *evidence* (which PRs/fixtures proved each control) rides the wind-tunnel
47
+ * manifest (ADR-110 §6), not the per-rule marker.
48
+ */
49
+ export declare const ProvenanceRecordSchema: z.ZodObject<{
50
+ /** Merged PR the rule was mined from (positive integer PR number). */
51
+ mergedPr: z.ZodNumber;
52
+ /**
53
+ * Reference to the review thread that adjudicated the rule. Rejects empty and
54
+ * whitespace-only via a NON-MUTATING refinement (greptile/CR #2186): a
55
+ * `.trim()` transform would silently normalize a padded value on parse, so a
56
+ * stamped rule's on-disk JSON could differ from its parsed form and churn the
57
+ * manifest hash on the next `verify-manifest`. `.refine` validates without
58
+ * mutating, so the stored value round-trips byte-identically.
59
+ */
60
+ reviewThread: z.ZodEffects<z.ZodString, string, string>;
61
+ /** Full 40-hex git commit SHA the rule was frozen at. */
62
+ commitSha: z.ZodString;
63
+ }, "strip", z.ZodTypeAny, {
64
+ mergedPr: number;
65
+ reviewThread: string;
66
+ commitSha: string;
67
+ }, {
68
+ mergedPr: number;
69
+ reviewThread: string;
70
+ commitSha: string;
71
+ }>;
72
+ export type ProvenanceRecord = z.infer<typeof ProvenanceRecordSchema>;
73
+ /**
74
+ * mmnto-ai/totem#2183 — the three **peer** legs of the ADR-110 §3 legitimacy
75
+ * bar, mapping 1:1 onto the strategy#666 Tenet-9 three-check so the Gate-1
76
+ * wind-tunnel reads per-rule eligibility off the marker with no translation
77
+ * layer: `provenance` (§3.1) / `positiveControl` (§3.2) / `negativeControl`
78
+ * (§3.3). Controls are pass/fail booleans, **required** when `legitimacy` is
79
+ * present (never defaulted, so an absent control can't silently read as a
80
+ * failed one); the evidence behind each pass lives in the wind-tunnel manifest.
81
+ */
82
+ export declare const LegitimacySchema: z.ZodObject<{
83
+ provenance: z.ZodObject<{
84
+ /** Merged PR the rule was mined from (positive integer PR number). */
85
+ mergedPr: z.ZodNumber;
86
+ /**
87
+ * Reference to the review thread that adjudicated the rule. Rejects empty and
88
+ * whitespace-only via a NON-MUTATING refinement (greptile/CR #2186): a
89
+ * `.trim()` transform would silently normalize a padded value on parse, so a
90
+ * stamped rule's on-disk JSON could differ from its parsed form and churn the
91
+ * manifest hash on the next `verify-manifest`. `.refine` validates without
92
+ * mutating, so the stored value round-trips byte-identically.
93
+ */
94
+ reviewThread: z.ZodEffects<z.ZodString, string, string>;
95
+ /** Full 40-hex git commit SHA the rule was frozen at. */
96
+ commitSha: z.ZodString;
97
+ }, "strip", z.ZodTypeAny, {
98
+ mergedPr: number;
99
+ reviewThread: string;
100
+ commitSha: string;
101
+ }, {
102
+ mergedPr: number;
103
+ reviewThread: string;
104
+ commitSha: string;
105
+ }>;
106
+ positiveControl: z.ZodBoolean;
107
+ negativeControl: z.ZodBoolean;
108
+ }, "strip", z.ZodTypeAny, {
109
+ provenance: {
110
+ mergedPr: number;
111
+ reviewThread: string;
112
+ commitSha: string;
113
+ };
114
+ positiveControl: boolean;
115
+ negativeControl: boolean;
116
+ }, {
117
+ provenance: {
118
+ mergedPr: number;
119
+ reviewThread: string;
120
+ commitSha: string;
121
+ };
122
+ positiveControl: boolean;
123
+ negativeControl: boolean;
124
+ }>;
125
+ export type Legitimacy = z.infer<typeof LegitimacySchema>;
126
+ /**
127
+ * mmnto-ai/totem#2183 — derive the enforcement tier from the ADR-110 §3
128
+ * legitimacy bar. Pure + deterministic (Tenet 9). A rule is `'hard'` ONLY when
129
+ * all three legs hold AND the rule is promoted: `legitimacy` present, the
130
+ * owning rule's ADR-089 `unverified` flag is not `true`, and both controls
131
+ * passed. Anything else — no legitimacy, unpromoted, or a failed control — is
132
+ * `'advisory'`. Promotion reads the rule's TOP-LEVEL `unverified` (the single
133
+ * source of truth; #1485 / #1479 already read it), never a nested copy.
134
+ *
135
+ * **Unwired** from `buildCompiledRule` in this slice: the rule-compilation
136
+ * freeze stands, so the sanctioned writer is spine regeneration (strategy#516),
137
+ * which owns the wiring. Exposed as a pure helper for that regenerator and for
138
+ * the consistency superRefine below.
139
+ */
140
+ export declare function deriveRuleClass(rule: {
141
+ legitimacy?: Legitimacy;
142
+ unverified?: boolean;
143
+ }): 'hard' | 'advisory';
39
144
  export declare const CompiledRuleSchema: z.ZodEffects<z.ZodObject<{
40
145
  /** SHA-256 hash (first 16 hex chars) of heading + body — detects edits */
41
146
  lessonHash: z.ZodString;
@@ -195,6 +300,68 @@ export declare const CompiledRuleSchema: z.ZodEffects<z.ZodObject<{
195
300
  * produce identical output.
196
301
  */
197
302
  unverified: z.ZodOptional<z.ZodBoolean>;
303
+ /**
304
+ * mmnto-ai/totem#2183 — the ADR-110 §3 legitimacy bar (three peer legs). Set
305
+ * by spine rule-regeneration (strategy#516); **absent on every legacy rule.**
306
+ * When present, `ruleClass` MUST also be present and equal to
307
+ * `deriveRuleClass(rule)` — enforced by the superRefine on
308
+ * `CompiledRuleSchema`. Never written with defaults: absence is the legacy
309
+ * signal and preserves pre-#2183 manifest hashes via canonicalStringify.
310
+ */
311
+ legitimacy: z.ZodOptional<z.ZodObject<{
312
+ provenance: z.ZodObject<{
313
+ /** Merged PR the rule was mined from (positive integer PR number). */
314
+ mergedPr: z.ZodNumber;
315
+ /**
316
+ * Reference to the review thread that adjudicated the rule. Rejects empty and
317
+ * whitespace-only via a NON-MUTATING refinement (greptile/CR #2186): a
318
+ * `.trim()` transform would silently normalize a padded value on parse, so a
319
+ * stamped rule's on-disk JSON could differ from its parsed form and churn the
320
+ * manifest hash on the next `verify-manifest`. `.refine` validates without
321
+ * mutating, so the stored value round-trips byte-identically.
322
+ */
323
+ reviewThread: z.ZodEffects<z.ZodString, string, string>;
324
+ /** Full 40-hex git commit SHA the rule was frozen at. */
325
+ commitSha: z.ZodString;
326
+ }, "strip", z.ZodTypeAny, {
327
+ mergedPr: number;
328
+ reviewThread: string;
329
+ commitSha: string;
330
+ }, {
331
+ mergedPr: number;
332
+ reviewThread: string;
333
+ commitSha: string;
334
+ }>;
335
+ positiveControl: z.ZodBoolean;
336
+ negativeControl: z.ZodBoolean;
337
+ }, "strip", z.ZodTypeAny, {
338
+ provenance: {
339
+ mergedPr: number;
340
+ reviewThread: string;
341
+ commitSha: string;
342
+ };
343
+ positiveControl: boolean;
344
+ negativeControl: boolean;
345
+ }, {
346
+ provenance: {
347
+ mergedPr: number;
348
+ reviewThread: string;
349
+ commitSha: string;
350
+ };
351
+ positiveControl: boolean;
352
+ negativeControl: boolean;
353
+ }>>;
354
+ /**
355
+ * mmnto-ai/totem#2183 — the first-class, **derived** enforcement-tier marker
356
+ * that retires the engine-type proxy (#2181). `'hard'` blocks (subject to the
357
+ * unchanged severity gate — error blocks, warning does not); `'advisory'` is
358
+ * printed, non-blocking. Derived from `legitimacy` at mint via
359
+ * `deriveRuleClass`; the reader TRUSTS this frozen stamp and never re-derives
360
+ * at lint-time (ADR-110 §1 mint+validate boundary; Tenet-15
361
+ * verifiable-freezing). Present **iff** `legitimacy` is present; absent ⇒ the
362
+ * reader falls back to the legacy engine-type proxy.
363
+ */
364
+ ruleClass: z.ZodOptional<z.ZodEnum<["hard", "advisory"]>>;
198
365
  }, "strip", z.ZodTypeAny, {
199
366
  message: string;
200
367
  lessonHash: string;
@@ -220,6 +387,16 @@ export declare const CompiledRuleSchema: z.ZodEffects<z.ZodObject<{
220
387
  manual?: boolean | undefined;
221
388
  immutable?: boolean | undefined;
222
389
  unverified?: boolean | undefined;
390
+ legitimacy?: {
391
+ provenance: {
392
+ mergedPr: number;
393
+ reviewThread: string;
394
+ commitSha: string;
395
+ };
396
+ positiveControl: boolean;
397
+ negativeControl: boolean;
398
+ } | undefined;
399
+ ruleClass?: "hard" | "advisory" | undefined;
223
400
  }, {
224
401
  message: string;
225
402
  lessonHash: string;
@@ -245,6 +422,16 @@ export declare const CompiledRuleSchema: z.ZodEffects<z.ZodObject<{
245
422
  manual?: boolean | undefined;
246
423
  immutable?: boolean | undefined;
247
424
  unverified?: boolean | undefined;
425
+ legitimacy?: {
426
+ provenance: {
427
+ mergedPr: number;
428
+ reviewThread: string;
429
+ commitSha: string;
430
+ };
431
+ positiveControl: boolean;
432
+ negativeControl: boolean;
433
+ } | undefined;
434
+ ruleClass?: "hard" | "advisory" | undefined;
248
435
  }>, {
249
436
  message: string;
250
437
  lessonHash: string;
@@ -270,6 +457,16 @@ export declare const CompiledRuleSchema: z.ZodEffects<z.ZodObject<{
270
457
  manual?: boolean | undefined;
271
458
  immutable?: boolean | undefined;
272
459
  unverified?: boolean | undefined;
460
+ legitimacy?: {
461
+ provenance: {
462
+ mergedPr: number;
463
+ reviewThread: string;
464
+ commitSha: string;
465
+ };
466
+ positiveControl: boolean;
467
+ negativeControl: boolean;
468
+ } | undefined;
469
+ ruleClass?: "hard" | "advisory" | undefined;
273
470
  }, {
274
471
  message: string;
275
472
  lessonHash: string;
@@ -295,6 +492,16 @@ export declare const CompiledRuleSchema: z.ZodEffects<z.ZodObject<{
295
492
  manual?: boolean | undefined;
296
493
  immutable?: boolean | undefined;
297
494
  unverified?: boolean | undefined;
495
+ legitimacy?: {
496
+ provenance: {
497
+ mergedPr: number;
498
+ reviewThread: string;
499
+ commitSha: string;
500
+ };
501
+ positiveControl: boolean;
502
+ negativeControl: boolean;
503
+ } | undefined;
504
+ ruleClass?: "hard" | "advisory" | undefined;
298
505
  }>;
299
506
  export type CompiledRule = z.infer<typeof CompiledRuleSchema>;
300
507
  /**
@@ -578,6 +785,68 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
578
785
  * produce identical output.
579
786
  */
580
787
  unverified: z.ZodOptional<z.ZodBoolean>;
788
+ /**
789
+ * mmnto-ai/totem#2183 — the ADR-110 §3 legitimacy bar (three peer legs). Set
790
+ * by spine rule-regeneration (strategy#516); **absent on every legacy rule.**
791
+ * When present, `ruleClass` MUST also be present and equal to
792
+ * `deriveRuleClass(rule)` — enforced by the superRefine on
793
+ * `CompiledRuleSchema`. Never written with defaults: absence is the legacy
794
+ * signal and preserves pre-#2183 manifest hashes via canonicalStringify.
795
+ */
796
+ legitimacy: z.ZodOptional<z.ZodObject<{
797
+ provenance: z.ZodObject<{
798
+ /** Merged PR the rule was mined from (positive integer PR number). */
799
+ mergedPr: z.ZodNumber;
800
+ /**
801
+ * Reference to the review thread that adjudicated the rule. Rejects empty and
802
+ * whitespace-only via a NON-MUTATING refinement (greptile/CR #2186): a
803
+ * `.trim()` transform would silently normalize a padded value on parse, so a
804
+ * stamped rule's on-disk JSON could differ from its parsed form and churn the
805
+ * manifest hash on the next `verify-manifest`. `.refine` validates without
806
+ * mutating, so the stored value round-trips byte-identically.
807
+ */
808
+ reviewThread: z.ZodEffects<z.ZodString, string, string>;
809
+ /** Full 40-hex git commit SHA the rule was frozen at. */
810
+ commitSha: z.ZodString;
811
+ }, "strip", z.ZodTypeAny, {
812
+ mergedPr: number;
813
+ reviewThread: string;
814
+ commitSha: string;
815
+ }, {
816
+ mergedPr: number;
817
+ reviewThread: string;
818
+ commitSha: string;
819
+ }>;
820
+ positiveControl: z.ZodBoolean;
821
+ negativeControl: z.ZodBoolean;
822
+ }, "strip", z.ZodTypeAny, {
823
+ provenance: {
824
+ mergedPr: number;
825
+ reviewThread: string;
826
+ commitSha: string;
827
+ };
828
+ positiveControl: boolean;
829
+ negativeControl: boolean;
830
+ }, {
831
+ provenance: {
832
+ mergedPr: number;
833
+ reviewThread: string;
834
+ commitSha: string;
835
+ };
836
+ positiveControl: boolean;
837
+ negativeControl: boolean;
838
+ }>>;
839
+ /**
840
+ * mmnto-ai/totem#2183 — the first-class, **derived** enforcement-tier marker
841
+ * that retires the engine-type proxy (#2181). `'hard'` blocks (subject to the
842
+ * unchanged severity gate — error blocks, warning does not); `'advisory'` is
843
+ * printed, non-blocking. Derived from `legitimacy` at mint via
844
+ * `deriveRuleClass`; the reader TRUSTS this frozen stamp and never re-derives
845
+ * at lint-time (ADR-110 §1 mint+validate boundary; Tenet-15
846
+ * verifiable-freezing). Present **iff** `legitimacy` is present; absent ⇒ the
847
+ * reader falls back to the legacy engine-type proxy.
848
+ */
849
+ ruleClass: z.ZodOptional<z.ZodEnum<["hard", "advisory"]>>;
581
850
  }, "strip", z.ZodTypeAny, {
582
851
  message: string;
583
852
  lessonHash: string;
@@ -603,6 +872,16 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
603
872
  manual?: boolean | undefined;
604
873
  immutable?: boolean | undefined;
605
874
  unverified?: boolean | undefined;
875
+ legitimacy?: {
876
+ provenance: {
877
+ mergedPr: number;
878
+ reviewThread: string;
879
+ commitSha: string;
880
+ };
881
+ positiveControl: boolean;
882
+ negativeControl: boolean;
883
+ } | undefined;
884
+ ruleClass?: "hard" | "advisory" | undefined;
606
885
  }, {
607
886
  message: string;
608
887
  lessonHash: string;
@@ -628,6 +907,16 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
628
907
  manual?: boolean | undefined;
629
908
  immutable?: boolean | undefined;
630
909
  unverified?: boolean | undefined;
910
+ legitimacy?: {
911
+ provenance: {
912
+ mergedPr: number;
913
+ reviewThread: string;
914
+ commitSha: string;
915
+ };
916
+ positiveControl: boolean;
917
+ negativeControl: boolean;
918
+ } | undefined;
919
+ ruleClass?: "hard" | "advisory" | undefined;
631
920
  }>, {
632
921
  message: string;
633
922
  lessonHash: string;
@@ -653,6 +942,16 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
653
942
  manual?: boolean | undefined;
654
943
  immutable?: boolean | undefined;
655
944
  unverified?: boolean | undefined;
945
+ legitimacy?: {
946
+ provenance: {
947
+ mergedPr: number;
948
+ reviewThread: string;
949
+ commitSha: string;
950
+ };
951
+ positiveControl: boolean;
952
+ negativeControl: boolean;
953
+ } | undefined;
954
+ ruleClass?: "hard" | "advisory" | undefined;
656
955
  }, {
657
956
  message: string;
658
957
  lessonHash: string;
@@ -678,6 +977,16 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
678
977
  manual?: boolean | undefined;
679
978
  immutable?: boolean | undefined;
680
979
  unverified?: boolean | undefined;
980
+ legitimacy?: {
981
+ provenance: {
982
+ mergedPr: number;
983
+ reviewThread: string;
984
+ commitSha: string;
985
+ };
986
+ positiveControl: boolean;
987
+ negativeControl: boolean;
988
+ } | undefined;
989
+ ruleClass?: "hard" | "advisory" | undefined;
681
990
  }>, "many">;
682
991
  /**
683
992
  * Lessons that could not be compiled into a rule. 4-tuple shape since
@@ -753,6 +1062,16 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
753
1062
  manual?: boolean | undefined;
754
1063
  immutable?: boolean | undefined;
755
1064
  unverified?: boolean | undefined;
1065
+ legitimacy?: {
1066
+ provenance: {
1067
+ mergedPr: number;
1068
+ reviewThread: string;
1069
+ commitSha: string;
1070
+ };
1071
+ positiveControl: boolean;
1072
+ negativeControl: boolean;
1073
+ } | undefined;
1074
+ ruleClass?: "hard" | "advisory" | undefined;
756
1075
  }[];
757
1076
  nonCompilable?: {
758
1077
  hash: string;
@@ -787,6 +1106,16 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
787
1106
  manual?: boolean | undefined;
788
1107
  immutable?: boolean | undefined;
789
1108
  unverified?: boolean | undefined;
1109
+ legitimacy?: {
1110
+ provenance: {
1111
+ mergedPr: number;
1112
+ reviewThread: string;
1113
+ commitSha: string;
1114
+ };
1115
+ positiveControl: boolean;
1116
+ negativeControl: boolean;
1117
+ } | undefined;
1118
+ ruleClass?: "hard" | "advisory" | undefined;
790
1119
  }[];
791
1120
  nonCompilable?: (string | {
792
1121
  hash: string;