Skip to content

relayburn-cli: burn overhead + overhead trim presenters (#248 D2)#312

Merged
willwashburn merged 3 commits intomainfrom
rust-port/cli-overhead
May 6, 2026
Merged

relayburn-cli: burn overhead + overhead trim presenters (#248 D2)#312
willwashburn merged 3 commits intomainfrom
rust-port/cli-overhead

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Summary

  • Implement burn overhead and burn overhead trim as thin presenters over relayburn_sdk::overhead / ::overhead_trim, matching the TS CLI flag set + output.
  • Un-ignore the four overhead golden invocations.

Notes

  • Widened relayburn_sdk::OverheadAttributionDetail to carry totalTokens + sessionCosts and re-ordered the field set to match the TS shape; OverheadSectionCost.section now carries the full MarkdownSection rather than a slim projection. Both moves were needed to make the SDK's JSON serialization byte-equivalent with the TS sibling.
  • The CLI's --json writer post-processes integer-valued f64s back to bare integers (0 not 0.0) so the golden snapshots match JSON.stringify.

Test plan

  • cargo test --workspace
  • BURN_GOLDEN=1 cargo test --test golden -p relayburn-cli
  • burn overhead --help / burn overhead trim --help match TS flag set

🤖 Generated with Claude Code

Wire `burn overhead` and `burn overhead trim` as thin presenters over
`relayburn_sdk::overhead` / `::overhead_trim`. Output (human + `--json`)
is byte-equivalent with the TS CLI; the four overhead golden invocations
flip to `enabled: true`.

To make the JSON shape match TS, widen `OverheadAttributionDetail` to
include `totalTokens` + `sessionCosts` (in TS field order) and let
`OverheadSectionCost.section` carry the full `MarkdownSection` rather
than a slim projection. The CLI's `--json` writer post-processes
integer-valued `f64`s back to bare integers (`0` not `0.0`) so the
golden snapshots stay byte-identical to `JSON.stringify` output.

Smoke test: drop `overhead` from the not-yet-implemented gate.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 56091f41-e6a3-4f49-92c7-f20234682bb9

📥 Commits

Reviewing files that changed from the base of the PR and between 980716f and e2fde5f.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • crates/relayburn-cli/Cargo.toml
  • crates/relayburn-cli/src/cli.rs
  • crates/relayburn-cli/src/commands/overhead.rs
  • crates/relayburn-cli/src/main.rs
  • crates/relayburn-cli/tests/smoke.rs
  • crates/relayburn-sdk/src/lib.rs
  • tests/fixtures/cli-golden/invocations.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/relayburn-cli/src/main.rs
  • crates/relayburn-cli/src/commands/overhead.rs

📝 Walkthrough

Walkthrough

This PR fully implements the Rust CLI burn overhead and burn overhead trim subcommands with structured Clap-based argument handling, end-to-end presenter logic in relayburn-cli, and expanded SDK re-exports. The overhead command now carries OverheadArgs, dispatches to report or trim paths, and renders results in both human and JSON formats with TS-compatible output. SDK query types (OverheadAttributionDetail, OverheadSectionCost, OverheadOptions) are augmented with richer cost data, and golden test invocations are enabled.

Changes

Overhead CLI Implementation

Layer / File(s) Summary
SDK Type Expansion
crates/relayburn-sdk/src/query_verbs.rs, crates/relayburn-sdk/src/lib.rs
OverheadOptions adds ledger_home field; OverheadAttributionDetail adds total_tokens and session_costs; OverheadSectionCost updates section type to MarkdownSection. SDK lib re-exports numerous overhead-related functions and types including SessionClaudeMdCost, OverheadFile, OverheadFileKind, PricingTable, and analytics primitives.
CLI Argument Structure
crates/relayburn-cli/src/cli.rs
New public types: OverheadArgs (Clap-derived struct with project, since, kind, action fields), OverheadKind enum (ValueEnum for file kinds), OverheadAction enum (Subcommand with Trim variant), OverheadTrimArgs (Clap-derived with top field). Command enum Overhead variant changes from unit-like to payload variant Overhead(OverheadArgs).
Overhead Command Handler
crates/relayburn-cli/src/commands/overhead.rs
Complete implementation with dual paths: report (constructs options, calls SDK, renders) and trim (builds trim options, calls SDK trim, renders). Includes JSON renderers (TS-compatible integer coercion), human renderers (per-file blocks, section tables, currency/token formatting), path resolution, and helper utilities for formatting USD, integers, tokens, line ranges. ~567 lines with unit tests for formatters.
Dispatch Wiring
crates/relayburn-cli/src/main.rs, crates/relayburn-cli/Cargo.toml
Dispatch logic destructures Command::Overhead(args) and passes to overhead handler. serde_json dependency gains preserve_order feature to ensure JSON key ordering matches TS CLI output.
Tests & Golden Fixtures
crates/relayburn-cli/tests/smoke.rs, tests/fixtures/cli-golden/invocations.json
New constant UNIMPLEMENTED_SUBCOMMANDS tracks subcommands not yet implemented; overhead now excluded. New test overhead_trim_help_exits_zero_with_non_empty_stdout verifies burn overhead trim --help output. Four golden-test invocations (overhead, overhead-json, overhead-trim, overhead-trim-json) enabled by flipping flags.
Changelog
CHANGELOG.md
Unreleased section documents relayburn-cli port of overhead and overhead trim as thin presenters over relayburn_sdk with byte-for-byte parity to TypeScript CLI (human output plus --json).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

  • AgentWorkforce/burn#289: Added new analyze types (MarkdownSection, SessionClaudeMdCost, overhead attribution/trim pieces) that this PR consumes in CLI and SDK wiring.
  • AgentWorkforce/burn#310: Added golden-test invocation scaffolds and snapshots that this PR enables and implements.
  • AgentWorkforce/burn#288: Implements overhead attribution module and types/functions that this PR's CLI and SDK changes directly use.

Poem

🐰 A CLI hopping into place,
With overhead traced through burnish space,
The trim comes neat, the JSON flows,
Byte-for-byte with TS—oh, how it glows!
✨ Our presenters stand proud and true.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: implementing burn overhead and overhead trim CLI commands as presenters over relayburn_sdk, which directly aligns with the substantial changes across cli.rs, commands/overhead.rs, and related SDK files.
Description check ✅ Passed The description is well-related to the changeset, providing a clear summary of the implementation work, SDK widening changes, and test plan that matches the file modifications documented in the raw summary.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rust-port/cli-overhead

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/relayburn-sdk/src/query_verbs.rs (1)

426-446: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

This mutates the published SDK surface in a breaking way.

OverheadSectionCost.section changes type and OverheadAttributionDetail gains new required fields, so downstream Rust callers that construct or destructure these public structs will stop compiling. If relayburn-sdk is being released independently, this needs a semver-major release or a compat layer/new v2 types instead of rewriting the existing ones in place.

🤖 Prompt for 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.

In `@crates/relayburn-sdk/src/query_verbs.rs` around lines 426 - 446, The change
breaks the public SDK surface by altering OverheadSectionCost.section's type and
adding required fields to OverheadAttributionDetail; either revert these
in-place changes or introduce a backward-compatible alternative: keep the
existing OverheadSectionCost and OverheadAttributionDetail as-is, and add new
structs (e.g., OverheadSectionCostV2 and OverheadAttributionDetailV2) with the
new MarkdownSection type and extra fields, update internal code to use the V2
types where needed, and leave the original types and serde signatures untouched
(or mark new fields as Option<T> with #[serde(default)] if you must mutate the
existing types). Ensure public symbols OverheadSectionCost,
OverheadAttributionDetail, OverheadSectionCostV2, and
OverheadAttributionDetailV2 are defined so downstream callers keep compiling or
can opt into v2.
🧹 Nitpick comments (1)
crates/relayburn-cli/tests/smoke.rs (1)

37-42: ⚡ Quick win

Add a smoke assertion for burn overhead trim --help.

Once overhead moves into IMPLEMENTED_SUBCOMMANDS, the suite no longer touches the nested trim help path. A dedicated assertion would cover one of this PR's unchecked acceptance items and catch clap wiring regressions early.

Suggested test shape
+#[test]
+fn overhead_trim_help_exits_zero_with_non_empty_stdout() {
+    let output = burn()
+        .args(["overhead", "trim", "--help"])
+        .assert()
+        .success()
+        .get_output()
+        .clone();
+    let stdout = String::from_utf8(output.stdout).expect("help should be valid UTF-8");
+    assert!(!stdout.is_empty(), "`overhead trim --help` should emit non-empty stdout");
+}
🤖 Prompt for 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.

In `@crates/relayburn-cli/tests/smoke.rs` around lines 37 - 42, Add a dedicated
smoke assertion that runs the CLI with the args ["overhead","trim","--help"] and
asserts it exits successfully and prints usage text; update the test suite in
crates/relayburn-cli/tests/smoke.rs (near IMPLEMENTED_SUBCOMMANDS and related
helpers like each_stub_exits_one_with_not_yet_implemented_message) by adding a
new test function (e.g., smoke_overhead_trim_help) that spawns the binary or
invokes the test runner helper, checks exit code == 0 and that stdout/stderr
contains the expected help/usage fragment for the trim subcommand to catch clap
wiring regressions early.
🤖 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 `@crates/relayburn-cli/src/commands/overhead.rs`:
- Around line 127-135: The JSON output currently may reorder object keys; update
the workspace dependency for serde_json to enable the preserve_order feature by
changing serde_json = "1" to serde_json = { version = "1", features =
["preserve_order"] } in Cargo.toml so that functions like
render_json_ts_compatible and coerce_integer_floats emit fields in declaration
order for byte-equivalent snapshots with the TypeScript CLI.
- Around line 143-156: The function coerce_integer_floats currently calls
Number::as_f64() on every serde_json::Number which forces integer numbers
through an f64 and can cause precision loss; change the logic to first check
n.is_f64() and only perform the as_f64()/fractional tests when the Number is
actually stored as a float, leaving integer-backed Numbers untouched; update the
branches around Number::as_f64() in coerce_integer_floats so integers are
skipped and only float-backed values are coerced to integer
Number::from(u64/i64) when appropriate.

---

Outside diff comments:
In `@crates/relayburn-sdk/src/query_verbs.rs`:
- Around line 426-446: The change breaks the public SDK surface by altering
OverheadSectionCost.section's type and adding required fields to
OverheadAttributionDetail; either revert these in-place changes or introduce a
backward-compatible alternative: keep the existing OverheadSectionCost and
OverheadAttributionDetail as-is, and add new structs (e.g.,
OverheadSectionCostV2 and OverheadAttributionDetailV2) with the new
MarkdownSection type and extra fields, update internal code to use the V2 types
where needed, and leave the original types and serde signatures untouched (or
mark new fields as Option<T> with #[serde(default)] if you must mutate the
existing types). Ensure public symbols OverheadSectionCost,
OverheadAttributionDetail, OverheadSectionCostV2, and
OverheadAttributionDetailV2 are defined so downstream callers keep compiling or
can opt into v2.

---

Nitpick comments:
In `@crates/relayburn-cli/tests/smoke.rs`:
- Around line 37-42: Add a dedicated smoke assertion that runs the CLI with the
args ["overhead","trim","--help"] and asserts it exits successfully and prints
usage text; update the test suite in crates/relayburn-cli/tests/smoke.rs (near
IMPLEMENTED_SUBCOMMANDS and related helpers like
each_stub_exits_one_with_not_yet_implemented_message) by adding a new test
function (e.g., smoke_overhead_trim_help) that spawns the binary or invokes the
test runner helper, checks exit code == 0 and that stdout/stderr contains the
expected help/usage fragment for the trim subcommand to catch clap wiring
regressions early.
🪄 Autofix (Beta)

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: 48ca14bd-08b0-4c64-828d-a58609df65ce

📥 Commits

Reviewing files that changed from the base of the PR and between 54f0682 and 980716f.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • crates/relayburn-cli/src/cli.rs
  • crates/relayburn-cli/src/commands/overhead.rs
  • crates/relayburn-cli/src/main.rs
  • crates/relayburn-cli/tests/smoke.rs
  • crates/relayburn-sdk/src/lib.rs
  • crates/relayburn-sdk/src/query_verbs.rs
  • tests/fixtures/cli-golden/invocations.json
  • tests/fixtures/cli-golden/ledger/.gitignore

Comment thread crates/relayburn-cli/src/commands/overhead.rs
Comment thread crates/relayburn-cli/src/commands/overhead.rs
Three non-architectural fixes from PR #312 review:

1. Add `is_f64()` guard in `coerce_integer_floats` so exact-integer
   JSON Numbers above 2^53 round-trip losslessly. Previously every
   Number went through `as_f64()` even when it was already an integer,
   and `9_007_199_254_740_993` (2^53 + 1) would silently truncate to
   `9_007_199_254_740_992`. Adds four unit tests covering the guarded
   path, the lossless large-u64 case, the whole-valued-float coercion,
   and the recurse-into-array-and-object arms.

2. Pin `features = ["preserve_order"]` on `serde_json` in
   relayburn-cli's Cargo.toml. Cargo's feature unification means the
   CLI inherits this transitively from the SDK today, but pinning it
   explicitly is defense-in-depth so a future SDK refactor can't
   silently regress the byte-equivalent JSON snapshots.

3. Add `overhead trim --help` smoke test. Now that `overhead` is in
   `IMPLEMENTED_SUBCOMMANDS`, the parent help-coverage test no longer
   touches the nested `trim` action; cover it explicitly so a
   regression in the nested-action help wiring doesn't slip past CI.
@willwashburn
Copy link
Copy Markdown
Member Author

Re: CodeRabbit's outside-diff flag on crates/relayburn-sdk/src/query_verbs.rs:426-446 (the in-place widening of OverheadAttributionDetail + OverheadSectionCost):

Keeping the widening — it's deliberate, not an oversight. Design rationale (confirmed with the project lead):

  1. Pre-1.0 SDK. relayburn-sdk is 0.0.0 and the crates.io contract doesn't lock until the [Rust port] Lockstep 2.0 release (TS 1.x final + cutover + npm deprecate) #249 cutover. Rich-shape iteration is explicitly within scope until then.
  2. CLI dogfoods SDK. The codified pattern is let r = sdk::verb(opts)?; render(r). The SDK owns composition; the CLI owns presentation. A slim verb that forces the CLI to re-assemble from primitives spreads compute logic across consumers (CLI + future MCP + wash), which is exactly the duplication CLAUDE.md warns against.
  3. TS shape is a guide, not a contract. TS @relayburn/sdk and the new Rust SDK don't need to be 1:1 — Rust gets to be richer / more typed / more idiomatic. MarkdownSection (rich) over OverheadSection (slim 4-field projection) is exactly that — Rust's enum-rich type captures structure the slim shape elided.

We'll lock the contract at the 1.0 cutover. Until then, additive widening is the path.

@willwashburn willwashburn merged commit d719c6b into main May 6, 2026
8 checks passed
@willwashburn willwashburn deleted the rust-port/cli-overhead branch May 6, 2026 18:49
willwashburn added a commit that referenced this pull request May 6, 2026
Folds D1+D2+D3 (PRs #315/#312/#314) into the D4 state branch.

Resolutions:
- CHANGELOG.md: union all four bullets, alphabetized.
- crates/relayburn-cli/src/cli.rs: keep all five typed Command variants
  (Summary/Hotspots/Overhead/Compare/State); merge ValueEnum import; keep
  D4's state-related types (StateArgs et al.) plus D2/D3's OverheadArgs /
  CompareArgs / OverheadKind.
- crates/relayburn-cli/src/main.rs: auto-merged — five typed dispatch arms.
- crates/relayburn-cli/tests/smoke.rs: drop REAL_COMMANDS allow-list and
  early-continue; remove "state" from UNIMPLEMENTED_SUBCOMMANDS, leaving
  ["run", "ingest", "mcp-server"].
- tests/fixtures/cli-golden/ledger/.gitignore: superset of patterns.
- Cargo.lock: regenerated from origin/main.
- tests/fixtures/cli-golden/snapshots/state-status*.stdout.txt: keep D4's
  2.0 SQLite layout (deliberate divergence) but refresh row counts to
  reflect the bootstrapped fixture (golden.rs on main now replays
  ledger.jsonl into burn.sqlite before running, so the fixture has 18
  rows instead of 0).
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