STATE.md corruption: stale file-history snapshot re-injected into working tree at context/compaction boundaries

Status Closed — not planned
Maintainer reply None cached
Activity 4 comments · opened Aug 23, 2026 · closed Aug 26, 2026

Summary

A version-controlled markdown file we actively edit (.planning/STATE.md, part of the get-shit-done planning workflow) has been silently overwritten in the working tree — with no edit from the agent, no tool call, no user action — by what appears to be a stale snapshot from Claude Code's own internal file-history store. This has now happened 8 times across sessions in the same repo, most recently caught live (diffed and stashed as evidence) rather than only found pre-existing at session start.

Environment

  • Claude Code CLI (exact version not captured at time of report; happy to provide on request)
  • macOS (Darwin 25.5.0)
  • Repo uses get-shit-done (GSD) planning workflow — ruled out as the cause (see below)

Observed corruption signature (consistent across instances)

  • milestone_name frontmatter field flattened to the literal string "milestone" (losing its real value, e.g. "V1 Launch Hardening (Phase 9.1)")
  • total_phases and percent frontmatter fields reverted to old/wrong numeric values (e.g. total_phases: 12 when the current correct value is 6; percent: 25 when correct is 50)
  • Prose sentences truncated mid-word
  • A Resume file: line wiped to literal None
  • last_updated timestamp sometimes patched to a current timestamp while surrounding prose is stale/truncated — i.e. only some fields get "refreshed," others get reverted to old content

Why we believe this is a Claude Code bug, not a workflow (GSD) bug

  • No hook in ~/.claude/hooks/ writes or restores STATE.md content — audited all hooks in the project, including the two most plausible candidates (a context monitor and a session-state hook), both read-only.
  • No script in the GSD tool's bin/lib/ matches the corrupted template/output shape.
  • The corrupted text is a near-verbatim match for a real STATE.md snapshot from a specific earlier session (days prior), which strongly suggests it's being read from somewhere Claude Code caches file edit history (e.g. an internal file-history/checkpoint store keyed by session id + path hash), not generated fresh.
  • Corruption events have repeatedly coincided with a context-exhaustion / compaction / pause-work boundary — i.e. right when a session is running low on context and some checkpoint/state-save code path may run.
  • Checked get-shit-done (GSD)'s own GitHub issues for a match — nothing corresponds to this exact signature.

Impact

  • Silent data corruption of a file we rely on for cross-session continuity. If a corrupted diff is committed without being caught (we now git diff STATE.md before every commit specifically because of this), it destroys real project history/decisions and misleads future sessions about project state.
  • Happened again live during a routine /resume-style workflow in this session, immediately after a context-usage warning fired (~75-79% usage), while performing an unrelated small doc edit to the same file — no compaction was requested by the user, but this may be an internal auto-compaction trigger.

What we'd like

  • Guidance on whether this matches a known internal code path (checkpoint/compaction writing a stale cached version of a tracked file back into the working tree).
  • If reproducible on your end, a fix; if not obviously reproducible, any pointers on what diagnostic info to capture next time it happens live (we can capture git diff output, but don't have visibility into Claude Code's internal file-history store to compare it directly).

Reproduction is inconsistent

We don't have a minimal repro — it has occurred unpredictably over ~8 sessions in the same fairly large repo (Next.js app, extensive .planning/ markdown docs, long-running sessions with heavy tool use and occasional context compaction). We can provide the actual corrupted diffs (currently preserved via git stash) if that would help.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