feat(FN-1553): reduce memory bloat with selective save behavior

- Update project memory instructions to encourage selective writes instead of unconditional appends
- Instruct agents to consolidate existing entries rather than add duplicates
- Add guidance to skip memory updates when no durable learnings were discovered
- Clarify what qualifies as durable learnings vs task-specific trivia
- Update user-facing memory documentation to reflect new selective behavior
- Add test coverage for selective memory write instructions
This commit is contained in:
gsxdsm
2026-04-11 00:35:39 -07:00
parent afa2e153ee
commit c8831f7b3b
6 changed files with 135 additions and 785 deletions

View File

@@ -173,10 +173,29 @@ describe("project-memory", () => {
expect(instructions).toMatch(/read.*memory\.md/i);
});
it("instructs agent to append learnings at end", () => {
it("instructs agent to selectively write learnings at end", () => {
const instructions = buildExecutionMemoryInstructions(testDir);
expect(instructions).toMatch(/end of execution|before calling.*task_done/i);
expect(instructions).toMatch(/append/i);
// Should mention selective/skip behavior, not just append
expect(instructions).toMatch(/skip.*memory.*update|selectively|durable.*learnings/i);
});
it("instructs agent to skip when nothing durable was learned", () => {
const instructions = buildExecutionMemoryInstructions(testDir);
// Should explicitly allow skipping when nothing durable was learned
expect(instructions).toMatch(/skip.*memory.*update|nothing durable|if nothing/i);
});
it("instructs agent to avoid task-specific trivia", () => {
const instructions = buildExecutionMemoryInstructions(testDir);
// Should explicitly forbid task-specific trivia
expect(instructions).toMatch(/avoid.*trivia|task-specific.*trivia|per-task.*log|changelog/i);
});
it("allows editing/consolidating existing entries", () => {
const instructions = buildExecutionMemoryInstructions(testDir);
// Should allow consolidation/editing, not forbid it
expect(instructions).toMatch(/consolidate|update.*refine.*existing|edit.*existing/i);
});
it("specifies project-root path not worktree-local", () => {
@@ -184,10 +203,5 @@ describe("project-memory", () => {
// Should use .fusion/memory.md (project root relative) not absolute worktree paths
expect(instructions).toContain("`.fusion/memory.md`");
});
it("warns against deleting existing content", () => {
const instructions = buildExecutionMemoryInstructions(testDir);
expect(instructions).toMatch(/do not delete|only append/i);
});
});
});

View File

@@ -115,7 +115,12 @@ This project has a memory file at \`.fusion/memory.md\` that stores durable proj
* Build the memory instruction section for the execution prompt.
*
* Tells the executor agent to read the memory file at the start of execution
* and append new durable learnings at the end.
* and selectively update it with durable learnings at the end.
*
* Key behavioral changes from legacy append-only pattern:
* - Agents SHOULD skip memory updates when nothing durable was learned
* - Agents CAN edit/consolidate existing entries (not just append)
* - Only genuinely reusable insights qualify — not task-specific trivia
*
* The path is always the project-root relative path (`.fusion/memory.md`),
* not a worktree-local path. Agents running in worktrees should access
@@ -137,10 +142,19 @@ This project has a memory file at \`.fusion/memory.md\` that stores durable proj
3. Apply these learnings to your implementation — follow documented patterns and avoid known pitfalls
**At the end of execution (before calling \`task_done()\`):**
1. Review what you learned during this task that would benefit future runs
2. If you discovered new patterns, conventions, pitfalls, or important context, **append them** to the appropriate section in \`.fusion/memory.md\`
3. Only add genuinely durable, reusable learnings — not task-specific trivia
4. Do NOT delete or reorganize existing content; only append new items
1. Review what you learned during this task that would genuinely benefit future runs
2. **If nothing durable was learned, skip the memory update entirely** — do not append trivial or task-specific notes
3. Only write when you have genuinely durable, reusable insights such as:
- New architectural patterns or module boundaries discovered
- Conventions or standards that should be followed
- Pitfalls or anti-patterns to avoid in future work
- Important constraints or context that affects implementation decisions
4. **Avoid** writing task-specific trivia such as:
- Per-task implementation logs or changelog entries
- Transient failures resolved without broader lessons
- One-off file paths, variable names, or minor code changes
- Notes about what you did rather than what future agents should know
5. **Consolidate when possible**: If an existing entry already covers a concept, update or refine it rather than adding a duplicate. Delete entries that are no longer accurate.
**Format for additions:** Add bullet points under the relevant section heading:
- Use \`- \` prefix for list items

View File

@@ -2234,13 +2234,18 @@ describe("buildExecutionPrompt", () => {
expect(result).toContain(".fusion/memory.md");
});
it("includes append instruction for updating memory at end of execution", () => {
it("includes selective memory write instruction for durable learnings at end of execution", () => {
const task = createMockTaskDetail();
const result = buildExecutionPrompt(task, "/project", {
memoryEnabled: true,
} as any);
expect(result).toContain("append");
// Should instruct selective writes, not unconditional appends
expect(result).toMatch(/skip.*memory.*update|selectively|durable.*learnings/i);
expect(result).toMatch(/end of execution|before calling.*task_done/i);
// Should forbid task-specific trivia
expect(result).toMatch(/avoid.*trivia|task-specific.*trivia|per-task.*log/i);
// Should allow consolidation/editing
expect(result).toMatch(/consolidate|update.*refine.*existing|edit.*existing/i);
});
it("uses project-root memory path not worktree-local path", () => {