Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5afec71
refactor(sdk/analyze): consolidate percentile + hotspots_action helpers
willwashburn Jun 21, 2026
736eb1c
refactor(sdk/analyze): add cost::total_cost_for_turn + sum_turn_costs…
willwashburn Jun 21, 2026
9c2c2e3
refactor(sdk/analyze): add WasteFinding::session_cost builder
willwashburn Jun 21, 2026
c3763bb
refactor(sdk/analyze): extract shared detect_streaks skeleton for pat…
willwashburn Jun 21, 2026
4ce1229
style(sdk/analyze): rustfmt the session_cost finding adapters
willwashburn Jun 21, 2026
ed38eb5
refactor(sdk): consume analyze via its public surface, not submodule …
willwashburn Jun 21, 2026
5eb24f1
refactor(sdk/analyze): split patterns.rs into per-family detector sub…
willwashburn Jun 22, 2026
a37b6a1
refactor(sdk/analyze): externalize hotspots tests to hotspots_tests.rs
willwashburn Jun 22, 2026
0cfb784
refactor(sdk/analyze): externalize tool_output_bloat tests
willwashburn Jun 22, 2026
cb5c70a
refactor(sdk/analyze): externalize subagent_tree + context_delta tests
willwashburn Jun 22, 2026
ca4d968
refactor(sdk/analyze): consolidate three duplicated helpers
willwashburn Jun 22, 2026
1bda2bc
refactor(sdk/analyze): add group_turns_by_session_sorted, fold the po…
willwashburn Jun 22, 2026
f3fbf72
refactor(sdk/analyze): consolidate first-seen-unique into util helpers
willwashburn Jun 22, 2026
cce05ea
docs(sdk/analyze): explain why quality::parse_iso8601_ms is not shared
willwashburn Jun 22, 2026
63b0b74
refactor(sdk/analyze): externalize ghost_surface tests
willwashburn Jun 22, 2026
225594e
refactor(sdk/analyze): remove the legacy subagent-tree builder
willwashburn Jun 22, 2026
68245f6
refactor(sdk): drop two duplicate ISO-8601 parsers, use util::time
willwashburn Jun 22, 2026
b372c2f
refactor(sdk): centralize Hinnant civil-date math in util::time
willwashburn Jun 22, 2026
35f8f24
refactor(sdk): single util::time::format_iso_ms for the wire timestam…
willwashburn Jun 22, 2026
003fe5a
refactor(sdk): share bucket-partition loop between summary and compare
willwashburn Jun 22, 2026
b086886
style(sdk): cargo fmt (de-indent externalized ghost_surface tests)
willwashburn Jun 22, 2026
263e7fa
docs(changelog): note subagent-tree legacy path removal
willwashburn Jun 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Cross-package release notes for relayburn. Package changelogs contain package-le

## [Unreleased]

- `burn` subagent-tree views now require a re-ingest to render pre-Root-emission event logs (legacy reconstruction path removed).

## [3.4.0] - 2026-06-20

- `burn summary` and `burn compare` accept `--bucket <DURATION>` to emit a per-bucket time-series across the `--since` window instead of a single total (`{ "bucketSeconds": N, "buckets": [...] }` in JSON). Bucket units: `30s` / `5m` / `1h` / `12h` / `1d` / `7d` — note `m` is minutes here, unlike `--since` where `m` is months. `summary --bucket` supports only the default grouped (`byModel` / `--by-provider`) modes; `hotspots` / `overhead` are unchanged.
Expand Down
18 changes: 2 additions & 16 deletions crates/relayburn-sdk/src/analyze/claude_md.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use serde::{Deserialize, Serialize};

use crate::analyze::cost::{lookup_model_rate, PER_MILLION};
use crate::analyze::pricing::PricingTable;
use crate::analyze::util::{group_turns_by_session, tokens_from_bytes};
use crate::analyze::util::{group_turns_by_session_sorted, percentile, tokens_from_bytes};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -325,13 +325,11 @@ pub(crate) fn attribute_claude_md_refs(
};
}

let by_session = group_turns_by_session(turns.iter().copied());
let by_session = group_turns_by_session_sorted(turns.iter().copied());

let mut session_costs: Vec<SessionClaudeMdCost> = Vec::new();
let mut total_cost = 0.0_f64;
for (session_id, turns) in by_session {
let mut turns = turns;
turns.sort_by_key(|t| t.turn_index);
let mut cost = 0.0_f64;
let mut riding_turns: u64 = 0;
let mut model_counts: IndexMap<String, u64> = IndexMap::new();
Expand Down Expand Up @@ -417,18 +415,6 @@ fn pick_dominant_model(counts: &IndexMap<String, u64>) -> String {
best_model
}

fn percentile(sorted: &[f64], p: f64) -> f64 {
if sorted.is_empty() {
return 0.0;
}
if sorted.len() == 1 {
return sorted[0];
}
let raw = (p * sorted.len() as f64).ceil() as i64 - 1;
let idx = raw.clamp(0, sorted.len() as i64 - 1) as usize;
sorted[idx]
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TrimRecommendation {
Expand Down
Loading
Loading