fix: refresh session-store cache when file size changes within same mtime tick#32191
fix: refresh session-store cache when file size changes within same mtime tick#32191
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6ac71cbdc
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Greptile SummaryThis PR improves the session-store cache invalidation by adding file size as a secondary signal alongside
Confidence Score: 4/5
Last reviewed commit: e6ac71c |
e6ac71c to
4fc8ebd
Compare
…time tick The session-store cache used only mtime for invalidation. In fast CI runs (especially under bun), test writes to the session store can complete within the same filesystem mtime granularity (~1s on HFS+/ext4), so the cache returns stale data. This caused non-deterministic failures in model precedence tests where a session override written to disk was not observed by the next loadSessionStore() call. Fix: add file size as a secondary cache invalidation signal. The cache now checks both mtimeMs and sizeBytes — if either differs from the cached values, it reloads from disk. Changes: - cache-utils.ts: add getFileSizeBytes() helper - sessions/store.ts: extend SessionStoreCacheEntry with sizeBytes field, check size in cache-hit path, populate size on cache writes - sessions.cache.test.ts: add regression test for same-mtime rewrite
c9c209c to
3b7411c
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3b7411c9e3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| fs.writeFileSync(storePath, json2); | ||
|
|
||
| // Force mtime to match the cached value so only size differs | ||
| fs.utimesSync(storePath, preWriteStat.atime, preWriteStat.mtime); |
There was a problem hiding this comment.
Preserve precise mtime when forcing same-tick rewrite
fs.utimesSync(storePath, preWriteStat.atime, preWriteStat.mtime) uses Date values, which can shift away from the original mtimeMs precision on filesystems with sub-millisecond timestamps (fresh evidence: on this branch, a Date-based utimes changed mtimeMs for the same file). When that happens, this regression test reloads due to mtime mismatch instead of size mismatch, so it can still pass even if size-based invalidation regresses; set mtime from the original high-precision timestamp (mtimeMs) so only size differences trigger the reload.
Useful? React with 👍 / 👎.
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🔵 Static code scan cache can be bypassed by rewriting a file while preserving mtime and size
DescriptionThe This allows stale scan results to be reused if an attacker (or fast CI/filesystems with coarse timestamp granularity) rewrites a file such that:
In that case, Vulnerable code: if (
cached.size !== params.size ||
cached.mtimeMs !== params.mtimeMs ||
cached.maxFileBytes !== params.maxFileBytes
) {
FILE_SCAN_CACHE.delete(params.filePath);
return undefined;
}
return cached;RecommendationStrengthen cache invalidation so content changes cannot be hidden behind identical Recommended options (pick one):
// when stat-ing
const st = await fs.stat(filePath);
const cached = getCachedFileScanResult({
filePath,
size: st.size,
mtimeMs: st.mtimeMs,
ctimeMs: st.ctimeMs,
maxFileBytes,
});
Also update tests to cover the same-size rewrite case (i.e., content change with identical size) to prevent regressions. Analyzed PR: #32191 at commit Last updated on: 2026-03-02T23:13:24Z |
Problem
The session-store cache used only
mtimeMsfor invalidation. In fast CI runs (especially under bun), test writes to the session store can complete within the same filesystem mtime granularity (~1s on HFS+/ext4), so the cache returns stale data.This caused non-deterministic failures in model precedence tests (
isolated-agent.uses-last-non-empty-agent-text-as.test.ts) where a session override written to disk was not picked up by the nextloadSessionStore()call — the default anthropic provider was returned instead of the expected openai override.Fix
Add file size as a secondary cache invalidation signal. The cache now checks both
mtimeMsandsizeBytes— if either differs from the cached values, it reloads from disk.Changes
src/config/cache-utils.ts: addgetFileSizeBytes()helpersrc/config/sessions/store.ts: extendSessionStoreCacheEntrywithsizeBytesfield, check size in cache-hit path, populate size on cache writessrc/config/sessions.cache.test.ts: add regression test for same-mtime rewrite scenarioTesting
All 9 session cache tests pass locally (8 existing + 1 new regression test). The flaky model precedence test passes consistently with this fix.