fix(rig): exclude test cassettes from the published crate - #2350
Merged
gold-silver-copper merged 1 commit intoAug 16, 2026
Conversation
The root manifest is the `rig` facade, so every path beside it is swept into the published tarball. That included `tests/cassettes/`, 1,100+ provider replay fixtures, which had grown the crate to 9.51 MiB against the crates.io 10 MiB upload limit. That left 517 KiB of headroom on a trend that added 1.5 MiB in the last release cycle, so the next release was on track to be rejected. The limit is enforced server-side, so `cargo publish --dry-run` reports success right up until the real upload fails. A 22-crate release that dies partway through leaves the workspace half-published, and the burned versions cannot be reused. Excluding the cassettes takes the tarball from 9.51 MiB to 3.33 MiB, and the file count from 1,704 to 589. They are read at runtime from `CARGO_MANIFEST_DIR` and never embedded with `include_*!`, so nothing in the package needs them to compile. Repo-local test runs are unaffected: `exclude` governs packaging only, not the working tree.
pull Bot
pushed a commit
to appelgriebsch/rig
that referenced
this pull request
Aug 20, 2026
… a recorded embedding matrix for all seven keyed providers (0xPlaygrounds#2390) * feat(telemetry): gen_ai spans for every non-completion modality Completions were the only instrumented model calls; the normalized usage and identity every modality response carries since the type-erasure sweep never reached a span. Add `ModalityOperation` + `ModalitySpanBuilder` (operation names embeddings / rerank / transcription / image_generation / audio_generation on target `rig::modalities`) and one shared seam, `telemetry::instrument_modality`, which opens the canonical span, runs the call inside it, and records `gen_ai.usage.*`, `gen_ai.response.id` and `gen_ai.response.model` off the normalized response on success. Unlike `CompletionSpanBuilder`, modality spans never adopt an ambient span: the adoption contract exists so one model *turn* has exactly one completion span, and a modality call is not a turn — an agent's RAG lookup nests as its own child span instead of overwriting the turn's fields. Every provider implementation of `embed_texts_response`, `embed_images_response`, `rerank`, `transcription`, `image_generation` and `audio_generation` now routes through the seam — the shared OpenAI embeddings/rerank/transcription/image/audio drivers cover their whole compatible families at once, plus the hand-written seams (Cohere, Gemini REST, Voyage, Ollama, Copilot, Hugging Face, Mistral, OpenRouter, Hyperbolic) and the external crates (Bedrock, Gemini gRPC, FastEmbed). The vector-store search path needs no store-side change: `embed_text` / `embed_texts` are defaults derived from `embed_texts_response`, so a `top_n` query records the same telemetry through the seam the model call opens — pinned by a test driving `InMemoryVectorIndex::top_n` over the OpenAI driver and counting the recorded usage fields. * fix(mistral): capture mistral-correlation-id on embedding responses Mistral sends its transport id on embedding responses exactly as on completions (`mistral-correlation-id`, declared on its OpenAICompatibleProvider impl), but the embeddings ext inherited the OpenAIEmbeddingsCompatible trait's `None` header default, so the shared driver read no header and every normalized embedding response reported `provider_request_id: None` — the id Mistral support asks for, silently dropped. Latent since the embeddings driver gained request-id capture. Found while recording the embedding matrix; pinned by the recorded `embedding_matrix/bug_mistral_request_id_dropped` cell, whose cassette carries the live header. * test(embeddings): a recorded embedding matrix for every keyed provider One `embedding_matrix` cassette suite per embedding-capable provider with an API key in the recording environment — openai, gemini, cohere, mistral, venice, doubleword, openrouter — recorded live and replayed in CI. Cells per provider: the normalized response is complete (input order, provider attribution, and usage / model echo / transport request id asserted exactly as the recorded wire reports them — `None`/zero pinned as the documented outcome where a provider reports nothing, never skipped); `raw` round-trips to the provider's own wire type and re-normalizes to the same view; the inherent `raw_embed_texts` route agrees with the normalized call (two live exchanges per recording, the raw-parity matrices' shape); the single-text conveniences derive from the full method; `embedding_model_with_ndims` round-trips the width where the provider supports one (OpenAI `dimensions`, Mistral `output_dimension` on codestral-embed, Gemini `output_dimensionality`, Venice); and a rejected request preserves the provider's status and raw body. Cohere adds the image half: one answer per image, `raw` as the per-image array, token usage honestly zero (Cohere bills image embeds as `billed_units.images`, which is not token-denominated and stays on the raw payload). Mistral's suite carries `bug_mistral_request_id_dropped`, the recorded pin for the correlation-id fix in the previous commit. Shared expectations live in `tests/common/support.rs` (`EmbeddingMatrixExpectations` / `assert_normalized_embedding_response`); the new `with_mistral_embedding_cassette` wrapper is registered with the cassette-safety guard. Keys present but provider not embeddings-capable (checked, not applicable): anthropic, xai, groq, deepseek, perplexity. No existing cassette was modified; the new recordings total ~3.0 MiB and are excluded from the published tarball (0xPlaygrounds#2350).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The root manifest is the
rigfacade package, so every path sitting beside it gets swept into the published tarball. The facade's ownsrc/is ~12 KiB of re-exports; the other 99.9% of what we ship to crates.io is repo furniture, dominated bytests/cassettes/(1,100+ provider replay fixtures).That has been quietly compounding:
.cratesizemaincrates.io enforces a 10 MiB upload limit, so
maintoday has 517 KiB of headroom after a cycle that added ~1.5 MiB. The next release was on track to be rejected outright.The part that makes this worth fixing pre-emptively rather than reactively: the limit is enforced server-side.
cargo publish --dry-runreports success right up until the real upload returns an error. And because a release publishes 22 crates in dependency order, a failure partway through leaves the workspace half-published on crates.io with versions that cannot be reused.Adding
exclude = ["tests/cassettes/**"]to the root[package]:cargo add rigdownloads 6.17 MiB lessThis is safe because the cassettes are data the test binaries read at runtime from
CARGO_MANIFEST_DIR(tests/common/cassette_safety.rs:11). They are never embedded withinclude_str!/include_bytes!, so nothing in the package needs them to compile.excludegoverns packaging only, so repo-local and CI test runs are completely unaffected.There is prior art in-repo:
crates/rig-core/Cargo.tomlalready usesexcludefortests/macro_hygiene.rs.Type of change
Testing
Verified in a throwaway worktree, no registry token required:
cargo publish -p rig --dry-run— exit 0, verification build compiles the packaged tarball with the cassettes absent, zero errors and no new warnings (notably nowarning: ignoring test ..., which would indicate the exclude had orphaned a test target).cargo package -p rig --list | grep -c tests/cassettes/— 0, confirming the glob actually matches.Baseline for the numbers above came from a full
cargo publish --workspace --dry-runsimulation of the pending release PR (#2221), which verified all 22 crates green — so this is the only thing standing between the workspace and a clean 0.42.0.Checklist:
Notes
Scoped deliberately to the cassettes, since they are 6.17 MiB of the 6.6 MiB of excludable bulk and fix the problem on their own. Worth a follow-up conversation, but not included here:
tests/providers/(~0.48 MiB) and the roottests/*.rsstill ship. They now ship without their fixtures, so a downstream consumer who runscargo teston the unpacked crate (some distro packagers do) would see failures rather than the passes they'd have seen before. Excludingtests/**outright would be the more complete fix; I did not want to widen the blast radius of a release-unblocking change without a maintainer opinion.