Skip to content

relayburn-sdk: integration test + make workspace publish-ready (closes #246)#304

Merged
willwashburn merged 1 commit intomainfrom
claude/sdk-publish-and-integration-test
May 5, 2026
Merged

relayburn-sdk: integration test + make workspace publish-ready (closes #246)#304
willwashburn merged 1 commit intomainfrom
claude/sdk-publish-and-integration-test

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Summary

Final PR in the #246 series. Closes the remaining acceptance gates after #299/#300/#301/#302/#303 landed the scaffold, module split, and the nine verbs.

What changed

Integration test — `crates/relayburn-sdk/tests/integration.rs`. Opens a fixture ledger in a `TempDir`, seeds one turn / one content blob (with a unique FTS token) / one stamp, and exercises every one of the nine verbs in both forms (`LedgerHandle` method + free function):

  • `summary` / `session_cost` / `overhead` / `overhead_trim` / `hotspots`
  • `search` / `export_ledger` / `export_stamps`
  • `ingest` (with empty roots → all-zero report; `#[tokio::test]`)

Assertions are structural — turn count, FTS hit, exported `kind=turn` / `kind=stamp` rows in the JSONL streams, ingest scan-zero report. Goal is "the wrappers plumb through correctly."

Workspace publish-ready. `cargo publish --workspace --dry-run --allow-dirty` now succeeds end to end. To get there:

  • Drop `publish = false` from `relayburn-{reader,ledger,analyze,ingest}`. The architecture in Epic: rewrite burn in Rust (v2 — supersedes #222) #240 has the lower crates publish in lockstep with `relayburn-sdk` (mirroring the TS tree's eight published `@relayburn/*` packages).
  • Add `version = "0.0.0"` alongside every internal `path` dep so cargo accepts the manifests for upload (path-only deps fail with "all dependencies must have a version requirement").
  • Vendor `models.dev.json` into `crates/relayburn-analyze/data/` and point `include_str!` at the in-crate copy. Without this, the verify step of `cargo package` couldn't see the file (the TS-tree path is outside the crate's tarball). The TS copy stays in place; `scripts/update-pricing.mjs` now writes both copies in lockstep so they can't drift.

Per-crate vs workspace dry-run

`cargo publish --dry-run -p relayburn-sdk` (the literal acceptance criterion) requires the lower crates to already be on crates.io — once the path is dropped during packaging, cargo resolves `relayburn-analyze` etc. from the registry, which won't have them until the first publish. `cargo publish --workspace --dry-run` is the equivalent gate for local verification (uses a temp registry to chain the dependency order in one shot), and that's the gate this PR makes green.

Acceptance for #246

  • `cargo doc --no-deps -p relayburn-sdk` produces complete public API docs
  • All 9 verbs callable as both `LedgerHandle` methods and free functions
  • Integration test: open a ledger, run all 9 verbs, assert results match expectations on a fixture ledger
  • `cargo publish --workspace --dry-run` succeeds (per-crate `-p relayburn-sdk` requires lower crates published; see above)
  • `cargo test --workspace` green throughout (now 25 SDK tests including the 2 new integration tests)

Closes #246.

Test plan

  • `cargo test --workspace`
  • `cargo doc --no-deps -p relayburn-sdk`
  • `cargo publish --workspace --dry-run --allow-dirty`

🤖 Generated with Claude Code

Closes the last acceptance gates on #246:

* Integration test (`crates/relayburn-sdk/tests/integration.rs`): opens a
  fixture ledger, seeds one turn / one content blob with a unique FTS
  token / one stamp, then exercises every one of the nine verbs in both
  forms (LedgerHandle method + free function). Asserts structural
  correctness (turn count, FTS hit, exported `kind=turn` / `kind=stamp`
  rows, ingest scan-zero report).

* `cargo publish --workspace --dry-run --allow-dirty` now succeeds end
  to end. To get there:
  - Drop `publish = false` from relayburn-{reader,ledger,analyze,ingest};
    the lower crates publish in lockstep with relayburn-sdk per the #240
    architecture (the TS sibling does the same with the eight @relayburn
    npm packages).
  - Add `version = "0.0.0"` alongside every internal `path` dep so cargo
    accepts the manifests for upload (path-only deps fail
    "all dependencies must have a version requirement").
  - Vendor `models.dev.json` into `crates/relayburn-analyze/data/` and
    point `include_str!` at the in-crate copy. Without this, the verify
    step of `cargo package` couldn't see the file (the TS-tree path is
    outside the crate's tarball). The TS copy stays in place; the
    `pricing:update` script now writes both copies in lockstep so they
    can't drift.

Per-crate `cargo publish --dry-run -p relayburn-sdk` requires the lower
crates to be on crates.io first (cargo resolves via the registry once
the path is dropped from the packaged manifest); the workspace flag is
the right gate for local verification and that's now green.

Closes #246.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

📝 Walkthrough

Walkthrough

This PR prepares relayburn crates for publication by removing publish = false flags and pinning workspace dependency versions to 0.0.0 across Cargo.toml files. It reorganizes pricing data paths, updates the pricing update script to write dual outputs, and adds comprehensive end-to-end integration tests validating all nine SDK verbs via both handle-based and free-function interfaces.

Changes

SDK Publishing & Integration Validation

Layer / File(s) Summary
Publishing Setup
crates/relayburn-*/Cargo.toml, crates/relayburn-sdk/Cargo.toml
Removed publish = false from relayburn-analyze, relayburn-reader, relayburn-ledger, relayburn-ingest. Added explicit version = "0.0.0" to all workspace path dependencies (relayburn-reader, relayburn-ledger, relayburn-analyze, relayburn-ingest) in relayburn-sdk and dependent crates.
Data Resources & Build Support
crates/relayburn-analyze/src/pricing.rs, scripts/update-pricing.mjs
Updated BUILTIN_PRICING_JSON include path from ../../../packages/analyze/pricing/models.dev.json to ../data/models.dev.json with added doc comment. Modified update-pricing.mjs to write pricing models to two output files (OUTS array) instead of single output.
Integration Tests & Validation
crates/relayburn-sdk/tests/integration.rs
Added comprehensive end-to-end test module with helpers (make_turn, make_content, make_stamp, populate) and two tests: all_nine_verbs_round_trip_against_a_fixture_ledger exercises all SDK verbs via handle and free-function wrappers with assertions on counts and IDs; ingest_with_empty_roots_returns_zero_report_via_handle_and_free_fn verifies ingest behavior with empty roots in isolated environment.

Sequence Diagram

sequenceDiagram
    participant Test as Integration Test
    participant SDK as SDK Handle
    participant Ledger as Ledger
    participant Analysis as Analysis Engine
    participant Export as Export

    Test->>Ledger: Populate fixture with Turn, Content, Stamp
    Test->>SDK: Create handle with fixture home
    
    Test->>SDK: summary()
    SDK->>Analysis: Analyze ledger state
    Analysis-->>SDK: Summary stats
    SDK-->>Test: Results with counts

    Test->>SDK: session_cost()
    SDK->>Ledger: Query session data
    Ledger-->>SDK: Session records
    SDK-->>Test: Cost metrics

    Test->>SDK: overhead/hotspots/search()
    SDK->>Analysis: Process queries
    Analysis-->>SDK: Analysis results
    SDK-->>Test: Row data with kinds

    Test->>SDK: export_ledger/export_stamps()
    SDK->>Export: Serialize data
    Export-->>SDK: Exported records
    SDK-->>Test: Exported content

    Test->>SDK: ingest()
    SDK->>Ledger: Append new data
    Ledger-->>SDK: Ingest report
    SDK-->>Test: Report with scanned/appended counts
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • AgentWorkforce/burn#246: The integration tests and Cargo.toml publishing changes directly address the goal of validating SDK functionality and making relayburn crates publishable.

Possibly related PRs

  • AgentWorkforce/burn#299: Coordinated changes to relayburn-sdk/Cargo.toml (explicit workspace dependency versions) and new integration tests that exercise the SDK verbs and LedgerHandle scaffolding introduced in that PR.

Poem

🐇 A hop through versioned paths we trod,
Where pricing models find their new abode,
Nine verbs now dance in tests so bright,
Publishing flags removed in flight—
The relayburn crates stand ready, light!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main changes: adding an integration test to relayburn-sdk and making the workspace publish-ready for crates.io.
Description check ✅ Passed The description thoroughly explains both the integration test implementation and workspace publish-readiness changes, directly corresponding to the raw summary and file changes.
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 claude/sdk-publish-and-integration-test

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

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: 2a3e2f682b

ℹ️ 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 on lines +15 to +18
relayburn-reader = { path = "../relayburn-reader", version = "0.0.0" }
relayburn-ledger = { path = "../relayburn-ledger", version = "0.0.0" }
relayburn-analyze = { path = "../relayburn-analyze", version = "0.0.0" }
relayburn-ingest = { path = "../relayburn-ingest", version = "0.0.0" }
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 Stop pinning internal deps to version 0.0.0

These dependency constraints will break as soon as the workspace version is bumped above 0.0.x: Cargo treats "0.0.0" as a caret requirement (>=0.0.0, <0.0.1) and also validates the local path crate version against it, so a normal release bump (for example to 0.1.0 or 1.x) will make this manifest unsatisfiable and block cargo build/cargo publish. This makes the workspace not actually “publish-ready” beyond the initial 0.0.0 version unless every dependency spec is manually rewritten each release.

Useful? React with 👍 / 👎.

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.

🧹 Nitpick comments (2)
crates/relayburn-sdk/tests/integration.rs (2)

256-259: ⚡ Quick win

Restore RELAYBURN_HOME after the test.

This mutates process-global state and never puts the previous value back. That can leak into later tests in the same binary and make them order-dependent. Snapshot the old value and restore it with a drop guard around the ingest assertions.

🤖 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/tests/integration.rs` around lines 256 - 259, The test
sets RELAYBURN_HOME via std::env::set_var("RELAYBURN_HOME", home.path()) but
never restores the previous value; wrap the change so you snapshot the prior
value using std::env::var_os before calling set_var and restore it after the
ingest_all assertions (or use a RAII/drop guard) to reset RELAYBURN_HOME; ensure
the guard covers the calls that invoke cleanup_stale_pending_stamps, load_config
and ingest_all so process-global state is always restored even on test failure.

154-244: ⚡ Quick win

Assert the free-function results instead of discarding them.

Line 154, Line 171, Line 188, Line 222, and Line 240 only prove that the free wrapper returns Ok(_). A wrapper bug that opens the wrong ledger or maps the payload incorrectly would still pass here. Since this test is meant to validate both call surfaces, compare those free-function results to the handle-path results for overhead, overhead_trim, hotspots, export_ledger, and export_stamps.

🤖 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/tests/integration.rs` around lines 154 - 244, The
free-function results for overhead, overhead_trim, hotspots, export_ledger, and
export_stamps are only checked for Ok(_) and discarded (variables _oh2, _trim2,
_h2, _ledger_rows2, _stamp_rows2); bind those free-function returns to
meaningful names and assert they match the corresponding handle-path results
(e.g., compare overhead summaries/recommendations from overhead and _oh2,
compare trim.recommendations and _trim2, ensure hotspots discriminated
shape/refused flag matches h and _h2, compare exported ledger rows/JSONL
contents between ledger_rows and _ledger_rows2 including presence of kind="turn"
and SESSION_ID where applicable, and compare stamp_rows and _stamp_rows2
including kind="stamp"); update assertions to check equality or equivalent
content/length checks rather than just Ok.
🤖 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.

Nitpick comments:
In `@crates/relayburn-sdk/tests/integration.rs`:
- Around line 256-259: The test sets RELAYBURN_HOME via
std::env::set_var("RELAYBURN_HOME", home.path()) but never restores the previous
value; wrap the change so you snapshot the prior value using std::env::var_os
before calling set_var and restore it after the ingest_all assertions (or use a
RAII/drop guard) to reset RELAYBURN_HOME; ensure the guard covers the calls that
invoke cleanup_stale_pending_stamps, load_config and ingest_all so
process-global state is always restored even on test failure.
- Around line 154-244: The free-function results for overhead, overhead_trim,
hotspots, export_ledger, and export_stamps are only checked for Ok(_) and
discarded (variables _oh2, _trim2, _h2, _ledger_rows2, _stamp_rows2); bind those
free-function returns to meaningful names and assert they match the
corresponding handle-path results (e.g., compare overhead
summaries/recommendations from overhead and _oh2, compare trim.recommendations
and _trim2, ensure hotspots discriminated shape/refused flag matches h and _h2,
compare exported ledger rows/JSONL contents between ledger_rows and
_ledger_rows2 including presence of kind="turn" and SESSION_ID where applicable,
and compare stamp_rows and _stamp_rows2 including kind="stamp"); update
assertions to check equality or equivalent content/length checks rather than
just Ok.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d23c869-29a6-4f67-8be8-ba1c6d8bafc5

📥 Commits

Reviewing files that changed from the base of the PR and between 9637850 and 2a3e2f6.

📒 Files selected for processing (9)
  • crates/relayburn-analyze/Cargo.toml
  • crates/relayburn-analyze/data/models.dev.json
  • crates/relayburn-analyze/src/pricing.rs
  • crates/relayburn-ingest/Cargo.toml
  • crates/relayburn-ledger/Cargo.toml
  • crates/relayburn-reader/Cargo.toml
  • crates/relayburn-sdk/Cargo.toml
  • crates/relayburn-sdk/tests/integration.rs
  • scripts/update-pricing.mjs
💤 Files with no reviewable changes (1)
  • crates/relayburn-reader/Cargo.toml

@willwashburn willwashburn merged commit 3b3bad4 into main May 5, 2026
3 checks passed
@willwashburn willwashburn deleted the claude/sdk-publish-and-integration-test branch May 5, 2026 23:28
willwashburn added a commit that referenced this pull request May 6, 2026
Absorbs `relayburn-{reader,ledger,analyze,ingest}` into `relayburn-sdk`
as `src/{reader,ledger,analyze,ingest}/` modules. The Rust workspace is
now three crates (`relayburn-sdk`, `relayburn-cli`, `relayburn-sdk-node`)
instead of seven. Only the SDK and CLI are published to crates.io; the
four absorbed modules become internal implementation details rather than
a public crates.io contract.

Why: keeping the lower crates separate forced a lockstep-publish
arrangement (the prep for which landed in #304) for what is really a
single implementation. The CLI's `relayburn-sdk` dep now exercises the
SDK's public surface as an external embedder would, which is the
property we actually wanted from the split.

Mechanics:

- `git mv` each lower crate's `src/` into the corresponding SDK
  submodule, with each crate's old `lib.rs` becoming the module root.
- Cross-crate imports rewritten in two passes: first scope-rename
  intra-module sibling refs (`crate::config::` → `crate::ledger::config::`),
  then `relayburn_X::` → `crate::X::`.
- `models.dev.json` moves to `crates/relayburn-sdk/data/`; the
  `include_str!` path and `scripts/update-pricing.mjs` follow.
- Ingest's four `tests/*.rs` files become in-crate `#[cfg(test)] mod`s
  (they exercise crate-private items that the SDK doesn't re-export).
  Their per-binary `static ENV_LOCK` / `GAP_LOCK` mutexes are
  consolidated into shared `TEST_ENV_LOCK` / `TEST_GAP_LOCK` in
  `crate::ingest`; without that, bundling them into one binary races
  `$RELAYBURN_HOME` and gap-state mutations across modules.
- `relayburn-cli` and `relayburn-sdk-node` `Cargo.toml`s now depend
  only on `relayburn-sdk`. The CLI's version requirement is `0.0`
  (= `>=0.0.0, <0.1.0`) so it satisfies both the local 0.0.0 path dep
  and the published `relayburn-sdk` 0.0.1 on crates.io.
- `AGENTS.md` (`CLAUDE.md`) Layout / When-in-doubt sections updated to
  describe the three-crate shape and module-path pointers.

Verification: `cargo build --workspace` and `cargo test --workspace`
green (605 unit + 2 integration + 3 doctests, including all four
absorbed ingest test files); `cargo doc --no-deps -p relayburn-sdk`,
`cargo publish --dry-run -p relayburn-sdk --allow-dirty`, and
`cargo publish --dry-run -p relayburn-cli --allow-dirty` all succeed.

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.

[Rust port] relayburn-sdk: embedding API mirroring TS surface

1 participant