Release checklist
This page documents the steps required before publishing any matten release.
It is the canonical gate referenced by RFC-015.
This page covers whether a release is fit to go out. It does not decide when one happens —
that is RFC-094’s release cadence policy: a correctness fix to published code is a patch and ships
as soon as it is reviewed; anything adding public API is a minor and batches until two or more
themes have landed, 28 days have passed, or the owner asks; and a change that does not reach
crates.io is not a release at all. The last is testable rather than editorial — if
git diff --name-only <last-tag>..HEAD -- crates/ is empty, there is nothing to release.
Before every release
Release tags use bare SemVer with no v prefix, for example 0.46.0.
1. Source verification
cargo fmt --all --check
cargo fmt --manifest-path tools/matten-report/Cargo.toml --check
cargo fmt --manifest-path tools/matten-migrate/Cargo.toml --check
bash scripts/check-core-dependency-boundary.sh # RFC-022 core boundary gate
bash scripts/check-published-dependency-isolation.sh # RFC-049 §B1 per-crate peer-dep isolation
bash scripts/check-matten-data-scope.sh # RFC-042 matten-data anti-scope guard
bash scripts/check-benchmark-dependency-sync.sh # benchmark harness ndarray pin == workspace requirement
bash scripts/check-streaming-scope.sh # RFC-037 streaming / large-CSV anti-scope guard
bash scripts/check-release-docs.sh # doc-truth + examples naming-band guards
bash scripts/check-doc-code.sh # every non-ignored ```rust block in docs/src compiles
bash scripts/check-report-demos.sh # docs/src/reports/*.md match matten-report's current output
bash scripts/check-tool-tests.sh # RFC-117: workspace-excluded tools' own shell test suites
cargo clippy --all-targets --all-features -- -D warnings
cargo clippy --all-targets --no-default-features -- -D warnings
cargo clippy --all-targets --no-default-features --features dynamic -- -D warnings
RUSTFLAGS="-D warnings" cargo check --all-targets --all-features
cargo test --all-targets
cargo test --doc --all-features
2. Feature matrix
cargo test --no-default-features
cargo test --no-default-features --features serde
cargo test --no-default-features --features json
cargo test --no-default-features --features csv
cargo test --no-default-features --features dynamic
cargo test --no-default-features --features dynamic,json
cargo test --no-default-features --features dynamic,csv
cargo test --no-default-features --features dynamic,json,csv
cargo test --all-features
3. Examples
cargo check --examples
cargo check --examples --all-features
cargo run --example 00_quickstart
cargo run --example 06_broadcasting
cargo run --example 08_slicing_builder
cargo run --example 12_boundary_error_handling
cargo run --example 57_visual_shape_axis_summary
cargo run --example dynamic_00_quickstart --features dynamic,json,csv
cargo run --example dynamic_05_dirty_csv_cleanup --features dynamic,json,csv
cargo check -p matten --example dynamic_09_visual_readiness_summary
cargo run -p matten --example dynamic_09_visual_readiness_summary --features dynamic
cargo run -p matten-data --example data_06_visual_readiness_summary
cargo run -p matten-mlprep --example mlprep_visual_standardize_summary
cargo check --manifest-path tools/matten-report/Cargo.toml
cargo test --manifest-path tools/matten-report/Cargo.toml
bash tools/matten-report/tests/process-boundary.sh
bash tools/matten-report/tests/module-boundaries.sh
bash tools/matten-report/tests/module-boundaries.sh --self-test
cargo clippy --manifest-path tools/matten-report/Cargo.toml -- -D warnings
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo data-readiness
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo data-readiness --output target/matten-report-demo.md
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo data-readiness --format html --output target/matten-report-data-readiness.html
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo data-readiness --format json --output target/matten-report-data-readiness.json
cargo run --manifest-path tools/matten-report/Cargo.toml -- --input tools/matten-report/fixtures/small.csv --kind data-readiness --select sales,cost
cargo run --manifest-path tools/matten-report/Cargo.toml -- --input tools/matten-report/fixtures/small.csv --kind data-readiness --select sales,cost --format html --output target/matten-report-input.html
cargo run --manifest-path tools/matten-report/Cargo.toml -- --input tools/matten-report/fixtures/non_numeric.csv --kind data-readiness --select sales,cost --format html --output target/matten-report-input-error.html
cargo run --manifest-path tools/matten-report/Cargo.toml -- --input tools/matten-report/fixtures/small.csv --kind data-readiness --select sales,cost --format json --output target/matten-report-input.json
cargo run --manifest-path tools/matten-report/Cargo.toml -- --input tools/matten-report/fixtures/non_numeric.csv --kind data-readiness --select sales,cost --format json --output target/matten-report-input-error.json
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo shape-flow
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo shape-flow --output target/matten-report-shape-flow.md
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo shape-flow --format html --output target/matten-report-shape-flow.html
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo shape-flow --format json --output target/matten-report-shape-flow.json
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo dynamic-readiness
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo dynamic-readiness --output target/matten-report-dynamic-readiness.md
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo dynamic-readiness --format html --output target/matten-report-dynamic-readiness.html
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo dynamic-readiness --format json --output target/matten-report-dynamic-readiness.json
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo mlprep-standardization
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo mlprep-standardization --output target/matten-report-mlprep-standardization.md
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo mlprep-standardization --format html --output target/matten-report-mlprep-standardization.html
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo mlprep-standardization --format json --output target/matten-report-mlprep-standardization.json
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo educational-path
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo educational-path --output target/matten-report-educational-path.md
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo educational-path --format html --output target/matten-report-educational-path.html
cargo run --manifest-path tools/matten-report/Cargo.toml -- --demo educational-path --format json --output target/matten-report-educational-path.json
cargo check --manifest-path tools/matten-migrate/Cargo.toml
cargo test --manifest-path tools/matten-migrate/Cargo.toml
cargo clippy --manifest-path tools/matten-migrate/Cargo.toml -- -D warnings
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- list-targets
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- inspect tools/matten-migrate/fixtures/simple-core-project
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- report tools/matten-migrate/fixtures/simple-core-project
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- report tools/matten-migrate/fixtures/simple-core-project --output target/matten-migration-report.md
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- suggest --target ndarray tools/matten-migrate/fixtures/receiver-method-project
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- suggest --target polars-pandas tools/matten-migrate/fixtures/common-rust-collisions-project
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- suggest --target stay-with-matten tools/matten-migrate/fixtures/simple-core-project
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- explain-api Tensor::matmul
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- explain-api matmul
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- explain-api matten_ndarray::to_arrayd
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- explain-api matten_data::Table
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- check-bridges tools/matten-migrate/fixtures/ndarray-bridge-project
cargo run --manifest-path tools/matten-migrate/Cargo.toml -- check-bridges tools/matten-migrate/fixtures/simple-core-project
4. MSRV
cargo +1.85.0 build
cargo +1.85.0 test --all-features --quiet
5. Public API audit
Compare the current public surface against docs/src/reference/public-api-snapshot.md.
Allowed root exports:
TensorMattenErrorDataFormatMattenLimitsSliceBuilderElement(under#[cfg(feature = "dynamic")])NumericPolicy(under#[cfg(feature = "dynamic")])
Allowed #[doc(hidden)] exports (compiler visibility only, not user-facing):
IntoSliceRangeSliceConvertSliceSpecRepr
Run a spot-check:
grep -n "^pub use" src/lib.rs
Verify no module accidentally became pub mod.
cargo public-api snapshot (manual, pre-v1.0 minimum-viable step; RFC-066
NF-2, re-confirmed open by the RFC-074 re-audit). Not wired as a CI gate or
project dependency. Before a minor/major release that touches public API
surface, run it by hand for matten and any companion whose surface changed,
and reconcile the output against docs/src/reference/public-api-snapshot.md
and each crate’s ## Public API README block:
cargo install cargo-public-api # one-time, not a project dependency
cargo public-api --manifest-path crates/matten/Cargo.toml
cargo public-api --manifest-path crates/matten-ndarray/Cargo.toml
cargo public-api --manifest-path crates/matten-mlprep/Cargo.toml
cargo public-api --manifest-path crates/matten-data/Cargo.toml
cargo public-api --manifest-path crates/matten-stats/Cargo.toml
Wiring this into CI (toolchain pinning, nightly requirements) is a separate, explicit decision — do not add it silently as part of a routine release.
6. Documentation truth pass
# No stale version strings in user-facing files
grep -R "Status:.*0\.[0-9]\{2\}\." README.md docs/src/ src/lib.rs || true
# No stale "matten 0.x" in runtime messages
grep -rn "matten 0\." src/ | grep -v "CHANGELOG\|#\[" || true
# No version-specific claims in lib.rs crate docs
grep "This is.*0\." src/lib.rs || true
7. CHANGELOG
- Every API change has a changelog entry.
- Changelog entries describe actual changes, not planned ones.
- No changelog entry claims a fix that is not in the code.
- If the entire scope of this release is local-tool-only (workspace-excluded,
publish = falsecrates such astools/matten-reportortools/matten-migrate), the CHANGELOG entry must include a one-line justification for cutting a lock-step family checkpoint despite no published-crate change (RFC-075 §3.1).
8. Version bump
Update Cargo.toml version. During v0.x, patch releases (0.13.x) should not
introduce new public API unless a minor release (0.14.0) is intended.
Additional gates for minor releases (0.14.0, 0.15.0, …)
- New public API has a corresponding accepted RFC.
- Public API snapshot is regenerated and reviewed.
- mdBook examples for new APIs compile and run.
- Migration guide updated if any method signature changed.
Public-dependency-minor changes
When a published crate re-exposes a third-party type in its public API (for example
matten-ndarray exposing ndarray::ArrayD<f64> through to_arrayd/from_arrayd), changing the
supported minor of that dependency is a public-API compatibility event — not a routine
cargo update — and is handled as a lock-step family minor (RFC-030). Before releasing such a
change:
- The change has an accepted RFC recording the supported version(s) and the decision (a single
bump vs. a bounded range). Precedent: RFC-062 (
ndarray→0.17), which weighed a0.16+0.17range before the maintainer chose a single-version requirement to keepCargo.tomlsimple. - If a range is supported, CI verifies the crate’s tests, doctests, and examples against each
supported minor — e.g.
cargo update -p <dep> --precise <ver>in a fresh checkout (so the per-job lockfile edit is not committed). A single-version requirement needs only the normal job against the resolved patch (document which patch CI targets). - No version-conditional bridge/crate code. If the unchanged crate cannot compile against every
supported minor, narrow the range instead of adding
#[cfg(...)]branches or per-version feature flags. - Docs state that the resolved dependency minor is part of the crate’s public type identity, name any yanked patch that is excluded and not a tested target, and note that docs.rs renders a single resolved minor even though CI verifies the full range.
- MSRV is re-verified with the new dependency version in the graph. A dependency’s own
rust-versionis not sufficient — its transitive dependencies can raise the floor independently. - Core
mattendependency isolation is re-confirmed (the published-dependency-isolation guard still passes; the change must not leak a peer dependency into the core graph). - If the dependency is also used by the workspace-excluded benchmark harness (e.g. a peer pin in
benchmarks/Cargo.toml), its pin is synced by hand andcheck-benchmark-dependency-sync.shpasses — the harness cannot inherit{ workspace = true }, so this guard catches a forgotten sync.
Workspace core-dependency requirement
Companion crates inherit core matten through [workspace.dependencies] as
matten = { version = "0", path = "crates/matten", default-features = false }
(RFC-064). Do not narrow this requirement during routine family releases. User
docs and examples still show explicit matched release pins so downstreams see the
supported family set.
Push, confirm CI green, then publish
This section applies to every release, patch included — not only minor ones. Pushing, confirming
CI, tagging, and publishing happen regardless of release size, so this lives outside ## Additional gates for minor releases on purpose: a patch release must not be able to read that heading and skip
straight to tagging.
Push, confirm CI green, then tag
The release sequence is push → confirm CI green → tag → publish, in that order, for a reason at each step:
-
Push
main. CI runs on push; it cannot report on a commit that has not been pushed yet. -
Confirm CI is green on the commit just pushed — not “CI was green recently,” not the previous run, the commit that is about to be tagged. A red run on that commit stops the release. Do not tag or publish until it is green. Check with:
gh run list --limit 5or the repository’s Actions tab, and match the run against the commit SHA just pushed.
-
Tag, only after step 1 has already landed on the remote. A tag pointing at a commit absent from the remote is the orphaned-tag defect this project repaired once, for
0.38.0/0.39.0. -
Publish — see below.
0.46.0 was tagged and published across four consecutive red CI runs because this step did not
exist: every local gate passed, and the workflow result on the commit just pushed was never checked
(RFC-117, RFC-118). This step does not automate that check — it only makes it impossible to miss by
accident.
Publishing: one workspace command, not five per-crate ones
cargo publish --workspace --dry-run
cargo publish --workspace
Publish the whole workspace in one invocation. Cargo resolves the order itself and — the reason this matters — verifies every crate before uploading any, so a failure in the last companion aborts before core is irreversibly live. crates.io has no unpublish, only yank, which makes a half-published family a permanent artifact of the registry rather than a mistake you can undo.
This supersedes the older instruction to publish matten first and then each companion in
dependency order. That sequence predates cargo publish --workspace and carried exactly the
partial-publication hazard above; it was still being followed as late as the 0.42.0 release, where
the owner stopped it before the first upload. Keep the following in mind, but do not turn them back
into a manual sequence:
mattenis still published before the companions — cargo does this for you.- A companion dry-run run on its own may fail before core is visible on crates.io. That is a
sequencing artifact, not a dependency-policy failure, and
--workspaceavoids it entirely. - If the broad
version = "0"requirement is intentionally changed, update RFC-030/RFC-064, this checklist, companion README compatibility notes, and package dry-run expectations in the same review slice.
Verify afterwards against the sparse index, not the JSON API:
curl -s https://index.crates.io/ma/tt/matten-stats | grep '"vers":"<version>"'
https://crates.io/api/v1/crates/<name> now returns HTTP 403 under the crates.io data-access
policy, so a verification step built on it reports nothing and looks like a failed publish.
v1.0.0 gate
v1.0.0 requires explicit confirmation from the maintainer (nabbisen). It is not triggered automatically by any feature or test passing.
Before v1.0.0, the project should have:
- stable core public API;
- clear dynamic on-ramp story;
- strong, scoped examples;
- reliable diagnostics;
- documented companion-crate boundary (RFC-022);
- clean feature matrix across all profiles;
- an RFC-067 family maturity table in the v1.0 release RFC if any lock-step
family crate remains
production-ready candidate.