feat(FN-4063): enforce planning and triage memory write contracts
Enforces memory write contracts for triage and planning agents, adding tests in both `project-memory.test.ts` and `triage.test.ts` to guard the contract boundaries established in `project-memory.ts`. Fusion-Task-Id: FN-4063 Fusion-Task-Lineage: 5f86295b-d583-4757-9aa5-30a64b2cc2d6
This commit is contained in:
@@ -536,6 +536,9 @@ describe("project-memory", () => {
|
|||||||
const instructions = buildTriageMemoryInstructions(testDir, settings);
|
const instructions = buildTriageMemoryInstructions(testDir, settings);
|
||||||
expect(instructions).toContain(".fusion/memory/MEMORY.md");
|
expect(instructions).toContain(".fusion/memory/MEMORY.md");
|
||||||
expect(instructions).toContain("## Project Memory");
|
expect(instructions).toContain("## Project Memory");
|
||||||
|
expect(instructions).toContain("fn_memory_append");
|
||||||
|
expect(instructions).toContain("Do **not** write");
|
||||||
|
expect(instructions).toContain("or any other memory files directly");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes read-only wording for readonly backend without write directives", () => {
|
it("includes read-only wording for readonly backend without write directives", () => {
|
||||||
@@ -558,6 +561,8 @@ describe("project-memory", () => {
|
|||||||
expect(instructions).not.toContain(".fusion/memory/MEMORY.md");
|
expect(instructions).not.toContain(".fusion/memory/MEMORY.md");
|
||||||
expect(instructions).toContain("memory_search");
|
expect(instructions).toContain("memory_search");
|
||||||
expect(instructions).toContain("memory_get");
|
expect(instructions).toContain("memory_get");
|
||||||
|
expect(instructions).toContain("fn_memory_append");
|
||||||
|
expect(instructions).toContain("Do **not** write memory files directly");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("QMD triage instructions completeness - contains consult guidance", () => {
|
it("QMD triage instructions completeness - contains consult guidance", () => {
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ export function createTaskStoreTestHarness() {
|
|||||||
afterEach: async () => {
|
afterEach: async () => {
|
||||||
vi.useRealTimers();
|
vi.useRealTimers();
|
||||||
store.stopWatching();
|
store.stopWatching();
|
||||||
await new Promise<void>((resolve) => process.nextTick(resolve));
|
// Yield one microtask tick without relying on process.nextTick,
|
||||||
|
// which can be faked in timer-heavy suites and hang teardown.
|
||||||
|
await Promise.resolve();
|
||||||
store.close();
|
store.close();
|
||||||
await rm(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
await rm(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
||||||
await rm(globalDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
await rm(globalDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
||||||
|
|||||||
@@ -374,6 +374,10 @@ This project has OpenClaw-style memory files:
|
|||||||
2. Use \`fn_memory_get\` only for specific memory files/line ranges returned by search
|
2. Use \`fn_memory_get\` only for specific memory files/line ranges returned by search
|
||||||
3. Incorporate relevant learnings into your specification — reference actual patterns, constraints, and conventions documented there
|
3. Incorporate relevant learnings into your specification — reference actual patterns, constraints, and conventions documented there
|
||||||
|
|
||||||
|
**Memory write contract for planning agents:**
|
||||||
|
- If you need to save durable planning context, use \`fn_memory_append\` (choose scope/layer intentionally)
|
||||||
|
- Do **not** write \`.fusion/memory/MEMORY.md\`, \`.fusion/memory/YYYY-MM-DD.md\`, or any other memory files directly when \`fn_memory_append\` is available
|
||||||
|
|
||||||
Do not read all memory directly by default. If memory is irrelevant, skip it.
|
Do not read all memory directly by default. If memory is irrelevant, skip it.
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -389,6 +393,10 @@ This project has a memory system that stores durable project learnings.
|
|||||||
2. Use \`fn_memory_get\` only for specific memory files/line ranges returned by search
|
2. Use \`fn_memory_get\` only for specific memory files/line ranges returned by search
|
||||||
3. Incorporate useful learnings into your specification
|
3. Incorporate useful learnings into your specification
|
||||||
|
|
||||||
|
**Memory write contract for planning agents:**
|
||||||
|
- If you need to save durable planning context, use \`fn_memory_append\` (choose scope/layer intentionally)
|
||||||
|
- Do **not** write memory files directly when \`fn_memory_append\` is available
|
||||||
|
|
||||||
**If the memory contains useful context for this task, reference it in the specification.**
|
**If the memory contains useful context for this task, reference it in the specification.**
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -418,6 +418,9 @@ describe("buildSpecificationPrompt", () => {
|
|||||||
);
|
);
|
||||||
expect(prompt).toContain("## Project Memory");
|
expect(prompt).toContain("## Project Memory");
|
||||||
expect(prompt).toContain(".fusion/memory/");
|
expect(prompt).toContain(".fusion/memory/");
|
||||||
|
expect(prompt).toContain("fn_memory_append");
|
||||||
|
expect(prompt).toContain("Do **not** write");
|
||||||
|
expect(prompt).toContain("or any other memory files directly");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes read-only wording for readonly backend without write directives", () => {
|
it("includes read-only wording for readonly backend without write directives", () => {
|
||||||
@@ -462,6 +465,8 @@ describe("buildSpecificationPrompt", () => {
|
|||||||
expect(prompt).not.toContain(".fusion/memory/");
|
expect(prompt).not.toContain(".fusion/memory/");
|
||||||
expect(prompt).toContain("fn_memory_search");
|
expect(prompt).toContain("fn_memory_search");
|
||||||
expect(prompt).toContain("fn_memory_get");
|
expect(prompt).toContain("fn_memory_get");
|
||||||
|
expect(prompt).toContain("fn_memory_append");
|
||||||
|
expect(prompt).toContain("Do **not** write memory files directly");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("QMD prompt has actionable memory instructions", () => {
|
it("QMD prompt has actionable memory instructions", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user