mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-06 02:49:56 +00:00
style(impact-pdg): prettier formatting + drop unused import
Root prettier --write across the feature's changed files (whitespace only; ground-truth.json values and the data-based annotation fingerprint unchanged — --check still PASS). Remove an unused loadMeta import flagged by eslint (unused-imports/no-unused-imports).
This commit is contained in:
parent
306f0ee071
commit
620e9e008a
23 changed files with 139 additions and 90 deletions
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/dispatcher.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "kind === 'b'",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "inter",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/facade.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "enrich(order)",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "inter",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/pipeline.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "stageTransform(acc)",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "inter",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/branch.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "'zero'",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "intra",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/guard.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "y + 1",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "intra",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/loop.ts",
|
||||
"direction": "upstream",
|
||||
"marker": "count + 1",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "intra",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/accumulator.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "sum + x",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "intra",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -11,9 +11,24 @@
|
|||
"provenance": "manual",
|
||||
"analyzerVersion": "1.6.7",
|
||||
"intra_AIS": [
|
||||
{ "symbol": "chainCompute", "filePath": "src/chain.ts", "line": 8, "note": "`b = a * 2` is directly data-dependent on the def of `a`" },
|
||||
{ "symbol": "chainCompute", "filePath": "src/chain.ts", "line": 9, "note": "`c = b - 3` is transitively data-dependent on `a` via `b`" },
|
||||
{ "symbol": "chainCompute", "filePath": "src/chain.ts", "line": 10, "note": "`return c` is transitively data-dependent on `a` via the chain" }
|
||||
{
|
||||
"symbol": "chainCompute",
|
||||
"filePath": "src/chain.ts",
|
||||
"line": 8,
|
||||
"note": "`b = a * 2` is directly data-dependent on the def of `a`"
|
||||
},
|
||||
{
|
||||
"symbol": "chainCompute",
|
||||
"filePath": "src/chain.ts",
|
||||
"line": 9,
|
||||
"note": "`c = b - 3` is transitively data-dependent on `a` via `b`"
|
||||
},
|
||||
{
|
||||
"symbol": "chainCompute",
|
||||
"filePath": "src/chain.ts",
|
||||
"line": 10,
|
||||
"note": "`return c` is transitively data-dependent on `a` via the chain"
|
||||
}
|
||||
],
|
||||
"inter_AIS": [],
|
||||
"rationale": "Criterion's changed statement is the def of `a` (line 7). A straight-line REACHING_DEF chain carries `a` -> `b` (line 8) -> `c` (line 9) -> `return` (line 10). Every downstream statement in the function is data-dependent on `a`; none escapes the function (no calls, no annotated caller). intra_AIS is exactly the three downstream lines; inter_AIS is empty. This case stresses transitive forward def->use reachability with no control structure, isolating the RD-forward arm of the KTD4 truth table."
|
||||
|
|
|
|||
|
|
@ -11,8 +11,18 @@
|
|||
"provenance": "manual",
|
||||
"analyzerVersion": "1.6.7",
|
||||
"intra_AIS": [
|
||||
{ "symbol": "reassignSum", "filePath": "src/reassign.ts", "line": 7, "note": "first def `total = a` reaches the criterion use transitively via the second def" },
|
||||
{ "symbol": "reassignSum", "filePath": "src/reassign.ts", "line": 8, "note": "second def `total = total + b` is the immediately-reaching def of the criterion use" }
|
||||
{
|
||||
"symbol": "reassignSum",
|
||||
"filePath": "src/reassign.ts",
|
||||
"line": 7,
|
||||
"note": "first def `total = a` reaches the criterion use transitively via the second def"
|
||||
},
|
||||
{
|
||||
"symbol": "reassignSum",
|
||||
"filePath": "src/reassign.ts",
|
||||
"line": 8,
|
||||
"note": "second def `total = total + b` is the immediately-reaching def of the criterion use"
|
||||
}
|
||||
],
|
||||
"inter_AIS": [],
|
||||
"rationale": "Direction is UPSTREAM: the criterion `reassignSum`'s relevant statement is the `return total` use (line 9), and we ask which definitions reach it. The immediately-reaching def is line 8 (`total = total + b`); that def itself uses `total`, whose reaching def is line 7 (`total = a`). Both defs are upstream data-dependencies of the criterion use, both intra-procedural. intra_AIS = {line 7, line 8}; inter_AIS empty. This isolates the RD-reverse arm of the KTD4 truth table and a reassigned variable's def chain."
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/mixed.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "score + v",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "mixed",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/mixed.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "key === 0",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "mixed",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@
|
|||
"filePath": "src/mixed.ts",
|
||||
"direction": "downstream",
|
||||
"marker": "normalized + 1",
|
||||
"pdgEdgeKinds": [
|
||||
"REACHING_DEF",
|
||||
"CDG"
|
||||
]
|
||||
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
|
||||
},
|
||||
"locus": "mixed",
|
||||
"provenance": "manual",
|
||||
|
|
|
|||
|
|
@ -123,7 +123,9 @@ async function analyzeAndImpact(fx, home, { pdgOn = true } = {}) {
|
|||
// reads the REAL registry under getGlobalDir() (no mock). A fresh backend per
|
||||
// fixture avoids cross-fixture pool/registry caching.
|
||||
process.env.GITNEXUS_HOME = home;
|
||||
const { LocalBackend } = await import(path.join(REPO_ROOT, 'src', 'mcp', 'local', 'local-backend.ts'));
|
||||
const { LocalBackend } = await import(
|
||||
path.join(REPO_ROOT, 'src', 'mcp', 'local', 'local-backend.ts')
|
||||
);
|
||||
const backend = new LocalBackend();
|
||||
await backend.init();
|
||||
|
||||
|
|
@ -177,11 +179,7 @@ async function validateFixture(fx, work, exec) {
|
|||
// marker (the same technique the U6 smoke test uses) and count CDG/RD edges
|
||||
// sourced inside them.
|
||||
const marker = fx.gt.criterion.marker;
|
||||
const blocks = await exec(
|
||||
lbugPath,
|
||||
`MATCH (b:BasicBlock) RETURN b.id AS id, b.text AS text`,
|
||||
{},
|
||||
);
|
||||
const blocks = await exec(lbugPath, `MATCH (b:BasicBlock) RETURN b.id AS id, b.text AS text`, {});
|
||||
const idsByAnchor = new Map();
|
||||
let anchor;
|
||||
for (const b of blocks) {
|
||||
|
|
@ -237,9 +235,12 @@ async function validateFixture(fx, work, exec) {
|
|||
|
||||
const problems = [];
|
||||
if (!anchor) problems.push(`criterion blocks not locatable via marker ${JSON.stringify(marker)}`);
|
||||
if (critEdges === 0) problems.push('criterion produces ZERO PDG edges (unmeasurable ground truth)');
|
||||
if (critEdges === 0)
|
||||
problems.push('criterion produces ZERO PDG edges (unmeasurable ground truth)');
|
||||
if (sameLineCollision)
|
||||
problems.push('criterion shares (filePath,startLine) with another Function/Method (R4 ambiguity)');
|
||||
problems.push(
|
||||
'criterion shares (filePath,startLine) with another Function/Method (R4 ambiguity)',
|
||||
);
|
||||
return { critEdges, sameLineCollision, problems, measurable: problems.length === 0 };
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +344,9 @@ function decisionRecommendation(strata, underpowered, exclusions) {
|
|||
`the symbol BFS chain natively into the PDG and give intra reach a symbol-level meaning.`,
|
||||
);
|
||||
if (exclusions.length > 0) {
|
||||
lines.push(`Excluded from scoring: ${exclusions.map((e) => `${e.name} (${e.reason})`).join('; ')}.`);
|
||||
lines.push(
|
||||
`Excluded from scoring: ${exclusions.map((e) => `${e.name} (${e.reason})`).join('; ')}.`,
|
||||
);
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
|
@ -400,7 +403,8 @@ async function run() {
|
|||
|
||||
for (const fx of fixtures) {
|
||||
if (fx.excluded) {
|
||||
if (runIdx === 0) exclusions.push({ name: fx.name, reason: 'no-body (pdgScoring:exclude / KTD6)' });
|
||||
if (runIdx === 0)
|
||||
exclusions.push({ name: fx.name, reason: 'no-body (pdgScoring:exclude / KTD6)' });
|
||||
continue;
|
||||
}
|
||||
const { work, results } = await analyzeAndImpact(fx, home, { pdgOn: true });
|
||||
|
|
@ -408,8 +412,7 @@ async function run() {
|
|||
// Step 0 — reconcile annotation against the live traversal.
|
||||
const v = await validateFixture(fx, work, exec);
|
||||
if (!v.measurable) {
|
||||
if (runIdx === 0)
|
||||
exclusions.push({ name: fx.name, reason: v.problems.join(' + ') });
|
||||
if (runIdx === 0) exclusions.push({ name: fx.name, reason: v.problems.join(' + ') });
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -498,8 +501,12 @@ async function run() {
|
|||
report[s] = {};
|
||||
for (const m of MODES) {
|
||||
const f1s = perRunStrata.map((r) => r[s][m].f1).filter((v) => v !== null && v !== undefined);
|
||||
const pmeds = perRunStrata.map((r) => r[s][m].precision).filter((v) => v !== null && v !== undefined);
|
||||
const rmeds = perRunStrata.map((r) => r[s][m].recall).filter((v) => v !== null && v !== undefined);
|
||||
const pmeds = perRunStrata
|
||||
.map((r) => r[s][m].precision)
|
||||
.filter((v) => v !== null && v !== undefined);
|
||||
const rmeds = perRunStrata
|
||||
.map((r) => r[s][m].recall)
|
||||
.filter((v) => v !== null && v !== undefined);
|
||||
report[s][m] = {
|
||||
...strata0[s][m],
|
||||
f1: f1s.length ? median(f1s) : null,
|
||||
|
|
@ -516,12 +523,15 @@ async function run() {
|
|||
);
|
||||
const underpowered =
|
||||
measurableTotal < FLOOR_TOTAL ||
|
||||
SCOPES.some((s) => Math.max(report[s].callgraph.nCases, report[s].pdg.nCases) < FLOOR_PER_STRATUM);
|
||||
SCOPES.some(
|
||||
(s) => Math.max(report[s].callgraph.nCases, report[s].pdg.nCases) < FLOOR_PER_STRATUM,
|
||||
);
|
||||
|
||||
const annotationFingerprint = fingerprintAnnotationSet(fixtures, sha256);
|
||||
|
||||
const machineReport = {
|
||||
analyzerVersion: JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8')).version,
|
||||
analyzerVersion: JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8'))
|
||||
.version,
|
||||
corpus: { total: fixtures.length, measurable: measurableTotal, excluded: exclusions },
|
||||
underpowered,
|
||||
floor: { perStratum: FLOOR_PER_STRATUM, total: FLOOR_TOTAL },
|
||||
|
|
|
|||
|
|
@ -183,7 +183,9 @@ export function aisByScope(gt) {
|
|||
const critKey = symbolKey(gt.criterion.name, gt.criterion.filePath);
|
||||
const intra = new Set();
|
||||
if (Array.isArray(gt.intra_AIS) && gt.intra_AIS.length > 0) intra.add(critKey);
|
||||
const inter = toKeySet((gt.inter_AIS ?? []).map((e) => ({ symbol: e.symbol, filePath: e.filePath })));
|
||||
const inter = toKeySet(
|
||||
(gt.inter_AIS ?? []).map((e) => ({ symbol: e.symbol, filePath: e.filePath })),
|
||||
);
|
||||
return { criterionKey: critKey, intra, inter, mixed: new Set([...intra, ...inter]) };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ export function formatImpactResult(result: any): string {
|
|||
} else {
|
||||
pdgLines.push('');
|
||||
pdgLines.push(
|
||||
"ℹ️ Intra-procedural Program Dependence Graph — cross-function impact is not modeled in this mode.",
|
||||
'ℹ️ Intra-procedural Program Dependence Graph — cross-function impact is not modeled in this mode.',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5154,8 +5154,7 @@ export class LocalBackend {
|
|||
? rawLimit
|
||||
: PDG_QUERY_DEFAULT_LIMIT;
|
||||
// Depth: clamp to a sane positive integer (the caller default is 3).
|
||||
const depthBudget =
|
||||
Number.isInteger(maxDepth) && maxDepth >= 1 ? maxDepth : 3;
|
||||
const depthBudget = Number.isInteger(maxDepth) && maxDepth >= 1 ? maxDepth : 3;
|
||||
|
||||
// ── Seed: resolve the target symbol to its BasicBlocks (KTD2 reuse) ───────
|
||||
// resolveBlockAnchor maps the symbol to its block id-prefix + the corrected
|
||||
|
|
@ -5313,7 +5312,12 @@ export class LocalBackend {
|
|||
});
|
||||
|
||||
return assemblePdgImpactResult({
|
||||
target: { id: sym.id, name: sym.name, type: deps.symType || 'Function', filePath: sym.filePath },
|
||||
target: {
|
||||
id: sym.id,
|
||||
name: sym.name,
|
||||
type: deps.symType || 'Function',
|
||||
filePath: sym.filePath,
|
||||
},
|
||||
direction,
|
||||
reachableBlocks,
|
||||
projection,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ const SEED = [
|
|||
const SEED_EDGE = `MATCH (a:BasicBlock {id: 'BasicBlock:src/hot.ts:1:0:0'}), (b:BasicBlock {id: 'BasicBlock:src/hot.ts:1:0:1'})
|
||||
CREATE (a)-[:CodeRelation {type: 'CDG', confidence: 1.0, reason: 'T', step: 0}]->(b)`;
|
||||
|
||||
const META = (pdg?: RepoMeta['pdg']): RepoMeta => ({ pdg } as unknown as RepoMeta);
|
||||
const META = (pdg?: RepoMeta['pdg']): RepoMeta => ({ pdg }) as unknown as RepoMeta;
|
||||
|
||||
withTestLbugDB(
|
||||
'impact-pdg-degradation',
|
||||
|
|
|
|||
|
|
@ -213,7 +213,9 @@ describe('U6 — impact-PDG fixture ground-truth schema', () => {
|
|||
expect(c.marker!.length).toBeGreaterThan(0);
|
||||
// The marker must appear in the criterion file's source.
|
||||
const src = fs.readFileSync(path.join(fx.dir, c.filePath), 'utf8');
|
||||
expect(src.includes(c.marker!), `marker ${JSON.stringify(c.marker)} in source`).toBe(true);
|
||||
expect(src.includes(c.marker!), `marker ${JSON.stringify(c.marker)} in source`).toBe(
|
||||
true,
|
||||
);
|
||||
// Measurable cases declare which PDG edge kinds the criterion produces.
|
||||
expect(Array.isArray(c.pdgEdgeKinds), `${fx.name} needs criterion.pdgEdgeKinds`).toBe(
|
||||
true,
|
||||
|
|
@ -346,10 +348,7 @@ describe('U6 — impact-PDG fixtures analyze under {pdg:true} with measurable cr
|
|||
).toBeGreaterThan(0);
|
||||
}
|
||||
if (kinds.includes('CDG')) {
|
||||
expect(
|
||||
crit.cdg,
|
||||
`${fx.name} criterion declares CDG but produced none`,
|
||||
).toBeGreaterThan(0);
|
||||
expect(crit.cdg, `${fx.name} criterion declares CDG but produced none`).toBeGreaterThan(0);
|
||||
}
|
||||
}, 60000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,10 +37,7 @@ import type { RepoMeta } from '../../src/storage/repo-manager.js';
|
|||
import { LocalBackend } from '../../src/mcp/local/local-backend.js';
|
||||
import { listRegisteredRepos } from '../../src/storage/repo-manager.js';
|
||||
import { withTestLbugDB } from '../helpers/test-indexed-db.js';
|
||||
import {
|
||||
collectImpactSymbolUids,
|
||||
mergeRisk,
|
||||
} from '../../src/core/group/cross-impact.js';
|
||||
import { collectImpactSymbolUids, mergeRisk } from '../../src/core/group/cross-impact.js';
|
||||
import type { CrossRepoImpact } from '../../src/core/group/types.js';
|
||||
|
||||
vi.mock('../../src/storage/repo-manager.js', async (importOriginal) => {
|
||||
|
|
@ -177,7 +174,7 @@ withTestLbugDB(
|
|||
expect(result.summary.modules_affected).toBe(0);
|
||||
});
|
||||
|
||||
it("epistemic/note is PDG-specific, NOT the callgraph DI/dynamic-dispatch copy", async () => {
|
||||
it('epistemic/note is PDG-specific, NOT the callgraph DI/dynamic-dispatch copy', async () => {
|
||||
const result = await downstream();
|
||||
// PDG marker, not the callgraph 'lower-bound'/'exact'.
|
||||
expect(result.epistemic).toBe('pdg-intra-procedural');
|
||||
|
|
@ -221,9 +218,7 @@ withTestLbugDB(
|
|||
// NEVER coerced to a confident 'LOW' (the false-safe this guards).
|
||||
expect(mergeRisk(localRisk, [])).toBe('UNKNOWN');
|
||||
// With a cross-repo hit, 'UNKNOWN' bumps UP to 'MEDIUM' (never down to LOW).
|
||||
const cross = [
|
||||
{ contract: { confidence: 0.5 } },
|
||||
] as unknown as CrossRepoImpact[];
|
||||
const cross = [{ contract: { confidence: 0.5 } }] as unknown as CrossRepoImpact[];
|
||||
expect(mergeRisk(localRisk, cross)).toBe('MEDIUM');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
import { describe, it, expect, beforeAll, vi } from 'vitest';
|
||||
import type { RepoMeta } from '../../src/storage/repo-manager.js';
|
||||
import { LocalBackend } from '../../src/mcp/local/local-backend.js';
|
||||
import { listRegisteredRepos, loadMeta } from '../../src/storage/repo-manager.js';
|
||||
import { listRegisteredRepos } from '../../src/storage/repo-manager.js';
|
||||
import { withTestLbugDB } from '../helpers/test-indexed-db.js';
|
||||
|
||||
vi.mock('../../src/storage/repo-manager.js', async (importOriginal) => {
|
||||
|
|
@ -234,7 +234,7 @@ withTestLbugDB(
|
|||
});
|
||||
|
||||
describe('KTD11 injection safety', () => {
|
||||
it("a target containing a quote/colon is bound, not interpolated (no crash, no injection)", async () => {
|
||||
it('a target containing a quote/colon is bound, not interpolated (no crash, no injection)', async () => {
|
||||
// A malicious-looking target must flow through a bind param. It simply
|
||||
// resolves to not-found here (no such symbol) — never a Cypher error.
|
||||
const result = await backend.callTool('impact', {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,11 @@ import {
|
|||
REPO_ID_HASH_LENGTH,
|
||||
parseListReposPagination,
|
||||
} from '../../src/mcp/local/local-backend.js';
|
||||
import { listRegisteredRepos, cleanupOldKuzuFiles, loadMeta } from '../../src/storage/repo-manager.js';
|
||||
import {
|
||||
listRegisteredRepos,
|
||||
cleanupOldKuzuFiles,
|
||||
loadMeta,
|
||||
} from '../../src/storage/repo-manager.js';
|
||||
import { getGitRoot } from '../../src/storage/git.js';
|
||||
import { _captureLogger } from '../../src/core/logger.js';
|
||||
import {
|
||||
|
|
@ -1514,7 +1518,13 @@ describe('LocalBackend impact mode (KTD1/KTD5/KTD12)', () => {
|
|||
it("ambiguous target under mode:'pdg' never invokes the callgraph fan-out (KTD5 ambiguous trap)", async () => {
|
||||
// Two same-name Functions → resolver returns ambiguous.
|
||||
(executeParameterized as any).mockResolvedValue([
|
||||
{ id: 'func:login:1', name: 'login', type: 'Function', filePath: 'src/auth.ts', startLine: 5 },
|
||||
{
|
||||
id: 'func:login:1',
|
||||
name: 'login',
|
||||
type: 'Function',
|
||||
filePath: 'src/auth.ts',
|
||||
startLine: 5,
|
||||
},
|
||||
{
|
||||
id: 'func:login:2',
|
||||
name: 'login',
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ describe('formatImpactResult — PDG (mode:pdg) rendering', () => {
|
|||
const out = formatImpactResult({
|
||||
mode: 'pdg',
|
||||
pdgLayer: 'no-layer',
|
||||
note: "No PDG layer in this index. Run `gitnexus analyze --pdg` to build it.",
|
||||
note: 'No PDG layer in this index. Run `gitnexus analyze --pdg` to build it.',
|
||||
target: { name: 'computeTotal' },
|
||||
direction: 'downstream',
|
||||
impactedCount: 0,
|
||||
|
|
@ -178,7 +178,12 @@ describe('formatImpactResult — PDG (mode:pdg) rendering', () => {
|
|||
// Shaped like `_runImpactPDG`'s no-body early return.
|
||||
const out = formatImpactResult({
|
||||
mode: 'pdg',
|
||||
target: { id: 'Interface:src/types.ts:Card', name: 'Card', type: 'Interface', filePath: 'src/types.ts' },
|
||||
target: {
|
||||
id: 'Interface:src/types.ts:Card',
|
||||
name: 'Card',
|
||||
type: 'Interface',
|
||||
filePath: 'src/types.ts',
|
||||
},
|
||||
direction: 'downstream',
|
||||
reachableBlocks: [],
|
||||
blockCount: 0,
|
||||
|
|
@ -213,7 +218,12 @@ describe('formatImpactResult — PDG (mode:pdg) rendering', () => {
|
|||
// `_runImpactPDG` reachableBlocks.length === 0 path (body exists, no edges).
|
||||
const out = formatImpactResult({
|
||||
mode: 'pdg',
|
||||
target: { id: 'Function:src/svc.ts:noop', name: 'noop', type: 'Function', filePath: 'src/svc.ts' },
|
||||
target: {
|
||||
id: 'Function:src/svc.ts:noop',
|
||||
name: 'noop',
|
||||
type: 'Function',
|
||||
filePath: 'src/svc.ts',
|
||||
},
|
||||
direction: 'downstream',
|
||||
impactedCount: 0,
|
||||
risk: 'UNKNOWN',
|
||||
|
|
|
|||
|
|
@ -235,7 +235,17 @@ describe('impact-pdg metric math — annotation fingerprint (KTD10)', () => {
|
|||
it('trips when the criterion direction flips', () => {
|
||||
const base = M.fingerprintAnnotationSet([fx({})], fakeHash);
|
||||
const flipped = M.fingerprintAnnotationSet(
|
||||
[fx({ criterion: { name: 'f', filePath: 'src/f.ts', direction: 'upstream', marker: 'x', pdgEdgeKinds: ['REACHING_DEF'] } })],
|
||||
[
|
||||
fx({
|
||||
criterion: {
|
||||
name: 'f',
|
||||
filePath: 'src/f.ts',
|
||||
direction: 'upstream',
|
||||
marker: 'x',
|
||||
pdgEdgeKinds: ['REACHING_DEF'],
|
||||
},
|
||||
}),
|
||||
],
|
||||
fakeHash,
|
||||
);
|
||||
expect(flipped).not.toBe(base);
|
||||
|
|
@ -243,11 +253,25 @@ describe('impact-pdg metric math — annotation fingerprint (KTD10)', () => {
|
|||
|
||||
it('is STABLE under a pure reordering of AIS entries within a case', () => {
|
||||
const a = M.fingerprintAnnotationSet(
|
||||
[fx({ intra_AIS: [{ symbol: 'f', filePath: 'src/f.ts', line: 3 }, { symbol: 'f', filePath: 'src/f.ts', line: 5 }] })],
|
||||
[
|
||||
fx({
|
||||
intra_AIS: [
|
||||
{ symbol: 'f', filePath: 'src/f.ts', line: 3 },
|
||||
{ symbol: 'f', filePath: 'src/f.ts', line: 5 },
|
||||
],
|
||||
}),
|
||||
],
|
||||
fakeHash,
|
||||
);
|
||||
const b = M.fingerprintAnnotationSet(
|
||||
[fx({ intra_AIS: [{ symbol: 'f', filePath: 'src/f.ts', line: 5 }, { symbol: 'f', filePath: 'src/f.ts', line: 3 }] })],
|
||||
[
|
||||
fx({
|
||||
intra_AIS: [
|
||||
{ symbol: 'f', filePath: 'src/f.ts', line: 5 },
|
||||
{ symbol: 'f', filePath: 'src/f.ts', line: 3 },
|
||||
],
|
||||
}),
|
||||
],
|
||||
fakeHash,
|
||||
);
|
||||
expect(a).toBe(b);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue