Skip to content

fix(panel): report model and source time as wall clock - #70

Merged
choi138 merged 2 commits into
mainfrom
fix/model-time-wall-clock
Aug 5, 2026
Merged

fix(panel): report model and source time as wall clock#70
choi138 merged 2 commits into
mainfrom
fix/model-time-wall-clock

Conversation

@choi138

@choi138 choi138 commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Why

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. 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.secondsByKey is built with summedDurationByStream, 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.

  • 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, reusing the existing WorkTimeMetrics.parallelMultiplier formula.
  • Bound each per-source row by its model's merged span, so summing origins cannot exceed the time the model was actually in use. This is what the All Devices view needed: a model present on two devices collapses into one row via fallbackSource, which is how a single row reached 22h.
  • 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 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:

model · source agent wall displayed
claude-opus-5 · Claude Code 109,709s (30h 28m) 14,421s 4h used · x7.6 parallel
gpt-5.6-sol · Codex 50,745s (14h 6m) 17,591s 4h 53m used · x2.9 parallel

Every row is now bounded by elapsed time.

  • 477 app tests and 125 package tests pass (473 and 125 before; 4 new).
  • Each new test was confirmed to fail first: replacing the merge with the summed value fails the estimator test (300 vs 210), and before the fix the aggregation test saw wallClockSeconds = 0 and reportedSeconds = 450.
  • swiftformat --lint 0/211, swiftlint --strict, and git diff --check clean.
  • xcodegen generate produced the included project.pbxproj diff 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 열이 추가되었습니다.
    • 겹치는 세션이 중복 계산되지 않도록 시간이 조정됩니다.

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.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@choi138, you've reached your PR review limit, so we couldn't start this review.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0416b0de-76ae-4be6-b5f3-dbb3317467f9

📥 Commits

Reviewing files that changed from the base of the PR and between 7a346a7 and 0282c19.

📒 Files selected for processing (2)
  • Sources/TokiUsageReaders/ReaderSupport.swift
  • TokiTests/UsageServiceActiveTimeTests.swift

Walkthrough

활동 구간의 모델별 wall-clock 시간을 계산합니다. 모델·소스 사용량에 이를 누적합니다. 통계 표시와 CSV 내보내기에 경과 시간과 병렬 배율을 반영합니다. 겹치는 구간과 원격·로컬 병합 동작을 테스트합니다.

Changes

Wall-clock 사용량

Layer / File(s) Summary
시간 추정과 원시 사용량 계약
Sources/TokiUsageCore/ActivityTimeEstimator.swift, Sources/TokiUsageCore/RawTokenUsage.swift, Sources/TokiUsageReaders/ReaderSupport.swift, TokiTests/ActivityTimeEstimatorTests.swift
키별 활동 구간의 스트림 합산 시간과 병합 wall-clock 시간을 계산합니다. 모델별 원시 사용량에 wall-clock 시간을 누적합니다.
모델·소스별 사용량 병합
Toki/Infrastructure/UsageReaders/UsageModelSourceMerge.swift, Toki/Domain/Usage/UsageReportModelStats.swift, Toki/Infrastructure/UsageReaders/UsageAggregator.swift, Toki.xcodeproj/project.pbxproj, TokiTests/UsageOriginAggregationTests.swift, TokiTests/UsageServiceActiveTimeTests.swift
모델·소스별 사용량을 병합합니다. 모델 및 소스 통계에 wall-clock 시간을 전달합니다. 프로젝트 빌드에 병합 파일을 등록합니다. 겹치는 로컬·원격 사용량과 동시 세션을 검증합니다.
통계 표시와 보고서 내보내기
Toki/Domain/Usage/UsageData.swift, Toki/Domain/Usage/UsageFormatting.swift, Toki/Domain/Usage/UsageReportExport.swift, Toki/Features/UsagePanel/PanelSourceExportViews.swift, Toki/Features/UsagePanel/PanelStatComponents.swift, Toki/Infrastructure/RemoteSync/RemoteUsageMapper.swift
통계 타입에 wall-clock 시간, 보고 시간, 병렬 배율을 추가합니다. UI는 보고 시간과 병렬 배율을 표시합니다. CSV는 wall_clock_seconds 열과 값을 출력합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • choi138/toki#14: 기존 작업 시간 및 동시성 모델을 확장하는 변경입니다.
  • choi138/toki#48: ActivityTimeEstimatePerModelUsage 경로를 공유합니다.
  • choi138/toki#55: UsageAggregator와 원본별 집계 테스트를 공유합니다.

Poem

깡충 rabbit이 시간밭을 달려요
겹친 구간은 하나로 합쳐요
모델마다 시계를 세고
병렬 배율을 곱해요
CSV에도 또박또박 기록해요

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 패널의 모델 및 소스 사용 시간을 합산 시간이 아닌 벽시계 시간으로 보고하는 핵심 변경을 정확하고 간결하게 설명합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/model-time-wall-clock

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0436600 and 7a346a7.

📒 Files selected for processing (16)
  • Sources/TokiUsageCore/ActivityTimeEstimator.swift
  • Sources/TokiUsageCore/RawTokenUsage.swift
  • Sources/TokiUsageReaders/ReaderSupport.swift
  • Toki.xcodeproj/project.pbxproj
  • Toki/Domain/Usage/UsageData.swift
  • Toki/Domain/Usage/UsageFormatting.swift
  • Toki/Domain/Usage/UsageReportExport.swift
  • Toki/Domain/Usage/UsageReportModelStats.swift
  • Toki/Features/UsagePanel/PanelSourceExportViews.swift
  • Toki/Features/UsagePanel/PanelStatComponents.swift
  • Toki/Infrastructure/RemoteSync/RemoteUsageMapper.swift
  • Toki/Infrastructure/UsageReaders/UsageAggregator.swift
  • Toki/Infrastructure/UsageReaders/UsageModelSourceMerge.swift
  • TokiTests/ActivityTimeEstimatorTests.swift
  • TokiTests/UsageOriginAggregationTests.swift
  • TokiTests/UsageServiceActiveTimeTests.swift

Comment thread Sources/TokiUsageReaders/ReaderSupport.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.
@choi138

choi138 commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@choi138
choi138 merged commit c21e914 into main Aug 5, 2026
7 checks passed
@choi138
choi138 deleted the fix/model-time-wall-clock branch August 5, 2026 01:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant