Round 3 adversarial-panel fixes for PR #999:
- Snapshot writes now go through a per-queryKey file plus a CAS re-read
guard before rename, closing the last-writer-wins race where a slower
recompute against an older corpus could clobber a fresher save, and
where distinct queryKeys used to evict each other's single shared slot
(B-G1).
- cline-cli's discoverSessions now fingerprints the growing
<sessionId>.messages.json sibling instead of the static
<sessionId>.json metadata file, so new turns in a live session are no
longer invisible to computeCorpusFingerprint (C-G1).
- computeCorpusFingerprint folds in computeEnvFingerprint per discovered
provider, so non-discovery env vars like CODEBURN_CURSOR_MAX_BUBBLES
and KIMI_MODEL_NAME can no longer serve a stale-forever snapshot (A-G1).
- collectFilesRecursive now resolves symlinked subdirectories and
recurses into them (with a visited-inode guard against cycles) instead
of misclassifying them as leaf files (C-G2).
- Added tests/session-cache-status-snapshot.test.ts covering concurrent
writers against the snapshot file, mirroring session-cache-shards.test.ts's
existing coverage for the main cache (D-G9).
Responds to ozymandiashh's CHANGES_REQUESTED review on #999.
Structural: kept the disk status-snapshot, scoped to serve's documented
CLI-spawn-fallback path, after bringing its invalidation to parity with
serve's own in-process memo (see docs/design/perf-cache-fix.md for the full
reconciliation reasoning against #972's serve.ts/watcher invalidation,
already merged into this branch's ancestry).
Correctness fixes:
1. queryKey now includes the same four pricing-config hashes parser.ts's
own cacheKey deliberately includes (proxyPaths/modelAliases/
priceOverrides/localModelSavings), so an edited pricing config
invalidates the snapshot instead of waiting for an unrelated corpus
change.
2. computeCorpusFingerprint now gives network providers (e.g.
vercel-gateway) a now-stamped synthetic fingerprint entry every call,
mirroring parseAllSessions' own treatment of the same sources, instead
of letting them contribute nothing to the hash.
3. computeCorpusFingerprint generically expands any directory-shaped
non-Claude source (e.g. mistral-vibe) via a new collectFilesRecursive
helper, instead of only Claude getting leaf-file expansion.
4. saveStatusSnapshot is now gated on isSessionHydrationComplete(), so a
degraded read-only parse can no longer be checkpointed as authoritative.
5. The settle-window defer in loadStatusSnapshot now anchors on wall-clock
time since the fingerprint FIRST mismatched (persisted via a new
mismatchFirstSeenAt field) instead of the corpus-wide newest mtime,
which fix#2 can otherwise keep perpetually "recent."
Also fixes a 6th instance of the same defect class as #1, found while
root-causing a test failure: the query key omitted the active display
currency, so switching currencies kept serving stale numbers. Updates
tests/parse-workers.test.ts, whose "warm" assertion assumed every
menubar-json call does a full parse — no longer true within the settle
window after this PR's own snapshot feature.