relayburn-analyze: port tool-output-bloat detector#286
Conversation
Port `packages/analyze/src/tool-output-bloat.ts` to the Rust analyze crate. Brings up both signals — Claude `BASH_MAX_OUTPUT_LENGTH` static-config check (with `~/.claude/settings.json` and `<cwd>/.claude/settings.json` loader) and cross-harness observed oversized `tool_result` aggregation — plus the `WasteFinding` adapter for both kinds. Public surface mirrors `@relayburn/analyze`: `BASH_MAX_OUTPUT_ENV_KEY`, `DEFAULT_BLOAT_TOKEN_THRESHOLD`, `detect_observed_bloat`, `detect_static_config_bloat`, `detect_tool_output_bloat`, `load_claude_settings`, `project_claude_settings_path`, `user_claude_settings_path`, `tool_output_bloat_to_finding`, plus `ToolOutputBloat`, `ToolOutputBloatKind`, `ClaudeSettings`, `LoadedClaudeSettings`, and the three `Detect*Options` request types. Foundation crate is sync, so the loader uses `std::fs::read_to_string` and returns `Option<LoadedClaudeSettings>` (None for missing or malformed JSON, matching the TS `undefined` behavior). Tests cover both files-present and files-absent fixtures via `tempfile::TempDir`, the shared TS/Rust fixture corpus under `tests/fixtures/`, and the unit cases mirrored from `tool-output-bloat.test.ts`. Closes #271
…1-webhooks-Di7rr # Conflicts: # crates/relayburn-analyze/Cargo.toml # crates/relayburn-analyze/src/lib.rs
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis pull request ports the tool-output-bloat detector from TypeScript to Rust within the ChangesTool Output Bloat Detector
Sequence DiagramsequenceDiagram
participant User
participant Loader as Settings Loader
participant StaticSig as Signal A:<br/>Static Config
participant EventScan as Signal B:<br/>Observed Events
participant Orchest as Orchestrator
participant Adapter as Finding Adapter
participant Output as Bloat Findings
User->>Loader: load_claude_settings(paths)
Loader->>Loader: read & parse ~/.claude/settings.json<br/>+ ./.claude/settings.json
Loader-->>User: LoadedClaudeSettings
User->>Orchest: detect_tool_output_bloat(opts)
Orchest->>StaticSig: detect_static_config_bloat(opts)
StaticSig->>StaticSig: check BASH_MAX_OUTPUT_LENGTH<br/>against threshold
StaticSig-->>Orchest: Vec<ToolOutputBloat> [static]
Orchest->>EventScan: detect_observed_bloat(opts)
EventScan->>EventScan: scan tool_result events<br/>aggregate by (source, toolName)<br/>compute p95 + pricing cost
EventScan-->>Orchest: Vec<ToolOutputBloat> [observed]
Orchest->>Orchest: concat + sort by cost desc
Orchest-->>User: Vec<ToolOutputBloat>
User->>Adapter: tool_output_bloat_to_finding(bloat)
Adapter->>Adapter: format remediation:<br/>- static: paste safe BASH_MAX_OUTPUT_LENGTH<br/>- observed: filter/pagination advice
Adapter-->>Output: WasteFinding
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
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 |
Summary
Ports
packages/analyze/src/tool-output-bloat.tsto therelayburn-analyzeRust crate. Brings up both signal sources from the TS implementation:BASH_MAX_OUTPUT_LENGTHfrom~/.claude/settings.jsonand<cwd>/.claude/settings.json, converts the char-unit value to tokens via the samebytes/4heuristic, and flags when the merged value exceeds the threshold (default 15k tokens). Project settings override user settings.tool_result/function_call_outputevents whose enrichedapproxTokens(orbytes/4fallback for legacy ledgers) exceed the threshold, bucketed by(source, normalizedToolName), priced via the source turn's model rate.WasteFindingadapter: emits asettings.jsonpaste suggestion for Signal A (at the60000-char boundary that matches the 15k-token threshold) and aCLAUDE.md/AGENTS.mdinstruction paste for Signal B.Public surface mirrors
@relayburn/analyze:BASH_MAX_OUTPUT_ENV_KEY,DEFAULT_BLOAT_TOKEN_THRESHOLD,detect_observed_bloat,detect_static_config_bloat,detect_tool_output_bloat,load_claude_settings,project_claude_settings_path,user_claude_settings_path,tool_output_bloat_to_finding, plus all the typed records and request shapes.Foundation crate is sync, so the loader uses
std::fs::read_to_stringand returnsOption<LoadedClaudeSettings>—Nonemeans missing or malformed JSON (indistinguishable from "no waste"), matching the TSundefinedbehavior.Test plan
cargo test -p relayburn-analyze— 114 tests pass (38 added for the new module).cargo test --workspace— full Rust suite green.cargo build --workspace --all-targets— matches CI's build step.tool-output-bloat.test.ts(Signal A merge + threshold semantics, settings.json fixture, observed bloat aggregation across sources, custom thresholds, orphan-event fallback, carrier vs. notification de-dup, finding adapter shape).tests/fixtures/claude/oversized-bash-output.jsonl,tests/fixtures/codex/oversized-shell-output.jsonl, andtests/fixtures/claude/settings/oversized-bash-output-length.jsoncorpus so the TS and Rust suites assert against the same bytes.Closes #271
Generated by Claude Code