fix(state): invalidate disk scan cache in writeStateMd (#1967)

Add _diskScanCache.delete(cwd) at the start of writeStateMd before
buildStateFrontmatter is called. This prevents stale reads if multiple
state-mutating operations occur within the same Node process — the
write may create new PLAN/SUMMARY files that the next frontmatter
computation must see.

Matters for:
- SDK callers that require() gsd-tools.cjs as a module
- Future dispatcher extensions handling compound operations
- Tests that import state.cjs directly

Adds tests/bug-1967-cache-invalidation.test.cjs which exercises two
sequential writes in the same process with a new phase directory
created between them, asserting the second write sees the new disk
state (total_phases: 2, completed_phases: 1) instead of the cached
pre-write snapshot (total_phases: 1, completed_phases: 0).

Review feedback on #2054 from @trek-e.
This commit is contained in:
Tibsfox
2026-04-11 03:35:00 -07:00
parent 5638448296
commit 67aeb049c2
2 changed files with 104 additions and 0 deletions

View File

@@ -921,6 +921,10 @@ function releaseStateLock(lockPath) {
* each other's changes (race condition with read-modify-write cycle).
*/
function writeStateMd(statePath, content, cwd) {
// Invalidate disk scan cache before computing new frontmatter — the write
// may create new PLAN/SUMMARY files that buildStateFrontmatter must see.
// Safe for any calling pattern, not just short-lived CLI processes (#1967).
if (cwd) _diskScanCache.delete(cwd);
const synced = syncStateFrontmatter(content, cwd);
const lockPath = acquireStateLock(statePath);
try {