Skip to content

Avoid rewriting unchanged plan history files - #2878

Merged
steipete merged 1 commit into
mainfrom
fix/issue-2495-plan-history-noop-writes
Aug 12, 2026
Merged

Avoid rewriting unchanged plan history files#2878
steipete merged 1 commit into
mainfrom
fix/issue-2495-plan-history-noop-writes

Conversation

@steipete

Copy link
Copy Markdown
Owner

Summary

  • skip atomic replacement when a provider's deterministic plan-history JSON is byte-identical to the existing file
  • preserve the existing write, repair, and deletion paths for changed, missing, malformed, unreadable, or empty provider histories
  • verify unchanged file bytes, modification time, and inode, plus cross-provider isolation

Fixes #2495

Root cause

PlanUtilizationHistoryStore.save deterministically encoded every known provider and then always called atomic Data.write, even when the encoded bytes exactly matched the existing provider file. Because an update to one provider saves the complete history dictionary, unchanged sibling files such as history/claude.json and history/codex.json were repeatedly replaced as well.

Implementation

After encoding the canonical sorted payload, the store reads the current file and returns early only when the bytes are identical. A missing or failed read falls through to the existing atomic write. Empty histories still remove stale files, malformed files are replaced with valid canonical JSON, and changed providers still round-trip normally.

Validation

  • focused UsageStorePlanUtilizationTests: 92 tests passed
  • new regression coverage proves:
    • an unchanged provider preserves bytes, modification time, and inode
    • changing one provider rewrites and reloads it without touching an unchanged sibling
    • saving an empty provider removes its prior file
    • a malformed provider file is replaced by canonical valid JSON
  • make check: passed
  • full make test: 840 selections across 70 groups passed with no retries or timeouts
  • structured Codex autoreview: clean, no accepted or actionable findings
  • TruffleHog patch scan: clean

One earlier full run hit host-load flakiness in the unrelated BoundedChildProcessProofTests lane: the PTY latency assertion took 25 seconds and the synthetic Grok handshake timed out. That exact three-test suite then passed in isolation in 5.3 seconds, and the complete matrix rerun passed all 70 groups without retries.

@clawsweeper

clawsweeper Bot commented Aug 12, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@steipete

Copy link
Copy Markdown
Owner Author

@clawsweeper review

@steipete

Copy link
Copy Markdown
Owner Author

@codex review

@clawsweeper

clawsweeper Bot commented Aug 12, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 01076474ba

ℹ️ 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".

@clawsweeper

clawsweeper Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed August 12, 2026, 2:31 AM ET / 06:31 UTC.

ClawSweeper review

What this changes

The branch skips atomic replacement of a provider’s deterministic plan-history JSON when the existing bytes are unchanged, and adds filesystem-state regression tests.

Merge readiness

⚠️ Ready for maintainer review - 1 item remains

This owner-authored PR remains necessary: current main still atomically replaces every non-empty provider history file, while the branch adds a narrow exact-byte guard with focused regression coverage.

Priority: P2
Reviewed head: 01076474bab4c3b79a3771212a5cc102faf522c6

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A narrow persistence fix with strong targeted regression coverage and no identified correctness or security finding.
Proof confidence 🐚 platinum hermit (4/6) Not applicable: This owner-authored persistence repair is outside the external-contributor proof gate; the PR body also reports focused filesystem tests and full-suite validation.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: This owner-authored persistence repair is outside the external-contributor proof gate; the PR body also reports focused filesystem tests and full-suite validation.
Evidence reviewed 5 items Current-main behavior: Current main deterministically encodes each non-empty provider payload and unconditionally performs an atomic write, so unchanged sibling files are replaced during a save.
Branch implementation: The proposed guard continues only when the existing file can be read and is byte-identical; otherwise the established atomic write path remains intact.
Focused regression coverage: New tests cover unchanged file identity, unchanged sibling isolation, empty-history deletion, and malformed-file replacement.
Findings None None.
Security None None.

How this fits together

CodexBar saves per-provider plan-utilization history as local JSON files. Provider refreshes feed the history store, which removes empty histories or persists changed data for later reload and menu-history rendering.

