GitNexus/gitnexus/test/unit/ai-context-read-path-must.test.ts
Gergő Magyar 9f82ffd6bf
fix: MUST graph tools on structural reads in generated agent block (#3125)
* fix: add a read-path MUST so generated agent blocks invoke GitNexus on structural questions

The managed Always-Do list gated every MUST on edit/commit/rename, so read-only sessions had no reason to call query, context, or impact. Replace the advisory Explore/Use bullets and keep the #2059 call shapes.

Fixes #3076

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(review): assert pdg_query, Spring Actuator, and Explore/Use absence

Co-authored-by: Cursor <cursoragent@cursor.com>

* style: prettier-wrap read-path MUST unit assertions

CI quality/format failed on the two test files that grew beyond printWidth.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Address PR review feedback (#3125)

- Assert the read-path MUST bullet is immediately followed by the Spring Actuator Always-Do line, not merely that both substrings exist.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test: pin the read-path MUST to Always-Do so CI cannot miss a move

The previous floor and whole-block toContain still passed if the MUST left Always-Do while pdg_query kept the count. Own-line and ungated-length asserts close that hole.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: pick graph tools by question type and require graph-first reads

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-01 09:03:08 +00:00

48 lines
2.2 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { generateGitNexusContent } from '../../src/cli/ai-context.js';
// Regression guard for #3076. The Explore/Use Always-Do lines were advisory, so
// read-only sessions had no MUST to call query/context/impact. The replacement
// bullet is not hasPdg-gated (unlike pdg_query) and is not nested in an
// edit/commit/rename-only sentence.
describe('generateGitNexusContent emits a read-path MUST (#3076)', () => {
const stats = { nodes: 50, edges: 100, processes: 5 };
const mustBullet =
'- **MUST use `query({search_query: "concept"})` for concepts/flows, `context({name: "symbolName"})` for a named symbol, or `impact` for blast radius, on read-only callers, dependencies, imports, or execution flow.** Graph first; text search only for empty/`UNKNOWN`/literals.';
function alwaysDoSection(content: string): string {
return content.slice(content.indexOf('## Always Do'), content.indexOf('## Never Do'));
}
function assertNoAdvisoryExploreUse(content: string): void {
expect(content).not.toMatch(/Explore\s+with/);
expect(content).not.toMatch(/Use\s+`context\(\{name:/);
expect(alwaysDoSection(content)).not.toMatch(/^- [^\n]*Explore/m);
}
it.each([true, false])(
'renders the MUST and drops Explore/Use bullets when hasPdg=%s',
(hasPdg) => {
const content = generateGitNexusContent('ReadPathProject', stats, { hasPdg });
expect(alwaysDoSection(content)).toContain(`\n${mustBullet}\n`);
assertNoAdvisoryExploreUse(content);
if (hasPdg) {
expect(content).toContain('pdg_query');
}
},
);
it('keeps the MUST beside the Spring Actuator Always-Do line', () => {
const content = generateGitNexusContent('SpringProject', stats, { hasSpringActuator: true });
expect(alwaysDoSection(content)).toContain(
`${mustBullet}\n- Spring Actuator runtime evidence is enabled`,
);
assertNoAdvisoryExploreUse(content);
});
it('keeps pdg_query gated on hasPdg while the read-path MUST stays always-emitted', () => {
const withoutPdg = generateGitNexusContent('PlainProject', stats);
expect(alwaysDoSection(withoutPdg)).toContain(`\n${mustBullet}\n`);
expect(withoutPdg).not.toContain('pdg_query');
});
});