code-auditor-mcp 3.5.0 → 3.7.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 (110) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +62 -0
  3. package/dist/analyzers/applicability.d.ts +6 -5
  4. package/dist/analyzers/applicability.d.ts.map +1 -1
  5. package/dist/analyzers/applicability.js +1 -26
  6. package/dist/analyzers/applicability.js.map +1 -1
  7. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  8. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +12 -1
  9. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  10. package/dist/analyzers/ruleRegistry.d.ts +14 -12
  11. package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
  12. package/dist/analyzers/ruleRegistry.js +138 -98
  13. package/dist/analyzers/ruleRegistry.js.map +1 -1
  14. package/dist/analyzers/ruleTiming.d.ts +2 -2
  15. package/dist/analyzers/ruleTiming.js +2 -2
  16. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +29 -0
  17. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
  18. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +376 -6
  19. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  20. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +6 -0
  21. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  22. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +41 -7
  23. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  24. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  25. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +13 -2
  26. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  27. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +20 -5
  28. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  29. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +83 -14
  30. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  31. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  32. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +5 -2
  33. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  34. package/dist/analyzers/universal/UniversalSecretsAnalyzer.d.ts +55 -0
  35. package/dist/analyzers/universal/UniversalSecretsAnalyzer.d.ts.map +1 -0
  36. package/dist/analyzers/universal/UniversalSecretsAnalyzer.js +318 -0
  37. package/dist/analyzers/universal/UniversalSecretsAnalyzer.js.map +1 -0
  38. package/dist/analyzers/universal/functionConcerns.d.ts +52 -0
  39. package/dist/analyzers/universal/functionConcerns.d.ts.map +1 -0
  40. package/dist/analyzers/universal/functionConcerns.js +225 -0
  41. package/dist/analyzers/universal/functionConcerns.js.map +1 -0
  42. package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
  43. package/dist/analyzers/universal/schema/codeAnalysis.js +9 -3
  44. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
  45. package/dist/analyzers/universal/schema/discovery.d.ts +29 -1
  46. package/dist/analyzers/universal/schema/discovery.d.ts.map +1 -1
  47. package/dist/analyzers/universal/schema/discovery.js +76 -21
  48. package/dist/analyzers/universal/schema/discovery.js.map +1 -1
  49. package/dist/auditRunner.d.ts.map +1 -1
  50. package/dist/auditRunner.js +73 -74
  51. package/dist/auditRunner.js.map +1 -1
  52. package/dist/cli.js +109 -105
  53. package/dist/cli.js.map +1 -1
  54. package/dist/codeIndexDB.js +6 -6
  55. package/dist/codeIndexDB.js.map +1 -1
  56. package/dist/config/configLoader.d.ts.map +1 -1
  57. package/dist/config/configLoader.js +15 -0
  58. package/dist/config/configLoader.js.map +1 -1
  59. package/dist/config/defaults.d.ts +11 -1
  60. package/dist/config/defaults.d.ts.map +1 -1
  61. package/dist/config/defaults.js +25 -3
  62. package/dist/config/defaults.js.map +1 -1
  63. package/dist/config/effectiveConfig.d.ts.map +1 -1
  64. package/dist/config/effectiveConfig.js +2 -0
  65. package/dist/config/effectiveConfig.js.map +1 -1
  66. package/dist/dataPaths.js +18 -1
  67. package/dist/dataPaths.js.map +1 -1
  68. package/dist/enforcement/gate.d.ts +14 -19
  69. package/dist/enforcement/gate.d.ts.map +1 -1
  70. package/dist/enforcement/gate.js +27 -45
  71. package/dist/enforcement/gate.js.map +1 -1
  72. package/dist/graph/importGraph.d.ts +11 -0
  73. package/dist/graph/importGraph.d.ts.map +1 -1
  74. package/dist/graph/importGraph.js +11 -3
  75. package/dist/graph/importGraph.js.map +1 -1
  76. package/dist/installer.d.ts.map +1 -1
  77. package/dist/installer.js +2 -5
  78. package/dist/installer.js.map +1 -1
  79. package/dist/mcp.js +1 -1
  80. package/dist/mcp.js.map +1 -1
  81. package/dist/pipeline.d.ts.map +1 -1
  82. package/dist/pipeline.js +21 -3
  83. package/dist/pipeline.js.map +1 -1
  84. package/dist/pipelineAdapters.d.ts +1 -0
  85. package/dist/pipelineAdapters.d.ts.map +1 -1
  86. package/dist/pipelineAdapters.js +227 -4
  87. package/dist/pipelineAdapters.js.map +1 -1
  88. package/dist/styles/styleExtractor.js +2 -2
  89. package/dist/styles/styleExtractor.js.map +1 -1
  90. package/dist/styles/styleIndexer.js +7 -6
  91. package/dist/styles/styleIndexer.js.map +1 -1
  92. package/dist/styles/tailwindProbe.d.ts +8 -0
  93. package/dist/styles/tailwindProbe.d.ts.map +1 -1
  94. package/dist/styles/tailwindProbe.js +11 -1
  95. package/dist/styles/tailwindProbe.js.map +1 -1
  96. package/dist/styles/types.d.ts +3 -2
  97. package/dist/styles/types.d.ts.map +1 -1
  98. package/dist/types/crossLanguage.d.ts +1 -0
  99. package/dist/types/crossLanguage.d.ts.map +1 -1
  100. package/dist/types.d.ts +23 -30
  101. package/dist/types.d.ts.map +1 -1
  102. package/dist/types.js.map +1 -1
  103. package/package.json +13 -4
  104. package/plugin/.claude-plugin/plugin.json +1 -1
  105. package/plugin/README.md +5 -3
  106. package/plugin/scripts/hook-audit.sh +20 -30
  107. package/plugin/scripts/hook-common.sh +63 -0
  108. package/plugin/scripts/hook-self-audit.sh +23 -31
  109. package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +4 -2
  110. package/plugin/skills/code-auditor/SKILL.md +20 -12
