Repository navigation
Description
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.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.
State as of 2026-05-14 (after #236, #237, #238, #239 merged)
✅ Already done
- Strategic publish scrub (per
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. - Per-crate READMEs on all 6 publishable crates (docs(publish): add per-crate READMEs for uffs-time and uffs-text #237 + docs(publish): add per-crate READMEs for the 4 post-polars publishable crates #239).
- manifest-audit allow-list for per-crate readme override (feat(manifest-audit): permit per-crate readme override via allow-list (invariant 3.5) #238).
[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-plz.toml complete: workspace-style tags, workspace CHANGELOG,
release_commitsfilter,git_only = truebaseline,release_always = falsegate, per-packagechangelog_pathfor the 2 ready-today crates,release = falsefor the polars-blocked + deferred crates. - cargo publish --dry-run on
uffs-time+uffs-text: ✅ both succeed today (verified locally on 2026-05-14).
������ Remaining gaps (genuine, actionable now, polars-independent)
1. Per-crate keywords + categories override (allow-list mechanism + apply)
Workspace-level defaults in root Cargo.toml:
keywords = ["mft", "ntfs", "file-search", "windows", "polars"]
categories = ["filesystem", "command-line-utilities"]These are correct for the app (uffs-cli — the search engine binary) but wrong for library crates. Examples of better per-crate metadata:
| Crate | Suggested keywords | Suggested categories |
|---|---|---|
uffs-time |
["ntfs", "filetime", "datetime", "windows", "no-std"] |
["date-and-time"] |
uffs-text |
["unicode", "ntfs", "case-folding", "trigram", "i18n"] |
["text-processing"] |
uffs-mft |
(current workspace defaults are fine — keep inheriting) | (current workspace defaults are fine) |
uffs-client |
["ipc", "rpc", "client", "uffs", "search"] |
["api-bindings", "filesystem"] |
uffs-mcp |
["mcp", "ai", "model-context-protocol", "rmcp", "uffs"] |
["api-bindings", "command-line-utilities"] |
uffs-cli |
(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>andcategories_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+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 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.rscrates/uffs-text/src/lib.rscrates/uffs-mft/src/lib.rscrates/uffs-client/src/lib.rscrates/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.
9. Workspace publish = false per-package overrides for uffs-time + uffs-text
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_cfgdirective on 5 lib.rs files — trivial, mechanical. - PR-B: keywords + categories allow-list + apply — mirror of feat(manifest-audit): permit per-crate readme override via allow-list (invariant 3.5) #238 pattern.
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.
Acceptance criteria
- PR-A merged:
doc_auto_cfgdirective inuffs-time,uffs-text,uffs-mft,uffs-client,uffs-mcplib.rs files. - PR-B merged:
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). - 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-clisucceeds for every crate (today already true for the 2 polars-free ones). - After both PRs land:
cargo run -p uffs-manifest-auditreports zero findings. - Documented in
CHANGELOG.mdunder the next release entry.
Related
- Issue chore(publish): apply per-crate readme override on all 6 publishable crates (silence cargo package warning) #240 (per-crate readme override flip on 6 manifests) — has the same publish-day coordination shape and could fold into the publish-day PR.
- PR feat(manifest-audit): permit per-crate readme override via allow-list (invariant 3.5) #238 (readme override allow-list) — the exact pattern PR-B mirrors.
docs/architecture/release-automation-plan.md§R6–R9 — master plan covering the publish-day actions.
Activity
githubrobbi commentedon May 15, 2026
Update 2026-05-15: actionable-now backlog CLOSED
Both PR-A and PR-B (the two genuinely-actionable items beyond Polars) are now open with auto-merge enabled.
#![cfg_attr(docsrs, feature(doc_cfg))]directive on 5 publishable lib.rs filesuffs-time,uffs-text,uffs-client,uffs-mcp)Implementation footnotes worth recording
doc_auto_cfgis dead: it was merged intodoc_cfgin Rust 1.92 (rust-lang/rust#138907). The unifieddoc_cfgfeature preserves the automatic cfg-badge inference. Our pinned nightly (nightly-2026-05-14, rustc 1.97-nightly) errored out ondoc_auto_cfgwithE0557: feature has been removed. The umbrella issue body still referencesdoc_auto_cfgfor historical accuracy but the actual landed directive isfeature(doc_cfg).cargo publish --dry-run -p uffs-time --allow-dirtyand-p uffs-text --allow-dirtyboth passed locally with the new per-crate keywords + categories applied — crates.io's validator accepted every keyword (regex + length) and both category slugs (date-and-time,text-processing).keywordsandcategories. Empty arrays still fire — they're legal TOML but defeat the override's discoverability purpose.cargo publish --dry-runregression: the samecrates-io-dry-run.ymlweekly workflow that runs on Mondays at 06:00 UTC continues to enumerate exactly the same 2 ready-today crates (uffs-time,uffs-text) and will validate them with the new metadata next Monday. The 4 polars-blocked crates still skip the workflow via theirpublish = falseinheritance.Remaining work (publish-day only — not actionable today)
Per the original umbrella body §5–§9, all four remaining items are deliberately deferred to the same coordinated PR that performs the first crates.io publish:
CARGO_REGISTRY_TOKENand maintainer go-ahead.FAIL_ON_DRY_RUN_ERROR='true'in.github/workflows/crates-io-dry-run.yml.FAIL_ON_SEMVER_BREAK='true'in.github/workflows/crates-io-dry-run.yml.semver_check = trueinrelease-plz.toml.Plus #240 (per-crate readme override flip on 6 publishable manifests) — same publish-day cohort.
This issue stays open until those publish-day flips land in a single coordinated PR.
chore(publish-prep): opt the 5 publishable lib crates into docs.rs cf…
feat(manifest-audit): permit per-crate keywords/categories override v…
fix(ci): re-defer release-plz auto-trigger — cargo package bootstrap (#…
githubrobbi commentedon Jun 10, 2026
Status: all actionable items landed — closing
Acceptance criteria
#![cfg_attr(docsrs, feature(doc_auto_cfg))]present in all 5 lib.rs files (uffs-time,uffs-text,uffs-mft,uffs-client,uffs-mcp). Verified by grep.keywords_override_ok+categories_override_okallow-lists inscripts/ci/manifest-audit/src/audit.rswith shape constraints + tests; per-cratekeywords/categoriesapplied onuffs-time,uffs-text,uffs-client,uffs-mcpper the table.cargo run -p uffs-manifest-audit→ zero findings (verified 2026-06-10).cargo publish --dry-run→ ✅uffs-time, ✅uffs-text.cargo metadata --no-deps(authoritative — resolves workspace inheritance) shows the live publishable set is 2 crates, not 6:publishuffs-timeuffs-textuffs-mftfalseuffs-clientfalseuffs-mcpfalseuffs-clifalseThe 4 non-leaf crates depend on never-publish crates (
uffs-polars/uffs-security/uffs-format), so the acceptance line "dry-run succeeds for every crate (6)" is unachievable as written — by deliberate architecture decision, not a gap. Recorded inrelease-automation-plan.md§8.1 ("R8 prep" row, 2026-06-10; PRs #385/#386).Publish-day items (5–9) — explicitly out of scope here, now fully specified
cargo publish -p uffs-time→cargo publish -p uffs-text(both leaves; order interchangeable). Names verified available.CARGO_REGISTRY_TOKEN(crates.io Trusted Publishing is per-crate config requiring the crate to already exist). After bootstrap: configure trusted publishers, setvars.ENABLE_CRATES_IO_PUBLISHto activate the dormant R7 OIDC job, revoke the token.FAIL_ON_DRY_RUN_ERROR,FAIL_ON_SEMVER_BREAK,semver_check) happen in the same coordinated publish-day PR, per this issue's own sequencing section. Tracked by plan §R8/§R9.githubrobbi commentedon Jun 10, 2026
Both actionable PRs landed and verified; publish-day items are tracked by release-automation-plan.md §R8/§R9 + the §8.1 R8-prep deviation row.