From d039e212950237f172dc35a61e798a91f5644faf Mon Sep 17 00:00:00 2001 From: Devin Oldenburg Date: Sun, 21 Jun 2026 13:38:31 +0200 Subject: [PATCH] fix(core): actually invoke persistence.cleanup() on guard startup (#218) #420 added and unit-tested persistence.cleanup() (prunes orphaned snapshot files from worktrees that no longer run) but never called it, so orphans still accumulated. Wire it into guard startup (best-effort, optional-chained so test doubles are unaffected) and assert the wiring. --- plugins/goal-guard/guard.js | 10 ++++++++++ tests/integration.test.mjs | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/plugins/goal-guard/guard.js b/plugins/goal-guard/guard.js index 69f39ae..2fc3a0b 100644 --- a/plugins/goal-guard/guard.js +++ b/plugins/goal-guard/guard.js @@ -185,6 +185,16 @@ export function createGuard(input = {}, options = {}, overrides = {}) { /* ignore corrupt state */ } + // Opportunistically prune orphaned snapshot files left by worktrees that no + // longer run (issue #218): without this the persistence dir grows forever. + // Best-effort — a cleanup failure must never break guard startup, and the + // optional call keeps injected test doubles (which omit cleanup) working. + try { + persistence.cleanup?.(); + } catch { + /* best-effort */ + } + // Persist the resolved config alongside the sessions so the TUI sidebar (which reads // only the on-disk snapshot) evaluates completion with the SAME config the server // used — otherwise a non-default `contextualGates` would make the sidebar disagree diff --git a/tests/integration.test.mjs b/tests/integration.test.mjs index c470a83..cab4852 100644 --- a/tests/integration.test.mjs +++ b/tests/integration.test.mjs @@ -13,6 +13,18 @@ function makeGuard(options = {}) { ); } +test("integration: guard startup prunes orphaned persistence files (#218 wiring)", () => { + let cleaned = 0; + const persistence = { ...noopPersistence, cleanup: () => { cleaned += 1; } }; + let t = 0; + createGuard( + { client: { app: { log: async () => undefined }, tui: { showToast: async () => undefined } } }, + {}, + { persistence, clock: () => (t += 1), syncIdle: true }, + ); + assert.equal(cleaned, 1, "createGuard must invoke persistence.cleanup() once at startup"); +}); + /** * End-to-end simulation of a realistic goal lifecycle driven entirely through * the plugin hooks, asserting the guard blocks completion until the full