@kernlang/review 3.3.7 → 3.3.9

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 (53) hide show
  1. package/dist/cache.js +1 -1
  2. package/dist/concept-rules/auth-propagation-drift.d.ts +10 -0
  3. package/dist/concept-rules/auth-propagation-drift.js +83 -0
  4. package/dist/concept-rules/auth-propagation-drift.js.map +1 -0
  5. package/dist/concept-rules/body-shape-drift.d.ts +32 -0
  6. package/dist/concept-rules/body-shape-drift.js +96 -0
  7. package/dist/concept-rules/body-shape-drift.js.map +1 -0
  8. package/dist/concept-rules/cross-stack-utils.d.ts +24 -0
  9. package/dist/concept-rules/cross-stack-utils.js +123 -29
  10. package/dist/concept-rules/cross-stack-utils.js.map +1 -1
  11. package/dist/concept-rules/index.d.ts +4 -2
  12. package/dist/concept-rules/index.js +56 -4
  13. package/dist/concept-rules/index.js.map +1 -1
  14. package/dist/concept-rules/mutation-without-idempotency.d.ts +10 -0
  15. package/dist/concept-rules/mutation-without-idempotency.js +47 -0
  16. package/dist/concept-rules/mutation-without-idempotency.js.map +1 -0
  17. package/dist/concept-rules/param-name-swap.d.ts +22 -0
  18. package/dist/concept-rules/param-name-swap.js +120 -0
  19. package/dist/concept-rules/param-name-swap.js.map +1 -0
  20. package/dist/concept-rules/request-validation-drift.d.ts +11 -0
  21. package/dist/concept-rules/request-validation-drift.js +96 -0
  22. package/dist/concept-rules/request-validation-drift.js.map +1 -0
  23. package/dist/concept-rules/unbounded-collection-query.d.ts +10 -0
  24. package/dist/concept-rules/unbounded-collection-query.js +56 -0
  25. package/dist/concept-rules/unbounded-collection-query.js.map +1 -0
  26. package/dist/concept-rules/unhandled-api-error-shape.d.ts +10 -0
  27. package/dist/concept-rules/unhandled-api-error-shape.js +57 -0
  28. package/dist/concept-rules/unhandled-api-error-shape.js.map +1 -0
  29. package/dist/external-tools.js +52 -3
  30. package/dist/external-tools.js.map +1 -1
  31. package/dist/index.d.ts +13 -0
  32. package/dist/index.js +188 -38
  33. package/dist/index.js.map +1 -1
  34. package/dist/mappers/ts-concepts.js +663 -1
  35. package/dist/mappers/ts-concepts.js.map +1 -1
  36. package/dist/python-fallback.d.ts +2 -0
  37. package/dist/python-fallback.js +506 -0
  38. package/dist/python-fallback.js.map +1 -0
  39. package/dist/reporter.js +84 -1
  40. package/dist/reporter.js.map +1 -1
  41. package/dist/rules/async.js +159 -1
  42. package/dist/rules/async.js.map +1 -1
  43. package/dist/rules/base.js +21 -3
  44. package/dist/rules/base.js.map +1 -1
  45. package/dist/rules/index.js +40 -0
  46. package/dist/rules/index.js.map +1 -1
  47. package/dist/rules/kern-source.js +1 -0
  48. package/dist/rules/kern-source.js.map +1 -1
  49. package/dist/rules/suggest-kern-primitive.js +5 -5
  50. package/dist/rules/suggest-kern-primitive.js.map +1 -1
  51. package/dist/types.d.ts +25 -0
  52. package/dist/types.js.map +1 -1
  53. package/package.json +2 -2
package/dist/cache.js CHANGED
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync
3
3
  import { homedir } from 'os';
4
4
  import { dirname, join, resolve } from 'path';
5
5
  // Version stamp for cache invalidation — changes when rules/analyzers change
6
- const REVIEW_CACHE_VERSION = '3.2.3-review-cache-3';
6
+ const REVIEW_CACHE_VERSION = '3.3.9-review-cache-1';
7
7
  const IMPORT_SPECIFIER_RE = /(?:import|export)\s+(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]|import\(\s*['"]([^'"]+)['"]\s*\)/g;
