mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-08 03:08:13 +00:00
Some checks are pending
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
* fix(scope-resolution): link Record graph nodes Register Record definitions and caller anchors so Java and C# record targets and initializer sources resolve to canonical nodes. Keep generated LadybugDB relation pairs and the production benchmark baseline synchronized. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(bench): harden schema-pair production gate Derive the production count from executable DDL, fail closed when its budget is missing, and independently pin Record-to-Property coverage. Keep benchmark evidence machine-scoped and correct stale schema counts. --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
import type { NodeLabel } from 'gitnexus-shared';
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
import { createKnowledgeGraph } from '../../../src/core/graph/graph.js';
|
|
import { createSemanticModel } from '../../../src/core/ingestion/model/semantic-model.js';
|
|
import { mergeChunkResults } from '../../../src/core/ingestion/parsing-processor.js';
|
|
import {
|
|
buildGraphNodeLookup,
|
|
qualifiedKey,
|
|
simpleKey,
|
|
} from '../../../src/core/ingestion/scope-resolution/graph-bridge/node-lookup.js';
|
|
import { resolveDefGraphId } from '../../../src/core/ingestion/scope-resolution/graph-bridge/ids.js';
|
|
import type { ParseWorkerResult } from '../../../src/core/ingestion/workers/parse-worker.js';
|
|
|
|
const FILE = 'src/service.ts';
|
|
|
|
interface Candidate {
|
|
id: string;
|
|
label?: NodeLabel;
|
|
name?: string;
|
|
qualifiedName?: string;
|
|
startLine?: number;
|
|
}
|
|
|
|
function buildLookup(candidates: readonly Candidate[]) {
|
|
const graph = createKnowledgeGraph();
|
|
const nodes = candidates.map(
|
|
(candidate) =>
|
|
({
|
|
id: candidate.id,
|
|
label: candidate.label ?? ('Method' as NodeLabel),
|
|
properties: {
|
|
name: candidate.name ?? 'save',
|
|
qualifiedName: candidate.qualifiedName ?? 'Service.save',
|
|
filePath: FILE,
|
|
...(candidate.startLine !== undefined ? { startLine: candidate.startLine } : {}),
|
|
},
|
|
}) satisfies ParseWorkerResult['nodes'][number],
|
|
);
|
|
const result: ParseWorkerResult = {
|
|
nodes,
|
|
relationships: [],
|
|
symbols: [],
|
|
calls: [],
|
|
assignments: [],
|
|
routes: [],
|
|
fetchCalls: [],
|
|
fetchWrapperDefs: [],
|
|
decoratorRoutes: [],
|
|
routerIncludes: [],
|
|
routerImports: [],
|
|
toolDefs: [],
|
|
ormQueries: [],
|
|
constructorBindings: [],
|
|
fileScopeBindings: [],
|
|
parsedFiles: [],
|
|
skippedLanguages: {},
|
|
fileCount: 1,
|
|
};
|
|
|
|
mergeChunkResults(graph, createSemanticModel().symbols, [result]);
|
|
return buildGraphNodeLookup(graph);
|
|
}
|
|
|
|
describe('parse-result graph insertion determinism', () => {
|
|
it('selects the earliest source definition regardless of worker result order', () => {
|
|
const early = { id: `Method:${FILE}:Service.save#1`, startLine: 10 };
|
|
const late = { id: `Method:${FILE}:Service.save#2`, startLine: 20 };
|
|
|
|
const lateFirst = buildLookup([late, early]);
|
|
const earlyFirst = buildLookup([early, late]);
|
|
|
|
for (const key of [simpleKey(FILE, 'save'), qualifiedKey(FILE, 'Method', 'Service.save')]) {
|
|
expect(lateFirst.get(key)).toBe(early.id);
|
|
expect(earlyFirst.get(key)).toBe(early.id);
|
|
}
|
|
});
|
|
|
|
it('uses the stable node id when source positions are identical', () => {
|
|
const first = { id: `Method:${FILE}:Service.save#1`, startLine: 10 };
|
|
const second = { id: `Method:${FILE}:Service.save#2`, startLine: 10 };
|
|
|
|
const firstLookup = buildLookup([second, first]);
|
|
const secondLookup = buildLookup([first, second]);
|
|
|
|
expect(firstLookup.get(simpleKey(FILE, 'save'))).toBe(first.id);
|
|
expect(secondLookup.get(simpleKey(FILE, 'save'))).toBe(first.id);
|
|
});
|
|
|
|
it('uses the stable node id when source positions are unavailable', () => {
|
|
const first = { id: `Method:${FILE}:Service.save#1` };
|
|
const second = { id: `Method:${FILE}:Service.save#2` };
|
|
|
|
const lookup = buildLookup([second, first]);
|
|
|
|
expect(lookup.get(simpleKey(FILE, 'save'))).toBe(first.id);
|
|
});
|
|
|
|
it('resolves a Record definition to its Record node instead of a same-named fallback', () => {
|
|
const record = {
|
|
id: `Record:${FILE}:Person`,
|
|
label: 'Record' as const,
|
|
name: 'Person',
|
|
qualifiedName: 'Person',
|
|
startLine: 10,
|
|
};
|
|
const sameNamedMethod = {
|
|
id: `Method:${FILE}:Factory.Person#0`,
|
|
label: 'Method' as const,
|
|
name: 'Person',
|
|
qualifiedName: 'Factory.Person',
|
|
startLine: 20,
|
|
};
|
|
|
|
const lookup = buildLookup([sameNamedMethod, record]);
|
|
|
|
expect(lookup.get(qualifiedKey(FILE, 'Record', 'Person'))).toBe(record.id);
|
|
expect(
|
|
resolveDefGraphId(
|
|
FILE,
|
|
{
|
|
type: 'Record',
|
|
qualifiedName: 'Person',
|
|
},
|
|
lookup,
|
|
),
|
|
).toBe(record.id);
|
|
});
|
|
});
|