flowchart LR
A[Provider refresh] --> B[Plan history store]
B --> C[Encode canonical JSON]
C --> D{Existing bytes identical?}
D -->|Yes| E[Preserve existing file]
D -->|No| F[Atomically write file]
B -->|Empty history| G[Remove stale file]
E --> H[Later history reload]
F --> H
G --> H
Loading

Before merge

  • Resolve merge risk (P1) - Required GitHub checks were still in progress at review time; merge should wait for their completion.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production versus test delta production +5, tests +123, changelog +1 The small persistence-path guard is backed by targeted filesystem identity and isolation coverage.

Merge-risk options

Maintainer options:

  1. Decide the mitigation before merge
    Merge the exact-byte persistence guard after required checks pass, retaining the established deletion and repair paths for non-identical histories.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Technical review

Best possible solution:

Merge the exact-byte persistence guard after required checks pass, retaining the established deletion and repair paths for non-identical histories.

Do we have a high-confidence way to reproduce the issue?

Yes—current main’s save loop deterministically encodes non-empty provider histories and always reaches atomic write; the branch’s focused tests exercise the unchanged-file path.

Is this the best way to solve the issue?

Yes—the byte-equality comparison is the narrowest solution because it preserves existing behavior for changed, missing, unreadable, malformed, and empty histories.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 6e0a50001f98.

Labels

Label changes:

  • add P2: The change fixes unnecessary local disk writes with bounded persistence impact and no evidence of data loss or availability failure.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: This owner-authored persistence repair is outside the external-contributor proof gate; the PR body also reports focused filesystem tests and full-suite validation.

Label justifications:

  • P2: The change fixes unnecessary local disk writes with bounded persistence impact and no evidence of data loss or availability failure.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: This owner-authored persistence repair is outside the external-contributor proof gate; the PR body also reports focused filesystem tests and full-suite validation.

Evidence

What I checked:

Likely related people:

  • steipete: Current-history blame attributes both the existing write path and this focused repair to Peter Steinberger. (role: feature owner and recent area contributor; confidence: high; commits: 330ae4384b18, 01076474bab4; files: Sources/CodexBar/PlanUtilizationHistoryStore.swift, Tests/CodexBarTests/UsageStorePlanUtilizationTests.swift)
  • Yuxin-Qiao: History records the plan-history asynchronous-load refactor, making this contributor a relevant secondary routing contact for persistence lifecycle changes. (role: recent adjacent contributor; confidence: medium; commits: 04e4898a92f8; files: Sources/CodexBar/PlanUtilizationHistoryStore.swift)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (1 earlier review cycle)
  • reviewed 2026-08-12T06:27:08.605Z sha 0107647 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Aug 12, 2026
@steipete
steipete merged commit a90dfed into main Aug 12, 2026
9 checks passed
@steipete

Copy link
Copy Markdown
Owner Author

Landed and verified.

Behavior:

  • PlanUtilizationHistoryStore now preserves an existing provider history file when its canonical encoded bytes are unchanged.
  • Changed, missing, unreadable, malformed, and empty histories retain the existing atomic-write, repair, or deletion behavior.

Proof:

  • swift test --filter UsageStorePlanUtilizationTests: 92 tests passed.
  • New regression tests verify unchanged bytes, modification time, and inode; changed-provider reload with untouched sibling identity; empty-history deletion; and malformed-file replacement.
  • make check: passed.
  • Structured Codex autoreview: clean, no accepted or actionable findings.
  • TruffleHog patch scan: clean.
  • Full make test rerun: 840 selections across 70 groups passed with no retries or timeouts.
  • The first full run hit unrelated host-load flakiness in BoundedChildProcessProofTests: the PTY latency assertion took 25 seconds and the synthetic Grok handshake timed out. That exact three-test suite passed immediately in isolation in 5.3 seconds, and the complete rerun passed all 70 groups.
  • Exact-head CI passed on 01076474bab4c3b79a3771212a5cc102faf522c6: https://github.com/steipete/CodexBar/actions/runs/31569887873
  • Exact-head Codex and ClawSweeper reviews reported no actionable correctness or security finding.

Merged as a90dfed5c264f12e37b0caf6ea9cead276873ed4. Final-main CI passed: https://github.com/steipete/CodexBar/actions/runs/31571308842

No release, tag, appcast, package, or artifact publication was performed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lot of disk write for codexbar

1 participant