8
8
  const EXTENSION_FALLBACK = {
9
9
  '.js': ['.ts', '.tsx', '.mts', '.cts'],
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Rule: auth-propagation-drift
3
+ *
4
+ * Cross-stack rule — complements `auth-drift` by catching non-raw-fetch API
5
+ * clients (axios/got/ky-style direct calls) that call an authenticated server
6
+ * route without visible auth/session propagation.
7
+ */
8
+ import type { ReviewFinding } from '../types.js';
9
+ import type { ConceptRuleContext } from './index.js';
10
+ export declare function authPropagationDrift(ctx: ConceptRuleContext): ReviewFinding[];
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Rule: auth-propagation-drift
3
+ *
4
+ * Cross-stack rule — complements `auth-drift` by catching non-raw-fetch API
5
+ * clients (axios/got/ky-style direct calls) that call an authenticated server
6
+ * route without visible auth/session propagation.
7
+ */
8
+ import { createFingerprint } from '../types.js';
9
+ import { CROSS_STACK_EXACT_CONFIDENCE, collectRoutesAcrossGraph, findHighConfidenceRouteForMethod, findMatchingRouteForMethod, normalizeClientUrl, } from './cross-stack-utils.js';
10
+ export function authPropagationDrift(ctx) {
11
+ if (!ctx.allConcepts || ctx.allConcepts.size === 0)
12
+ return [];
13
+ const serverRoutes = collectRoutesAcrossGraph(ctx.allConcepts);
14
+ if (serverRoutes.length === 0)
15
+ return [];
16
+ const authGuardContainers = collectAuthGuardContainers(ctx.allConcepts);
17
+ if (authGuardContainers.size === 0)
18
+ return [];
19
+ const findings = [];
20
+ const localConcepts = ctx.allConcepts.get(ctx.filePath) ?? ctx.concepts;
21
+ for (const node of localConcepts.nodes) {
22
+ if (node.kind !== 'effect' || node.payload.kind !== 'effect' || node.payload.subtype !== 'network')
23
+ continue;
24
+ if (node.payload.authPropagation !== 'absent')
25
+ continue;
26
+ // `auth-drift` owns the raw fetch/no Authorization case for backward
27
+ // compatibility with the existing rule ID. This rule covers richer clients.
28
+ if (node.payload.hasAuthHeader === false)
29
+ continue;
30
+ const target = node.payload.target;
31
+ if (typeof target !== 'string')
32
+ continue;
33
+ const normalized = normalizeClientUrl(target);
34
+ if (!normalized)
35
+ continue;
36
+ const route = ctx.crossStackMode === 'audit'
37
+ ? findMatchingRouteForMethod(normalized, node.payload.method, serverRoutes)
38
+ : findHighConfidenceRouteForMethod(normalized, node.payload.method, serverRoutes);
39
+ if (!route?.node)
40
+ continue;
41
+ const fileGuards = authGuardContainers.get(route.node.primarySpan.file);
42
+ if (!fileGuards)
43
+ continue;
44
+ const routeContainer = route.node.containerId;
45
+ const guardedByContainer = routeContainer !== undefined && fileGuards.routeContainers.has(routeContainer);
46
+ const guardedBySingleRouteFile = fileGuards.totalRoutesInFile === 1;
47
+ if (!guardedByContainer && !guardedBySingleRouteFile)
48
+ continue;
49
+ findings.push({
50
+ source: 'kern',
51
+ ruleId: 'auth-propagation-drift',
52
+ severity: 'warning',
53
+ category: 'bug',
54
+ message: `Client calls authenticated route \`${target}\` without visible auth/session propagation. Add an Authorization/Cookie/session credential path or route this call through an authenticated client wrapper.`,
55
+ primarySpan: node.primarySpan,
56
+ relatedSpans: [route.node.primarySpan],
57
+ fingerprint: createFingerprint('auth-propagation-drift', node.primarySpan.startLine, node.primarySpan.startCol),
58
+ confidence: node.confidence * CROSS_STACK_EXACT_CONFIDENCE,
59
+ });
60
+ }
61
+ return findings;
62
+ }
63
+ function collectAuthGuardContainers(allConcepts) {
64
+ const result = new Map();
65
+ for (const [filePath, map] of allConcepts) {
66
+ const routeContainers = new Set();
67
+ let routeCount = 0;
68
+ for (const node of map.nodes) {
69
+ if (node.kind === 'entrypoint' && node.payload.kind === 'entrypoint' && node.payload.subtype === 'route') {
70
+ routeCount++;
71
+ continue;
72
+ }
73
+ if (node.kind !== 'guard' || node.payload.kind !== 'guard' || node.payload.subtype !== 'auth')
74
+ continue;
75
+ if (node.containerId !== undefined)
76
+ routeContainers.add(node.containerId);
77
+ }
78
+ if (routeContainers.size > 0)
79
+ result.set(filePath, { routeContainers, totalRoutesInFile: routeCount });
80
+ }
81
+ return result;
82
+ }
83
+ //# sourceMappingURL=auth-propagation-drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-propagation-drift.js","sourceRoot":"","sources":["../../src/concept-rules/auth-propagation-drift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Rule: body-shape-drift
3
+ *
4
+ * Cross-stack rule — fires when a client `fetch(url, { body: JSON.stringify({ … }) })`
5
+ * omits one or more fields that the matching server handler reads off
6
+ * `req.body` (Express inline handler). Classic LLM-authored drift:
7
+ *
8
+ * client: fetch('/api/users', { body: JSON.stringify({ name }) })
9
+ * server: app.post('/api/users', (req, res) => {
10
+ * const { name, email } = req.body; // ← email never sent
11
+ * ...
12
+ * });
13
+ *
14
+ * V1 is deliberately narrow per the red-team consensus on the body-shape
15
+ * plan:
16
+ * - Express only (no Pydantic/FastAPI cross-file model resolution).
17
+ * - Raw `fetch` only on the client (no axios/ky/got/wrapper clients).
18
+ * - Inline handlers only (imported-identifier handlers stay silent).
19
+ * - Missing-fields direction only (client omits what server needs). The
20
+ * "extra" direction (client sends what server ignores) conflicts with
21
+ * legitimate pass-through handlers and is deferred.
22
+ * - Fires only when BOTH `sentFieldsResolved` and `bodyFieldsResolved`
23
+ * are true. Opaque bodies, wrapper clients, whole-body forwarding all
24
+ * stay silent by design — false negatives are the price of zero
25
+ * false positives.
26
+ *
27
+ * Requires graph mode: the client call and server route live in different
28
+ * files by definition. Single-file review returns no findings.
29
+ */
30
+ import type { ReviewFinding } from '../types.js';
31
+ import type { ConceptRuleContext } from './index.js';
32
+ export declare function bodyShapeDrift(ctx: ConceptRuleContext): ReviewFinding[];
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Rule: body-shape-drift
3
+ *
4
+ * Cross-stack rule — fires when a client `fetch(url, { body: JSON.stringify({ … }) })`
5
+ * omits one or more fields that the matching server handler reads off
6
+ * `req.body` (Express inline handler). Classic LLM-authored drift:
7
+ *
8
+ * client: fetch('/api/users', { body: JSON.stringify({ name }) })
9
+ * server: app.post('/api/users', (req, res) => {
10
+ * const { name, email } = req.body; // ← email never sent
11
+ * ...
12
+ * });
13
+ *
14
+ * V1 is deliberately narrow per the red-team consensus on the body-shape
15
+ * plan:
16
+ * - Express only (no Pydantic/FastAPI cross-file model resolution).
17
+ * - Raw `fetch` only on the client (no axios/ky/got/wrapper clients).
18
+ * - Inline handlers only (imported-identifier handlers stay silent).
19
+ * - Missing-fields direction only (client omits what server needs). The
20
+ * "extra" direction (client sends what server ignores) conflicts with
21
+ * legitimate pass-through handlers and is deferred.
22
+ * - Fires only when BOTH `sentFieldsResolved` and `bodyFieldsResolved`
23
+ * are true. Opaque bodies, wrapper clients, whole-body forwarding all
24
+ * stay silent by design — false negatives are the price of zero
25
+ * false positives.
26
+ *
27
+ * Requires graph mode: the client call and server route live in different
28
+ * files by definition. Single-file review returns no findings.
29
+ */
30
+ import { createFingerprint } from '../types.js';
31
+ import { API_PATH_RE, CROSS_STACK_HEURISTIC_CONFIDENCE, collectRoutesAcrossGraph, findMatchingRoute, normalizeClientUrl, } from './cross-stack-utils.js';
32
+ export function bodyShapeDrift(ctx) {
33
+ if (!ctx.allConcepts || ctx.allConcepts.size === 0)
34
+ return [];
35
+ const serverRoutes = collectRoutesAcrossGraph(ctx.allConcepts);
36
+ if (serverRoutes.length === 0)
37
+ return [];
38
+ const clientCalls = [];
39
+ for (const [, conceptMap] of ctx.allConcepts) {
40
+ for (const node of conceptMap.nodes) {
41
+ if (node.kind !== 'effect' || node.payload.kind !== 'effect' || node.payload.subtype !== 'network')
42
+ continue;
43
+ if (node.payload.sentFieldsResolved !== true)
44
+ continue;
45
+ const fields = node.payload.sentFields;
46
+ if (!fields)
47
+ continue;
48
+ const target = node.payload.target;
49
+ if (typeof target !== 'string')
50
+ continue;
51
+ const normalized = normalizeClientUrl(target);
52
+ if (!normalized || !API_PATH_RE.test(normalized))
53
+ continue;
54
+ clientCalls.push({ target, normalizedPath: normalized, sentFields: fields, node });
55
+ }
56
+ }
57
+ if (clientCalls.length === 0)
58
+ return [];
59
+ const findings = [];
60
+ const seen = new Set();
61
+ for (const call of clientCalls) {
62
+ if (call.node.primarySpan.file !== ctx.filePath)
63
+ continue;
64
+ const route = findMatchingRoute(call.normalizedPath, serverRoutes);
65
+ if (!route || !route.node)
66
+ continue;
67
+ if (route.node.payload.kind !== 'entrypoint')
68
+ continue;
69
+ if (route.node.payload.bodyFieldsResolved !== true)
70
+ continue;
71
+ const serverFields = route.node.payload.bodyFields;
72
+ if (!serverFields || serverFields.length === 0)
73
+ continue;
74
+ const missing = serverFields.filter((f) => !call.sentFields.includes(f));
75
+ if (missing.length === 0)
76
+ continue;
77
+ const fingerprint = createFingerprint('body-shape-drift', call.node.primarySpan.startLine, call.node.primarySpan.startCol);
78
+ if (seen.has(fingerprint))
79
+ continue;
80
+ seen.add(fingerprint);
81
+ const missingList = missing.map((f) => `\`${f}\``).join(', ');
82
+ const plural = missing.length === 1 ? 'field' : 'fields';
83
+ findings.push({
84
+ source: 'kern',
85
+ ruleId: 'body-shape-drift',
86
+ severity: 'warning',
87
+ category: 'bug',
88
+ message: `Frontend POSTs to \`${call.normalizedPath}\` without ${plural} ${missingList}, but the matching server handler reads ${missing.length === 1 ? 'it' : 'them'} off \`req.body\`. The handler will see \`undefined\` for the missing ${plural}.`,
89
+ primarySpan: call.node.primarySpan,
90
+ fingerprint,
91
+ confidence: call.node.confidence * CROSS_STACK_HEURISTIC_CONFIDENCE,
92
+ });
93
+ }
94
+ return findings;
95
+ }
96
+ //# sourceMappingURL=body-shape-drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-shape-drift.js","sourceRoot":"","sources":["../../src/concept-rules/body-shape-drift.ts"],"names":[],"mappings":"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"}
@@ -84,6 +84,17 @@ export declare function normalizeClientUrl(raw: string): string | undefined;
84
84
  * behaviour).
