diff --git a/gitnexus/src/mcp/tools.ts b/gitnexus/src/mcp/tools.ts index 121845566..5db37438e 100644 --- a/gitnexus/src/mcp/tools.ts +++ b/gitnexus/src/mcp/tools.ts @@ -469,9 +469,14 @@ SERVICE: optional monorepo path prefix (case-sensitive path segments). When "rep }, line: { type: 'integer', - minimum: 1, + // `minimum: 0` (not 1) so strict client/agent adapters that materialize + // an omitted optional numeric field as `0` do not reject the request + // before sending (#2279). A positive line is still required for a real + // pdg anchor — the backend enforces that — but `0`/omitted means "no + // statement anchor" and is tolerated on the callgraph path. + minimum: 0, description: - "1-based source line — PDG statement anchor (mode:'pdg'). Seeds affectedStatements on the statement at this line; inter-procedural symbols are still returned in interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket.", + "1-based source line — PDG statement anchor (mode:'pdg'). Seeds affectedStatements on the statement at this line; inter-procedural symbols are still returned in interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket. 0 (or omitted) means no statement anchor; mode:'pdg' requires a positive line.", }, file_path: { type: 'string', diff --git a/gitnexus/test/unit/tools.test.ts b/gitnexus/test/unit/tools.test.ts index a2cb484c7..0b90061a8 100644 --- a/gitnexus/test/unit/tools.test.ts +++ b/gitnexus/test/unit/tools.test.ts @@ -134,17 +134,22 @@ describe('GITNEXUS_TOOLS', () => { expect(impactTool.inputSchema.required).toContain('direction'); }); - it('impact tool advertises the PDG-only `line` statement anchor (integer, min 1, not required)', () => { + it('impact tool advertises the PDG-only `line` statement anchor (integer, min 0, not required)', () => { const impactTool = GITNEXUS_TOOLS.find((t) => t.name === 'impact')!; const line = (impactTool.inputSchema.properties as Record).line; expect(line).toBeDefined(); expect(line.type).toBe('integer'); - expect(line.minimum).toBe(1); + // minimum is 0 (not 1) so strict adapters that materialize an omitted + // optional numeric field as `0` are not rejected client-side (#2279); a + // positive line is enforced backend-side for a real pdg anchor. + expect(line.minimum).toBe(0); // Statement-anchored slice is optional — never required. expect(impactTool.inputSchema.required).not.toContain('line'); - // The description names the mode:'pdg' statement-anchor semantics. + // The description names the mode:'pdg' statement-anchor semantics and the + // 0/omitted = no-anchor compatibility convention. expect(line.description).toMatch(/statement anchor/i); expect(line.description).toMatch(/pdg/i); + expect(line.description).toMatch(/0 \(or omitted\) means no statement anchor/i); // The top-level description mentions the statement-anchored slice and result shape. expect(impactTool.description).toMatch(/statement-anchored|STATEMENT-ANCHORED/); expect(impactTool.description).toContain('affectedStatements');