diff --git a/packages/prompt-variance/src/index.ts b/packages/prompt-variance/src/index.ts index c535243e2..53064fb82 100644 --- a/packages/prompt-variance/src/index.ts +++ b/packages/prompt-variance/src/index.ts @@ -17,9 +17,16 @@ export { // padding whitespace), so no exact tool fingerprint repeats 3x and the shared // threshold guard stays silent. This forbids that specific variation // (muse-rule precedent, CL-7869); no signature normalization ships in -// first-party code. Named export rather than a family row: it travels the +// first-party code. The re-read bullet is narrowed, not absolute (CL-9921): +// it discourages redundant unchanged re-read loops while permitting +// necessary re-reads (unread pages, changed content, targeted uncertainty +// resolution, compaction-lost evidence) with a stated reason and bounded +// scope. Named export rather than a family row: it travels the // ModelFamilyPolicy.promptResidual seam, composed over the gpt narrate note. export const astraResidual: string = "Tool discipline (gpt-6-astra worker):\n" + "- Never re-issue a tool call that repeats a prior call with only trivial argument changes (path prefix, offset, limit, whitespace).\n" + - "- Never re-read a file you have already read this session."; + "- Avoid re-reading content you already have; do not loop full-file re-reads that add no new information.\n" + + "- A re-read is permitted when it adds information: unread pages (a new offset/limit range), content that changed since the last read, a targeted re-read to resolve a specific uncertainty, or evidence lost to compaction.\n" + + "- A necessary re-read states its reason and bounded scope first (path, range, and the question it answers) and does not restart a broad investigation.\n" + + "- Boundary: the same path with default offset/limit after a full read is redundant; the same path with a new page range or after an edit is necessary."; diff --git a/src/agent/astra-reread-guidance.test.ts b/src/agent/astra-reread-guidance.test.ts new file mode 100644 index 000000000..d7f0d37d7 --- /dev/null +++ b/src/agent/astra-reread-guidance.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, test } from "bun:test"; +import { ASTRA_PROMPT_RESIDUAL } from "./model-family-policy.js"; + +// CL-9921: the astra residual permits necessary re-reads while still +// discouraging redundant unchanged re-read loops. Each test names the +// scripted scenario the wording must allow (or, for the negative +// control, keep forbidding). +describe("astra necessary-reread guidance (CL-9921)", () => { + test("changed-file scenario: re-reading content that changed since the last read is permitted", () => { + expect(ASTRA_PROMPT_RESIDUAL).toContain("changed since"); + }); + + test("paginated-report scenario: reading unread pages is permitted", () => { + expect(ASTRA_PROMPT_RESIDUAL).toContain("unread pages"); + }); + + test("compacted-evidence scenario: targeted re-reads that resolve uncertainty or recover compaction-lost evidence are permitted, with a stated reason and bounded scope", () => { + expect(ASTRA_PROMPT_RESIDUAL).toContain("uncertainty"); + expect(ASTRA_PROMPT_RESIDUAL).toContain("compaction"); + expect(ASTRA_PROMPT_RESIDUAL).toContain("reason and bounded scope"); + }); + + test("unchanged-repetition negative control: unchanged full-file re-read loops stay discouraged, the absolute ban is gone, and the boundary is stated", () => { + expect(ASTRA_PROMPT_RESIDUAL).toContain("full-file re-read"); + expect(ASTRA_PROMPT_RESIDUAL).toContain("Boundary"); + expect(ASTRA_PROMPT_RESIDUAL).not.toContain( + "Never re-read a file you have already read", + ); + }); +});