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:
Gergo Magyar 2026-06-16 09:11:03 +00:00
parent 306f0ee071
commit 620e9e008a
23 changed files with 139 additions and 90 deletions

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -5,10 +5,7 @@
"filePath": "src/branch.ts",
"direction": "downstream",
"marker": "'zero'",
"pdgEdgeKinds": [
"REACHING_DEF",
"CDG"
]
"pdgEdgeKinds": ["REACHING_DEF", "CDG"]
},
"locus": "intra",
"provenance": "manual",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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."

View file

@ -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."

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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 },

View file

@ -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]) };
}

View file

@ -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.',
);
}

View file

@ -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,

View file

@ -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',

View file

@ -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);
}

View file

@ -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');
});
});

View file

@ -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', {

View file

@ -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',

View file

@ -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',

View file

@ -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);