@kernlang/review 2.0.0 → 3.0.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.
- package/dist/concept-rules/boundary-mutation.d.ts +13 -0
- package/dist/concept-rules/boundary-mutation.js +40 -0
- package/dist/concept-rules/boundary-mutation.js.map +1 -0
- package/dist/concept-rules/ignored-error.d.ts +13 -0
- package/dist/concept-rules/ignored-error.js +40 -0
- package/dist/concept-rules/ignored-error.js.map +1 -0
- package/dist/concept-rules/illegal-dependency.d.ts +13 -0
- package/dist/concept-rules/illegal-dependency.js +49 -0
- package/dist/concept-rules/illegal-dependency.js.map +1 -0
- package/dist/concept-rules/index.d.ts +15 -0
- package/dist/concept-rules/index.js +27 -0
- package/dist/concept-rules/index.js.map +1 -0
- package/dist/concept-rules/unguarded-effect.d.ts +13 -0
- package/dist/concept-rules/unguarded-effect.js +58 -0
- package/dist/concept-rules/unguarded-effect.js.map +1 -0
- package/dist/concept-rules/unrecovered-effect.d.ts +13 -0
- package/dist/concept-rules/unrecovered-effect.js +61 -0
- package/dist/concept-rules/unrecovered-effect.js.map +1 -0
- package/dist/confidence.d.ts +92 -0
- package/dist/confidence.js +263 -0
- package/dist/confidence.js.map +1 -0
- package/dist/differ.js +4 -2
- package/dist/differ.js.map +1 -1
- package/dist/external-tools.js +7 -3
- package/dist/external-tools.js.map +1 -1
- package/dist/file-role.d.ts +10 -0
- package/dist/file-role.js +80 -0
- package/dist/file-role.js.map +1 -0
- package/dist/graph.d.ts +11 -0
- package/dist/graph.js +152 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +46 -3
- package/dist/index.js +313 -27
- package/dist/index.js.map +1 -1
- package/dist/inferrer.js +123 -25
- package/dist/inferrer.js.map +1 -1
- package/dist/kern-lint.d.ts +18 -0
- package/dist/kern-lint.js +24 -0
- package/dist/kern-lint.js.map +1 -0
- package/dist/llm-bridge.d.ts +42 -0
- package/dist/llm-bridge.js +176 -0
- package/dist/llm-bridge.js.map +1 -0
- package/dist/llm-review.d.ts +8 -1
- package/dist/llm-review.js +20 -7
- package/dist/llm-review.js.map +1 -1
- package/dist/mappers/ts-concepts.d.ts +9 -0
- package/dist/mappers/ts-concepts.js +512 -0
- package/dist/mappers/ts-concepts.js.map +1 -0
- package/dist/quality-rules.d.ts +3 -3
- package/dist/quality-rules.js +3 -11
- package/dist/quality-rules.js.map +1 -1
- package/dist/reporter.d.ts +19 -3
- package/dist/reporter.js +232 -20
- package/dist/reporter.js.map +1 -1
- package/dist/rules/base.js +164 -15
- package/dist/rules/base.js.map +1 -1
- package/dist/rules/confidence.d.ts +37 -0
- package/dist/rules/confidence.js +159 -0
- package/dist/rules/confidence.js.map +1 -0
- package/dist/rules/dead-logic.d.ts +13 -0
- package/dist/rules/dead-logic.js +386 -0
- package/dist/rules/dead-logic.js.map +1 -0
- package/dist/rules/express.js +69 -2
- package/dist/rules/express.js.map +1 -1
- package/dist/rules/ground-layer.d.ts +23 -0
- package/dist/rules/ground-layer.js +132 -0
- package/dist/rules/ground-layer.js.map +1 -0
- package/dist/rules/index.d.ts +1 -1
- package/dist/rules/index.js +8 -2
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/kern-source.d.ts +16 -0
- package/dist/rules/kern-source.js +726 -0
- package/dist/rules/kern-source.js.map +1 -0
- package/dist/rules/nextjs.js +38 -10
- package/dist/rules/nextjs.js.map +1 -1
- package/dist/rules/null-safety.d.ts +12 -0
- package/dist/rules/null-safety.js +121 -0
- package/dist/rules/null-safety.js.map +1 -0
- package/dist/rules/react.js +64 -1
- package/dist/rules/react.js.map +1 -1
- package/dist/rules/security-v2.d.ts +12 -0
- package/dist/rules/security-v2.js +415 -0
- package/dist/rules/security-v2.js.map +1 -0
- package/dist/rules/security-v3.d.ts +12 -0
- package/dist/rules/security-v3.js +397 -0
- package/dist/rules/security-v3.js.map +1 -0
- package/dist/rules/security-v4.d.ts +22 -0
- package/dist/rules/security-v4.js +688 -0
- package/dist/rules/security-v4.js.map +1 -0
- package/dist/rules/security.d.ts +12 -0
- package/dist/rules/security.js +286 -0
- package/dist/rules/security.js.map +1 -0
- package/dist/rules/utils.d.ts +7 -0
- package/dist/rules/utils.js +21 -0
- package/dist/rules/utils.js.map +1 -0
- package/dist/rules/vue.js +1 -1
- package/dist/rules/vue.js.map +1 -1
- package/dist/spec-checker.d.ts +83 -0
- package/dist/spec-checker.js +405 -0
- package/dist/spec-checker.js.map +1 -0
- package/dist/suppression/apply-suppression.d.ts +17 -0
- package/dist/suppression/apply-suppression.js +94 -0
- package/dist/suppression/apply-suppression.js.map +1 -0
- package/dist/suppression/index.d.ts +6 -0
- package/dist/suppression/index.js +6 -0
- package/dist/suppression/index.js.map +1 -0
- package/dist/suppression/parse-directives.d.ts +25 -0
- package/dist/suppression/parse-directives.js +161 -0
- package/dist/suppression/parse-directives.js.map +1 -0
- package/dist/suppression/types.d.ts +32 -0
- package/dist/suppression/types.js +5 -0
- package/dist/suppression/types.js.map +1 -0
- package/dist/taint.d.ts +115 -0
- package/dist/taint.js +1052 -0
- package/dist/taint.js.map +1 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.js.map +1 -1
- package/package.json +6 -3
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: boundary-mutation
|
|
3
|
+
*
|
|
4
|
+
* Fires when a state mutation targets global/shared scope.
|
|
5
|
+
* Works on any language that emits state_mutation concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: mutating a global cache or shared singleton
|
|
8
|
+
* Python: mutating a shared module-level dict
|
|
9
|
+
* Go: mutating shared package-level state
|
|
10
|
+
*/
|
|
11
|
+
import type { ConceptRuleContext } from './index.js';
|
|
12
|
+
import type { ReviewFinding } from '../types.js';
|
|
13
|
+
export declare function boundaryMutation(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: boundary-mutation
|
|
3
|
+
*
|
|
4
|
+
* Fires when a state mutation targets global/shared scope.
|
|
5
|
+
* Works on any language that emits state_mutation concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: mutating a global cache or shared singleton
|
|
8
|
+
* Python: mutating a shared module-level dict
|
|
9
|
+
* Go: mutating shared package-level state
|
|
10
|
+
*/
|
|
11
|
+
import { createFingerprint } from '../types.js';
|
|
12
|
+
export function boundaryMutation(ctx) {
|
|
13
|
+
const findings = [];
|
|
14
|
+
for (const node of ctx.concepts.nodes) {
|
|
15
|
+
if (node.kind !== 'state_mutation')
|
|
16
|
+
continue;
|
|
17
|
+
if (node.payload.kind !== 'state_mutation')
|
|
18
|
+
continue;
|
|
19
|
+
if (node.payload.scope !== 'global' && node.payload.scope !== 'shared')
|
|
20
|
+
continue;
|
|
21
|
+
findings.push({
|
|
22
|
+
source: 'kern',
|
|
23
|
+
ruleId: 'boundary-mutation',
|
|
24
|
+
severity: 'warning',
|
|
25
|
+
category: 'pattern',
|
|
26
|
+
message: `Global/shared state mutation — consider encapsulating in a store or module`,
|
|
27
|
+
primarySpan: {
|
|
28
|
+
file: node.primarySpan.file,
|
|
29
|
+
startLine: node.primarySpan.startLine,
|
|
30
|
+
startCol: node.primarySpan.startCol,
|
|
31
|
+
endLine: node.primarySpan.endLine,
|
|
32
|
+
endCol: node.primarySpan.endCol,
|
|
33
|
+
},
|
|
34
|
+
fingerprint: createFingerprint('boundary-mutation', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
35
|
+
confidence: node.confidence,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return findings;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=boundary-mutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundary-mutation.js","sourceRoot":"","sources":["../../src/concept-rules/boundary-mutation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,UAAU,gBAAgB,CAAC,GAAuB;IACtD,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB;YAAE,SAAS;QAC7C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,gBAAgB;YAAE,SAAS;QACrD,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,QAAQ;YAAE,SAAS;QAEjF,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,mBAAmB;YAC3B,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,4EAA4E;YACrF,WAAW,EAAE;gBACX,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC3B,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS;gBACrC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;gBACnC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;gBACjC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;aAChC;YACD,WAAW,EAAE,iBAAiB,CAAC,mBAAmB,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YAC1G,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: ignored-error
|
|
3
|
+
*
|
|
4
|
+
* Fires when an error is caught/received but not handled.
|
|
5
|
+
* Works on any language that emits error_handle concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: catch (e) {}
|
|
8
|
+
* Python: except: pass
|
|
9
|
+
* Go: if err != nil {}
|
|
10
|
+
*/
|
|
11
|
+
import type { ConceptRuleContext } from './index.js';
|
|
12
|
+
import type { ReviewFinding } from '../types.js';
|
|
13
|
+
export declare function ignoredError(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: ignored-error
|
|
3
|
+
*
|
|
4
|
+
* Fires when an error is caught/received but not handled.
|
|
5
|
+
* Works on any language that emits error_handle concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: catch (e) {}
|
|
8
|
+
* Python: except: pass
|
|
9
|
+
* Go: if err != nil {}
|
|
10
|
+
*/
|
|
11
|
+
import { createFingerprint } from '../types.js';
|
|
12
|
+
export function ignoredError(ctx) {
|
|
13
|
+
const findings = [];
|
|
14
|
+
for (const node of ctx.concepts.nodes) {
|
|
15
|
+
if (node.kind !== 'error_handle')
|
|
16
|
+
continue;
|
|
17
|
+
if (node.payload.kind !== 'error_handle')
|
|
18
|
+
continue;
|
|
19
|
+
if (node.payload.disposition !== 'ignored')
|
|
20
|
+
continue;
|
|
21
|
+
findings.push({
|
|
22
|
+
source: 'kern',
|
|
23
|
+
ruleId: 'ignored-error',
|
|
24
|
+
severity: 'error',
|
|
25
|
+
category: 'bug',
|
|
26
|
+
message: `Error is caught but ignored — handle, log, or rethrow`,
|
|
27
|
+
primarySpan: {
|
|
28
|
+
file: node.primarySpan.file,
|
|
29
|
+
startLine: node.primarySpan.startLine,
|
|
30
|
+
startCol: node.primarySpan.startCol,
|
|
31
|
+
endLine: node.primarySpan.endLine,
|
|
32
|
+
endCol: node.primarySpan.endCol,
|
|
33
|
+
},
|
|
34
|
+
fingerprint: createFingerprint('ignored-error', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
35
|
+
confidence: node.confidence,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return findings;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=ignored-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ignored-error.js","sourceRoot":"","sources":["../../src/concept-rules/ignored-error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,UAAU,YAAY,CAAC,GAAuB;IAClD,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc;YAAE,SAAS;QAC3C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,cAAc;YAAE,SAAS;QACnD,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS;YAAE,SAAS;QAErD,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,eAAe;YACvB,QAAQ,EAAE,OAAO;YACjB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,uDAAuD;YAChE,WAAW,EAAE;gBACX,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC3B,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS;gBACrC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;gBACnC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;gBACjC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;aAChC;YACD,WAAW,EAAE,iBAAiB,CAAC,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YACtG,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: illegal-dependency
|
|
3
|
+
*
|
|
4
|
+
* Fires when an internal dependency reaches too far up the directory tree.
|
|
5
|
+
* Works on any language that emits dependency concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: import x from '../../../shared/module'
|
|
8
|
+
* Python: from ...core.shared import x
|
|
9
|
+
* Go: internal import path that walks too far upward
|
|
10
|
+
*/
|
|
11
|
+
import type { ConceptRuleContext } from './index.js';
|
|
12
|
+
import type { ReviewFinding } from '../types.js';
|
|
13
|
+
export declare function illegalDependency(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: illegal-dependency
|
|
3
|
+
*
|
|
4
|
+
* Fires when an internal dependency reaches too far up the directory tree.
|
|
5
|
+
* Works on any language that emits dependency concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: import x from '../../../shared/module'
|
|
8
|
+
* Python: from ...core.shared import x
|
|
9
|
+
* Go: internal import path that walks too far upward
|
|
10
|
+
*/
|
|
11
|
+
import { createFingerprint } from '../types.js';
|
|
12
|
+
export function illegalDependency(ctx) {
|
|
13
|
+
const findings = [];
|
|
14
|
+
for (const edge of ctx.concepts.edges) {
|
|
15
|
+
if (edge.kind !== 'dependency')
|
|
16
|
+
continue;
|
|
17
|
+
if (edge.payload.kind !== 'dependency')
|
|
18
|
+
continue;
|
|
19
|
+
if (edge.payload.subtype !== 'internal')
|
|
20
|
+
continue;
|
|
21
|
+
const upLevels = countUpLevels(edge.payload.specifier);
|
|
22
|
+
if (upLevels <= 2)
|
|
23
|
+
continue;
|
|
24
|
+
findings.push({
|
|
25
|
+
source: 'kern',
|
|
26
|
+
ruleId: 'illegal-dependency',
|
|
27
|
+
severity: 'warning',
|
|
28
|
+
category: 'structure',
|
|
29
|
+
message: `Deep cross-boundary import — may violate module architecture`,
|
|
30
|
+
primarySpan: {
|
|
31
|
+
file: edge.primarySpan.file,
|
|
32
|
+
startLine: edge.primarySpan.startLine,
|
|
33
|
+
startCol: edge.primarySpan.startCol,
|
|
34
|
+
endLine: edge.primarySpan.endLine,
|
|
35
|
+
endCol: edge.primarySpan.endCol,
|
|
36
|
+
},
|
|
37
|
+
fingerprint: createFingerprint('illegal-dependency', edge.primarySpan.startLine, edge.primarySpan.startCol),
|
|
38
|
+
confidence: edge.confidence * 0.8, // lower confidence since this is a path-depth heuristic
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return findings;
|
|
42
|
+
}
|
|
43
|
+
function countUpLevels(specifier) {
|
|
44
|
+
const match = specifier.match(/^(\.\.\/)+/);
|
|
45
|
+
if (!match)
|
|
46
|
+
return 0;
|
|
47
|
+
return match[0].length / 3;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=illegal-dependency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"illegal-dependency.js","sourceRoot":"","sources":["../../src/concept-rules/illegal-dependency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;YAAE,SAAS;QACzC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;YAAE,SAAS;QACjD,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,UAAU;YAAE,SAAS;QAElD,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,QAAQ,IAAI,CAAC;YAAE,SAAS;QAE5B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,oBAAoB;YAC5B,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,WAAW;YACrB,OAAO,EAAE,8DAA8D;YACvE,WAAW,EAAE;gBACX,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC3B,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS;gBACrC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;gBACnC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;gBACjC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;aAChC;YACD,WAAW,EAAE,iBAAiB,CAAC,oBAAoB,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YAC3G,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,GAAG,EAAE,wDAAwD;SAC5F,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,aAAa,CAAC,SAAiB;IACtC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC;IACrB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Concept Rules — universal rules that operate on ConceptMap.
|
|
3
|
+
*
|
|
4
|
+
* These rules work on any language that emits concepts.
|
|
5
|
+
* Language-agnostic by design.
|
|
6
|
+
*/
|
|
7
|
+
import type { ConceptMap } from '@kernlang/core';
|
|
8
|
+
import type { ReviewFinding } from '../types.js';
|
|
9
|
+
export interface ConceptRuleContext {
|
|
10
|
+
concepts: ConceptMap;
|
|
11
|
+
filePath: string;
|
|
12
|
+
}
|
|
13
|
+
export type ConceptRule = (ctx: ConceptRuleContext) => ReviewFinding[];
|
|
14
|
+
export declare const conceptRules: ConceptRule[];
|
|
15
|
+
export declare function runConceptRules(concepts: ConceptMap, filePath: string): ReviewFinding[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Concept Rules — universal rules that operate on ConceptMap.
|
|
3
|
+
*
|
|
4
|
+
* These rules work on any language that emits concepts.
|
|
5
|
+
* Language-agnostic by design.
|
|
6
|
+
*/
|
|
7
|
+
import { boundaryMutation } from './boundary-mutation.js';
|
|
8
|
+
import { ignoredError } from './ignored-error.js';
|
|
9
|
+
import { illegalDependency } from './illegal-dependency.js';
|
|
10
|
+
import { unguardedEffect } from './unguarded-effect.js';
|
|
11
|
+
import { unrecoveredEffect } from './unrecovered-effect.js';
|
|
12
|
+
export const conceptRules = [
|
|
13
|
+
boundaryMutation,
|
|
14
|
+
ignoredError,
|
|
15
|
+
illegalDependency,
|
|
16
|
+
unguardedEffect,
|
|
17
|
+
unrecoveredEffect,
|
|
18
|
+
];
|
|
19
|
+
export function runConceptRules(concepts, filePath) {
|
|
20
|
+
const ctx = { concepts, filePath };
|
|
21
|
+
const findings = [];
|
|
22
|
+
for (const rule of conceptRules) {
|
|
23
|
+
findings.push(...rule(ctx));
|
|
24
|
+
}
|
|
25
|
+
return findings;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/concept-rules/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAS5D,MAAM,CAAC,MAAM,YAAY,GAAkB;IACzC,gBAAgB;IAChB,YAAY;IACZ,iBAAiB;IACjB,eAAe;IACf,iBAAiB;CAClB,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,QAAoB,EAAE,QAAgB;IACpE,MAAM,GAAG,GAAuB,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACvD,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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: unguarded-effect
|
|
3
|
+
*
|
|
4
|
+
* Fires when a network/db effect has no auth/validation guard in the same container.
|
|
5
|
+
* Works on any language that emits effect + guard concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: fetch() in a route handler without auth/validation
|
|
8
|
+
* Python: requests.get() in a view without auth/validation
|
|
9
|
+
* Go: db.Query() in a handler without auth/validation
|
|
10
|
+
*/
|
|
11
|
+
import type { ConceptRuleContext } from './index.js';
|
|
12
|
+
import type { ReviewFinding } from '../types.js';
|
|
13
|
+
export declare function unguardedEffect(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: unguarded-effect
|
|
3
|
+
*
|
|
4
|
+
* Fires when a network/db effect has no auth/validation guard in the same container.
|
|
5
|
+
* Works on any language that emits effect + guard concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: fetch() in a route handler without auth/validation
|
|
8
|
+
* Python: requests.get() in a view without auth/validation
|
|
9
|
+
* Go: db.Query() in a handler without auth/validation
|
|
10
|
+
*/
|
|
11
|
+
import { createFingerprint } from '../types.js';
|
|
12
|
+
const GUARD_SUBTYPES = new Set(['auth', 'validation']);
|
|
13
|
+
export function unguardedEffect(ctx) {
|
|
14
|
+
const findings = [];
|
|
15
|
+
// Build a set of containerIds that have auth/validation guards
|
|
16
|
+
const guardedContainers = new Set();
|
|
17
|
+
for (const node of ctx.concepts.nodes) {
|
|
18
|
+
if (node.kind !== 'guard')
|
|
19
|
+
continue;
|
|
20
|
+
if (node.payload.kind !== 'guard')
|
|
21
|
+
continue;
|
|
22
|
+
if (!GUARD_SUBTYPES.has(node.payload.subtype))
|
|
23
|
+
continue;
|
|
24
|
+
if (node.containerId) {
|
|
25
|
+
guardedContainers.add(node.containerId);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Find network/db effects without a guard in the same container
|
|
29
|
+
for (const node of ctx.concepts.nodes) {
|
|
30
|
+
if (node.kind !== 'effect')
|
|
31
|
+
continue;
|
|
32
|
+
if (node.payload.kind !== 'effect')
|
|
33
|
+
continue;
|
|
34
|
+
const { subtype } = node.payload;
|
|
35
|
+
if (subtype !== 'network' && subtype !== 'db')
|
|
36
|
+
continue;
|
|
37
|
+
if (node.containerId && guardedContainers.has(node.containerId))
|
|
38
|
+
continue;
|
|
39
|
+
findings.push({
|
|
40
|
+
source: 'kern',
|
|
41
|
+
ruleId: 'unguarded-effect',
|
|
42
|
+
severity: 'warning',
|
|
43
|
+
category: 'bug',
|
|
44
|
+
message: `Network/DB effect without auth/validation guard`,
|
|
45
|
+
primarySpan: {
|
|
46
|
+
file: node.primarySpan.file,
|
|
47
|
+
startLine: node.primarySpan.startLine,
|
|
48
|
+
startCol: node.primarySpan.startCol,
|
|
49
|
+
endLine: node.primarySpan.endLine,
|
|
50
|
+
endCol: node.primarySpan.endCol,
|
|
51
|
+
},
|
|
52
|
+
fingerprint: createFingerprint('unguarded-effect', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
53
|
+
confidence: node.confidence * 0.8, // lower confidence since container scoping is heuristic
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return findings;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=unguarded-effect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unguarded-effect.js","sourceRoot":"","sources":["../../src/concept-rules/unguarded-effect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;AAEvD,MAAM,UAAU,eAAe,CAAC,GAAuB;IACrD,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,+DAA+D;IAC/D,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;YAAE,SAAS;QACpC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO;YAAE,SAAS;QAC5C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;YAAE,SAAS;QACxD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QAE7C,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACjC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI;YAAE,SAAS;QAExD,IAAI,IAAI,CAAC,WAAW,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;YAAE,SAAS;QAE1E,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,kBAAkB;YAC1B,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,iDAAiD;YAC1D,WAAW,EAAE;gBACX,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC3B,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS;gBACrC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;gBACnC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;gBACjC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;aAChC;YACD,WAAW,EAAE,iBAAiB,CAAC,kBAAkB,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YACzG,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,GAAG,EAAE,wDAAwD;SAC5F,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: unrecovered-effect
|
|
3
|
+
*
|
|
4
|
+
* Fires when a network/db effect has no error recovery ancestor.
|
|
5
|
+
* Works on any language that emits effect + error_handle concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: fetch() without try/catch
|
|
8
|
+
* Python: requests.get() without try/except
|
|
9
|
+
* Go: http.Get() with err ignored
|
|
10
|
+
*/
|
|
11
|
+
import type { ConceptRuleContext } from './index.js';
|
|
12
|
+
import type { ReviewFinding } from '../types.js';
|
|
13
|
+
export declare function unrecoveredEffect(ctx: ConceptRuleContext): ReviewFinding[];
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: unrecovered-effect
|
|
3
|
+
*
|
|
4
|
+
* Fires when a network/db effect has no error recovery ancestor.
|
|
5
|
+
* Works on any language that emits effect + error_handle concepts.
|
|
6
|
+
*
|
|
7
|
+
* TS: fetch() without try/catch
|
|
8
|
+
* Python: requests.get() without try/except
|
|
9
|
+
* Go: http.Get() with err ignored
|
|
10
|
+
*/
|
|
11
|
+
import { createFingerprint } from '../types.js';
|
|
12
|
+
const RECOVERABLE_DISPOSITIONS = new Set(['wrapped', 'returned', 'rethrown', 'retried']);
|
|
13
|
+
export function unrecoveredEffect(ctx) {
|
|
14
|
+
const findings = [];
|
|
15
|
+
// Build a set of containerIds that have error recovery
|
|
16
|
+
const recoveredContainers = new Set();
|
|
17
|
+
for (const node of ctx.concepts.nodes) {
|
|
18
|
+
if (node.kind !== 'error_handle')
|
|
19
|
+
continue;
|
|
20
|
+
if (node.payload.kind !== 'error_handle')
|
|
21
|
+
continue;
|
|
22
|
+
if (RECOVERABLE_DISPOSITIONS.has(node.payload.disposition) && node.containerId) {
|
|
23
|
+
recoveredContainers.add(node.containerId);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Find effects without recovery in the same container
|
|
27
|
+
for (const node of ctx.concepts.nodes) {
|
|
28
|
+
if (node.kind !== 'effect')
|
|
29
|
+
continue;
|
|
30
|
+
if (node.payload.kind !== 'effect')
|
|
31
|
+
continue;
|
|
32
|
+
const { subtype } = node.payload;
|
|
33
|
+
if (subtype !== 'network' && subtype !== 'db')
|
|
34
|
+
continue;
|
|
35
|
+
// Check if the container function has error recovery
|
|
36
|
+
if (node.containerId && recoveredContainers.has(node.containerId))
|
|
37
|
+
continue;
|
|
38
|
+
// Also check if there's any error_handle in the same container (even logged)
|
|
39
|
+
const hasAnyHandler = ctx.concepts.nodes.some(n => n.kind === 'error_handle' && n.containerId === node.containerId);
|
|
40
|
+
if (hasAnyHandler)
|
|
41
|
+
continue;
|
|
42
|
+
findings.push({
|
|
43
|
+
source: 'kern',
|
|
44
|
+
ruleId: 'unrecovered-effect',
|
|
45
|
+
severity: 'warning',
|
|
46
|
+
category: 'bug',
|
|
47
|
+
message: `${subtype} effect without error recovery — wrap in try/catch or add .catch()`,
|
|
48
|
+
primarySpan: {
|
|
49
|
+
file: node.primarySpan.file,
|
|
50
|
+
startLine: node.primarySpan.startLine,
|
|
51
|
+
startCol: node.primarySpan.startCol,
|
|
52
|
+
endLine: node.primarySpan.endLine,
|
|
53
|
+
endCol: node.primarySpan.endCol,
|
|
54
|
+
},
|
|
55
|
+
fingerprint: createFingerprint('unrecovered-effect', node.primarySpan.startLine, node.primarySpan.startCol),
|
|
56
|
+
confidence: node.confidence * 0.8, // lower confidence since container scoping is heuristic
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return findings;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=unrecovered-effect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unrecovered-effect.js","sourceRoot":"","sources":["../../src/concept-rules/unrecovered-effect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AAEzF,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,uDAAuD;IACvD,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc;YAAE,SAAS;QAC3C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,cAAc;YAAE,SAAS;QACnD,IAAI,wBAAwB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAC/E,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QAE7C,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACjC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI;YAAE,SAAS;QAExD,qDAAqD;QACrD,IAAI,IAAI,CAAC,WAAW,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;YAAE,SAAS;QAE5E,6EAA6E;QAC7E,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAChD,CAAC,CAAC,IAAI,KAAK,cAAc,IAAI,CAAC,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,CAChE,CAAC;QACF,IAAI,aAAa;YAAE,SAAS;QAE5B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,oBAAoB;YAC5B,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,GAAG,OAAO,oEAAoE;YACvF,WAAW,EAAE;gBACX,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC3B,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS;gBACrC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;gBACnC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;gBACjC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;aAChC;YACD,WAAW,EAAE,iBAAiB,CAAC,oBAAoB,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YAC3G,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,GAAG,EAAE,wDAAwD;SAC5F,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confidence Graph — Layer 5 propagation engine
|
|
3
|
+
*
|
|
4
|
+
* Builds a directed graph of confidence dependencies between KERN IR nodes,
|
|
5
|
+
* then propagates confidence values using Kahn's topological sort.
|
|
6
|
+
*
|
|
7
|
+
* Supports single-file and multi-file graphs. Cross-file resolution allows
|
|
8
|
+
* `confidence=from:authMethod` to resolve across .kern files.
|
|
9
|
+
*
|
|
10
|
+
* Strategies:
|
|
11
|
+
* - literal: confidence=0.7 — direct value
|
|
12
|
+
* - from:X — inherits from one source (min strategy)
|
|
13
|
+
* - min:X,Y — inherits from multiple sources (weakest link)
|
|
14
|
+
*/
|
|
15
|
+
import type { IRNode } from '@kernlang/core';
|
|
16
|
+
export interface ConfidenceSpec {
|
|
17
|
+
kind: 'literal' | 'inherited';
|
|
18
|
+
value?: number;
|
|
19
|
+
strategy: 'min';
|
|
20
|
+
sources?: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface ConfidenceNode {
|
|
23
|
+
name: string;
|
|
24
|
+
nodeRef: {
|
|
25
|
+
type: string;
|
|
26
|
+
line: number;
|
|
27
|
+
};
|
|
28
|
+
sourceFile?: string;
|
|
29
|
+
spec: ConfidenceSpec;
|
|
30
|
+
resolved: number | null;
|
|
31
|
+
dependsOn: string[];
|
|
32
|
+
dependedBy: string[];
|
|
33
|
+
needs: NeedsEntry[];
|
|
34
|
+
inCycle: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface NeedsEntry {
|
|
37
|
+
what: string;
|
|
38
|
+
wouldRaiseTo: number | undefined;
|
|
39
|
+
resolved: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface ConfidenceGraph {
|
|
42
|
+
nodes: Map<string, ConfidenceNode>;
|
|
43
|
+
topoOrder: string[];
|
|
44
|
+
cycles: string[][];
|
|
45
|
+
}
|
|
46
|
+
export interface DuplicateNameEntry {
|
|
47
|
+
name: string;
|
|
48
|
+
files: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface MultiFileConfidenceGraph extends ConfidenceGraph {
|
|
51
|
+
duplicates: DuplicateNameEntry[];
|
|
52
|
+
}
|
|
53
|
+
/** Serializable form of the graph (no IRNode references) */
|
|
54
|
+
export interface SerializedConfidenceGraph {
|
|
55
|
+
nodes: Array<{
|
|
56
|
+
name: string;
|
|
57
|
+
nodeRef: {
|
|
58
|
+
type: string;
|
|
59
|
+
line: number;
|
|
60
|
+
};
|
|
61
|
+
sourceFile?: string;
|
|
62
|
+
spec: ConfidenceSpec;
|
|
63
|
+
resolved: number | null;
|
|
64
|
+
dependsOn: string[];
|
|
65
|
+
needs: NeedsEntry[];
|
|
66
|
+
inCycle: boolean;
|
|
67
|
+
}>;
|
|
68
|
+
topoOrder: string[];
|
|
69
|
+
cycles: string[][];
|
|
70
|
+
duplicates?: DuplicateNameEntry[];
|
|
71
|
+
}
|
|
72
|
+
export interface ConfidenceSummary {
|
|
73
|
+
high: number;
|
|
74
|
+
medium: number;
|
|
75
|
+
low: number;
|
|
76
|
+
unresolved: number;
|
|
77
|
+
unresolvedNeeds: number;
|
|
78
|
+
}
|
|
79
|
+
/** Parse a raw confidence prop value into a spec. Returns undefined for malformed. */
|
|
80
|
+
export declare function parseConfidence(raw: unknown): ConfidenceSpec | undefined;
|
|
81
|
+
/** Build confidence graph from flat list of IR nodes. O(n). */
|
|
82
|
+
export declare function buildConfidenceGraph(irNodes: IRNode[]): ConfidenceGraph;
|
|
83
|
+
/** Build confidence graph from multiple .kern files. Resolves cross-file from: references. */
|
|
84
|
+
export declare function buildMultiFileConfidenceGraph(fileMap: Map<string, IRNode[]>): MultiFileConfidenceGraph;
|
|
85
|
+
/** Resolve base confidence for a literal node, applying resolved needs. */
|
|
86
|
+
export declare function resolveBaseConfidence(node: ConfidenceNode): number;
|
|
87
|
+
/** Propagate confidence values through the graph in topological order. */
|
|
88
|
+
export declare function propagateConfidence(graph: ConfidenceGraph): void;
|
|
89
|
+
/** Serialize a confidence graph (strips Map, uses arrays). */
|
|
90
|
+
export declare function serializeGraph(graph: ConfidenceGraph): SerializedConfidenceGraph;
|
|
91
|
+
/** Compute confidence summary bands. */
|
|
92
|
+
export declare function computeConfidenceSummary(graph: ConfidenceGraph): ConfidenceSummary;
|