@@ -11,7 +11,6 @@ export const RULE_REGISTRY = {
11
11
  analyzer: 'solid',
12
12
  field: 'rule',
13
13
  input: ['files'],
14
- gating: true,
15
14
  resolvable: true,
16
15
  message: 'Class "{name}" has {methods} methods, exceeding the maximum of {max}. Consider splitting responsibilities.',
17
16
  docs: 'solid/class-size',
@@ -32,7 +31,6 @@ export const RULE_REGISTRY = {
32
31
  analyzer: 'solid',
33
32
  field: 'rule',
34
33
  input: ['files'],
35
- gating: false,
36
34
  resolvable: false,
37
35
  message: 'Method "{name}" has cyclomatic complexity {complexity}, exceeding the maximum of {max}.',
38
36
  docs: 'solid/method-complexity',
@@ -50,7 +48,6 @@ export const RULE_REGISTRY = {
50
48
  analyzer: 'solid',
51
49
  field: 'rule',
52
50
  input: ['files'],
53
- gating: false,
54
51
  resolvable: false,
55
52
  message: 'Class "{name}" violates the Open/Closed Principle.',
56
53
  docs: 'solid/open-closed',
@@ -68,11 +65,12 @@ export const RULE_REGISTRY = {
68
65
  analyzer: 'solid',
69
66
  field: 'rule',
70
67
  input: ['files'],
71
- gating: true,
72
68
  resolvable: true,
73
- message: 'Function "{name}" has {count} {metric}, exceeding the maximum of {max}. Break it down.',
69
+ message: 'Function "{name}" mixes unrelated responsibilities. Split it into one function per concern.',
74
70
  docs: 'solid/single-responsibility',
75
- thresholds: ['maxParametersPerMethod', 'maxLinesPerMethod'],
71
+ // #131: the mixed-concern check has no tunable threshold. The size proxies
72
+ // (line count, parameter count) moved to function-length / parameter-count.
73
+ thresholds: [],
76
74
  samples: {
77
75
  valid: [
78
76
  { code: 'function parse(input) {\n return input.trim().split(",");\n}', nearMiss: true },
@@ -85,11 +83,50 @@ export const RULE_REGISTRY = {
85
83
  ],
86
84
  },
87
85
  },
86
+ 'function-length': {
87
+ analyzer: 'solid',
88
+ field: 'rule',
89
+ input: ['files'],
90
+ resolvable: true,
91
+ message: 'Function "{name}" has {lines} lines, exceeding the maximum of {max}. Consider breaking it down.',
92
+ docs: 'function-length',
93
+ thresholds: ['maxLinesPerMethod'],
94
+ samples: {
95
+ valid: [
96
+ { code: 'function short(x) {\n const a = transform(x);\n const b = validate(a);\n return b;\n}', nearMiss: true },
97
+ ],
98
+ invalid: [
99
+ {
100
+ code: 'function long(input) {\n let a = step1(input);\n let b = step2(a);\n let c = step3(b);\n let d = step4(c);\n let e = step5(d);\n let f = step6(e);\n let g = step7(f);\n let h = step8(g);\n let i = step9(h);\n let j = step10(i);\n let k = step11(j);\n let l = step12(k);\n let m = step13(l);\n let n = step14(m);\n let o = step15(n);\n let p = step16(o);\n let q = step17(p);\n let r = step18(q);\n let s = step19(r);\n let t = step20(s);\n let u = step21(t);\n let v = step22(u);\n let w = step23(v);\n let x = step24(w);\n let y = step25(x);\n let z = step26(y);\n let aa = step27(z);\n let ab = step28(aa);\n let ac = step29(ab);\n let ad = step30(ac);\n let ae = step31(ad);\n let af = step32(ae);\n let ag = step33(af);\n let ah = step34(ag);\n let ai = step35(ah);\n let aj = step36(ai);\n let ak = step37(aj);\n let al = step38(ak);\n let am = step39(al);\n let an = step40(am);\n let ao = step41(an);\n let ap = step42(ao);\n let aq = step43(ap);\n let ar = step44(aq);\n let as = step45(ar);\n let at = step46(as);\n let au = step47(at);\n let av = step48(au);\n let aw = step49(av);\n let ax = step50(aw);\n let ay = step51(ax);\n return ay;\n}',
101
+ resolution: { action: 'break-down-function', summary: 'Break "long" into smaller functions, extracting named helper blocks for each pipeline stage.', symbols: ['long'] },
102
+ },
103
+ ],
104
+ },
105
+ },
106
+ 'parameter-count': {
107
+ analyzer: 'solid',
108
+ field: 'rule',
109
+ input: ['files'],
110
+ resolvable: true,
111
+ message: 'Function "{name}" has {params} parameters, exceeding the maximum of {max}. Consider using an options object.',
112
+ docs: 'parameter-count',
113
+ thresholds: ['maxParametersPerMethod'],
114
+ samples: {
115
+ valid: [
116
+ { code: 'function combine(a, b, c, d) {\n return a + b + c + d;\n}', nearMiss: true },
117
+ ],
118
+ invalid: [
119
+ {
120
+ code: 'function combine(a, b, c, d, e) {\n return a + b + c + d + e;\n}',
121
+ resolution: { action: 'bundle-params', summary: 'Bundle the 5 parameters of "combine" into an options object.', symbols: ['a', 'b', 'c', 'd', 'e'] },
122
+ },
123
+ ],
124
+ },
125
+ },
88
126
  'solid/interface-segregation': {
89
127
  analyzer: 'solid',
90
128
  field: 'rule',
91
129
  input: ['files'],
92
- gating: false,
93
130
  resolvable: false,
94
131
  message: 'Interface "{name}" has many members.',
95
132
  docs: 'solid/interface-segregation',
@@ -107,7 +144,6 @@ export const RULE_REGISTRY = {
107
144
  analyzer: 'solid',
108
145
  field: 'rule',
109
146
  input: ['files'],
110
- gating: false,
111
147
  resolvable: false,
112
148
  message: 'Method "{name}" overrides a parent method and throws where the parent does not.',
113
149
  docs: 'solid/liskov-substitution',
@@ -125,7 +161,6 @@ export const RULE_REGISTRY = {
125
161
  analyzer: 'solid',
126
162
  field: 'rule',
127
163
  input: ['files'],
128
- gating: false,
129
164
  resolvable: false,
130
165
  message: 'Module "{name}" violates the Dependency Inversion Principle.',
131
166
  docs: 'solid/dependency-inversion',
@@ -144,7 +179,6 @@ export const RULE_REGISTRY = {
144
179
  analyzer: 'dry',
145
180
  field: 'rule',
146
181
  input: ['files'],
147
- gating: true,
148
182
  resolvable: true,
149
183
  message: 'Duplicate code block detected ({lines} lines). First occurrence at {file}:{line}.',
150
184
  docs: 'dry/duplicate',
@@ -166,7 +200,6 @@ export const RULE_REGISTRY = {
166
200
  field: 'rule',
167
201
  configGate: 'checkStructuralSimilarity',
168
202
  input: ['files'],
169
- gating: false,
170
203
  resolvable: false,
171
204
  message: 'Structurally similar code block detected ({similarity}% similar to {file}:{line}).',
172
205
  docs: 'dry/structural-similarity',
@@ -180,12 +213,47 @@ export const RULE_REGISTRY = {
180
213
  ],
181
214
  },
182
215
  },
216
+ 'dry/similar-expression': {
217
+ analyzer: 'dry',
218
+ field: 'rule',
219
+ configGate: 'checkExpressionSimilarity',
220
+ input: ['files'],
221
+ resolvable: true,
222
+ message: 'Near-identical expression detected ({shared} shared {unit}: {names}). First occurrence at {file}:{line}.',
223
+ docs: 'dry/similar-expression',
224
+ // #133: on by default. The floor (minShapeNames) counts the field/method
225
+ // names two fragments must share. Fluent library/builder chains (query and
226
+ // schema builders, Zod validators, commander, promises, DOM and stdlib
227
+ // method chains) are excluded and object literals must target the same
228
+ // identifier, so default-on stays quiet on idiomatic API surface and schema
229
+ // literals while still firing on the `resultSummary` object built twice.
230
+ thresholds: ['minShapeNames'],
231
+ samples: {
232
+ valid: [
233
+ {
234
+ // Same target assigned twice, but the field lists share nothing — a
235
+ // "built twice" shape that is not actually near-identical.
236
+ code: 'const state = {};\nstate.summary = { a: 1, b: 2, c: 3, d: 4 };\nstate.summary = { e: 5, f: 6, g: 7, h: 8 };',
237
+ nearMiss: true,
238
+ },
239
+ ],
240
+ invalid: [
241
+ {
242
+ code: 'const info = {};\ninfo.resultSummary = { completedAt: now, tables: t, tableCounts: tc, stagingCounts: sc, steps: st };\ninfo.resultSummary = { completedAt: now, tables: t, tableCounts: tc, stagingCounts: sc, steps: st, durationMs: d };',
243
+ resolution: {
244
+ action: 'extract-shared-expression',
245
+ summary: 'Extract the shared field list (completedAt, tables, tableCounts, stagingCounts, steps) into a shared builder or constant both sites use.',
246
+ symbols: ['info.resultSummary'],
247
+ },
248
+ },
249
+ ],
250
+ },
251
+ },
183
252
  'duplicate-string-literal': {
184
253
  analyzer: 'dry',
185
254
  field: 'rule',
186
255
  configGate: 'checkStrings',
187
256
  input: ['files'],
188
- gating: false,
189
257
  resolvable: false,
190
258
  message: 'String literal "{text}" is duplicated {count} times.',
191
259
  docs: 'duplicate-string-literal',
@@ -204,7 +272,6 @@ export const RULE_REGISTRY = {
204
272
  field: 'rule',
205
273
  configGate: 'checkImports',
206
274
  input: ['files'],
207
- gating: false,
208
275
  resolvable: false,
209
276
  message: 'Duplicate import of "{module}".',
210
277
  docs: 'duplicate-import',
@@ -223,7 +290,6 @@ export const RULE_REGISTRY = {
223
290
  analyzer: 'data-access',
224
291
  field: 'rule',
225
292
  input: ['files'],
226
- gating: true,
227
293
  resolvable: true,
228
294
  message: 'Potential SQL injection risk in {method}. Use parameterized queries.',
229
295
  docs: 'sql-injection-risk',
@@ -244,7 +310,6 @@ export const RULE_REGISTRY = {
244
310
  analyzer: 'data-access',
245
311
  field: 'rule',
246
312
  input: ['schema'],
247
- gating: false,
248
313
  resolvable: false,
249
314
  message: 'Query on {tables} is missing an organization/tenant filter.',
250
315
  docs: 'missing-org-filter',
@@ -262,7 +327,6 @@ export const RULE_REGISTRY = {
262
327
  analyzer: 'data-access',
263
328
  field: 'rule',
264
329
  input: ['files'],
265
- gating: false,
266
330
  resolvable: false,
267
331
  message: 'Query references {tables} tables.',
268
332
  docs: 'complex-query',
@@ -280,7 +344,6 @@ export const RULE_REGISTRY = {
280
344
  analyzer: 'data-access',
281
345
  field: 'rule',
282
346
  input: ['files'],
283
- gating: false,
284
347
  resolvable: false,
285
348
  message: 'Query on {tables} has no filter.',
286
349
  docs: 'unfiltered-query',
@@ -298,7 +361,6 @@ export const RULE_REGISTRY = {
298
361
  analyzer: 'data-access',
299
362
  field: 'rule',
300
363
  input: ['files'],
301
- gating: false,
302
364
  resolvable: false,
303
365
  message: 'Hardcoded database connection string detected.',
304
366
  docs: 'hardcoded-connection',
@@ -316,7 +378,6 @@ export const RULE_REGISTRY = {
316
378
  analyzer: 'data-access',
317
379
  field: 'rule',
318
380
  input: ['files'],
319
- gating: false,
320
381
  resolvable: false,
321
382
  message: 'Database query inside a loop detected in {method}.',
322
383
  docs: 'loop-query',
@@ -330,12 +391,47 @@ export const RULE_REGISTRY = {
330
391
  ],
331
392
  },
332
393
  },
394
+ // ── secrets (UniversalSecretsAnalyzer) ──────────────────────────────────
395
+ 'hardcoded-secret': {
396
+ analyzer: 'secrets',
397
+ field: 'rule',
398
+ configGate: 'checkHardcodedSecrets',
399
+ input: ['files'],
400
+ resolvable: true,
401
+ message: 'Hardcoded secret detected: a credential value is embedded in source. Move it to an environment variable or secret store.',
402
+ docs: 'hardcoded-secret',
403
+ thresholds: [],
404
+ samples: {
405
+ valid: [
406
+ // Placeholder value — named like a secret, but the value is a known placeholder.
407
+ { code: "const apiKey = 'your-api-key';", nearMiss: true },
408
+ // Env var reference — not a string literal, so never a candidate.
409
+ { code: 'const apiKey = process.env.API_KEY;', nearMiss: true },
410
+ ],
411
+ invalid: [
412
+ {
413
+ code: "const password = 'hunter2Secret9';",
414
+ resolution: {
415
+ action: 'remove-hardcoded-secret',
416
+ summary: 'Replace the hardcoded "password" credential with a reference to an environment variable or secret store (e.g. process.env.PASSWORD).',
417
+ symbols: ['password'],
418
+ },
419
+ },
420
+ {
421
+ code: "await page.type('#password', 'vyy8AUVvish34Fq');",
422
+ resolution: {
423
+ action: 'remove-hardcoded-secret',
424
+ summary: 'Replace the hardcoded credential with a reference to an environment variable or secret store (e.g. process.env.SECRET).',
425
+ },
426
+ },
427
+ ],
428
+ },
429
+ },
333
430
  // ── documentation (UniversalDocumentationAnalyzer) ─────────────────────
334
431
  'file-documentation': {
335
432
  analyzer: 'documentation',
336
433
  field: 'rule',
337
434
  input: ['files'],
338
- gating: false,
339
435
  resolvable: false,
340
436
  message: 'File is missing a leading documentation comment.',
341
437
  docs: 'file-documentation',
@@ -353,7 +449,6 @@ export const RULE_REGISTRY = {
353
449
  analyzer: 'documentation',
354
450
  field: 'rule',
355
451
  input: ['files'],
356
- gating: false,
357
452
  resolvable: false,
358
453
  message: 'Function "{name}" is missing a doc comment.',
359
454
  docs: 'function-documentation',
@@ -371,7 +466,6 @@ export const RULE_REGISTRY = {
371
466
  analyzer: 'documentation',
372
467
  field: 'rule',
373
468
  input: ['files'],
374
- gating: false,
375
469
  resolvable: false,
376
470
  message: 'Parameter "{name}" in function "{func}" is missing a @param tag.',
377
471
  docs: 'parameter-documentation',
@@ -389,7 +483,6 @@ export const RULE_REGISTRY = {
389
483
  analyzer: 'documentation',
390
484
  field: 'rule',
391
485
  input: ['files'],
392
- gating: false,
393
486
  resolvable: false,
394
487
  message: 'Function "{name}" is missing a @returns tag.',
395
488
  docs: 'return-documentation',
@@ -407,7 +500,6 @@ export const RULE_REGISTRY = {
407
500
  analyzer: 'documentation',
408
501
  field: 'rule',
409
502
  input: ['files'],
410
- gating: false,
411
503
  resolvable: false,
412
504
  message: 'Class "{name}" is missing a doc comment.',
413
505
  docs: 'class-documentation',
@@ -425,7 +517,6 @@ export const RULE_REGISTRY = {
425
517
  analyzer: 'documentation',
426
518
  field: 'rule',
427
519
  input: ['files'],
428
- gating: false,
429
520
  resolvable: false,
430
521
  message: 'Method "{name}" is missing a doc comment.',
431
522
  docs: 'method-documentation',
@@ -445,7 +536,6 @@ export const RULE_REGISTRY = {
445
536
  analyzer: 'schema',
446
537
  field: 'rule',
447
538
  input: ['schema-json'],
448
- gating: false,
449
539
  resolvable: false,
450
540
  message: 'Invalid JSON: {error}.',
451
541
  docs: 'invalid-json',
@@ -463,7 +553,6 @@ export const RULE_REGISTRY = {
463
553
  analyzer: 'schema',
464
554
  field: 'rule',
465
555
  input: ['schema-json'],
466
- gating: false,
467
556
  resolvable: false,
468
557
  message: 'Missing JSON schema declaration.',
469
558
  docs: 'missing-schema-declaration',
@@ -481,7 +570,6 @@ export const RULE_REGISTRY = {
481
570
  analyzer: 'schema',
482
571
  field: 'rule',
483
572
  input: ['schema-json'],
484
- gating: false,
485
573
  resolvable: false,
486
574
  message: 'Undefined required field "{field}".',
487
575
  docs: 'undefined-required-field',
@@ -499,7 +587,6 @@ export const RULE_REGISTRY = {
499
587
  analyzer: 'schema',
500
588
  field: 'rule',
501
589
  input: ['schema-json'],
502
- gating: false,
503
590
  resolvable: false,
504
591
  message: 'Invalid type for field "{field}".',
505
592
  docs: 'invalid-type',
@@ -517,7 +604,6 @@ export const RULE_REGISTRY = {
517
604
  analyzer: 'schema',
518
605
  field: 'rule',
519
606
  input: ['schema-json'],
520
- gating: false,
521
607
  resolvable: false,
522
608
  message: 'Invalid range for field "{field}".',
523
609
  docs: 'invalid-range',
@@ -535,7 +621,6 @@ export const RULE_REGISTRY = {
535
621
  analyzer: 'schema',
536
622
  field: 'rule',
537
623
  input: ['schema-json'],
538
- gating: false,
539
624
  resolvable: false,
540
625
  message: 'Error processing schema file: {error}.',
541
626
  docs: 'file-error',
@@ -553,7 +638,6 @@ export const RULE_REGISTRY = {
553
638
  analyzer: 'schema',
554
639
  field: 'rule',
555
640
  input: ['schema-json'],
556
- gating: false,
557
641
  resolvable: false,
558
642
  message: 'Type mismatch for field "{field}".',
559
643
  docs: 'type-mismatch',
@@ -571,7 +655,6 @@ export const RULE_REGISTRY = {
571
655
  analyzer: 'schema',
572
656
  field: 'rule',
573
657
  input: ['schema-json'],
574
- gating: false,
575
658
  resolvable: false,
576
659
  message: 'String value too short for field "{field}".',
577
660
  docs: 'string-too-short',
@@ -589,7 +672,6 @@ export const RULE_REGISTRY = {
589
672
  analyzer: 'schema',
590
673
  field: 'rule',
591
674
  input: ['schema-json'],
592
- gating: false,
593
675
  resolvable: false,
594
676
  message: 'String value too long for field "{field}".',
595
677
  docs: 'string-too-long',
@@ -607,7 +689,6 @@ export const RULE_REGISTRY = {
607
689
  analyzer: 'schema',
608
690
  field: 'rule',
609
691
  input: ['schema-json'],
610
- gating: false,
611
692
  resolvable: false,
612
693
  message: 'Value does not match pattern for field "{field}".',
613
694
  docs: 'pattern-mismatch',
@@ -625,7 +706,6 @@ export const RULE_REGISTRY = {
625
706
  analyzer: 'schema',
626
707
  field: 'rule',
627
708
  input: ['schema-json'],
628
- gating: false,
629
709
  resolvable: false,
630
710
  message: 'Invalid format for field "{field}".',
631
711
  docs: 'invalid-format',
@@ -643,7 +723,6 @@ export const RULE_REGISTRY = {
643
723
  analyzer: 'schema',
644
724
  field: 'rule',
645
725
  input: ['schema-json'],
646
- gating: false,
647
726
  resolvable: false,
648
727
  message: 'Value below minimum for field "{field}".',
649
728
  docs: 'below-minimum',
@@ -661,7 +740,6 @@ export const RULE_REGISTRY = {
661
740
  analyzer: 'schema',
662
741
  field: 'rule',
663
742
  input: ['schema-json'],
664
- gating: false,
665
743
  resolvable: false,
666
744
  message: 'Value above maximum for field "{field}".',
667
745
  docs: 'above-maximum',
@@ -679,7 +757,6 @@ export const RULE_REGISTRY = {
679
757
  analyzer: 'schema',
680
758
  field: 'rule',
681
759
  input: ['schema-json'],
682
- gating: false,
683
760
  resolvable: false,
684
761
  message: 'Too few items for field "{field}".',
685
762
  docs: 'too-few-items',
@@ -697,7 +774,6 @@ export const RULE_REGISTRY = {
697
774
  analyzer: 'schema',
698
775
  field: 'rule',
699
776
  input: ['schema-json'],
700
- gating: false,
701
777
  resolvable: false,
702
778
  message: 'Too many items for field "{field}".',
703
779
  docs: 'too-many-items',
@@ -715,7 +791,6 @@ export const RULE_REGISTRY = {
715
791
  analyzer: 'schema',
716
792
  field: 'rule',
717
793
  input: ['schema-json'],
718
- gating: false,
719
794
  resolvable: false,
720
795
  message: 'Missing required field "{field}".',
721
796
  docs: 'missing-required-field',
@@ -733,7 +808,6 @@ export const RULE_REGISTRY = {
733
808
  analyzer: 'schema',
734
809
  field: 'rule',
735
810
  input: ['schema-json'],
736
- gating: false,
737
811
  resolvable: false,
738
812
  message: 'Unexpected property "{property}".',
739
813
  docs: 'unexpected-property',
@@ -751,7 +825,6 @@ export const RULE_REGISTRY = {
751
825
  analyzer: 'schema',
752
826
  field: 'rule',
753
827
  input: ['schema-json'],
754
- gating: false,
755
828
  resolvable: false,
756
829
  message: 'Value does not match any enum value for field "{field}".',
757
830
  docs: 'enum-mismatch',
@@ -770,7 +843,6 @@ export const RULE_REGISTRY = {
770
843
  analyzer: 'schema',
771
844
  field: 'rule',
772
845
  input: ['schema-code'],
773
- gating: false,
774
846
  resolvable: false,
775
847
  message: 'Potential SQL injection via string interpolation in {method}.',
776
848
  docs: 'sql-injection',
@@ -791,7 +863,6 @@ export const RULE_REGISTRY = {
791
863
  field: 'rule',
792
864
  configGate: 'checkNamingConventions',
793
865
  input: ['schema-code'],
794
- gating: false,
795
866
  resolvable: false,
796
867
  message: 'Table name "{table}" should use snake_case convention.',
797
868
  docs: 'table-naming-convention',
@@ -810,7 +881,6 @@ export const RULE_REGISTRY = {
810
881
  analyzer: 'schema',
811
882
  field: 'rule',
812
883
  input: ['schema-code'],
813
- gating: true,
814
884
  resolvable: true,
815
885
  message: 'Reference to unknown table "{table}" ({type}). Did you mean: {suggestions}?',
816
886
  docs: 'unknown-table',
@@ -832,7 +902,6 @@ export const RULE_REGISTRY = {
832
902
  analyzer: 'react',
833
903
  field: 'rule',
834
904
  input: ['files'],
835
- gating: false,
836
905
  resolvable: false,
837
906
  message: 'React hook "{name}" does not follow the "use*" naming convention.',
838
907
  docs: 'hooks-naming',
@@ -850,7 +919,6 @@ export const RULE_REGISTRY = {
850
919
  analyzer: 'react',
851
920
  field: 'rule',
852
921
  input: ['files'],
853
- gating: false,
854
922
  resolvable: false,
855
923
  message: 'React component "{name}" has complexity {complexity}, exceeding the maximum.',
856
924
  docs: 'complexity',
@@ -869,7 +937,6 @@ export const RULE_REGISTRY = {
869
937
  field: 'rule',
870
938
  configGate: 'requirePropTypes',
871
939
  input: ['files'],
872
- gating: false,
873
940
  resolvable: false,
874
941
  message: 'React component "{name}" is missing prop-types.',
875
942
  docs: 'missing-props',
@@ -887,7 +954,6 @@ export const RULE_REGISTRY = {
887
954
  analyzer: 'react',
888
955
  field: 'rule',
889
956
  input: ['files'],
890
- gating: false,
891
957
  resolvable: false,
892
958
  message: 'React component tree is missing an error boundary.',
893
959
  docs: 'no-error-boundary',
@@ -906,7 +972,6 @@ export const RULE_REGISTRY = {
906
972
  field: 'rule',
907
973
  configGate: 'requireMemoization',
908
974
  input: ['files'],
909
- gating: false,
910
975
  resolvable: false,
911
976
  message: 'React component "{name}" is missing memoization.',
912
977
  docs: 'performance',
@@ -924,7 +989,6 @@ export const RULE_REGISTRY = {
924
989
  analyzer: 'react',
925
990
  field: 'rule',
926
991
  input: ['files'],
927
- gating: false,
928
992
  resolvable: false,
929
993
  message: 'Accessibility issue in component "{name}": {issue}.',
930
994
  docs: 'accessibility',
@@ -942,7 +1006,6 @@ export const RULE_REGISTRY = {
942
1006
  analyzer: 'react',
943
1007
  field: 'rule',
944
1008
  input: ['files'],
945
- gating: true,
946
1009
  resolvable: true,
947
1010
  message: 'raw `<{element}>` — this project uses `<{wrapper}>` ({file}).',
948
1011
  docs: 'raw-element',
@@ -965,7 +1028,6 @@ export const RULE_REGISTRY = {
965
1028
  analyzer: 'invariants',
966
1029
  field: 'rule',
967
1030
  input: ['files'],
968
- gating: false,
969
1031
  resolvable: false,
970
1032
  message: 'Invalid invariant config: {error}.',
971
1033
  docs: 'config-error',
@@ -983,7 +1045,6 @@ export const RULE_REGISTRY = {
983
1045
  analyzer: 'invariants',
984
1046
  field: 'rule',
985
1047
  input: ['files'],
986
- gating: false,
987
1048
  resolvable: false,
988
1049
  message: 'Invariant rule engine error: {error}.',
989
1050
  docs: 'engine-error',
@@ -1002,7 +1063,6 @@ export const RULE_REGISTRY = {
1002
1063
  analyzer: 'schema-validator',
1003
1064
  field: 'rule',
1004
1065
  input: ['cross-language-entities'],
1005
- gating: false,
1006
1066
  resolvable: false,
1007
1067
  message: 'Field mismatch: {detail}.',
1008
1068
  docs: 'field-mismatch',
@@ -1020,7 +1080,6 @@ export const RULE_REGISTRY = {
1020
1080
  analyzer: 'schema-validator',
1021
1081
  field: 'rule',
1022
1082
  input: ['cross-language-entities'],
1023
- gating: false,
1024
1083
  resolvable: false,
1025
1084
  message: 'Schema field type-name strings differ: {detail}.',
1026
1085
  docs: 'schema-field-mismatch',
@@ -1038,7 +1097,6 @@ export const RULE_REGISTRY = {
1038
1097
  analyzer: 'schema-validator',
1039
1098
  field: 'rule',
1040
1099
  input: ['cross-language-entities'],
1041
- gating: false,
1042
1100
  resolvable: false,
1043
1101
  message: 'Missing field: {field}.',
1044
1102
  docs: 'missing-field',
@@ -1056,7 +1114,6 @@ export const RULE_REGISTRY = {
1056
1114
  analyzer: 'schema-validator',
1057
1115
  field: 'rule',
1058
1116
  input: ['cross-language-entities'],
1059
- gating: false,
1060
1117
  resolvable: false,
1061
1118
  message: 'Extra field: {field}.',
1062
1119
  docs: 'extra-field',
@@ -1074,7 +1131,6 @@ export const RULE_REGISTRY = {
1074
1131
  analyzer: 'schema-validator',
1075
1132
  field: 'rule',
1076
1133
  input: ['cross-language-entities'],
1077
- gating: false,
1078
1134
  resolvable: false,
1079
1135
  message: 'Constraint mismatch: {detail}.',
1080
1136
  docs: 'constraint-mismatch',
@@ -1092,7 +1148,6 @@ export const RULE_REGISTRY = {
1092
1148
  analyzer: 'schema-validator',
1093
1149
  field: 'rule',
1094
1150
  input: ['cross-language-entities'],
1095
- gating: false,
1096
1151
  resolvable: false,
1097
1152
  message: 'Version mismatch: {detail}.',
1098
1153
  docs: 'version-mismatch',
@@ -1111,7 +1166,6 @@ export const RULE_REGISTRY = {
1111
1166
  analyzer: 'api-contract',
1112
1167
  field: 'rule',
1113
1168
  input: ['cross-language-entities'],
1114
- gating: false,
1115
1169
  resolvable: false,
1116
1170
  message: 'API type mismatch: {detail}.',
1117
1171
  docs: 'api-type-mismatch',
@@ -1129,7 +1183,6 @@ export const RULE_REGISTRY = {
1129
1183
  analyzer: 'api-contract',
1130
1184
  field: 'rule',
1131
1185
  input: ['cross-language-entities'],
1132
- gating: false,
1133
1186
  resolvable: false,
1134
1187
  message: 'Missing API endpoint: {endpoint}.',
1135
1188
  docs: 'missing-endpoint',
@@ -1147,7 +1200,6 @@ export const RULE_REGISTRY = {
1147
1200
  analyzer: 'api-contract',
1148
1201
  field: 'rule',
1149
1202
  input: ['cross-language-entities'],
1150
- gating: false,
1151
1203
  resolvable: false,
1152
1204
  message: 'Extra field in API response: {field}.',
1153
1205
  docs: 'api-extra-field',
@@ -1165,7 +1217,6 @@ export const RULE_REGISTRY = {
1165
1217
  analyzer: 'api-contract',
1166
1218
  field: 'rule',
1167
1219
  input: ['cross-language-entities'],
1168
- gating: false,
1169
1220
  resolvable: false,
1170
1221
  message: 'Missing field in API response: {field}.',
1171
1222
  docs: 'api-missing-field',
@@ -1183,7 +1234,6 @@ export const RULE_REGISTRY = {
1183
1234
  analyzer: 'api-contract',
1184
1235
  field: 'rule',
1185
1236
  input: ['cross-language-entities'],
1186
- gating: false,
1187
1237
  resolvable: false,
1188
1238
  message: 'HTTP method mismatch: {detail}.',
1189
1239
  docs: 'method-mismatch',
@@ -1201,7 +1251,6 @@ export const RULE_REGISTRY = {
1201
1251
  analyzer: 'api-contract',
1202
1252
  field: 'rule',
1203
1253
  input: ['cross-language-entities'],
1204
- gating: false,
1205
1254
  resolvable: false,
1206
1255
  message: 'Authentication mismatch: {detail}.',
1207
1256
  docs: 'auth-mismatch',
@@ -1220,7 +1269,6 @@ export const RULE_REGISTRY = {
1220
1269
  analyzer: 'dependency-graph',
1221
1270
  field: 'type',
1222
1271
  input: ['cross-language-entities'],
1223
- gating: false,
1224
1272
  resolvable: false,
1225
1273
  message: 'Circular dependency detected: {cycle}.',
1226
1274
  docs: 'circular-dependency',
@@ -1238,7 +1286,6 @@ export const RULE_REGISTRY = {
1238
1286
  analyzer: 'dependency-graph',
1239
1287
  field: 'type',
1240
1288
  input: ['cross-language-entities'],
1241
- gating: false,
1242
1289
  resolvable: false,
1243
1290
  message: 'Break dependency cycle: {cycle}.',
1244
1291
  docs: 'break-cycles',
@@ -1256,7 +1303,6 @@ export const RULE_REGISTRY = {
1256
1303
  analyzer: 'dependency-graph',
1257
1304
  field: 'type',
1258
1305
  input: ['cross-language-entities'],
1259
- gating: false,
1260
1306
  resolvable: false,
1261
1307
  message: 'Tight coupling detected between {a} and {b}.',
1262
1308
  docs: 'tight-coupling',
@@ -1274,7 +1320,6 @@ export const RULE_REGISTRY = {
1274
1320
  analyzer: 'dependency-graph',
1275
1321
  field: 'type',
1276
1322
  input: ['cross-language-entities'],
1277
- gating: false,
1278
1323
  resolvable: false,
1279
1324
  message: 'Reduce coupling between {a} and {b}.',
1280
1325
  docs: 'reduce-coupling',
@@ -1292,7 +1337,6 @@ export const RULE_REGISTRY = {
1292
1337
  analyzer: 'dependency-graph',
1293
1338
  field: 'type',
1294
1339
  input: ['cross-language-entities'],
1295
- gating: false,
1296
1340
  resolvable: false,
1297
1341
  message: 'Hub node "{node}" has {count} dependencies.',
1298
1342
  docs: 'hub-nodes',
@@ -1310,7 +1354,6 @@ export const RULE_REGISTRY = {
1310
1354
  analyzer: 'dependency-graph',
1311
1355
  field: 'type',
1312
1356
  input: ['cross-language-entities'],
1313
- gating: false,
1314
1357
  resolvable: false,
1315
1358
  message: 'Split responsibilities of node "{node}".',
1316
1359
  docs: 'split-responsibilities',
@@ -1328,7 +1371,6 @@ export const RULE_REGISTRY = {
1328
1371
  analyzer: 'dependency-graph',
1329
1372
  field: 'type',
1330
1373
  input: ['cross-language-entities'],
1331
- gating: false,
1332
1374
  resolvable: false,
1333
1375
  message: 'Orphaned node "{node}" has no connections.',
1334
1376
  docs: 'orphaned-nodes',
@@ -1346,7 +1388,6 @@ export const RULE_REGISTRY = {
1346
1388
  analyzer: 'dependency-graph',
1347
1389
  field: 'type',
1348
1390
  input: ['cross-language-entities'],
1349
- gating: false,
1350
1391
  resolvable: false,
1351
1392
  message: 'Review orphaned nodes: {nodes}.',
1352
1393
  docs: 'review-orphans',
@@ -1360,12 +1401,28 @@ export const RULE_REGISTRY = {
1360
1401
  ],
1361
1402
  },
1362
1403
  },
1404
+ 'unreferenced-module': {
1405
+ analyzer: 'dependency-graph',
1406
+ field: 'type',
1407
+ input: ['cross-language-entities'],
1408
+ resolvable: false,
1409
+ message: 'Module is not imported by any other file and is not a framework entry point — dead code candidate.',
1410
+ docs: 'unreferenced-module',
1411
+ thresholds: [],
1412
+ samples: {
1413
+ valid: [
1414
+ { code: 'export function used() {}', nearMiss: true },
1415
+ ],
1416
+ invalid: [
1417
+ { code: '// file exports symbols but nothing imports it' },
1418
+ ],
1419
+ },
1420
+ },
1363
1421
  // ── styles (UniversalStylesAnalyzer) ─────────────────────────────────────
1364
1422
  'styles/value-drift': {
1365
1423
  analyzer: 'styles',
1366
1424
  field: 'rule',
1367
1425
  input: ['styles-css'],
1368
- gating: false,
1369
1426
  resolvable: false,
1370
1427
  message: 'Color value "{value}" drifts from the dominant token.',
1371
1428
  docs: 'styles/value-drift',
@@ -1383,7 +1440,6 @@ export const RULE_REGISTRY = {
1383
1440
  analyzer: 'styles',
1384
1441
  field: 'rule',
1385
1442
  input: ['styles-css'],
1386
- gating: false,
1387
1443
  resolvable: false,
1388
1444
  message: 'Value "{value}" is off the project\'s design scale.',
1389
1445
  docs: 'styles/off-scale',
@@ -1401,7 +1457,6 @@ export const RULE_REGISTRY = {
1401
1457
  analyzer: 'styles',
1402
1458
  field: 'rule',
1403
1459
  input: ['styles-css'],
1404
- gating: true,
1405
1460
  resolvable: true,
1406
1461
  message: 'Undefined CSS class: "{class}" has no matching definition.',
1407
1462
  docs: 'styles/undefined-class',
@@ -1422,7 +1477,6 @@ export const RULE_REGISTRY = {
1422
1477
  analyzer: 'styles',
1423
1478
  field: 'rule',
1424
1479
  input: ['styles-css'],
1425
- gating: false,
1426
1480
  resolvable: false,
1427
1481
  message: 'Undefined-class detection skipped: {reason}.',
1428
1482
  docs: 'styles/undefined-class-disabled',
@@ -1440,7 +1494,6 @@ export const RULE_REGISTRY = {
1440
1494
  analyzer: 'styles',
1441
1495
  field: 'rule',
1442
1496
  input: ['styles-css'],
1443
- gating: false,
1444
1497
  resolvable: false,
1445
1498
  message: 'Token bypass: raw value "{value}" used instead of a design token.',
1446
1499
  docs: 'styles/token-bypass',
@@ -1458,7 +1511,6 @@ export const RULE_REGISTRY = {
1458
1511
  analyzer: 'styles',
1459
1512
  field: 'rule',
1460
1513
  input: ['styles-css'],
1461
- gating: false,
1462
1514
  resolvable: false,
1463
1515
  message: 'Styling mechanism fragmented across {count} mechanisms.',
1464
1516
  docs: 'styles/mechanism-fragmentation',
@@ -1476,7 +1528,6 @@ export const RULE_REGISTRY = {
1476
1528
  analyzer: 'styles',
1477
1529
  field: 'rule',
1478
1530
  input: ['styles-css'],
1479
- gating: false,
1480
1531
  resolvable: false,
1481
1532
  message: 'Mixing styling mechanisms in one file.',
1482
1533
  docs: 'styles/mechanism-mixing',
@@ -1494,7 +1545,6 @@ export const RULE_REGISTRY = {
1494
1545
  analyzer: 'styles',
1495
1546
  field: 'rule',
1496
1547
  input: ['styles-css'],
1497
- gating: false,
1498
1548
  resolvable: false,
1499
1549
  message: 'Declaration set similar to another block ({similarity}%).',
1500
1550
  docs: 'styles/declaration-set-similarity',
@@ -1512,7 +1562,6 @@ export const RULE_REGISTRY = {
1512
1562
  analyzer: 'styles',
1513
1563
  field: 'rule',
1514
1564
  input: ['styles-css'],
1515
- gating: false,
1516
1565
  resolvable: false,
1517
1566
  message: 'Z-index sprawl: {count} distinct z-index values.',
1518
1567
  docs: 'styles/z-index-sprawl',
@@ -1530,7 +1579,6 @@ export const RULE_REGISTRY = {
1530
1579
  analyzer: 'styles',
1531
1580
  field: 'rule',
1532
1581
  input: ['styles-css'],
1533
- gating: false,
1534
1582
  resolvable: false,
1535
1583
  message: 'Z-index value "{value}" appears only once.',
1536
1584
  docs: 'styles/z-index-singleton',
@@ -1549,7 +1597,6 @@ export const RULE_REGISTRY = {
1549
1597
  analyzer: 'conventions',
1550
1598
  field: 'rule',
1551
1599
  input: ['function-index'],
1552
- gating: true,
1553
1600
  resolvable: true,
1554
1601
  message: '{pct}% of `{antecedent}` callers also call `{consequent}`.',
1555
1602
  docs: 'conventions/usage-pair',
@@ -1570,7 +1617,6 @@ export const RULE_REGISTRY = {
1570
1617
  analyzer: 'conventions',
1571
1618
  field: 'rule',
1572
1619
  input: ['function-index'],
1573
- gating: false,
1574
1620
  resolvable: false,
1575
1621
  message: 'Import form mismatch: use {form} for "{source}".',
1576
1622
  docs: 'conventions/import-form',
@@ -1588,7 +1634,6 @@ export const RULE_REGISTRY = {
1588
1634
  analyzer: 'conventions',
1589
1635
  field: 'rule',
1590
1636
  input: ['function-index'],
1591
- gating: false,
1592
1637
  resolvable: false,
1593
1638
  message: 'Error-handling convention mismatch: {detail}.',
1594
1639
  docs: 'conventions/error-handling',
@@ -1606,7 +1651,6 @@ export const RULE_REGISTRY = {
1606
1651
  analyzer: 'conventions',
1607
1652
  field: 'rule',
1608
1653
  input: ['function-index'],
1609
- gating: false,
1610
1654
  resolvable: false,
1611
1655
  message: 'Export shape mismatch: {detail}.',
1612
1656
  docs: 'conventions/export-shape',
@@ -1624,7 +1668,6 @@ export const RULE_REGISTRY = {
1624
1668
  analyzer: 'conventions',
1625
1669
  field: 'rule',
1626
1670
  input: ['function-index'],
1627
- gating: false,
1628
1671
  resolvable: false,
1629
1672
  message: 'Naming convention mismatch: {detail}.',
1630
1673
  docs: 'conventions/naming',
@@ -1643,7 +1686,6 @@ export const RULE_REGISTRY = {
1643
1686
  analyzer: 'cross-domain',
1644
1687
  field: 'rule',
1645
1688
  input: ['schema_usage', 'functions'],
1646
- gating: false,
1647
1689
  resolvable: false,
1648
1690
  message: 'Table "{table}" is written but never read.',
1649
1691
  docs: 'cross-domain/written-never-read',
@@ -1661,7 +1703,6 @@ export const RULE_REGISTRY = {
1661
1703
  analyzer: 'cross-domain',
1662
1704
  field: 'rule',
1663
1705
  input: ['schema_usage', 'functions'],
1664
- gating: false,
1665
1706
  resolvable: false,
1666
1707
  message: 'Table "{table}" is read but never written.',
1667
1708
  docs: 'cross-domain/read-never-written',
@@ -1679,7 +1720,6 @@ export const RULE_REGISTRY = {
1679
1720
  analyzer: 'cross-domain',
1680
1721
  field: 'rule',
1681
1722
  input: ['schema_usage', 'functions'],
1682
- gating: false,
1683
1723
  resolvable: false,
1684
1724
  message: 'Transaction boundary spans {count} tables.',
1685
1725
  docs: 'cross-domain/transaction-boundary',
@@ -1697,7 +1737,6 @@ export const RULE_REGISTRY = {
1697
1737
  analyzer: 'cross-domain',
1698
1738
  field: 'rule',
1699
1739
  input: ['schema_usage', 'functions'],
1700
- gating: false,
1701
1740
  resolvable: false,
1702
1741
  message: 'Validation bypass: {detail}.',
1703
1742
  docs: 'cross-domain/validation-bypass',
@@ -1715,7 +1754,6 @@ export const RULE_REGISTRY = {
1715
1754
  analyzer: 'cross-domain',
1716
1755
  field: 'rule',
1717
1756
  input: ['schema_usage', 'functions'],
1718
- gating: false,
1719
1757
  resolvable: false,
1720
1758
  message: 'Uncovered risk: {detail}.',
1721
1759
  docs: 'cross-domain/uncovered-risk',
@@ -1765,11 +1803,13 @@ export const MCP_DEFAULT_ANALYZERS = [
1765
1803
  * The registry records which field on the Violation carries the rule ID
1766
1804
  * (`field` — `rule` for almost every analyzer, `type` for dependency-graph).
1767
1805
  * This helper reads that field off the violation and matches it against the
1768
- * registry key, so gate decisions (Spec 36 R4/R6) never hard-code a field.
1806
+ * registry key, so the gate's resolution-gap detection (Spec 45 R1) never
1807
+ * hard-codes a field.
1769
1808
  *
1770
1809
  * Invariant violations (user-defined rule IDs) have no registry entry and
1771
- * return `undefined` they are always "new" and never gating (their gate
1772
- * decision is made by the invariant rule engine, not this map).
1810
+ * return `undefined`. They still gate (Spec 45 R1) the gate blocks on every
1811
+ * finding at a blocking severity; the registry only determines whether a
1812
+ * missing resolution is a recorded gap.
1773
1813
  */
1774
1814
  export function getViolationRuleEntry(v) {
1775
1815
  if (!v.analyzer)