fix(panel): report model and source time as wall clock - #70
Conversation
Model and source rows labeled their seconds "used" while the value summed concurrent sessions, so a row could claim more time than the day contained. With twelve parallel Claude sessions plus a remote device, one row read 22h 12m on a day that was 17h 18m old. Overview already showed merged wall-clock time, so the same day disagreed between tabs. Report elapsed time and express the parallel work as a multiplier instead: - Add wallClockSecondsByKey to ActivityTimeEstimate, merging concurrent streams per key the way wallClockSeconds already does for the whole estimate. - Carry it through PerModelUsage, ModelStat, and SourceStat, and bound each per-source row by its model's merged span so summing origins cannot exceed the time the model was actually in use. - Render "4h used · x7.6 parallel", falling back to the summed value for readers that expose no activity events. - Add a wall_clock_seconds column and field to the exports, leaving active_seconds unchanged for existing consumers. Extract the model-to-source merge helpers into UsageModelSourceMerge.swift to keep UsageAggregator.swift within the file length limit.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
Next review available in: 35 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Walkthrough활동 구간의 모델별 wall-clock 시간을 계산합니다. 모델·소스 사용량에 이를 누적합니다. 통계 표시와 CSV 내보내기에 경과 시간과 병렬 배율을 반영합니다. 겹치는 구간과 원격·로컬 병합 동작을 테스트합니다. ChangesWall-clock 사용량
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Sources/TokiUsageReaders/ReaderSupport.swift`:
- Line 90: Update the activityEvents-empty guard in ReaderSupport so every
perModel entry initializes wallClockSeconds from fallbackActiveSecondsByModel
before returning. Preserve the existing per-model assignment for non-empty
activity events, and add a test covering fallback-only RawTokenUsage with
model-specific activeSeconds.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4d594f14-d4ac-4476-ae08-5bceb8d7e19c
📒 Files selected for processing (16)
Sources/TokiUsageCore/ActivityTimeEstimator.swiftSources/TokiUsageCore/RawTokenUsage.swiftSources/TokiUsageReaders/ReaderSupport.swiftToki.xcodeproj/project.pbxprojToki/Domain/Usage/UsageData.swiftToki/Domain/Usage/UsageFormatting.swiftToki/Domain/Usage/UsageReportExport.swiftToki/Domain/Usage/UsageReportModelStats.swiftToki/Features/UsagePanel/PanelSourceExportViews.swiftToki/Features/UsagePanel/PanelStatComponents.swiftToki/Infrastructure/RemoteSync/RemoteUsageMapper.swiftToki/Infrastructure/UsageReaders/UsageAggregator.swiftToki/Infrastructure/UsageReaders/UsageModelSourceMerge.swiftTokiTests/ActivityTimeEstimatorTests.swiftTokiTests/UsageOriginAggregationTests.swiftTokiTests/UsageServiceActiveTimeTests.swift
recomputeMergedActiveEstimate() returns before the estimate when a usage has no activity events, so readers that report totals without timestamps left every per-model wallClockSeconds at zero. The panel hid this because reportedSeconds falls back to the summed value, but the export wrote 0.000 into wall_clock_seconds for time that was in fact measured. Initialize the per-model wall clock from fallbackActiveSecondsByModel before that early return, matching what the non-empty path already does. Reported by CodeRabbit on #70.
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Why
Model and source rows labeled their seconds
usedwhile the value summed concurrent sessions, so a row could claim more time than the day contained. A row read 22h 12m used on a day that was 17h 18m old, and by the time this was implemented the same row's summed value had reached 30h 28m.Overview already used merged
workTime.wallClockSeconds, so the same day disagreed between tabs.Root cause:
ActivityTimeEstimator.secondsByKeyis built withsummedDurationByStream, which merges intervals within a stream but sums across streams. Reproduced against the real local cache: twelve concurrent Claude sessions gave 11h 36m summed versus 3h 0m merged — a 3.9x inflation from one device — and the remote device's already-summed value was then plain-added.What
Report elapsed time and express the parallel work as a multiplier.
wallClockSecondsByKeytoActivityTimeEstimate, merging concurrent streams per key the waywallClockSecondsalready does for the whole estimate.PerModelUsage,ModelStat, andSourceStat, reusing the existingWorkTimeMetrics.parallelMultiplierformula.All Devicesview needed: a model present on two devices collapses into one row viafallbackSource, which is how a single row reached 22h.4h used · x7.6 parallel, falling back to the summed value for readers that expose no activity events.wall_clock_secondscolumn and field to the exports, leavingactive_secondsunchanged for existing consumers.UsageModelSourceMerge.swiftto keepUsageAggregator.swiftwithin the 600-line limit.Semantics
Wall clock is merged across readers and devices: two machines active in the same minute count as one minute of calendar time, with the parallelism surfaced by the multiplier. Per-model spans may sum to more than the overall total because different models can be active in the same minute; that is expected.
Verification
Against the real caches that prompted this, the panel now reports:
4h used · x7.6 parallel4h 53m used · x2.9 parallelEvery row is now bounded by elapsed time.
wallClockSeconds = 0andreportedSeconds = 450.swiftformat --lint0/211,swiftlint --strict, andgit diff --checkclean.xcodegen generateproduced the includedproject.pbxprojdiff for the new file.Not included
Token totals are ~96% cache reads (Codex 371.6M/389.6M, opus-5 912.7M/949.4M). That is accurate and is a separate presentation question.
Summary by CodeRabbit
xN.N parallel배율을 사용 시간에 표시합니다.wall_clock_seconds열이 추가되었습니다.