Fix crates.io publishing for the current workspace layout - #125
Conversation
The library is published to crates.io (convex-core, convex-math, convex-curves, convex-bonds, convex-analytics at 0.11.1), but the README, release workflow, and workspace manifest all claimed it was not, and the config had drifted so that `cargo publish` no longer worked. - Cargo.toml: give the five published crates' internal deps a version alongside the path so `cargo publish` succeeds (path-only deps are rejected at publish time). - Mark the facade, FFI, WASM, MCP and pricing-engine/server crates publish = false so a release can't push applications or bindings. The `convex` facade additionally can't publish — the name belongs to an unrelated project on crates.io. - release.yml: add a publish-crates job that publishes the five library crates in dependency order, gated on the release tag, skipping any version already on crates.io so re-runs are safe. - README: correct the installation and architecture sections to the current 15-crate layout (published vs internal), fix the language bindings status, and replace the outdated code samples with snippets verified by compile-checked examples.
📝 WalkthroughWalkthroughAdds a CI Changescrates.io Publishing Setup
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
Cargo.toml (1)
43-56: 🩺 Stability & Availability | 🔵 TrivialAdd a CI check for these duplicated crate versions.
Lines 52-56 now duplicate the release version, but the release validation shown in
.github/workflows/release.ymlonly checks the rootCargo.tomlversion against the tag. If one of these entries is missed in a future bump, the failure will surface only whencargo publishreaches a downstream crate. Please add a pre-publish check that all publishable workspace dependency versions matchworkspace.package.version.🤖 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 `@Cargo.toml` around lines 43 - 56, The workspace publishable dependency entries in Cargo.toml can drift from workspace.package.version because they currently repeat the release version manually. Add a CI validation step in the release flow (alongside the existing release.yml checks) that inspects the publishable crates such as convex-core, convex-math, convex-curves, convex-bonds, and convex-analytics and verifies their version fields match workspace.package.version before publishing. Keep the check focused on the versioned path dependencies so a future bump failure is caught early, not during cargo publish.
🤖 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 @.github/workflows/release.yml:
- Around line 122-129: The publish-crates job is exposing more GitHub
credentials than needed, and the checkout step is still persisting auth before
cargo publish runs. Update the publish-crates workflow job to limit permissions
to contents: read and adjust the actions/checkout step in the release workflow
to disable credential persistence. Keep the job focused on repository read
access only so the crates.io token remains the sole credential used during
publish verification.
- Around line 153-161: The crates.io availability check in the release workflow
needs bounded retries and a timeout so transient DNS, 5xx, or slow responses
don’t fail the whole release. Update the probe around the `status=$(curl ...)`
block in the release job to use a small retry budget and a request timeout,
while preserving the existing 200/404 handling and the `Unexpected HTTP $status`
failure path.
In `@README.md`:
- Around line 31-38: The dependency example in the README does not match the
crates imported in the code snippets, so a downstream user cannot compile them
as written. Update the examples in the README sections around the repeated
import blocks to either add every directly used crate (`convex_bonds`,
`convex_core`, `convex_curves`, and `rust_decimal_macros`) to the dependency
snippet or rewrite the snippets to use only `convex_analytics` re-exports. Make
sure the imports shown in the examples are consistent with the dependency block
and avoid relying on workspace-only availability.
- Around line 189-206: The fenced architecture block in README.md is missing a
language tag, triggering markdownlint MD040. Update that Markdown code fence to
use a text language hint on the block containing the convex package tree so the
renderer/linter recognizes it correctly.
---
Nitpick comments:
In `@Cargo.toml`:
- Around line 43-56: The workspace publishable dependency entries in Cargo.toml
can drift from workspace.package.version because they currently repeat the
release version manually. Add a CI validation step in the release flow
(alongside the existing release.yml checks) that inspects the publishable crates
such as convex-core, convex-math, convex-curves, convex-bonds, and
convex-analytics and verifies their version fields match
workspace.package.version before publishing. Keep the check focused on the
versioned path dependencies so a future bump failure is caught early, not during
cargo publish.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: b192525b-3f4d-45d3-93f4-5ea7b911d28a
📒 Files selected for processing (15)
.github/workflows/release.ymlCargo.tomlREADME.mdcrates/convex-analytics/examples/readme_quickstart.rscrates/convex-analytics/examples/readme_zspread.rscrates/convex-engine/Cargo.tomlcrates/convex-ext-file/Cargo.tomlcrates/convex-ext-redb/Cargo.tomlcrates/convex-ffi/Cargo.tomlcrates/convex-mcp/Cargo.tomlcrates/convex-portfolio/Cargo.tomlcrates/convex-ports/Cargo.tomlcrates/convex-server/Cargo.tomlcrates/convex-wasm/Cargo.tomlcrates/convex/Cargo.toml
| publish-crates: | ||
| name: Publish to crates.io | ||
| runs-on: ubuntu-latest | ||
| needs: validate | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| ref: ${{ github.event.inputs.tag || github.ref }} |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Drop unnecessary GitHub token exposure from the publish job.
This job only needs repository read access, but checkout currently persists credentials and the job inherits default GITHUB_TOKEN permissions before running cargo publish. Tighten it to contents: read and disable credential persistence so the crates.io token is the only credential available during publish verification.
Suggested hardening diff
publish-crates:
name: Publish to crates.io
runs-on: ubuntu-latest
needs: validate
+ permissions:
+ contents: read
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.inputs.tag || github.ref }}
+ persist-credentials: false📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| publish-crates: | |
| name: Publish to crates.io | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| publish-crates: | |
| name: Publish to crates.io | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 127-129: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[warning] 122-166: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block
(excessive-permissions)
🤖 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 @.github/workflows/release.yml around lines 122 - 129, The publish-crates job
is exposing more GitHub credentials than needed, and the checkout step is still
persisting auth before cargo publish runs. Update the publish-crates workflow
job to limit permissions to contents: read and adjust the actions/checkout step
in the release workflow to disable credential persistence. Keep the job focused
on repository read access only so the crates.io token remains the sole
credential used during publish verification.
Source: Linters/SAST tools
| status=$(curl -s -o /dev/null -w '%{http_code}' \ | ||
| -H "User-Agent: $ua" \ | ||
| "https://crates.io/api/v1/crates/$crate/$VERSION") | ||
| if [ "$status" = "200" ]; then | ||
| echo "✓ $crate@$VERSION already on crates.io — skipping" | ||
| continue | ||
| elif [ "$status" != "404" ]; then | ||
| echo "Unexpected HTTP $status checking $crate@$VERSION on crates.io" >&2 | ||
| exit 1 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Add retries and timeouts around the crates.io probe.
A transient DNS/5xx/slow-response failure here aborts the whole release before publishing starts. Bound the call and give it a small retry budget.
Suggested retry/timeout diff
- status=$(curl -s -o /dev/null -w '%{http_code}' \
+ status=$(curl -s -o /dev/null -w '%{http_code}' \
+ --retry 5 --retry-all-errors --connect-timeout 10 --max-time 30 \
-H "User-Agent: $ua" \
"https://crates.io/api/v1/crates/$crate/$VERSION")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| status=$(curl -s -o /dev/null -w '%{http_code}' \ | |
| -H "User-Agent: $ua" \ | |
| "https://crates.io/api/v1/crates/$crate/$VERSION") | |
| if [ "$status" = "200" ]; then | |
| echo "✓ $crate@$VERSION already on crates.io — skipping" | |
| continue | |
| elif [ "$status" != "404" ]; then | |
| echo "Unexpected HTTP $status checking $crate@$VERSION on crates.io" >&2 | |
| exit 1 | |
| status=$(curl -s -o /dev/null -w '%{http_code}' \ | |
| --retry 5 --retry-all-errors --connect-timeout 10 --max-time 30 \ | |
| -H "User-Agent: $ua" \ | |
| "https://crates.io/api/v1/crates/$crate/$VERSION") | |
| if [ "$status" = "200" ]; then | |
| echo "✓ $crate@$VERSION already on crates.io — skipping" | |
| continue | |
| elif [ "$status" != "404" ]; then | |
| echo "Unexpected HTTP $status checking $crate@$VERSION on crates.io" >&2 | |
| exit 1 |
🤖 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 @.github/workflows/release.yml around lines 153 - 161, The crates.io
availability check in the release workflow needs bounded retries and a timeout
so transient DNS, 5xx, or slow responses don’t fail the whole release. Update
the probe around the `status=$(curl ...)` block in the release job to use a
small retry budget and a request timeout, while preserving the existing 200/404
handling and the `Unexpected HTTP $status` failure path.
| The core library crates are published to [crates.io](https://crates.io). Most | ||
| users only need `convex-analytics`, which re-exports the lower layers (core, | ||
| math, curves, bonds): | ||
|
|
||
| ```toml | ||
| [dependencies] | ||
| convex-bonds = { git = "https://github.com/sujitn/convex.git" } | ||
| convex-analytics = { git = "https://github.com/sujitn/convex.git" } | ||
| convex-curves = { git = "https://github.com/sujitn/convex.git" } | ||
| convex-analytics = "0.13" | ||
| ``` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
The dependency snippet does not match the imports in the examples.
convex-analytics = "0.13" alone is not enough for the code shown here: both snippets also import convex_bonds, convex_core, convex_curves, and rust_decimal_macros directly. The mirrored examples compile only because they live inside the workspace package; a downstream user copying this README will hit unresolved-crate errors. Either expand the dependency block to include every directly imported crate, or rewrite the snippets to use only convex_analytics re-exports.
Also applies to: 59-62, 88-92
🤖 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 `@README.md` around lines 31 - 38, The dependency example in the README does
not match the crates imported in the code snippets, so a downstream user cannot
compile them as written. Update the examples in the README sections around the
repeated import blocks to either add every directly used crate (`convex_bonds`,
`convex_core`, `convex_curves`, and `rust_decimal_macros`) to the dependency
snippet or rewrite the snippets to use only `convex_analytics` re-exports. Make
sure the imports shown in the examples are consistent with the dependency block
and avoid relying on workspace-only availability.
| ``` | ||
| convex/ | ||
| ├── convex-core # Core types (Date, Price, Yield, etc.) | ||
| ├── convex-math # Mathematical utilities and solvers | ||
| ├── convex-curves # Yield curve construction and interpolation | ||
| ├── convex-bonds # Bond instruments and definitions | ||
| ├── convex-analytics # Unified analytics (yields, spreads, risk) | ||
| ├── convex-wasm # WebAssembly bindings | ||
| └── convex-ffi # Foreign Function Interface for language bindings | ||
| ├── convex-core # Core types (Date, Price, Yield, calendars, day counts) [published] | ||
| ├── convex-math # Solvers and interpolators (Brent, Newton, LM) [published] | ||
| ├── convex-curves # Yield/credit curves, bootstrapping, multi-curve [published] | ||
| ├── convex-bonds # Bond instruments (fixed, FRN, callable, zero, sinker) [published] | ||
| ├── convex-analytics # Unified analytics: pricing, yields, spreads, risk [published] | ||
| ├── convex # Single-import facade re-exporting the public API (internal) | ||
| ├── convex-portfolio # Portfolio and ETF analytics (internal) | ||
| ├── convex-ffi # C-ABI FFI for language bindings (Java, Excel) (internal) | ||
| ├── convex-wasm # WebAssembly bindings for the browser demo (internal) | ||
| ├── convex-mcp # MCP server for tool/agent integration (internal) | ||
| ├── convex-ports # Hexagonal port traits (market/reference data, storage) (internal) | ||
| ├── convex-engine # Reactive pricing engine with a calculation graph (internal) | ||
| ├── convex-ext-file # File-backed market/reference data adapter (internal) | ||
| ├── convex-ext-redb # redb embedded-storage adapter (internal) | ||
| └── convex-server # REST + WebSocket pricing server (deployed to Fly.io) (internal) | ||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add a language to this fenced block.
This fence triggers markdownlint MD040 as written. text is enough here.
Suggested fix
-```
+```text
convex/
├── convex-core # Core types (Date, Price, Yield, calendars, day counts) [published]
...
└── convex-server # REST + WebSocket pricing server (deployed to Fly.io) (internal)</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 189-189: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 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 `@README.md` around lines 189 - 206, The fenced architecture block in README.md
is missing a language tag, triggering markdownlint MD040. Update that Markdown
code fence to use a text language hint on the block containing the convex
package tree so the renderer/linter recognizes it correctly.
Source: Linters/SAST tools
There was a problem hiding this comment.
2 issues found across 15 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".github/workflows/release.yml">
<violation number="1" location=".github/workflows/release.yml:153">
P2: Add retry and timeout options to this `curl` call. A transient DNS/5xx failure or slow response will abort the entire release pipeline. Consider `--retry 5 --retry-all-errors --connect-timeout 10 --max-time 30` to add resilience.</violation>
</file>
<file name="README.md">
<violation number="1" location="README.md:37">
P1: The dependency snippet tells users to add only `convex-analytics = "0.13"`, but both example snippets directly import from `convex_bonds`, `convex_core`, `convex_curves`, and `rust_decimal_macros`. In Rust, transitive dependencies cannot be used via `use crate_name::...` without an explicit `Cargo.toml` entry. Either expand the dependency block to list all directly imported crates, or rewrite the examples to use only `convex_analytics` re-export paths.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| convex-bonds = { git = "https://github.com/sujitn/convex.git" } | ||
| convex-analytics = { git = "https://github.com/sujitn/convex.git" } | ||
| convex-curves = { git = "https://github.com/sujitn/convex.git" } | ||
| convex-analytics = "0.13" |
There was a problem hiding this comment.
P1: The dependency snippet tells users to add only convex-analytics = "0.13", but both example snippets directly import from convex_bonds, convex_core, convex_curves, and rust_decimal_macros. In Rust, transitive dependencies cannot be used via use crate_name::... without an explicit Cargo.toml entry. Either expand the dependency block to list all directly imported crates, or rewrite the examples to use only convex_analytics re-export paths.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At README.md, line 37:
<comment>The dependency snippet tells users to add only `convex-analytics = "0.13"`, but both example snippets directly import from `convex_bonds`, `convex_core`, `convex_curves`, and `rust_decimal_macros`. In Rust, transitive dependencies cannot be used via `use crate_name::...` without an explicit `Cargo.toml` entry. Either expand the dependency block to list all directly imported crates, or rewrite the examples to use only `convex_analytics` re-export paths.</comment>
<file context>
@@ -22,69 +22,61 @@ Convex is a production-grade fixed income analytics library providing comprehens
-convex-bonds = { git = "https://github.com/sujitn/convex.git" }
-convex-analytics = { git = "https://github.com/sujitn/convex.git" }
-convex-curves = { git = "https://github.com/sujitn/convex.git" }
+convex-analytics = "0.13"
</file context>
</details>
| set -euo pipefail | ||
| ua="convex-release (https://github.com/sujitn/convex)" | ||
| for crate in convex-core convex-math convex-curves convex-bonds convex-analytics; do | ||
| status=$(curl -s -o /dev/null -w '%{http_code}' \ |
There was a problem hiding this comment.
P2: Add retry and timeout options to this curl call. A transient DNS/5xx failure or slow response will abort the entire release pipeline. Consider --retry 5 --retry-all-errors --connect-timeout 10 --max-time 30 to add resilience.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/release.yml, line 153:
<comment>Add retry and timeout options to this `curl` call. A transient DNS/5xx failure or slow response will abort the entire release pipeline. Consider `--retry 5 --retry-all-errors --connect-timeout 10 --max-time 30` to add resilience.</comment>
<file context>
@@ -119,10 +119,56 @@ jobs:
+ set -euo pipefail
+ ua="convex-release (https://github.com/sujitn/convex)"
+ for crate in convex-core convex-math convex-curves convex-bonds convex-analytics; do
+ status=$(curl -s -o /dev/null -w '%{http_code}' \
+ -H "User-Agent: $ua" \
+ "https://crates.io/api/v1/crates/$crate/$VERSION")
</file context>
| status=$(curl -s -o /dev/null -w '%{http_code}' \ | |
| status=$(curl -s -o /dev/null -w '%{http_code}' \ | |
| --retry 5 --retry-all-errors --connect-timeout 10 --max-time 30 \ |
Summary
The library is published to crates.io —
convex-core,convex-math,convex-curves,convex-bonds, andconvex-analyticsare live at 0.11.1 — but the README, the release workflow, and the workspace manifest all claimed it wasn't, and the config had drifted so thatcargo publishno longer works. This PR makes publishing correct again for the restructured workspace.What changed
Publishing config
Cargo.toml: the five published crates' internal deps were path-only (noversion), whichcargo publishrejects ("all dependencies must have a version specified"). Addedversion = "0.13.0"alongside each path so packaging succeeds. Verified withcargo package.publish = false: theconvexfacade,convex-ffi,convex-wasm,convex-mcp,convex-portfolio, and the pricing-engine/server stack (convex-ports,convex-engine,convex-ext-file,convex-ext-redb,convex-server). These are applications/bindings, not libraries. Theconvexfacade also can't publish — that name belongs to an unrelated project (convex.dev) on crates.io.Release automation
publish-cratesjob torelease.ymlthat publishes the five library crates in dependency order (core/math → curves → bonds → analytics), gated on the version tag.Docs
cargo run -p convex-analytics --example readme_quickstart/readme_zspread) so they stay accurate.Notes for release
CARGO_REGISTRY_TOKENrepo secret whose crates.io account owns the five crates.workspace.package.versionand the hardcoded internal dep versions inCargo.tomlin sync on each bump.Verification
cargo check --workspacepasses.cargo packagesucceeds for the leaf crates; dependent crates resolve once their deps are published in order.Summary by CodeRabbit
New Features
Documentation
Bug Fixes