@kernlang/review 3.1.6 → 3.1.8
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.
- package/dist/cache.d.ts +1 -1
- package/dist/cache.js +5 -3
- package/dist/cache.js.map +1 -1
- package/dist/call-graph.d.ts +63 -0
- package/dist/call-graph.js +380 -0
- package/dist/call-graph.js.map +1 -0
- package/dist/concept-rules/boundary-mutation.d.ts +1 -1
- package/dist/concept-rules/boundary-mutation.js.map +1 -1
- package/dist/concept-rules/ignored-error.d.ts +1 -1
- package/dist/concept-rules/ignored-error.js.map +1 -1
- package/dist/concept-rules/illegal-dependency.d.ts +1 -1
- package/dist/concept-rules/illegal-dependency.js.map +1 -1
- package/dist/concept-rules/index.js +1 -6
- package/dist/concept-rules/index.js.map +1 -1
- package/dist/concept-rules/unguarded-effect.d.ts +1 -1
- package/dist/concept-rules/unguarded-effect.js.map +1 -1
- package/dist/concept-rules/unrecovered-effect.d.ts +1 -1
- package/dist/concept-rules/unrecovered-effect.js +2 -1
- package/dist/concept-rules/unrecovered-effect.js.map +1 -1
- package/dist/confidence.js +12 -8
- package/dist/confidence.js.map +1 -1
- package/dist/differ.js +3 -7
- package/dist/differ.js.map +1 -1
- package/dist/external-tools.js +5 -6
- package/dist/external-tools.js.map +1 -1
- package/dist/file-context.d.ts +21 -0
- package/dist/file-context.js +234 -0
- package/dist/file-context.js.map +1 -0
- package/dist/file-role.js +14 -7
- package/dist/file-role.js.map +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/graph.js +24 -16
- package/dist/graph.js.map +1 -1
- package/dist/index.d.ts +44 -35
- package/dist/index.js +210 -121
- package/dist/index.js.map +1 -1
- package/dist/inferrer.d.ts +8 -2
- package/dist/inferrer.js +80 -47
- package/dist/inferrer.js.map +1 -1
- package/dist/kern-lint.d.ts +3 -4
- package/dist/kern-lint.js +7 -5
- package/dist/kern-lint.js.map +1 -1
- package/dist/llm-bridge.d.ts +23 -7
- package/dist/llm-bridge.js +267 -31
- package/dist/llm-bridge.js.map +1 -1
- package/dist/llm-review.d.ts +16 -2
- package/dist/llm-review.js +240 -35
- package/dist/llm-review.js.map +1 -1
- package/dist/mappers/ts-concepts.d.ts +1 -1
- package/dist/mappers/ts-concepts.js +303 -32
- package/dist/mappers/ts-concepts.js.map +1 -1
- package/dist/norm-miner.d.ts +31 -0
- package/dist/norm-miner.js +119 -0
- package/dist/norm-miner.js.map +1 -0
- package/dist/obligations.d.ts +63 -0
- package/dist/obligations.js +158 -0
- package/dist/obligations.js.map +1 -0
- package/dist/quality-rules.d.ts +3 -3
- package/dist/quality-rules.js +4 -2
- package/dist/quality-rules.js.map +1 -1
- package/dist/reporter.d.ts +7 -2
- package/dist/reporter.js +82 -51
- package/dist/reporter.js.map +1 -1
- package/dist/rule-eval.d.ts +1 -2
- package/dist/rule-eval.js +5 -9
- package/dist/rule-eval.js.map +1 -1
- package/dist/rule-loader.js +16 -14
- package/dist/rule-loader.js.map +1 -1
- package/dist/rules/base.js +153 -69
- package/dist/rules/base.js.map +1 -1
- package/dist/rules/cli.js +23 -19
- package/dist/rules/cli.js.map +1 -1
- package/dist/rules/confidence.d.ts +1 -1
- package/dist/rules/confidence.js +5 -5
- package/dist/rules/confidence.js.map +1 -1
- package/dist/rules/dead-code.d.ts +10 -0
- package/dist/rules/dead-code.js +75 -0
- package/dist/rules/dead-code.js.map +1 -0
- package/dist/rules/dead-logic.js +35 -31
- package/dist/rules/dead-logic.js.map +1 -1
- package/dist/rules/express.d.ts +2 -1
- package/dist/rules/express.js +380 -126
- package/dist/rules/express.js.map +1 -1
- package/dist/rules/fastapi.js +53 -19
- package/dist/rules/fastapi.js.map +1 -1
- package/dist/rules/ground-layer.js +3 -3
- package/dist/rules/ground-layer.js.map +1 -1
- package/dist/rules/index.js +574 -105
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/ink.js +9 -8
- package/dist/rules/ink.js.map +1 -1
- package/dist/rules/kern-source.js +202 -63
- package/dist/rules/kern-source.js.map +1 -1
- package/dist/rules/nextjs.js +88 -33
- package/dist/rules/nextjs.js.map +1 -1
- package/dist/rules/null-safety.js +52 -26
- package/dist/rules/null-safety.js.map +1 -1
- package/dist/rules/nuxt.js +24 -29
- package/dist/rules/nuxt.js.map +1 -1
- package/dist/rules/react.js +355 -69
- package/dist/rules/react.js.map +1 -1
- package/dist/rules/security-v2.js +71 -57
- package/dist/rules/security-v2.js.map +1 -1
- package/dist/rules/security-v3.js.map +1 -1
- package/dist/rules/security-v4.js +54 -27
- package/dist/rules/security-v4.js.map +1 -1
- package/dist/rules/security.js +35 -5
- package/dist/rules/security.js.map +1 -1
- package/dist/rules/terminal.js +17 -5
- package/dist/rules/terminal.js.map +1 -1
- package/dist/rules/vue.js +162 -107
- package/dist/rules/vue.js.map +1 -1
- package/dist/semantic-diff.d.ts +52 -0
- package/dist/semantic-diff.js +342 -0
- package/dist/semantic-diff.js.map +1 -0
- package/dist/spec-checker.js +11 -10
- package/dist/spec-checker.js.map +1 -1
- package/dist/suppression/apply-suppression.d.ts +2 -3
- package/dist/suppression/apply-suppression.js +3 -3
- package/dist/suppression/apply-suppression.js.map +1 -1
- package/dist/suppression/index.d.ts +2 -2
- package/dist/suppression/index.js +1 -1
- package/dist/suppression/index.js.map +1 -1
- package/dist/suppression/parse-directives.d.ts +1 -1
- package/dist/suppression/parse-directives.js +9 -4
- package/dist/suppression/parse-directives.js.map +1 -1
- package/dist/taint-ast.d.ts +20 -0
- package/dist/taint-ast.js +427 -0
- package/dist/taint-ast.js.map +1 -0
- package/dist/taint-crossfile.d.ts +28 -0
- package/dist/taint-crossfile.js +174 -0
- package/dist/taint-crossfile.js.map +1 -0
- package/dist/taint-findings.d.ts +17 -0
- package/dist/taint-findings.js +131 -0
- package/dist/taint-findings.js.map +1 -0
- package/dist/taint-regex.d.ts +61 -0
- package/dist/taint-regex.js +379 -0
- package/dist/taint-regex.js.map +1 -0
- package/dist/taint-types.d.ts +128 -0
- package/dist/taint-types.js +174 -0
- package/dist/taint-types.js.map +1 -0
- package/dist/taint.d.ts +13 -107
- package/dist/taint.js +16 -1067
- package/dist/taint.js.map +1 -1
- package/dist/template-detector.d.ts +2 -2
- package/dist/template-detector.js +11 -16
- package/dist/template-detector.js.map +1 -1
- package/dist/types.d.ts +35 -0
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Norm Miner — discovers implicit coding norms from peer function clusters.
|
|
3
|
+
*
|
|
4
|
+
* Groups function_declaration concepts by their child concept profile (e.g.,
|
|
5
|
+
* "has effect + error_handle" vs "has effect, no error_handle") and flags
|
|
6
|
+
* outliers that violate the majority pattern.
|
|
7
|
+
*
|
|
8
|
+
* Softened peer norms: clusters of 2 are allowed for effect-bearing functions
|
|
9
|
+
* (MIN_CLUSTER_SIZE = 2 for *:effect, 3 for *:pure).
|
|
10
|
+
*/
|
|
11
|
+
// ── Constants ───────────────────────────────────────────────────────────
|
|
12
|
+
/** Minimum cluster size: 2 for effect-bearing functions, 3 for pure */
|
|
13
|
+
function minClusterSize(hasEffect) {
|
|
14
|
+
return hasEffect ? 2 : 3;
|
|
15
|
+
}
|
|
16
|
+
/** Minimum prevalence threshold: what fraction of peers must exhibit a pattern */
|
|
17
|
+
const MIN_PREVALENCE = 0.75;
|
|
18
|
+
/** Concept kinds that define a function's "profile" for clustering */
|
|
19
|
+
const PROFILE_KINDS = ['effect', 'error_handle', 'guard', 'error_raise'];
|
|
20
|
+
// ── Core ────────────────────────────────────────────────────────────────
|
|
21
|
+
/**
|
|
22
|
+
* Build a child-concept profile for a function, matching by containerId prefix.
|
|
23
|
+
* Returns a set of concept kinds that appear as children of this function.
|
|
24
|
+
*/
|
|
25
|
+
function buildProfileByPrefix(prefix, allNodes) {
|
|
26
|
+
const kinds = new Set();
|
|
27
|
+
for (const node of allNodes) {
|
|
28
|
+
if (node.containerId?.startsWith(prefix) && PROFILE_KINDS.includes(node.kind)) {
|
|
29
|
+
kinds.add(node.kind);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return kinds;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Cluster key: deterministic string encoding which profile kinds are present.
|
|
36
|
+
* We cluster by EFFECT presence (the primary dimension) + effect subtype.
|
|
37
|
+
*/
|
|
38
|
+
function clusterKey(profile, effectSubtype) {
|
|
39
|
+
const hasEffect = profile.has('effect');
|
|
40
|
+
if (!hasEffect)
|
|
41
|
+
return 'pure';
|
|
42
|
+
return `effect:${effectSubtype || 'unknown'}`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get the effect subtype for a function (if any), matching by containerId prefix.
|
|
46
|
+
*/
|
|
47
|
+
function getEffectSubtypeByPrefix(prefix, allNodes) {
|
|
48
|
+
for (const node of allNodes) {
|
|
49
|
+
if (node.containerId?.startsWith(prefix) && node.kind === 'effect' && node.payload.kind === 'effect') {
|
|
50
|
+
return node.payload.subtype;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Mine peer norms from a set of concept maps.
|
|
57
|
+
* Clusters functions by their effect profile, then checks whether
|
|
58
|
+
* the majority pattern (e.g., "has error_handle") is violated by outliers.
|
|
59
|
+
*/
|
|
60
|
+
export function mineNorms(allConcepts) {
|
|
61
|
+
const violations = [];
|
|
62
|
+
// Collect all function profiles across all files
|
|
63
|
+
const profiles = [];
|
|
64
|
+
for (const [, concepts] of allConcepts) {
|
|
65
|
+
const fnNodes = concepts.nodes.filter((n) => n.kind === 'function_declaration');
|
|
66
|
+
for (const fnNode of fnNodes) {
|
|
67
|
+
const fnName = fnNode.payload.kind === 'function_declaration' ? fnNode.payload.name : 'anonymous';
|
|
68
|
+
// getContainerId format: filePath#fn:name@charOffset
|
|
69
|
+
// Match children by prefix: any containerId starting with "filePath#fn:name@"
|
|
70
|
+
const prefix = `${concepts.filePath}#fn:${fnName}@`;
|
|
71
|
+
const profile = buildProfileByPrefix(prefix, concepts.nodes);
|
|
72
|
+
const effectSubtype = getEffectSubtypeByPrefix(prefix, concepts.nodes);
|
|
73
|
+
profiles.push({ fnNode, containerId: prefix, profile, effectSubtype });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Group by cluster key
|
|
77
|
+
const clusters = new Map();
|
|
78
|
+
for (const p of profiles) {
|
|
79
|
+
const key = clusterKey(p.profile, p.effectSubtype);
|
|
80
|
+
const arr = clusters.get(key) || [];
|
|
81
|
+
arr.push(p);
|
|
82
|
+
clusters.set(key, arr);
|
|
83
|
+
}
|
|
84
|
+
// For each cluster, find the majority pattern and flag outliers
|
|
85
|
+
for (const [key, cluster] of clusters) {
|
|
86
|
+
const hasEffect = key !== 'pure';
|
|
87
|
+
const minSize = minClusterSize(hasEffect);
|
|
88
|
+
if (cluster.length < minSize)
|
|
89
|
+
continue;
|
|
90
|
+
// For each profile kind, count how many functions have it
|
|
91
|
+
for (const kind of PROFILE_KINDS) {
|
|
92
|
+
if (kind === 'effect')
|
|
93
|
+
continue; // effect is the clustering dimension, skip
|
|
94
|
+
const withKind = cluster.filter((p) => p.profile.has(kind));
|
|
95
|
+
let prevalence = withKind.length / cluster.length;
|
|
96
|
+
// Softened norms: multiply prevalence by 0.8 when cluster is small
|
|
97
|
+
if (cluster.length === 2) {
|
|
98
|
+
prevalence *= 0.8;
|
|
99
|
+
}
|
|
100
|
+
if (prevalence < MIN_PREVALENCE)
|
|
101
|
+
continue;
|
|
102
|
+
// Functions that DON'T have this kind are violating the norm
|
|
103
|
+
const violators = cluster.filter((p) => !p.profile.has(kind));
|
|
104
|
+
for (const v of violators) {
|
|
105
|
+
const normDesc = `functions with ${key} should have ${kind}`;
|
|
106
|
+
violations.push({
|
|
107
|
+
functionNode: v.fnNode,
|
|
108
|
+
norm: normDesc,
|
|
109
|
+
missingKind: kind,
|
|
110
|
+
peerCount: withKind.length,
|
|
111
|
+
prevalence,
|
|
112
|
+
weakNorm: cluster.length < 3 ? true : undefined,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return violations;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=norm-miner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"norm-miner.js","sourceRoot":"","sources":["../src/norm-miner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proof Obligations — generated from structure and peer norms.
|
|
3
|
+
*
|
|
4
|
+
* A ProofObligation is something a reviewer (human or LLM) must verify.
|
|
5
|
+
* Two sources:
|
|
6
|
+
* 1. Structural: derived from concept graph topology (no peers needed)
|
|
7
|
+
* 2. Norm-violation: derived from peer function comparison (norm-miner)
|
|
8
|
+
*
|
|
9
|
+
* Obligations are deduped: when a norm violation and a structural obligation
|
|
10
|
+
* target the same function + missing concept kind, the norm violation wins
|
|
11
|
+
* (it has stronger evidence).
|
|
12
|
+
*/
|
|
13
|
+
import type { ConceptMap, ConceptNodeKind } from '@kernlang/core';
|
|
14
|
+
import type { NormViolation } from './norm-miner.js';
|
|
15
|
+
import type { FileContext } from './types.js';
|
|
16
|
+
export type ObligationType = 'norm-violation' | 'structural';
|
|
17
|
+
export interface ProofObligation {
|
|
18
|
+
/** Unique ID for this obligation */
|
|
19
|
+
id: string;
|
|
20
|
+
/** What kind of evidence produced this obligation */
|
|
21
|
+
type: ObligationType;
|
|
22
|
+
/** The function this obligation targets */
|
|
23
|
+
functionId: string;
|
|
24
|
+
/** Human-readable function name */
|
|
25
|
+
functionName: string;
|
|
26
|
+
/** What concept kind is expected but missing */
|
|
27
|
+
missingKind: ConceptNodeKind;
|
|
28
|
+
/** Human-readable claim the reviewer must verify */
|
|
29
|
+
claim: string;
|
|
30
|
+
/** Priority: 1 = highest (norm-violation), 3 = lowest (structural) */
|
|
31
|
+
priority: number;
|
|
32
|
+
/** File path where the function lives */
|
|
33
|
+
filePath: string;
|
|
34
|
+
/** Line number of the function */
|
|
35
|
+
line: number;
|
|
36
|
+
/** Evidence supporting the claim */
|
|
37
|
+
evidence_for: string[];
|
|
38
|
+
/** Evidence against the claim */
|
|
39
|
+
evidence_against: string[];
|
|
40
|
+
/** How common this pattern is among peer functions (0-1) */
|
|
41
|
+
prevalence?: number;
|
|
42
|
+
/** Suggested verification action for the reviewer */
|
|
43
|
+
suggested_check: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Generate obligations from concept graph topology — no peer comparison needed.
|
|
47
|
+
*
|
|
48
|
+
* Rules:
|
|
49
|
+
* (A) Function has effect children but no error_handle child
|
|
50
|
+
* (B) Function is in boundary 'api' and has effect children but no guard child
|
|
51
|
+
* (C) Function has effect with subtype 'db' and no guard with subtype 'validation'
|
|
52
|
+
*/
|
|
53
|
+
export declare function obligationsFromStructure(allConcepts: Map<string, ConceptMap>, fileContextMap: Map<string, FileContext> | undefined, filePath: string): ProofObligation[];
|
|
54
|
+
/**
|
|
55
|
+
* Convert norm violations into proof obligations.
|
|
56
|
+
*/
|
|
57
|
+
export declare function obligationsFromNorms(violations: NormViolation[]): ProofObligation[];
|
|
58
|
+
/**
|
|
59
|
+
* Produce the final list of proof obligations for a file.
|
|
60
|
+
* Merges structural + norm obligations, deduplicating: when both sources
|
|
61
|
+
* target the same function + missing kind, the norm violation wins.
|
|
62
|
+
*/
|
|
63
|
+
export declare function synthesizeObligations(allConcepts: Map<string, ConceptMap>, fileContextMap: Map<string, FileContext> | undefined, filePath: string, normViolations: NormViolation[]): ProofObligation[];
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proof Obligations — generated from structure and peer norms.
|
|
3
|
+
*
|
|
4
|
+
* A ProofObligation is something a reviewer (human or LLM) must verify.
|
|
5
|
+
* Two sources:
|
|
6
|
+
* 1. Structural: derived from concept graph topology (no peers needed)
|
|
7
|
+
* 2. Norm-violation: derived from peer function comparison (norm-miner)
|
|
8
|
+
*
|
|
9
|
+
* Obligations are deduped: when a norm violation and a structural obligation
|
|
10
|
+
* target the same function + missing concept kind, the norm violation wins
|
|
11
|
+
* (it has stronger evidence).
|
|
12
|
+
*/
|
|
13
|
+
// ── Priority ────────────────────────────────────────────────────────────
|
|
14
|
+
const TYPE_PRIORITY = {
|
|
15
|
+
'norm-violation': 2,
|
|
16
|
+
structural: 3,
|
|
17
|
+
};
|
|
18
|
+
// ── Structural obligations ──────────────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Generate obligations from concept graph topology — no peer comparison needed.
|
|
21
|
+
*
|
|
22
|
+
* Rules:
|
|
23
|
+
* (A) Function has effect children but no error_handle child
|
|
24
|
+
* (B) Function is in boundary 'api' and has effect children but no guard child
|
|
25
|
+
* (C) Function has effect with subtype 'db' and no guard with subtype 'validation'
|
|
26
|
+
*/
|
|
27
|
+
export function obligationsFromStructure(allConcepts, fileContextMap, filePath) {
|
|
28
|
+
const obligations = [];
|
|
29
|
+
const concepts = allConcepts.get(filePath);
|
|
30
|
+
if (!concepts)
|
|
31
|
+
return obligations;
|
|
32
|
+
// Find all function declarations in this file
|
|
33
|
+
const fnNodes = concepts.nodes.filter((n) => n.kind === 'function_declaration');
|
|
34
|
+
for (const fnNode of fnNodes) {
|
|
35
|
+
const fnName = fnNode.payload.kind === 'function_declaration' ? fnNode.payload.name : 'anonymous';
|
|
36
|
+
const fnId = fnNode.id;
|
|
37
|
+
// Build the containerId that children would reference
|
|
38
|
+
// Match the getContainerId format: filePath#fn:name@offset
|
|
39
|
+
const containerPrefix = `${filePath}#fn:${fnName}@`;
|
|
40
|
+
// Find children of this function
|
|
41
|
+
const children = concepts.nodes.filter((n) => n.containerId?.startsWith(containerPrefix));
|
|
42
|
+
const effects = children.filter((n) => n.kind === 'effect');
|
|
43
|
+
const errorHandles = children.filter((n) => n.kind === 'error_handle');
|
|
44
|
+
const guards = children.filter((n) => n.kind === 'guard');
|
|
45
|
+
// (A) Function has effect children but no error_handle child
|
|
46
|
+
if (effects.length > 0 && errorHandles.length === 0) {
|
|
47
|
+
const effectSubtypes = [
|
|
48
|
+
...new Set(effects
|
|
49
|
+
.map((e) => (e.payload.kind === 'effect' ? e.payload.subtype : undefined))
|
|
50
|
+
.filter((s) => s !== undefined)),
|
|
51
|
+
];
|
|
52
|
+
obligations.push({
|
|
53
|
+
id: `struct-errh-${fnId}`,
|
|
54
|
+
type: 'structural',
|
|
55
|
+
functionId: fnId,
|
|
56
|
+
functionName: fnName,
|
|
57
|
+
missingKind: 'error_handle',
|
|
58
|
+
claim: `This function performs ${effectSubtypes.join(', ')} effects but has no error handling`,
|
|
59
|
+
priority: TYPE_PRIORITY.structural,
|
|
60
|
+
filePath,
|
|
61
|
+
line: fnNode.primarySpan.startLine,
|
|
62
|
+
evidence_for: [`Has ${effects.length} effect(s): ${effectSubtypes.join(', ')}`],
|
|
63
|
+
evidence_against: [],
|
|
64
|
+
suggested_check: 'Verify error handling is truly missing, not handled by a parent caller',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// (B) Function is in boundary 'api' and has effect children but no guard child
|
|
68
|
+
const fileCtx = fileContextMap?.get(filePath);
|
|
69
|
+
if (fileCtx?.boundary === 'api' && effects.length > 0 && guards.length === 0) {
|
|
70
|
+
const effectDescs = effects
|
|
71
|
+
.map((e) => (e.payload.kind === 'effect' ? e.payload.subtype : undefined))
|
|
72
|
+
.filter((s) => s !== undefined);
|
|
73
|
+
obligations.push({
|
|
74
|
+
id: `struct-guard-${fnId}`,
|
|
75
|
+
type: 'structural',
|
|
76
|
+
functionId: fnId,
|
|
77
|
+
functionName: fnName,
|
|
78
|
+
missingKind: 'guard',
|
|
79
|
+
claim: `This API handler reaches ${[...new Set(effectDescs)].join(', ')} effects without input validation`,
|
|
80
|
+
priority: TYPE_PRIORITY.structural,
|
|
81
|
+
filePath,
|
|
82
|
+
line: fnNode.primarySpan.startLine,
|
|
83
|
+
evidence_for: [`API boundary function with ${effects.length} unguarded effect(s)`],
|
|
84
|
+
evidence_against: [],
|
|
85
|
+
suggested_check: 'Check if validation is handled by middleware or a parent router',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// (C) Function has effect with subtype 'db' and no guard with subtype 'validation'
|
|
89
|
+
const hasDbEffect = effects.some((e) => e.payload.kind === 'effect' && e.payload.subtype === 'db');
|
|
90
|
+
const hasValidationGuard = guards.some((g) => g.payload.kind === 'guard' && g.payload.subtype === 'validation');
|
|
91
|
+
if (hasDbEffect && !hasValidationGuard) {
|
|
92
|
+
obligations.push({
|
|
93
|
+
id: `struct-dbval-${fnId}`,
|
|
94
|
+
type: 'structural',
|
|
95
|
+
functionId: fnId,
|
|
96
|
+
functionName: fnName,
|
|
97
|
+
missingKind: 'guard',
|
|
98
|
+
claim: 'DB write without input validation',
|
|
99
|
+
priority: TYPE_PRIORITY.structural,
|
|
100
|
+
filePath,
|
|
101
|
+
line: fnNode.primarySpan.startLine,
|
|
102
|
+
evidence_for: ['Has DB effect without validation guard'],
|
|
103
|
+
evidence_against: [],
|
|
104
|
+
suggested_check: 'Verify no ORM-level or middleware validation exists',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return obligations;
|
|
109
|
+
}
|
|
110
|
+
// ── Norm-based obligations ──────────────────────────────────────────────
|
|
111
|
+
/**
|
|
112
|
+
* Convert norm violations into proof obligations.
|
|
113
|
+
*/
|
|
114
|
+
export function obligationsFromNorms(violations) {
|
|
115
|
+
return violations.map((v) => {
|
|
116
|
+
let claim = `Norm: ${v.norm} (${v.peerCount} peers, ${Math.round(v.prevalence * 100)}% prevalence)`;
|
|
117
|
+
if (v.weakNorm) {
|
|
118
|
+
claim += ' (Note: limited peer evidence — 1 matching peer)';
|
|
119
|
+
}
|
|
120
|
+
const fnName = v.functionNode.payload.kind === 'function_declaration' ? v.functionNode.payload.name : 'anonymous';
|
|
121
|
+
return {
|
|
122
|
+
id: `norm-${v.functionNode.id}-${v.missingKind}`,
|
|
123
|
+
type: 'norm-violation',
|
|
124
|
+
functionId: v.functionNode.id,
|
|
125
|
+
functionName: fnName,
|
|
126
|
+
missingKind: v.missingKind,
|
|
127
|
+
claim,
|
|
128
|
+
priority: TYPE_PRIORITY['norm-violation'],
|
|
129
|
+
filePath: v.functionNode.primarySpan.file,
|
|
130
|
+
line: v.functionNode.primarySpan.startLine,
|
|
131
|
+
evidence_for: [`${v.peerCount} peer(s) have this pattern, ${Math.round(v.prevalence * 100)}% prevalence`],
|
|
132
|
+
evidence_against: v.weakNorm ? ['Limited peer evidence — only 1 matching peer'] : [],
|
|
133
|
+
prevalence: v.prevalence,
|
|
134
|
+
suggested_check: `Verify ${v.missingKind} is truly needed here, not handled elsewhere`,
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// ── Synthesize + Dedup ──────────────────────────────────────────────────
|
|
139
|
+
/**
|
|
140
|
+
* Produce the final list of proof obligations for a file.
|
|
141
|
+
* Merges structural + norm obligations, deduplicating: when both sources
|
|
142
|
+
* target the same function + missing kind, the norm violation wins.
|
|
143
|
+
*/
|
|
144
|
+
export function synthesizeObligations(allConcepts, fileContextMap, filePath, normViolations) {
|
|
145
|
+
// Structural obligations for this file
|
|
146
|
+
const structural = obligationsFromStructure(allConcepts, fileContextMap, filePath);
|
|
147
|
+
// Norm-based obligations (already scoped to specific functions)
|
|
148
|
+
const fileNormViolations = normViolations.filter((v) => v.functionNode.primarySpan.file === filePath);
|
|
149
|
+
const normObligations = obligationsFromNorms(fileNormViolations);
|
|
150
|
+
// Dedup: norm obligations take precedence over structural for same function+missingKind
|
|
151
|
+
const normKeys = new Set(normObligations.map((o) => `${o.functionId}::${o.missingKind}`));
|
|
152
|
+
const dedupedStructural = structural.filter((o) => !normKeys.has(`${o.functionId}::${o.missingKind}`));
|
|
153
|
+
// Merge and sort by priority (lower = higher priority)
|
|
154
|
+
const all = [...normObligations, ...dedupedStructural];
|
|
155
|
+
all.sort((a, b) => a.priority - b.priority || a.line - b.line);
|
|
156
|
+
return all;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=obligations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"obligations.js","sourceRoot":"","sources":["../src/obligations.ts"],"names":[],"mappings":"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"}
|
package/dist/quality-rules.d.ts
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* v2: Thin orchestrator. Actual rules live in ./rules/*.ts
|
|
5
5
|
*/
|
|
6
|
-
import type { SourceFile } from 'ts-morph';
|
|
7
|
-
import type {
|
|
6
|
+
import type { Project, SourceFile } from 'ts-morph';
|
|
7
|
+
import type { FileRole, InferResult, ReviewConfig, ReviewFinding, TemplateMatch } from './types.js';
|
|
8
8
|
/**
|
|
9
9
|
* Run all active quality rules against a source file.
|
|
10
10
|
* Returns unified ReviewFinding[] (sorting is done by caller via sortAndDedup).
|
|
11
11
|
*/
|
|
12
|
-
export declare function runQualityRules(sourceFile: SourceFile, inferred: InferResult[], templateMatches: TemplateMatch[], config?: ReviewConfig, fileRole?: FileRole): ReviewFinding[];
|
|
12
|
+
export declare function runQualityRules(sourceFile: SourceFile, inferred: InferResult[], templateMatches: TemplateMatch[], config?: ReviewConfig, fileRole?: FileRole, project?: Project): ReviewFinding[];
|
package/dist/quality-rules.js
CHANGED
|
@@ -8,12 +8,14 @@ import { getActiveRules } from './rules/index.js';
|
|
|
8
8
|
* Run all active quality rules against a source file.
|
|
9
9
|
* Returns unified ReviewFinding[] (sorting is done by caller via sortAndDedup).
|
|
10
10
|
*/
|
|
11
|
-
export function runQualityRules(sourceFile, inferred, templateMatches, config, fileRole = 'runtime') {
|
|
11
|
+
export function runQualityRules(sourceFile, inferred, templateMatches, config, fileRole = 'runtime', project) {
|
|
12
12
|
const filePath = sourceFile.getFilePath() || 'input.ts';
|
|
13
13
|
const rules = getActiveRules(config?.target);
|
|
14
|
+
// Resolve file context from import graph (if available)
|
|
15
|
+
const fileContext = config?.fileContextMap?.get(filePath);
|
|
14
16
|
const findings = [];
|
|
15
17
|
for (const rule of rules) {
|
|
16
|
-
findings.push(...rule({ sourceFile, inferred, templateMatches, config, filePath, fileRole }));
|
|
18
|
+
findings.push(...rule({ sourceFile, project, inferred, templateMatches, config, filePath, fileRole, fileContext }));
|
|
17
19
|
}
|
|
18
20
|
return findings;
|
|
19
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quality-rules.js","sourceRoot":"","sources":["../src/quality-rules.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"quality-rules.js","sourceRoot":"","sources":["../src/quality-rules.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,UAAsB,EACtB,QAAuB,EACvB,eAAgC,EAChC,MAAqB,EACrB,WAAqB,SAAS,EAC9B,OAAiB;IAEjB,MAAM,QAAQ,GAAG,UAAU,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC;IACxD,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7C,wDAAwD;IACxD,MAAM,WAAW,GAAG,MAAM,EAAE,cAAc,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IAE1D,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IACtH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/reporter.d.ts
CHANGED
|
@@ -4,8 +4,13 @@
|
|
|
4
4
|
* v2: Unified multi-source report with source tags [kern] [eslint] [tsc] [llm].
|
|
5
5
|
* Dedup across sources. Fingerprint-based cross-run stability.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
8
|
-
|
|
7
|
+
import type { EnforceResult, InferResult, ReviewConfig, ReviewFinding, ReviewReport, ReviewStats, TemplateMatch } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Assign calibrated confidence scores to findings that don't already have one.
|
|
10
|
+
* Call after all phases, before filtering/display.
|
|
11
|
+
*/
|
|
12
|
+
export declare function assignDefaultConfidence(findings: ReviewFinding[]): void;
|
|
13
|
+
export declare function calculateStats(inferred: InferResult[], templateMatches: TemplateMatch[], _findings: ReviewFinding[], totalLines: number): ReviewStats;
|
|
9
14
|
/**
|
|
10
15
|
* Deduplicate findings using fingerprint + message hash.
|
|
11
16
|
* Fingerprint alone can collide when a rule emits multiple findings at the same location
|