You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The UFFS workspace is in excellent shape for crates.io publishing. The infrastructure built up through Phases R3 → R7 of docs/architecture/release-automation-plan.md covers nearly everything a maintainer would otherwise have to assemble by hand. This issue tracks the last small gaps before crates.io publish-day is a one-command operation.
(current workspace defaults are correct — keep inheriting)
(current workspace defaults are correct)
Requires mirroring the #238 readme-override pattern in scripts/ci/manifest-audit/src/audit.rs:
Add KnownExceptions::keywords_override_ok: BTreeSet<&'static str> and categories_override_ok: BTreeSet<&'static str>.
Suppress invariant 3.5 firing for listed crates that carry an explicit override.
Constrain to reasonable shape (≤ 5 keywords, each ≤ 20 chars; categories must match the crates.io taxonomy — cargo enforces this on publish too).
4-6 new unit tests covering: allow-listed crate suppresses finding, unlisted crate still fires, oversize / invalid keywords still fire even for listed crate, workspace inheritance passes for every member.
Apply per-crate keywords + categories on the 4 library crates that benefit (the table above).
Owner: 1 PR, ≈ 1 hour.
2. #![cfg_attr(docsrs, feature(doc_auto_cfg))] in publishable lib.rs files
The [package.metadata.docs.rs] block in each publishable manifest already passes --cfg docsrs to rustdoc. But the per-crate lib.rs files don't opt into the doc_auto_cfg nightly feature, so cfg-gated items (e.g. #[cfg(windows)], #[cfg(feature = "async")]) don't render with their cfg badge on docs.rs.
5 single-line edits (uffs-cli has no lib.rs):
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
Goes at the top of each:
crates/uffs-time/src/lib.rs
crates/uffs-text/src/lib.rs
crates/uffs-mft/src/lib.rs
crates/uffs-client/src/lib.rs
crates/uffs-mcp/src/lib.rs
The directive is gated behind cfg(docsrs) so local cargo doc (which doesn't pass --cfg docsrs) never exercises the nightly-only feature. Zero risk to local builds.
Owner: 1 PR, ≈10 min.
������ Nice-to-have (low priority, defer or skip)
3. examples/ directories for the library crates
uffs-time, uffs-text, uffs-client, uffs-mcp could each ship a runnable examples/*.rs file demonstrating the canonical use case. Not required by crates.io; high-signal for new visitors browsing the crate detail page. Defer until post-first-publish.
4. Workspace homepage field
Currently no homepage is set in [workspace.package]. Cargo uses repository as the fallback link on crates.io, which is fine. Add homepage = "https://uffs.dev" (or similar) if/when a project site exists.
������ Publish-day actions (gated on first publish or coordination, not actionable today)
These flips are deliberately deferred until the same coordinated PR that performs the first crates.io publish. Doing them earlier would either no-op (semver checks have no baseline) or fire false positives (dry-run gate fails on crate-name lookups that haven't happened yet).
5. Crate name reservation on crates.io (Phase R6 step 6)
Publish stub 0.0.0 versions of all 6 publishable crate names so a squatter can't register them before us. Requires CARGO_REGISTRY_TOKEN and maintainer go-ahead. Reference: docs/architecture/release-automation-plan.md §R6 step 6.
6. Flip FAIL_ON_DRY_RUN_ERROR='true' in crates-io-dry-run.yml
Currently advisory. Flip to hard-gate after R6 step 6 lands so that future regressions surface as a CI failure, not just a workflow-summary annotation.
7. Flip FAIL_ON_SEMVER_BREAK='true' in crates-io-dry-run.yml
Currently no-op (no crates have a baseline on crates.io). Flip to hard-gate after R8 dress rehearsal lands so semver-breaking changes shipped under a non-major bump fail CI.
8. Flip semver_check = true in release-plz.toml
release-plz.toml:302 has it off pending Phase R6/R8. Flip to on at first publish so release-plz’s own release-PR generation enforces semver compliance.
The two ready-today crates already carry publish = true (visible in their Cargo.toml). Workspace default stays publish = false until the staggered rollout finishes. No change needed today.
Sequencing
The two actionable PRs are independent and can land in any order:
PR-A: doc_auto_cfg directive on 5 lib.rs files — trivial, mechanical.
Publish-day actions (5-9) are explicitly out of scope for this issue. When the maintainer is ready for the coordinated publish, those flips happen in one focused PR alongside the actual cargo publish invocation.
PR-B merged: KnownExceptions::keywords_override_ok + categories_override_ok in scripts/ci/manifest-audit/src/audit.rs, per-crate overrides applied where they materially help discoverability (uffs-time, uffs-text, uffs-client, uffs-mcp).
After both PRs land: cargo publish --dry-run -p uffs-time -p uffs-text -p uffs-mft -p uffs-client -p uffs-mcp -p uffs-cli succeeds for every crate (today already true for the 2 polars-free ones).
After both PRs land: cargo run -p uffs-manifest-audit reports zero findings.
Documented in CHANGELOG.md under the next release entry.
Why this issue exists
The UFFS workspace is in excellent shape for crates.io publishing. The infrastructure built up through Phases R3 → R7 of
docs/architecture/release-automation-plan.mdcovers nearly everything a maintainer would otherwise have to assemble by hand. This issue tracks the last small gaps before crates.io publish-day is a one-command operation.State as of 2026-05-14 (after #236, #237, #238, #239 merged)
✅ Already done
docs/refactor/crates-io-publishability-deep-dive.md): 6 publishable crates (uffs-time,uffs-text,uffs-mft,uffs-client,uffs-mcp,uffs-cli), 2 deferred-decision crates (uffs-core,uffs-daemon), 6 never-publish.[package.metadata.docs.rs]blocks on all 6 publishable crates (Phase R6).[workspace.lints.rust] missing_docs = "deny"— everypubitem compiler-enforced to have a doc comment.crates-io-dry-run.ymlscheduled CI workflow — runscargo publish --dry-run -p <crate>ANDcargo semver-checks check-release -p <crate>weekly (Mondays 06:00 UTC) on every publishable crate. Last run: 2026-05-11, ✅ success.release_commitsfilter,git_only = truebaseline,release_always = falsegate, per-packagechangelog_pathfor the 2 ready-today crates,release = falsefor the polars-blocked + deferred crates.uffs-time+uffs-text: ✅ both succeed today (verified locally on 2026-05-14).������ Remaining gaps (genuine, actionable now, polars-independent)
1. Per-crate
keywords+categoriesoverride (allow-list mechanism + apply)Workspace-level defaults in root
Cargo.toml:These are correct for the app (
uffs-cli— the search engine binary) but wrong for library crates. Examples of better per-crate metadata:uffs-time["ntfs", "filetime", "datetime", "windows", "no-std"]["date-and-time"]uffs-text["unicode", "ntfs", "case-folding", "trigram", "i18n"]["text-processing"]uffs-mftuffs-client["ipc", "rpc", "client", "uffs", "search"]["api-bindings", "filesystem"]uffs-mcp["mcp", "ai", "model-context-protocol", "rmcp", "uffs"]["api-bindings", "command-line-utilities"]uffs-cliRequires mirroring the #238 readme-override pattern in
scripts/ci/manifest-audit/src/audit.rs:KnownExceptions::keywords_override_ok: BTreeSet<&'static str>andcategories_override_ok: BTreeSet<&'static str>.keywords+categorieson the 4 library crates that benefit (the table above).Owner: 1 PR, ≈ 1 hour.
2.
#![cfg_attr(docsrs, feature(doc_auto_cfg))]in publishable lib.rs filesThe
[package.metadata.docs.rs]block in each publishable manifest already passes--cfg docsrsto rustdoc. But the per-cratelib.rsfiles don't opt into thedoc_auto_cfgnightly feature, so cfg-gated items (e.g.#[cfg(windows)],#[cfg(feature = "async")]) don't render with their cfg badge on docs.rs.5 single-line edits (uffs-cli has no lib.rs):
#![cfg_attr(docsrs, feature(doc_auto_cfg))]Goes at the top of each:
crates/uffs-time/src/lib.rscrates/uffs-text/src/lib.rscrates/uffs-mft/src/lib.rscrates/uffs-client/src/lib.rscrates/uffs-mcp/src/lib.rsThe directive is gated behind
cfg(docsrs)so localcargo doc(which doesn't pass--cfg docsrs) never exercises the nightly-only feature. Zero risk to local builds.Owner: 1 PR, ≈10 min.
������ Nice-to-have (low priority, defer or skip)
3.
examples/directories for the library cratesuffs-time,uffs-text,uffs-client,uffs-mcpcould each ship a runnableexamples/*.rsfile demonstrating the canonical use case. Not required by crates.io; high-signal for new visitors browsing the crate detail page. Defer until post-first-publish.4. Workspace
homepagefieldCurrently no
homepageis set in[workspace.package]. Cargo usesrepositoryas the fallback link on crates.io, which is fine. Addhomepage = "https://uffs.dev"(or similar) if/when a project site exists.������ Publish-day actions (gated on first publish or coordination, not actionable today)
These flips are deliberately deferred until the same coordinated PR that performs the first crates.io publish. Doing them earlier would either no-op (semver checks have no baseline) or fire false positives (dry-run gate fails on crate-name lookups that haven't happened yet).
5. Crate name reservation on crates.io (Phase R6 step 6)
Publish stub
0.0.0versions of all 6 publishable crate names so a squatter can't register them before us. RequiresCARGO_REGISTRY_TOKENand maintainer go-ahead. Reference:docs/architecture/release-automation-plan.md§R6 step 6.6. Flip
FAIL_ON_DRY_RUN_ERROR='true'incrates-io-dry-run.ymlCurrently advisory. Flip to hard-gate after R6 step 6 lands so that future regressions surface as a CI failure, not just a workflow-summary annotation.
7. Flip
FAIL_ON_SEMVER_BREAK='true'incrates-io-dry-run.ymlCurrently no-op (no crates have a baseline on crates.io). Flip to hard-gate after R8 dress rehearsal lands so semver-breaking changes shipped under a non-major bump fail CI.
8. Flip
semver_check = trueinrelease-plz.tomlrelease-plz.toml:302has it off pending Phase R6/R8. Flip to on at first publish so release-plz’s own release-PR generation enforces semver compliance.9. Workspace
publish = falseper-package overrides foruffs-time+uffs-textThe two ready-today crates already carry
publish = true(visible in theirCargo.toml). Workspace default stayspublish = falseuntil the staggered rollout finishes. No change needed today.Sequencing
The two actionable PRs are independent and can land in any order:
doc_auto_cfgdirective on 5 lib.rs files — trivial, mechanical.Publish-day actions (5-9) are explicitly out of scope for this issue. When the maintainer is ready for the coordinated publish, those flips happen in one focused PR alongside the actual
cargo publishinvocation.Acceptance criteria
doc_auto_cfgdirective inuffs-time,uffs-text,uffs-mft,uffs-client,uffs-mcplib.rs files.KnownExceptions::keywords_override_ok+categories_override_okinscripts/ci/manifest-audit/src/audit.rs, per-crate overrides applied where they materially help discoverability (uffs-time,uffs-text,uffs-client,uffs-mcp).cargo publish --dry-run -p uffs-time -p uffs-text -p uffs-mft -p uffs-client -p uffs-mcp -p uffs-clisucceeds for every crate (today already true for the 2 polars-free ones).cargo run -p uffs-manifest-auditreports zero findings.CHANGELOG.mdunder the next release entry.Related
docs/architecture/release-automation-plan.md§R6–R9 — master plan covering the publish-day actions.