Skip to content

fix(pre-read): skip repeated-read warning when file was modified since last read - #60

Open
AdarshJ173 wants to merge 1 commit into
cytostack:mainfrom
AdarshJ173:fix/pre-read-mtime-repeated-read
Open

fix(pre-read): skip repeated-read warning when file was modified since last read#60
AdarshJ173 wants to merge 1 commit into
cytostack:mainfrom
AdarshJ173:fix/pre-read-mtime-repeated-read

Conversation

@AdarshJ173

Copy link
Copy Markdown

Summary

Fixes #41pre-read hook blocks re-reads even after the file was modified during the session.

The pre-read hook currently warns on every re-read of a file seen this session, even when Claude just wrote to that file or the user edited it externally. This inflates repeated_reads_warned and estimated_savings_vs_bare_cli stats with false positives, and — more practically — suppresses the anatomy hint and re-read token estimate that Claude needs after a file changes.


What changed

src/hooks/pre-read.ts

  • Problem: session.files_read[normalizedFile] stored only count, tokens, and first_read — no mtime snapshot, so there was no way to detect a change between reads.
  • Change 1: When recording the initial read entry, capture read_mtime: fs.statSync(normalizedFile).mtimeMs (wrapped in try/catch; if statSync fails, read_mtime is left undefined and the old behaviour is preserved).
  • Change 2: On re-read, if prev.read_mtime !== undefined, compare current statSync(normalizedFile).mtimeMs against the stored value. If currentMtime > prev.read_mtime, the file changed — delete the stale entry and fall through to the normal first-read path (anatomy hint, no warning). If mtime is unchanged, the existing repeated-read warning fires as before.

src/hooks/post-write.ts

  • Problem: After Claude writes to a file, the files_read session entry for that file still held the old read_mtime. The next pre-read of the same file would have to go through a statSync comparison to detect the change, which is fine — but the write hook already knows the file changed.
  • Change: In section 3 (session tracker), add delete session.files_read[normalizedFile] immediately after updating files_written. This eagerly invalidates the read cache for the written file, so the very next re-read is treated as fresh without needing to compare mtimes at all.

Acceptance criteria

  • Claude reads foo.ts → Claude writes to foo.ts → Claude reads foo.ts again → no repeated-read warning, anatomy hint re-fires
  • Claude reads foo.ts → user edits foo.ts externally → Claude reads foo.ts again → no repeated-read warning (mtime changed)
  • Claude reads foo.ts → nothing changes → Claude reads foo.ts again → repeated-read warning fires (correct behaviour preserved)
  • repeated_reads_warned counter is not incremented for legitimate re-reads
  • statSync errors (deleted file, permission denied) do not crash the hook — they fall back to the original warn-on-reread behaviour

How to test

  1. openwolf init in a test project, open Claude Code
  2. Ask Claude to read any source file — note the anatomy hit in stderr
  3. Ask Claude to edit that same file, then read it again
  4. Expected: no ⚡ OpenWolf: ... was already read warning on the second read
  5. Edge case: ask Claude to read the same file twice without any write between — expected: warning fires on the second read (regression check)
  6. Edge case: externally touch src/foo.ts between two reads — expected: second read is treated as fresh

Notes

  • No schema changes
  • No new dependencies added
  • No server/API changes
  • No breaking changes to existing consumers — read_mtime is an optional field; sessions without it (e.g. old _session.json files) fall back to the original behaviour because the if (prev.read_mtime !== undefined) guard is skipped
  • statSync is already used in this file for the symbol-hint freshness check, so the import is not new
  • The post-write.ts change adds files_read to the SessionData interface there (was only in pre-read.ts's local interface) to make the delete type-safe

…e last read

Closes cytostack#41

- Track `read_mtime` (statSync.mtimeMs) alongside `first_read` in the
  files_read session entry so we can detect file changes between reads
- On re-read: compare current mtime against stored read_mtime; if file
  changed (by Claude or user), clear the stale entry and let the read
  proceed without a false repeated-read warning
- In post-write.ts section 3: delete session.files_read[normalizedFile]
  so a write immediately invalidates the cached read record, without
  waiting for the next statSync comparison
- Both statSync calls are wrapped in try/catch; on error the existing
  behaviour is preserved (warn or allow as before)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pre-read hook blocks re-reads even after the file was modified during the session

1 participant