[leas code] Share usage provider store lifecycle - #13558
Conversation
📝 WalkthroughWalkthroughAdded shared usage-calendar and worktree-fingerprint helpers. Added 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/main/usage/usage-provider-store-lifecycle.ts (1)
88-101: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winCompute the worktree fingerprint only when the freshness check needs it.
refreshcomputes the fingerprint before the gating check. Two costs follow:
- On the fresh path, every read (
getSummary,getDaily,getBreakdown,getRecentSessionseach callrefresh(false)) rebuilds the full worktree map and JSON-stringifies plus sorts every worktree, then discards the result.- On the
forcepath, the value is never used, andrunScancomputes the same fingerprint again.Move the computation inside the freshness branch.
♻️ Proposed refactor
async refresh(force = false): Promise<PublicUsageProviderScanState<DataPresenceKey>> { if (!this.state.scanState.enabled) { return this.getScanState() } - const currentWorktreeFingerprint = await this.getCurrentWorktreeFingerprint() if (!force && this.state.scanState.lastScanCompletedAt) { const ageMs = Date.now() - this.state.scanState.lastScanCompletedAt - if (ageMs < STALE_MS && this.state.worktreeFingerprint === currentWorktreeFingerprint) { + if (ageMs < STALE_MS && this.state.worktreeFingerprint === this.getCurrentWorktreeFingerprint()) { return this.getScanState() } }
getCurrentWorktreeFingerprintperforms no I/O, so it can also dropasync.src/main/claude-usage/store.ts (1)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRetire the
max-linesdisable directives if the refactor made them unnecessary. This PR moves cache loading, persistence, and scan orchestration out of both provider stores intoUsageProviderStoreLifecycle. Both files still carry a file-leveleslint-disable max-lines. The coding guidelines forbid this directive, so remove each one that the shrunken file no longer needs.
src/main/claude-usage/store.ts#L1-L1: measure the file against the configuredmax-lineslimit and delete the directive if the file now complies.src/main/opencode-usage/store.ts#L1-L1: apply the same check and delete the directive if the file now complies.As per coding guidelines: "Never add
eslint-disable max-linesoroxlint-disable max-lines, including line-specific variants."Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 899a15f6-d713-42aa-9984-af5708c26209
📒 Files selected for processing (13)
src/main/claude-usage/store.test.tssrc/main/claude-usage/store.tssrc/main/codex-usage/store-snapshot.benchmark.test.tssrc/main/codex-usage/store.test.tssrc/main/codex-usage/store.tssrc/main/opencode-usage/store.test.tssrc/main/opencode-usage/store.tssrc/main/usage/usage-calendar-range.test.tssrc/main/usage/usage-calendar-range.tssrc/main/usage/usage-provider-store-lifecycle.test.tssrc/main/usage/usage-provider-store-lifecycle.tssrc/main/usage/usage-worktree-refs.test.tssrc/main/usage/usage-worktree-refs.ts
| @@ -1,28 +1,24 @@ | |||
| /* eslint-disable max-lines -- Why: this store owns Codex analytics persistence, scan policy, and renderer query semantics. Keeping them together prevents the Codex range/scope rules from drifting away from the scanner’s event model. */ | |||
| /* eslint-disable max-lines -- Why: Codex pricing, range, scope, breakdown, and automation-attribution policies remain one cohesive store. */ | |||
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Remove the max-lines suppression.
Line 1 adds eslint-disable max-lines. The coding guidelines prohibit this suppression. Split CodexUsageStore at a concrete policy boundary until it meets the configured limit.
Source: Coding guidelines
Summary
Behavior is intended to remain unchanged.
Screenshots
No visual change.
Testing
pnpm lint(scoped lint and all changed-code gates passed)pnpm typecheckpnpm test(7 focused files / 45 tests passed)pnpm build(pnpm run build:electron-vitepassed)Additional gates passed:
pnpm run check:code-quality:changed -- origin/mainpnpm run check:reliability-gatespnpm run check:max-lines-ratchetgit diff origin/main...HEAD --checkAI Review Report
Three independent reviews traced cache schema normalization, persistence failure behavior, scan concurrency, stale/fingerprint gates, provider adapters, and local/folder/SSH workspace handling. Review found and fixed a legacy Claude cache edge case where a null enabled value was not defaulted, plus a vacuous orphan-temp-file assertion in the centralized tests. A final review found no remaining P0/P1/P2 issue.
Cross-platform review covered macOS, Linux, and Windows path handling. The existing path utilities and local-worktree metadata loader remain authoritative; there are no shortcut, label, shell, or new Electron platform branches in this change. No mobile-facing or remote-wire surface changed.
Security Audit
No dependency, command execution, IPC, network, auth, or secret-handling surface changed. Cache paths and durable atomic writes continue through the existing path resolver and
UsageCacheSnapshotWriter. Corrupt local analytics caches still fail closed to defaults, and scan persistence failures remain logged without turning successful scans into caller failures.Notes
origin/oom/11-b-providers-usageandorigin/oom/16-b-codexshould be restacked at the shared lifecycle persistence seam. Their bounded serialization work should retainUsageCacheSnapshotWriter, generation veto, durable rename, temp cleanup, andflush().