From 7a73e3185c36d55324ecfcdc1294bec335740956 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 18:09:24 +0000 Subject: [PATCH 1/3] test: assert the crate archive omits changelog/migration fragments RED. `packages/rust/Cargo.toml`'s `[package].exclude` covers `tests/` and the VitePress tooling under `docs/`, but not the fragment dirs, so `cargo package` ships all 57 of them -- roughly half the archive's 118 files. npm's `files` allowlist and maturin's wheel layout keep their fragments out structurally; cargo ships everything not excluded, so the crate needs the patterns named. Asserted against `cargo package --list` (the archive's own manifest) rather than against the exclude patterns, so a pattern that parses but matches nothing still fails. A third case pins `src/lib.rs` as present, so a `--list` that returned nothing cannot satisfy the two absence checks vacuously. Refs #939 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01V8dwtBuYy6sjaEYwNusb4z --- packages/rust/tests/crate_contents.rs | 82 +++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 packages/rust/tests/crate_contents.rs diff --git a/packages/rust/tests/crate_contents.rs b/packages/rust/tests/crate_contents.rs new file mode 100644 index 000000000..41d7a8e9b --- /dev/null +++ b/packages/rust/tests/crate_contents.rs @@ -0,0 +1,82 @@ +//! What the published `.crate` archive ships. +//! +//! `changelog.d/` and `migrations.d/` are repo *inputs* -- one fragment file +//! per change, assembled by nothing and read by no consumer of the crate. +//! The npm `files` allowlist and maturin's wheel layout keep them out of +//! their artifacts structurally; cargo ships everything not named in +//! `[package].exclude`, so the crate needs the patterns spelled out. +//! +//! Asserted against `cargo package --list` -- the archive's own manifest -- +//! rather than against the `exclude` patterns, so a pattern that parses but +//! matches nothing still fails here. + +use std::process::Command; + +/// Every path `cargo package` would write into the `.crate` archive. +fn packaged_paths() -> Vec { + let output = Command::new(env!("CARGO")) + .args([ + "package", + "--manifest-path", + concat!(env!("CARGO_MANIFEST_DIR"), "/Cargo.toml"), + "--list", + ]) + .output() + .expect("cargo package --list should run"); + + assert!( + output.status.success(), + "cargo package --list failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + + String::from_utf8(output.stdout) + .expect("cargo package --list emits utf-8") + .lines() + .map(str::to_string) + .collect() +} + +/// Archive paths under `prefix`. +fn shipped_under(prefix: &str) -> Vec { + packaged_paths() + .into_iter() + .filter(|path| path.starts_with(prefix)) + .collect() +} + +/// Guards the two assertions below against a vacuous pass: a `--list` that +/// silently returned nothing would otherwise satisfy every "does not ship" +/// check in this file. +#[test] +fn crate_archive_ships_the_library_source() { + let paths = packaged_paths(); + + assert!( + paths.iter().any(|p| p == "src/lib.rs"), + "expected src/lib.rs in the archive, got {} paths: {paths:?}", + paths.len() + ); +} + +#[test] +fn crate_archive_omits_changelog_fragments() { + let shipped = shipped_under("changelog.d/"); + + assert!( + shipped.is_empty(), + "changelog fragments are repo inputs and must not ship; \ + add `changelog.d/` to [package].exclude. Shipped: {shipped:?}" + ); +} + +#[test] +fn crate_archive_omits_migration_fragments() { + let shipped = shipped_under("migrations.d/"); + + assert!( + shipped.is_empty(), + "migration fragments are repo inputs and must not ship; \ + add `migrations.d/` to [package].exclude. Shipped: {shipped:?}" + ); +} From a446c7081b36c1844295cbb7928affe7fe9003d1 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 18:12:39 +0000 Subject: [PATCH 2/3] test: list the crate archive with --allow-dirty Still RED. `cargo package --list` aborts outright when a packaged file is uncommitted, so the moment you edit `[package].exclude` to try a fix the test stops reporting on its assertions and fails on the VCS check instead -- all three cases, including the sanity anchor. `--allow-dirty` asks the question the assertions actually mean: what would the working tree ship. The two fragment cases still fail against the unmodified manifest. Refs #939 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01V8dwtBuYy6sjaEYwNusb4z --- packages/rust/tests/crate_contents.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/rust/tests/crate_contents.rs b/packages/rust/tests/crate_contents.rs index 41d7a8e9b..6b80c17a9 100644 --- a/packages/rust/tests/crate_contents.rs +++ b/packages/rust/tests/crate_contents.rs @@ -13,6 +13,12 @@ use std::process::Command; /// Every path `cargo package` would write into the `.crate` archive. +/// +/// `--allow-dirty` because the question is what the *working tree* would +/// ship: without it cargo refuses outright the moment a packaged file is +/// uncommitted, so editing `exclude` and re-running would abort before +/// listing anything -- failing for a reason that has nothing to do with the +/// assertions below. fn packaged_paths() -> Vec { let output = Command::new(env!("CARGO")) .args([ @@ -20,6 +26,7 @@ fn packaged_paths() -> Vec { "--manifest-path", concat!(env!("CARGO_MANIFEST_DIR"), "/Cargo.toml"), "--list", + "--allow-dirty", ]) .output() .expect("cargo package --list should run"); From 6e78117fcef355a95dca9e77d90b2da7bf6343ae Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 18:16:06 +0000 Subject: [PATCH 3/3] fix(rust): exclude changelog.d/ and migrations.d/ from the crate archive GREEN. `cargo package` drops from 119 files to 59: the 60 fragment files no longer ship. Verified on the real archive, not just the listing -- `tar -tzf target/package/dirsql-0.2.7.crate` has zero entries under either dir, and `Packaged 59 files, 799.3KiB (207.1KiB compressed)`. npm's `files` allowlist and maturin's wheel layout already dropped their fragments structurally, and release-ci.yml's path filters treat every package's fragment dirs as non-shipping. The crate manifest was the one place that had not been told. Fixes #939 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01V8dwtBuYy6sjaEYwNusb4z --- packages/rust/Cargo.toml | 6 ++++++ .../2026-08-20-crate-excludes-fragment-dirs.md | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 packages/rust/changelog.d/2026-08-20-crate-excludes-fragment-dirs.md diff --git a/packages/rust/Cargo.toml b/packages/rust/Cargo.toml index 91b439190..256b6403e 100644 --- a/packages/rust/Cargo.toml +++ b/packages/rust/Cargo.toml @@ -19,8 +19,14 @@ repository.workspace = true # `tests/` is the integration suite -- excluded so test files never ship in the # published `.crate` (enforced by the `packaging` gate in CI). Inline unit tests # stay (they are `#[cfg(test)]` modules inside `src/`, not separate files). +# The fragment dirs are repo inputs -- one file per change, assembled into +# nothing and read by no crate consumer. They need naming here because cargo +# ships whatever is not excluded; npm and maturin drop theirs structurally, via +# an allowlist and the wheel layout respectively. exclude = [ "tests/", + "changelog.d/", + "migrations.d/", "docs/.vitepress", "docs/.claude", "docs/tests", diff --git a/packages/rust/changelog.d/2026-08-20-crate-excludes-fragment-dirs.md b/packages/rust/changelog.d/2026-08-20-crate-excludes-fragment-dirs.md new file mode 100644 index 000000000..6febda98c --- /dev/null +++ b/packages/rust/changelog.d/2026-08-20-crate-excludes-fragment-dirs.md @@ -0,0 +1,9 @@ +**Fixed** — the published `.crate` archive no longer ships `changelog.d/` and +`migrations.d/`. `[package].exclude` named `tests/` and the VitePress tooling +under `docs/` but not the fragment dirs, and cargo ships whatever is not +excluded, so every release carried 60 fragment files no crate consumer reads — +more than half the archive's entries (119 files → 59). + +No API, CLI or behavior change; the crate is smaller and its file list now +matches the npm package (an allowlist) and the wheel (maturin's layout), which +already dropped their fragments structurally.