Skip to content

Lift runOverhead into @relayburn/sdk (closes #235)#236

Merged
willwashburn merged 2 commits intomainfrom
claude/sdk-overhead-stacked
May 3, 2026
Merged

Lift runOverhead into @relayburn/sdk (closes #235)#236
willwashburn merged 2 commits intomainfrom
claude/sdk-overhead-stacked

Conversation

@willwashburn
Copy link
Copy Markdown
Member

@willwashburn willwashburn commented May 3, 2026

Closes #235. Follow-up to #232 (which made @relayburn/sdk the canonical in-process query surface). Applies the same pattern — CLI verb → pure SDK function + thin presenter — to burn overhead and burn overhead trim.

What changed

@relayburn/sdk — two new functions, both in-process pure data:

const result = await overhead({ project, since?, kind?, ledgerHome?, onLog? });
// → { project, files, perFile, grandTotal }

const trim = await overheadTrim({ project, since?, kind?, top?, includeDiff?, sinceLabel?, ... });
// → { project, since, recommendations, summary }

Both reuse the loadTurnsViaArchive helper from #232 so they get the same archive-with-fallback strategy summary / sessionCost already have. overheadTrim includes a unified-diff string per recommendation by default (matches burn overhead trim --json); pass includeDiff: false to skip the per-file disk reads when only recommendation rows are needed.

New types declared in index.d.ts so consumers don't have to reach into @relayburn/analyze for the attribution shape: OverheadFileSummary, OverheadPerFileEntry, OverheadSectionCost, OverheadAttributionDetail, plus the OverheadResult / OverheadTrimResult / option types.

@relayburn/cli — adds @relayburn/sdk as a workspace dep. runOverhead / runTrim drop ~280 lines of inline gather + attribution + JSON shaping; both now call the SDK and only own flag parsing, --since string→ISO conversion, and TTY/diff rendering. CLI keeps a narrow OverheadDeps { ingestAll? } injection seam (only ingest, not the whole pipeline) so tests can stub out the real ingest pass — without it, an isolated RELAYBURN_HOME test still triggers a real read of the user's ~/.claude / ~/.codex / ~/.opencode stores.

Wire shape unchanged. Both burn overhead --json and burn overhead trim --json emit the same payload they did before; the existing JSON-mode test was rewritten to use a real ledger (appendTurns into a tmp RELAYBURN_HOME) instead of dep-injection of queryAll/loadPricing, and asserts the same exact shape.

Test plan

  • pnpm run build clean
  • pnpm run test — 889/889 pass
  • Overhead JSON-mode test (the only structured assertion this verb has) passes against the SDK-backed implementation
  • Manual: burn overhead and burn overhead trim --top 3 against a real project produce the same TTY output as before

Out of scope

🤖 Generated with Claude Code


Open in Devin Review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f7ea96ef7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/sdk/index.js Outdated

const resolved = resolveProject(projectPath);
const q = { project: resolved.projectKey ?? projectPath };
if (opts.since) q.since = opts.since;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Parse relative --since values before ledger query

overhead()/overheadTrim() document since as accepting relative windows like 30d, but this code forwards opts.since directly into the ledger query. The ledger filter compares timestamps lexicographically (e.g. turn.ts < q.since in packages/ledger/src/adapters/file-adapter.ts), so passing 30d/7d silently filters out essentially all turns and returns near-zero attribution. This makes the new SDK API produce incorrect results for documented inputs unless callers pre-convert to ISO themselves.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 9fa7e45 — the SDK now normalizes since (accepts both ISO timestamps and relative ranges like 7d/4w/2m) before passing to the ledger query. Direct SDK callers get the same forgiving shape CLI users have. Also tightened the .d.ts doc to describe the accepted forms.

devin-ai-integration[bot]

This comment was marked as resolved.

willwashburn and others added 2 commits May 2, 2026 20:40
Closes #235. Follow-up to #232 (which made @relayburn/sdk the canonical
in-process query surface). The burn overhead verb is now a thin
presenter over two new SDK functions; the discovery + ingest + ledger
query + attribution pipeline lives in one place so a future
burn__overhead MCP tool (and embedders) can call it without
re-implementing it.

@relayburn/sdk:
- overhead({ project, since?, kind? }) returns the per-file +
  per-section attribution shape burn overhead --json now consumes
  (project / files / perFile / grandTotal).
- overheadTrim({ project, since?, kind?, top?, includeDiff?,
  sinceLabel? }) returns trim recommendations with projected savings
  and (by default) embedded unified diffs — the shape
  burn overhead trim --json now consumes. Pass includeDiff: false to
  skip the per-file disk reads when you only need recommendation rows.
- Both reuse the existing loadTurnsViaArchive helper, so they get the
  same archive-with-fallback strategy summary / sessionCost have.
- New OverheadFileSummary / OverheadPerFileEntry / OverheadSectionCost
  / OverheadAttributionDetail types declared in index.d.ts so
  consumers don't have to reach into @relayburn/analyze for the
  attribution shape.

@relayburn/cli:
- Adds @relayburn/sdk as a dep.
- runOverhead / runTrim drop ~280 lines of inline gather +
  attribution + JSON shaping; both now call the SDK and only own flag
  parsing, --since string→ISO conversion, and TTY/diff rendering.
- CLI keeps an OverheadDeps { ingestAll? } injection seam so tests
  can stub out the real ingest pass (which would otherwise read the
  user's ~/.claude / ~/.codex / ~/.opencode session stores during
  unit tests).
- Test rewritten: appendTurns into an isolated RELAYBURN_HOME, stub
  ingestAll, run the CLI, assert the exact same JSON shape the
  pre-refactor test asserted against.

Wire shape unchanged for both burn overhead --json and
burn overhead trim --json (verified by the existing JSON-mode tests).

Tests: 889/889 pass.

Note: this PR is stacked on top of #232 (claude/sdk-drives-mcp);
expect to rebase against main once that merges.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI fix:
- @relayburn/sdk now declares @relayburn/reader as a workspace dep.
  The SDK started importing resolveProject from @relayburn/reader in
  this PR, but the dep wasn't listed in package.json. pnpm hoists
  workspace packages locally so the import worked in dev, but
  --frozen-lockfile + strict module resolution on CI surfaced
  ERR_MODULE_NOT_FOUND. This caused all four MCP / CLI test files
  that import compiled SDK code to crash at load time.

Codex review (P1):
- summary() / overhead() / overheadTrim() now accept both an ISO
  timestamp AND a relative range (24h, 7d, 4w, 2m) for `since`. The
  SDK normalizes both forms internally before querying the ledger.
  Previously a raw relative string ("7d") fell through to the
  ledger's lexical timestamp comparison and silently filtered every
  turn out (since '7' > '2' lexically), returning near-zero
  attribution with no error. Direct SDK callers (and future MCP
  tools) now get the same forgiving input shape CLI users have.
- CLI overhead command no longer pre-converts --since to ISO; passes
  the raw user string to the SDK and the SDK handles normalization.
  Drops the `sinceLabel` opts plumbing the previous attempt added.

Devin review:
- Tighten OverheadTrimOptions.includeDiff doc — previous text "Skip
  the unified-diff text ... Default true" wrongly described the
  opposite of the actual behavior (true = include).
- Tighten OverheadOptions.since / SummaryOptions.since docs to
  describe the actual accepted shapes.

Tests: 889/889 pass locally with --frozen-lockfile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

Lift runOverhead into @relayburn/sdk as overhead()

1 participant