fix: Fix Metrics History Destruction & Self-Exclusion Blind Spot#34
Merged
Merged
Conversation
- Never-shrink guard in writeMetrics: skip the day-file write when the incoming entry's totalCost is below the existing snapshot's — Claude Code purges transcripts >30 days old, so every sync was overwriting correct per-day JSONL history with post-purge residue (~$5,160 measured destroyed across machines) - New standalone scripts/repair-metrics.mjs (dry-run default, --write) restoring shrunk day-files to their historical max from the metrics repo's git history; run manually post-release - Self-view max-merge: own-machine repo snapshots are max-merged into the live local view via new pure maxMergeEntries in fetcher.ts, so a machine sees its own synced history after local transcript purge (fixes --by-machine and watch mode too)
There was a problem hiding this comment.
Pull request overview
This PR prevents multi-machine sync from silently destroying historical daily metrics after Claude Code transcript retention purges, and fixes a related “self-exclusion” blind spot where a machine could no longer see its own synced history once local transcripts were gone.
Changes:
- Added a never-shrink guard in
writeMetricsso per-day snapshot files act as high-water marks and are not overwritten by lowertotalCostvalues. - Introduced a standalone one-time repair script (
scripts/repair-metrics.mjs) to restore shrunk day-files from the metrics repo’s git history (dry-run by default,--writerestores working tree only). - Fixed own-machine self-view by max-merging local live entries with the machine’s own repo snapshots before summing with other machines.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/node/sync/sync.ts | Adds the never-shrink write guard to protect historical day-file snapshots. |
| src/node/sync/tests/sync.test.ts | Adds coverage for shrink-skip, equal refresh, and corrupted/empty existing files. |
| scripts/repair-metrics.mjs | Adds a standalone repair tool to detect and restore shrunk metrics files from git history. |
| src/node/sync/tests/repair-metrics.test.ts | End-to-end tests for the repair script using a hermetic seeded git fixture repo. |
| src/node/core/fetcher.ts | Adds maxMergeEntries helper (whole-entry per-label max by totalCost). |
| src/node/core/cli.ts | Rewires merged fetch paths to max-merge own snapshots into the local view and read all machines in one pass. |
| src/node/core/tests/fetcher.test.ts | Adds unit tests for maxMergeEntries semantics (ties, copies, ordering, non-mutation). |
| src/node/core/tests/self-view-merge.test.ts | Composition test mirroring the multi-mode pipeline to validate corrected self-view behavior. |
| docs/memory/sync/multi-machine.md | Documents high-water-mark semantics, guarded writes, self-view max-merge, and the repair script contract. |
| docs/memory/sync/index.md | Updates sync memory index description/date to reflect new semantics. |
| docs/memory/cli/data-pipeline.md | Documents the updated multi-mode pipeline including maxMergeEntries. |
| docs/memory/cli/index.md | Updates CLI memory index date to reflect the pipeline update. |
| fab/changes/260610-srmi-fix-metrics-history-destruction/* | Adds/updates change tracking artifacts (intake/plan/status/history). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Meta
Pipeline: intake ✓ → apply ✓ → review ✓ → hydrate ✓ → ship → review-pr
Impact: +849/−5 code (excluding
fab/,docs/) · +1234/−9 totalSummary
Claude Code purges session transcripts older than
30 days, so a machine's live ccusage view of old dates collapses toward zero — and tu's multi-machine sync treated that live fetch as authoritative, unconditionally overwriting correct per-day JSONL snapshots in the shared metrics repo ($5,160 measured destroyed; e.g. 2026-04-24 went $308.12 → $9.46). A compounding self-exclusion bug meant a machine could not see its own synced history once local transcripts were purged. This change makes day-files true high-water marks via a never-shrink guard inwriteMetrics, ships a one-time repair script that restores shrunk files from the repo's git history (run manually post-release), and max-merges own-machine snapshots back into the live local view (fixing--by-machineand watch mode too).Changes
writeMetrics(src/node/sync/sync.ts)scripts/repair-metrics.mjs, new)src/node/core/cli.ts+src/node/core/fetcher.ts)