fix: README.md leaked into the teacher's system prompt

composeInstructions loaded EVERY .md in src/agent/prompts — including
README.md, the directory's human documentation, which rode into the
system prompt as its own section (visible in OpenRouter logs, old POC
paths and all).

The loader now enforces the documented convention: only numeric-prefix
fragments (\d+-*.md) compose. README.md stays in the directory as docs
and can never reach the model again. README's rule text updated to
match; composeInstructions exported for tests; regression test asserts
the README never leaks and every numeric fragment composes verbatim.
This commit is contained in:
amosblomqvist
2026-09-02 03:19:03 +03:00
parent 8f8659c8b4
commit 28ccc76594
3 changed files with 29 additions and 4 deletions
+18 -1
View File
@@ -38,7 +38,7 @@ import {
type SubagentSteerMessage,
type VisualResult,
} from "../src/core/contracts.ts";
import { createTeacherAgent } from "../src/agent/teacher-agent.ts";
import { composeInstructions, createTeacherAgent } from "../src/agent/teacher-agent.ts";
import { createTeacherTools } from "../src/agent/tools.ts";
import { handleChatRequest } from "../src/server/chat-handler.ts";
import { deliverJobResult, setTurnRunner } from "../src/server/jobs.ts";
@@ -687,3 +687,20 @@ describe("persistTurn id hygiene", () => {
assert.equal(new Set(ids).size, ids.length, "ids unique — React keys safe");
});
});
// ─── prompt composition hygiene (the README leak) ─────────────────────────────
describe("prompt composition", () => {
it("loads ONLY numeric-prefix fragments — README.md never enters the system prompt", () => {
const instructions = composeInstructions();
assert.ok(!instructions.includes("Prompt fragments"), "README content must not leak");
assert.ok(!instructions.includes("Rules for adding a fragment"), "README content must not leak (rules)");
// every numeric fragment DOES compose, verbatim, after the base prompt
const base = fs.readFileSync("src/agent/system-prompt.md", "utf-8").trim();
assert.ok(instructions.startsWith(base), "base prompt first");
for (const f of fs.readdirSync("src/agent/prompts").filter((f) => /^\d+-[\w.-]+\.md$/.test(f)).sort()) {
const body = fs.readFileSync(`src/agent/prompts/${f}`, "utf-8").trim();
assert.ok(instructions.includes(body), `fragment ${f} must compose verbatim`);
}
});
});