refactor(sdk): share aggregator shape across hotspots roll-ups#398
refactor(sdk): share aggregator shape across hotspots roll-ups#398willwashburn merged 1 commit intomainfrom
Conversation
- Extract a generic `aggregate` helper for `aggregate_by_file`, `aggregate_by_bash`, `aggregate_by_subagent`. Each caller passes its key extractor, row initializer, and accumulator; the shared helper owns iteration, deduping, and the cost-desc sort. - Switch cost comparators from `partial_cmp(...).unwrap_or(Ordering::Equal)` to `f64::total_cmp` so monotonic ordering is exact. Applies to file/bash/subagent aggregates plus the bash-verb path. - Fold the per-session grand-total accumulation into `attribute_session`'s existing turn loop, eliminating the second pass over `session_turns` in `attribute_hotspots`. Closes #340.
|
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR consolidates hotspot analysis logic: session grand totals are computed once in the attribution loop and reused downstream, three parallel aggregation functions are unified under a generic helper, and float comparisons are switched to deterministic ordering for consistent output. ChangesHotspot Attribution and Aggregation Refactor
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Closes #340.
Summary
Three small clean-ups in
crates/relayburn-sdk/src/analyze/hotspots.rs:aggregate_by_file,aggregate_by_bash, andaggregate_by_subagenthad near-parallel "filter → accumulate by key → sort by cost desc" boilerplate. Extract a private genericaggregate(…)helper parameterized by key/init/accumulate/cost closures; each public function now declares only the bits that actually differ.aggregate_by_bash_verbkeeps its own loop because it tracks distinct hashes and per-verb examples on top of the basic shape.f64::total_cmpfor monotonic cost ordering. Replace everypartial_cmp(...).unwrap_or(Ordering::Equal)cost comparator in this file withtotal_cmp— drop-in for our positive-cost values and removes the silent-Equal fallback for NaN. Covers the file/bash/subagent aggregates and both sorts in the bash-verb path.session_turnsinattribute_hotspots.attribute_sessionalready iterates the session's turns; have it accumulate the per-session grand total in that same pass viacost_for_turnand return it onSessionAttribution. The caller drops the secondfor t in &session_turns { … }loop. Behavior is unchanged — totals still route through the canonicalcost_for_turnso source-specific reasoning billing (Codexincluded_in_output, separate reasoning tariffs, etc.) stays in lock-step withcost.rs.No public-API changes. Existing
analyze::hotspotstests cover deterministic sort, Codex reasoning, and thegrand_total + unattributed = session_grandinvariant.Test plan
cargo test -p relayburn-sdk --lib analyze::hotspots(14 passed)cargo test --workspace(775 passed, 0 failed)cargo clippy -p relayburn-sdk --all-targets— no new warnings on the touched codehttps://claude.ai/code/session_01Wmh6iHN5aYaPKhFdR9bA14
Generated by Claude Code