85
85
  */
86
86
  export declare function findMatchingRoute(clientPath: string, routes: readonly ServerRoute[]): ServerRoute | undefined;
87
+ export declare function findMatchingRouteForMethod(clientPath: string, clientMethod: string | undefined, routes: readonly ServerRoute[]): ServerRoute | undefined;
88
+ /**
89
+ * Noise-gated route match for newer cross-stack rules.
90
+ *
91
+ * The older matcher intentionally returns the first path-shaped match so
92
+ * legacy rules retain broad coverage. Newer rules that can feel speculative
93
+ * should use this helper instead: it requires a known client method, exactly
94
+ * one matching server route for that method, a concrete internal API path, and
95
+ * no catch-all/wildcard route shapes.
96
+ */
97
+ export declare function findHighConfidenceRouteForMethod(clientPath: string, clientMethod: string | undefined, routes: readonly ServerRoute[]): ServerRoute | undefined;
87
98
  /** Boolean-returning thin wrapper preserved for callers that just need a yes/no. */
88
99
  export declare function hasMatchingRoute(clientPath: string, routes: readonly ServerRoute[]): boolean;
89
100
  /**
@@ -94,3 +105,16 @@ export declare function hasMatchingRoute(clientPath: string, routes: readonly Se
94
105
  * no one calls it" (method-drift / orphan-route territory).
95
106
  */
96
107
  export declare function findRoutesAtPath(clientPath: string, routes: readonly ServerRoute[]): ServerRoute[];
108
+ export declare function routeMethodMatches(routeMethod: string | undefined, clientMethod: string): boolean;
109
+ /**
110
+ * Resolve an inline Express handler's concept from a route node. Only
111
+ * meaningful for `route` entrypoints whose mapper set `handlerConceptId`
112
+ * (inline arrow/function handlers — not imported identifiers). Returns
113
+ * undefined when the route has no inline handler or the expected concept
114
+ * is absent from the map (e.g., stripped during serialisation).
115
+ *
116
+ * Rules that reason about handler body contents — body-shape drift, auth
117
+ * checks, response envelope detection — use this as the single lookup
118
+ * point so callers don't re-implement span-or-id matching in each rule.
119
+ */
120
+ export declare function findHandlerConcept(map: ConceptMap, route: ConceptNode): ConceptNode | undefined;
@@ -197,25 +197,52 @@ export function normalizeClientUrl(raw) {
197
197
  export function findMatchingRoute(clientPath, routes) {
198
198
  const clientSegments = trimTrailing(clientPath).split('/');
199
199
  for (const route of routes) {
200
- const routeSegments = trimTrailing(route.path).split('/');
201
- if (routeSegments.length !== clientSegments.length)
200
+ if (routePathMatchesSegments(route.path, clientSegments))
201
+ return route;
202
+ }
203
+ return undefined;
204
+ }
205
+ export function findMatchingRouteForMethod(clientPath, clientMethod, routes) {
206
+ const clientSegments = trimTrailing(clientPath).split('/');
207
+ for (const route of routes) {
208
+ if (!routePathMatchesSegments(route.path, clientSegments))
202
209
  continue;
203
- let matched = true;
204
- for (let i = 0; i < routeSegments.length; i++) {
205
- const rs = routeSegments[i];
206
- const cs = clientSegments[i];
207
- if (isParamSegment(rs))
208
- continue;
209
- if (rs !== cs) {
210
- matched = false;
211
- break;
212
- }
213
- }
214
- if (matched)
210
+ if (!clientMethod || routeMethodMatches(route.method, clientMethod))
215
211
  return route;
216
212
  }
217
213
  return undefined;
218
214
  }
215
+ /**
216
+ * Noise-gated route match for newer cross-stack rules.
217
+ *
218
+ * The older matcher intentionally returns the first path-shaped match so
219
+ * legacy rules retain broad coverage. Newer rules that can feel speculative
220
+ * should use this helper instead: it requires a known client method, exactly
221
+ * one matching server route for that method, a concrete internal API path, and
222
+ * no catch-all/wildcard route shapes.
223
+ */
224
+ export function findHighConfidenceRouteForMethod(clientPath, clientMethod, routes) {
225
+ if (!isHighConfidenceClientPath(clientPath))
226
+ return undefined;
227
+ if (!clientMethod)
228
+ return undefined;
229
+ const matches = findRoutesAtPath(clientPath, routes).filter((route) => {
230
+ if (!route.node)
231
+ return false;
232
+ if (route.node.confidence < 0.75)
233
+ return false;
234
+ if (!route.method)
235
+ return false;
236
+ if (WILDCARD_METHODS.has(route.method.toUpperCase()))
237
+ return false;
238
+ if (!routeMethodMatches(route.method, clientMethod))
239
+ return false;
240
+ if (!isHighConfidenceServerPath(route.path))
241
+ return false;
242
+ return true;
243
+ });
244
+ return matches.length === 1 ? matches[0] : undefined;
245
+ }
219
246
  /** Boolean-returning thin wrapper preserved for callers that just need a yes/no. */
220
247
  export function hasMatchingRoute(clientPath, routes) {
221
248
  return findMatchingRoute(clientPath, routes) !== undefined;
@@ -231,21 +258,7 @@ export function findRoutesAtPath(clientPath, routes) {
231
258
  const clientSegments = trimTrailing(clientPath).split('/');
232
259
  const matches = [];
233
260
  for (const route of routes) {
234
- const routeSegments = trimTrailing(route.path).split('/');
235
- if (routeSegments.length !== clientSegments.length)
236
- continue;
237
- let matched = true;
238
- for (let i = 0; i < routeSegments.length; i++) {
239
- const rs = routeSegments[i];
240
- const cs = clientSegments[i];
241
- if (isParamSegment(rs))
242
- continue;
243
- if (rs !== cs) {
244
- matched = false;
245
- break;
246
- }
247
- }
248
- if (matched)
261
+ if (routePathMatchesSegments(route.path, clientSegments))
249
262
  matches.push(route);
250
263
  }
251
264
  return matches;
@@ -253,6 +266,87 @@ export function findRoutesAtPath(clientPath, routes) {
253
266
  function trimTrailing(path) {
254
267
  return path.length > 1 && path.endsWith('/') ? path.slice(0, -1) : path;
255
268
  }
269
+ function routePathMatchesSegments(routePath, clientSegments) {
270
+ const routeSegments = trimTrailing(routePath).split('/');
271
+ if (routeSegments.length !== clientSegments.length)
272
+ return false;
273
+ for (let i = 0; i < routeSegments.length; i++) {
274
+ const rs = routeSegments[i];
275
+ const cs = clientSegments[i];
276
+ if (isParamSegment(rs))
277
+ continue;
278
+ if (rs !== cs)
279
+ return false;
280
+ }
281
+ return true;
282
+ }
283
+ function isHighConfidenceClientPath(path) {
284
+ if (!API_PATH_RE.test(path))
285
+ return false;
286
+ if (hasCatchAllOrWildcardSegment(path))
287
+ return false;
288
+ const segments = trimTrailing(path).split('/').filter(Boolean);
289
+ return segments.every((segment) => {
290
+ if (!segment.includes('${'))
291
+ return true;
292
+ return /^\$\{[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)?\}$/.test(segment);
293
+ });
294
+ }
295
+ function isHighConfidenceServerPath(path) {
296
+ if (!API_PATH_RE.test(path))
297
+ return false;
298
+ return !hasCatchAllOrWildcardSegment(path);
299
+ }
300
+ function hasCatchAllOrWildcardSegment(path) {
301
+ return trimTrailing(path)
302
+ .split('/')
303
+ .some((segment) => {
304
+ if (!segment)
305
+ return false;
306
+ if (segment === '*' || segment.includes('...'))
307
+ return true;
308
+ if (segment.startsWith('*'))
309
+ return true;
310
+ if (/^\{[^}:]+:path\}$/.test(segment))
311
+ return true;
312
+ return false;
313
+ });
314
+ }
315
+ // Verbs emitted by route declarations that intentionally accept any method.
316
+ const WILDCARD_METHODS = new Set(['ALL', 'ANY']);
317
+ export function routeMethodMatches(routeMethod, clientMethod) {
318
+ if (!routeMethod)
319
+ return true;
320
+ const r = routeMethod.toUpperCase();
321
+ if (WILDCARD_METHODS.has(r))
322
+ return true;
323
+ const c = clientMethod.toUpperCase();
324
+ if (r === c)
325
+ return true;
326
+ // Express and Starlette/FastAPI both auto-respond to HEAD on GET routes.
327
+ if (c === 'HEAD' && r === 'GET')
328
+ return true;
329
+ return false;
330
+ }
331
+ /**
332
+ * Resolve an inline Express handler's concept from a route node. Only
333
+ * meaningful for `route` entrypoints whose mapper set `handlerConceptId`
334
+ * (inline arrow/function handlers — not imported identifiers). Returns
335
+ * undefined when the route has no inline handler or the expected concept
336
+ * is absent from the map (e.g., stripped during serialisation).
337
+ *
338
+ * Rules that reason about handler body contents — body-shape drift, auth
339
+ * checks, response envelope detection — use this as the single lookup
340
+ * point so callers don't re-implement span-or-id matching in each rule.
341
+ */
342
+ export function findHandlerConcept(map, route) {
343
+ if (route.kind !== 'entrypoint' || route.payload.kind !== 'entrypoint')
344
+ return undefined;
345
+ const handlerId = route.payload.handlerConceptId;
346
+ if (!handlerId)
347
+ return undefined;
348
+ return map.nodes.find((n) => n.id === handlerId);
349
+ }
256
350
  function isParamSegment(seg) {
257
351
  return seg.startsWith(':') || (seg.startsWith('{') && seg.endsWith('}'));
258
352
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cross-stack-utils.js","sourceRoot":"","sources":["../../src/concept-rules/cross-stack-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cross-stack-utils.js","sourceRoot":"","sources":["../../src/concept-rules/cross-stack-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD,kEAAkE;AAClE,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AAStC,MAAM,UAAU,kBAAkB,CAAC,GAAe;IAChD,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;YAAE,OAAO,KAAK,CAAC;QACnF,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,IAAiB,EAAE,GAAgB;IACpF,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,KAAK,CAAC;IACnF,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IAC7C,OAAO,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,GAAe,EAAE,MAAqB;IAClE,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO;YAAE,SAAS;QACnH,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAChE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAA4C;IACnF,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,oEAAoE;IACpE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAoB,CAAC;IACnD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAwD,CAAC;IACvF,KAAK,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,WAAW,EAAE,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;gBAAE,SAAS;YAC/E,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,aAAa;gBAAE,SAAS;YACrD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YACjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;YAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;YAC/C,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;gBACpD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAClB,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YACzC,CAAC;YACD,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;gBAClD,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;gBACjC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,WAAW,EAAE,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;gBAAE,SAAS;YAC/E,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO;gBAAE,SAAS;YAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YAEhE,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;YACtG,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB,CACzB,SAAiB,EACjB,UAA8B,EAC9B,cAA6C,EAC7C,cAAiF;IAEjF,6EAA6E;IAC7E,+EAA+E;IAC/E,kFAAkF;IAClF,6EAA6E;IAC7E,yEAAyE;IACzE,KAAK,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,IAAI,cAAc,EAAE,CAAC;QACtD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACpC,MAAM,OAAO,GAAG,6BAA6B,CAAC,IAAI,CAAC,YAAY,CAAC;YAC9D,CAAC,CAAC,YAAY;YACd,CAAC,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC;QAC7C,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,OAAO,EAAE,CAAC;YAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC;IACD,iFAAiF;IACjF,uEAAuE;IACvE,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC/C,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;YAChE,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC,MAAM,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAC,MAAc,EAAE,IAAY;IAC7C,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1E,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC7D,IAAI,WAAW,KAAK,GAAG;QAAE,OAAO,aAAa,IAAI,GAAG,CAAC;IACrD,OAAO,GAAG,aAAa,GAAG,WAAW,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACnE,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAChC,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5D,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3D,GAAG,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACtD,CAAC;IACD,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,KAAK,CAAC,CAAC;QAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,KAAK,CAAC,CAAC;QAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpC,OAAO,GAAG,IAAI,SAAS,CAAC;AAC1B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB,EAAE,MAA8B;IAClF,MAAM,cAAc,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,wBAAwB,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC;YAAE,OAAO,KAAK,CAAC;IACzE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,UAAkB,EAClB,YAAgC,EAChC,MAA8B;IAE9B,MAAM,cAAc,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC;YAAE,SAAS;QACpE,IAAI,CAAC,YAAY,IAAI,kBAAkB,CAAC,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC;YAAE,OAAO,KAAK,CAAC;IACpF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gCAAgC,CAC9C,UAAkB,EAClB,YAAgC,EAChC,MAA8B;IAE9B,IAAI,CAAC,0BAA0B,CAAC,UAAU,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9D,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IAEpC,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QACpE,IAAI,CAAC,KAAK,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAC9B,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI;YAAE,OAAO,KAAK,CAAC;QAC/C,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;QACnE,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC;YAAE,OAAO,KAAK,CAAC;QAClE,IAAI,CAAC,0BAA0B,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,MAA8B;IACjF,OAAO,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,SAAS,CAAC;AAC7D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,MAA8B;IACjF,MAAM,cAAc,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,wBAAwB,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAiB,EAAE,cAAiC;IACpF,MAAM,aAAa,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzD,IAAI,aAAa,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACjE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,cAAc,CAAC,EAAE,CAAC;YAAE,SAAS;QACjC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,KAAK,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,0BAA0B,CAAC,IAAY;IAC9C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,4BAA4B,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/D,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE;QAChC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,OAAO,iDAAiD,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,0BAA0B,CAAC,IAAY;IAC9C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,OAAO,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,4BAA4B,CAAC,IAAY;IAChD,OAAO,YAAY,CAAC,IAAI,CAAC;SACtB,KAAK,CAAC,GAAG,CAAC;SACV,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;QAChB,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5D,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,IAAI,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QACnD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACP,CAAC;AAED,4EAA4E;AAC5E,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAEjD,MAAM,UAAU,kBAAkB,CAAC,WAA+B,EAAE,YAAoB;IACtF,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,CAAC,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;IACpC,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,CAAC,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,yEAAyE;IACzE,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAe,EAAE,KAAkB;IACpE,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,SAAS,CAAC;IACzF,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC;IACjD,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3E,CAAC"}
@@ -5,7 +5,7 @@
5
5
  * Language-agnostic by design.
6
6
  */
7
7
  import type { ConceptMap } from '@kernlang/core';
8
- import type { ReviewFinding } from '../types.js';
8
+ import type { ReviewConfig, ReviewFinding } from '../types.js';
9
9
  export interface ConceptRuleContext {
10
10
  concepts: ConceptMap;
11
11
  filePath: string;
@@ -13,7 +13,9 @@ export interface ConceptRuleContext {
13
13
  allConcepts?: Map<string, ConceptMap>;
14
14
  /** Resolved import graph — filePath → imported file paths */
15
15
  graphImports?: Map<string, string[]>;
16
+ /** Cross-stack precision mode. Defaults to guard. */
17
+ crossStackMode?: 'guard' | 'audit';
16
18
  }
17
19
  export type ConceptRule = (ctx: ConceptRuleContext) => ReviewFinding[];
18
20
  export declare const conceptRules: ConceptRule[];
19
- export declare function runConceptRules(concepts: ConceptMap, filePath: string, allConcepts?: Map<string, ConceptMap>, graphImports?: Map<string, string[]>): ReviewFinding[];
21
+ export declare function runConceptRules(concepts: ConceptMap, filePath: string, allConcepts?: Map<string, ConceptMap>, graphImports?: Map<string, string[]>, config?: Pick<ReviewConfig, 'crossStackMode'>): ReviewFinding[];
@@ -5,41 +5,93 @@
5
5
  * Language-agnostic by design.
6
6
  */
7
7
  import { authDrift } from './auth-drift.js';
8
+ import { authPropagationDrift } from './auth-propagation-drift.js';
9
+ import { bodyShapeDrift } from './body-shape-drift.js';
8
10
  import { boundaryMutation } from './boundary-mutation.js';
9
11
  import { contractDrift } from './contract-drift.js';
10
12
  import { contractMethodDrift } from './contract-method-drift.js';
11
13
  import { duplicateRoute } from './duplicate-route.js';
12
14
  import { ignoredError } from './ignored-error.js';
13
15
  import { missingResponseModel } from './missing-response-model.js';
16
+ import { mutationWithoutIdempotency } from './mutation-without-idempotency.js';
14
17
  import { orphanRoute } from './orphan-route.js';
18
+ import { paramNameSwap } from './param-name-swap.js';
19
+ import { requestValidationDrift } from './request-validation-drift.js';
15
20
  import { syncHandlerDoesIo } from './sync-handler-does-io.js';
16
21
  import { taintedAcrossWire } from './tainted-across-wire.js';
22
+ import { unboundedCollectionQuery } from './unbounded-collection-query.js';
17
23
  import { unguardedEffect } from './unguarded-effect.js';
24
+ import { unhandledApiErrorShape } from './unhandled-api-error-shape.js';
18
25
  import { unrecoveredEffect } from './unrecovered-effect.js';
19
26
  import { untypedApiResponse } from './untyped-api-response.js';
20
27
  import { untypedBothEndsResponse } from './untyped-both-ends-response.js';
21
28
  export const conceptRules = [
22
29
  authDrift,
30
+ authPropagationDrift,
31
+ bodyShapeDrift,
23
32
  boundaryMutation,
24
33
  contractDrift,
25
34
  contractMethodDrift,
26
35
  duplicateRoute,
27
36
  ignoredError,
28
37
  missingResponseModel,
29
- syncHandlerDoesIo,
38
+ mutationWithoutIdempotency,
30
39
  orphanRoute,
40
+ paramNameSwap,
41
+ requestValidationDrift,
42
+ syncHandlerDoesIo,
31
43
  taintedAcrossWire,
44
+ unboundedCollectionQuery,
32
45
  unguardedEffect,
46
+ unhandledApiErrorShape,
33
47
  unrecoveredEffect,
34
48
  untypedApiResponse,
35
49
  untypedBothEndsResponse,
36
50
  ];
37
- export function runConceptRules(concepts, filePath, allConcepts, graphImports) {
38
- const ctx = { concepts, filePath, allConcepts, graphImports };
51
+ export function runConceptRules(concepts, filePath, allConcepts, graphImports, config) {
52
+ const ctx = {
53
+ concepts,
54
+ filePath,
55
+ allConcepts,
56
+ graphImports,
57
+ crossStackMode: config?.crossStackMode,
58
+ };
39
59
  const findings = [];
40
60
  for (const rule of conceptRules) {
41
61
  findings.push(...rule(ctx));
42
62
  }
43
- return findings;
63
+ if (ctx.crossStackMode === 'audit')
64
+ return findings;
65
+ return suppressOverlappingNewRuleFindings(findings);
66
+ }
67
+ const NEW_RULE_OWNERS = {
68
+ 'auth-propagation-drift': ['auth-drift'],
69
+ 'unhandled-api-error-shape': ['auth-drift', 'contract-drift', 'contract-method-drift'],
70
+ 'unbounded-collection-query': ['contract-drift', 'contract-method-drift'],
71
+ 'request-validation-drift': ['body-shape-drift', 'contract-drift', 'contract-method-drift'],
72
+ };
73
+ function suppressOverlappingNewRuleFindings(findings) {
74
+ const ownerSpans = new Map();
75
+ for (const finding of findings) {
76
+ const spanKey = findingSpanKey(finding);
77
+ for (const owners of Object.values(NEW_RULE_OWNERS)) {
78
+ if (!owners.includes(finding.ruleId))
79
+ continue;
80
+ const existing = ownerSpans.get(finding.ruleId) ?? new Set();
81
+ existing.add(spanKey);
82
+ ownerSpans.set(finding.ruleId, existing);
83
+ }
84
+ }
85
+ return findings.filter((finding) => {
86
+ const owners = NEW_RULE_OWNERS[finding.ruleId];
87
+ if (!owners)
88
+ return true;
89
+ const spanKey = findingSpanKey(finding);
90
+ return !owners.some((owner) => ownerSpans.get(owner)?.has(spanKey));
91
+ });
92
+ }
93
+ function findingSpanKey(finding) {
94
+ const span = finding.primarySpan;
95
+ return `${span.file}:${span.startLine}:${span.startCol}`;
44
96
  }
45
97
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/concept-rules/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAa1E,MAAM,CAAC,MAAM,YAAY,GAAkB;IACzC,SAAS;IACT,gBAAgB;IAChB,aAAa;IACb,mBAAmB;IACnB,cAAc;IACd,YAAY;IACZ,oBAAoB;IACpB,iBAAiB;IACjB,WAAW;IACX,iBAAiB;IACjB,eAAe;IACf,iBAAiB;IACjB,kBAAkB;IAClB,uBAAuB;CACxB,CAAC;AAEF,MAAM,UAAU,eAAe,CAC7B,QAAoB,EACpB,QAAgB,EAChB,WAAqC,EACrC,YAAoC;IAEpC,MAAM,GAAG,GAAuB,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;IAClF,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/concept-rules/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAe1E,MAAM,CAAC,MAAM,YAAY,GAAkB;IACzC,SAAS;IACT,oBAAoB;IACpB,cAAc;IACd,gBAAgB;IAChB,aAAa;IACb,mBAAmB;IACnB,cAAc;IACd,YAAY;IACZ,oBAAoB;IACpB,0BAA0B;IAC1B,WAAW;IACX,aAAa;IACb,sBAAsB;IACtB,iBAAiB;IACjB,iBAAiB;IACjB,wBAAwB;IACxB,eAAe;IACf,sBAAsB;IACtB,iBAAiB;IACjB,kBAAkB;IAClB,uBAAuB;CACxB,CAAC;AAEF,MAAM,UAAU,eAAe,CAC7B,QAAoB,EACpB,QAAgB,EAChB,WAAqC,EACrC,YAAoC,EACpC,MAA6C;IAE7C,MAAM,GAAG,GAAuB;QAC9B,QAAQ;QACR,QAAQ;QACR,WAAW;QACX,YAAY;QACZ,cAAc,EAAE,MAAM,EAAE,cAAc;KACvC,CAAC;IACF,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,GAAG,CAAC,cAAc,KAAK,OAAO;QAAE,OAAO,QAAQ,CAAC;IACpD,OAAO,kCAAkC,CAAC,QAAQ,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,eAAe,GAAsC;IACzD,wBAAwB,EAAE,CAAC,YAAY,CAAC;IACxC,2BAA2B,EAAE,CAAC,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,CAAC;IACtF,4BAA4B,EAAE,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IACzE,0BAA0B,EAAE,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,uBAAuB,CAAC;CAC5F,CAAC;AAEF,SAAS,kCAAkC,CAAC,QAAkC;IAC5E,MAAM,UAAU,GAAG,IAAI,GAAG,EAAuB,CAAC;IAClD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACxC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,SAAS;YAC/C,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;YACrE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACtB,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QACjC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,cAAc,CAAC,OAAsB;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;IACjC,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Rule: mutation-without-idempotency
3
+ *
4
+ * Backend rule — fires on mutating HTTP routes that perform a DB write without
5
+ * visible idempotency, transaction, unique/upsert, or duplicate-protection
6
+ * evidence.
7
+ */
8
+ import type { ReviewFinding } from '../types.js';
9
+ import type { ConceptRuleContext } from './index.js';
10
+ export declare function mutationWithoutIdempotency(ctx: ConceptRuleContext): ReviewFinding[];