build(release-automation): R6 publishability + R3.5 dep version requirements#145
Merged
githubrobbi merged 1 commit intomainfrom May 7, 2026
Merged
Conversation
…rements Bundles two phases of the release-automation plan into one PR per the routing decision recorded in release-automation-plan.md §8.1 deviations log. Phase R3.5 — internal dependency version requirements: After R3 landed, the shadow-mode workflow ran 12+ days with empty output. Root cause: 'release-plz update' invokes 'cargo package' per crate, and cargo refuses to package any crate whose [dependencies] entries lack a 'version =' requirement, even with 'path =' present. UFFS had 8 internal-dep aliases in [workspace.dependencies], 2 direct path-deps in uffs-cli/Cargo.toml, and the polars git pin all unversioned. Fix: - Add 'version = "0.5.90"' to every internal-dep alias in root Cargo.toml - Add 'version = "0.5.90"' to uffs-cli's direct uffs-client + uffs-format path deps - Add 'version = "0.53.0"' to the polars git dep in uffs-polars/Cargo.toml - Update 'just polars' to keep the polars version pin in lockstep with the rev across major-version bumps Verified locally: 'release-plz update --config release-plz.toml' now lists all 12 publishable crates without error. Phase R6 — crates.io metadata audit + dry-run CI: - Add [package.metadata.docs.rs] blocks to all 12 publishable crates with appropriate 'targets' / 'default-target' per platform surface - Add explicit 'publish = false' to crates/uffs-diag/Cargo.toml (workspace-only diagnostic crate per plan §R6 step 2) - Add per-package 'release = false' blocks for uffs-ci-pipeline, uffs-gen-hooks, uffs-gen-workflow in release-plz.toml - Add .github/workflows/crates-io-dry-run.yml — weekly + workflow_dispatch scheduled per-crate 'cargo publish --dry-run' with summary table; advisory mode (FAIL_ON_DRY_RUN_ERROR=false) until R6 step 6 (crate name reservations) and R8 (polars/chrono resolution) land - Add docs/publishing.md DORMANT runbook covering pre-publish checklist, per-release checklist, yank decisions log, manual fallback ordering, OIDC section placeholder for R7 Update release-automation-plan.md §8 dashboard: R3 → 🟢 (PR #67), new R3.5 row 🟡, R6 → 🟡. Add three §8.1 deviations log entries documenting the version-requirements fix, the crate-name-reservation deferral, and the known-expected polars/chrono publishability gap. Append §10 R3.5+R6 addendum to release-automation-baseline.md with the silent-failure root cause, the fix diff, validation evidence, and forward-compat assertion (release-plz handles workspace version sync natively post-R5). Deliberately deferred: - crate-name reservations on crates.io (plan §R6 step 6 — happens from a throwaway workspace, not this repo) - cargo-semver-checks integration (no published baseline yet) - OIDC trusted-publisher scaffolding (R7 scope) - workspace-level publish=false flip (R8 scope)
07b6bf5 to
9f23a5e
Compare
githubrobbi
added a commit
that referenced
this pull request
May 8, 2026
…e tags + CHANGELOG) (#148) Phase R4 of `docs/architecture/release-automation-plan.md`. Flips `.github/workflows/release-plz.yml` from R3 SHADOW mode (`release-plz update`, local-only) to ACTIVE mode (`release-plz/action@v0.5.128` with `command: release-pr` + `command: release` in two parallel jobs, mirroring release-plz's own recommended workflow shape). Settled-pre-execution decisions (recorded in plan §R4 + baseline §11): * D1. Workspace-style tags — single `v{{ version }}` per release (`git_tag_name = "v{{ version }}"`) instead of release-plz's default `{{ package }}-v{{ version }}` per-crate scheme. Honors UFFS as one product (12 publishable crates moving in lockstep, sharing `[workspace.package].version`) and keeps the existing `release.yml` `on: push: tags: [v*]` trigger working with zero migration. Same pattern as cargo and rustls workspaces; diverges from tokio. * D2. Workspace-style CHANGELOG — 12 per-package `[[package]]` blocks with `changelog_path = "CHANGELOG.md"` flatten the per-crate changelog into the workspace-root file. `changelog_path` cannot be set at workspace level (release-plz docs explicitly forbid it). * D3. `git_only = true` workspace baseline — UFFS is unpublished through R8, so the crates.io registry has no version data to diff against. release-plz uses git tags as the baseline instead. Forward- compat note for R8: `git_only = true` and `publish = true` are mutually exclusive, so R8 will flip this back when ≥1 crate goes live. * D4. `release_commits` regex filter — restricts release-PR triggers to `feat:` / `fix:` / `perf:` / `security:` commits, matching the set that `cliff.toml`'s `commit_parsers` maps to changelog sections. Without this, every `chore:` / `docs:` / `ci:` push would re-open the release PR with no-op churn. Single source of truth for the suppression list. * D5. Two-job workflow — `release-plz/action` does NOT have a single "do both" command. Per the release-plz repo's own workflow, R4 ships two parallel jobs: `release-plz-pr` (opens/updates PR) and `release-plz-release` (creates tag on release-PR merge, no-ops otherwise). * D6. Default `GITHUB_TOKEN`, NOT GitHub App / PAT — known limitation: tags created by release-plz via `GITHUB_TOKEN` do NOT trigger `release.yml` (per GitHub's anti-loop policy). Three workarounds documented in the workflow header (GitHub App = canonical; PAT = simpler; `release.yml workflow_run` trigger = third option). R4 ships with default token to minimize new infra; an "R4.5" follow-up PR sets up Option A. * D7. First-release v0.5.91 bootstrap — out of scope for this PR. The v0.5.90 worktree predates R3.5's dep-version fix (cccf4f1), so release-plz's `git_only` baseline check fails when comparing HEAD against v0.5.90 — surfaces as "no version bump proposed" in the first few R4 runs. Maintainer manually bumps `[workspace.package] .version` 0.5.90 → 0.5.91 + hand-writes the CHANGELOG entry + pushes the tag (user push triggers `release.yml` normally). After bootstrap, release-plz takes over. Publishing dormancy (UNCHANGED from R3 → R6, see plan §6): * `release-plz.toml` workspace `publish = false` (first layer). * No `CARGO_REGISTRY_TOKEN` env var passed to the action (second layer). Both stay through R7 (OIDC scaffolding) and only flip in R8 (publishing dress rehearsal for `uffs-time`). Files modified: * `release-plz.toml` (~220 LOC added) — `git_only`, `git_tag_name`, `git_release_name`, `release_commits`, 12 `[[package]]` blocks with `changelog_path = "CHANGELOG.md"`. Header comment block rewritten for R4 phase. R6 `release = false` blocks for internal tools preserved. * `.github/workflows/release-plz.yml` (rewritten) — two-job pattern (`release-plz-pr` + `release-plz-release`) using `release-plz/action@1528104d2ca23787631a1c1f022abb64b34c1e11` (v0.5.128, SHA-pinned per supply-chain hygiene). Permissions elevated `contents: read → write`, `pull-requests: read → write` at job level. Manual diff-capture and "verify no git mutation" guard (R3 shadow-only) removed. * `docs/architecture/release-automation-plan.md` (§R4 rewritten, dashboard updated) — captures D1-D7 above; R3.5 + R6 dashboard rows promoted 🟡 → 🟢 (PR #145 cccf4f1); R4 row 🟡 in-progress pointing at this PR; two new §8.1 deviations log entries (R4 baseline self-healing transient + R4 downstream-trigger GITHUB_TOKEN limitation). * `docs/architecture/release-automation-baseline.md` (§11 R4 addendum appended) — durable record of D1-D6 with rationale, ecosystem precedent, reversibility cost. Includes the maintainer bootstrap procedure for v0.5.91 as standalone steps. Validation: * `cargo check --workspace --all-targets`: pass. * `cargo fmt --check --all`: pass. * `taplo format --check release-plz.toml`: pass. * `actionlint .github/workflows/release-plz.yml`: pass. * `typos`, `reuse lint`: pass. * `just lint-pre-push`: 20/20 gates green (97s). Rollback: `git revert` flips the workflow back to R3 shadow mode. Any tags created by future release-plz active runs stay (idempotent). The `release-plz.toml` R4 additions are additive — revert independently. Refs: * Phase R4 plan: `docs/architecture/release-automation-plan.md` * Settled decisions: `docs/architecture/release-automation-baseline.md` §11 * release-plz reference workflow: https://github.com/release-plz/release-plz/blob/main/.github/workflows/release-plz.yml
githubrobbi
added a commit
that referenced
this pull request
May 8, 2026
… tag creation through release-plz-* PRs only (#151) Why --- The first R4 active-mode workflow run on PR #149's merge (run 25549828912) failed the `release-plz-release` job with: failed to create ref refs/tags/v0.5.91 with sha 113f188... Reference update failed (HTTP 422) Root cause: release-plz's default `release_always = true` makes the `release` job attempt a tag-creation on EVERY push to `main`, racing `auto-tag-release.yml` -> `release.yml` (the existing R3-era path still active until R5 retires the bespoke flow). On PR #149's merge: 1. release-plz fired and tried to recompute the CHANGELOG (the bespoke `update_all_versions.rs` rewrites `## [0.5.90]` -> `## [0.5.91]` in place rather than producing a cliff-style entry, leaving state inconsistent with what release-plz expects). 2. release-plz committed the recomputation locally (synthetic SHA `113f188...`) and tried to tag that SHA. 3. Meanwhile `release.yml` had already created the `v0.5.91` tag at the actual merge commit `5ff321b04`. 4. Two tag-creators racing for the same ref -> release-plz lost -> workflow turned RED. Fix --- Set `release_always = false` workspace-level in `release-plz.toml`. This makes `release-plz release` only fire when the latest commit on `main` is the merge of a PR whose branch starts with `pr_branch_prefix` (`release-plz-`). Coexistence semantics: * Bespoke `just ship` cycles use `release/vX.Y.Z` branch names -> NOT `release-plz-*` -> `release` job NO-OPS cleanly. `auto-tag-release.yml` + `release.yml` remain the sole tag-creator during the R4 -> R5 transition window. * release-plz-driven cycles use `release-plz-vX.Y.Z` branches -> matches the gate -> `release` job fires correctly. Steady-state (post-R5): bespoke flow deleted -> only the `release-plz-*` path remains -> `release_always = false` continues gating correctly without modification. This is the recommended setting for any project using PR-gated releases per release-plz docs: https://release-plz.ieni.dev/docs/config (search for `release_always`). Documentation ------------- Updates two rows in `docs/architecture/release-automation-plan.md` \u00a78.1 deviations log: * Corrects the existing "R4 baseline" row's misprediction ("silently treats as no-baseline" -> actual: HARD-FAIL with `cargo package failed`). Records the v0.5.91 bootstrap details (PR #149 squash-merged to `5ff321b04`; tag created by `auto-tag-release.yml` -> `release.yml`, NOT release-plz). * Adds a new "R4 release-job race" row capturing the symptom + root cause + this fix + the post-R5 forward-compat note. Verification ------------ * `taplo format --check release-plz.toml` -> ok. * `cargo fmt --check --all` -> ok. * `typos release-plz.toml docs/architecture/release-automation-plan.md` -> ok. * Manual cross-check vs release-plz docs: `release_always` field documented in https://release-plz.ieni.dev/docs/config under the `[workspace]` reference; `pr_branch_prefix` already set to `release-plz-` in our config (line 113). Related ------- * PR #148 (R4 active mode landed) * PR #149 (v0.5.91 bootstrap via bespoke flow) * PR #145 (R3.5 dep-version + R6 publishability) * docs/architecture/release-automation-plan.md \u00a78.1 (deviations log)
githubrobbi
added a commit
that referenced
this pull request
May 8, 2026
…153) Phase R5 of `docs/architecture/release-automation-plan.md`. Deletes the parallel `auto-tag-release.yml` + `update_all_versions.rs` + `version-bump` recipes track that has been driving releases since v0.4.x; release-plz (R4 active since 2026-05-08) is now the sole version-bump + tag creator. This is the point-of-no-return milestone for the release-automation initiative; the bespoke flow can no longer be the fallback on the next push to `main`. Removed (~1430 LOC): - `.github/workflows/auto-tag-release.yml` (168 LOC). - `build/update_all_versions.rs` (1073 LOC). - `scripts/ci/ci-pipeline.rs` (53 LOC) — Phase 7 deprecation shim; `REMOVE-AFTER: v0.5.73` marker satisfied at v0.5.92. - `increment_version` + `version_bump` fns in `scripts/ci-pipeline/src/version.rs`. - `STEP_VERSION_INCREMENT` from `ALL_STEPS` in `scripts/ci-pipeline/src/workflow.rs`. - Version-bump step from `run_enhanced_phase2` (ship.rs) and `phase2_optimized` (phases.rs). - `version-bump` recipe in `just/build.just`. - Version-bump step from `quick-deploy` recipe in `just/dev.just`. - `!build/update_all_versions.rs` carve-out in `.gitignore`. Added (~140 LOC, mostly comments + workflow YAML): - `detect-release-bump` short-circuit job in `.github/workflows/release-cache-warm.yml` — diffs `[workspace.package].version` between `HEAD` and `HEAD~1` and skips the warm matrix when the push is a version bump (saves ~165 runner-min/release because `release.yml` rebuilds + caches that same dep graph anyway). - Bridge step in `release-plz.yml`'s release job — `gh workflow run release.yml ...` after release-plz creates the workspace tag. Replaces the GITHUB_TOKEN anti-loop workaround that R4 deferred to a future GitHub App / PAT setup; uses `workflow_dispatch` (explicitly carved out of the anti-loop policy) instead. Flips `git_release_enable = false` in `release-plz.toml` so `release.yml` owns the GitHub Release page (avoids the body-overwrite race that softprops/action-gh-release would otherwise hit when run against a release-plz-created Release with `body_path: release-notes.md`). Doc updates: - `docs/architecture/release-automation-plan.md` — flip R5 row to 🟢, append four deviation log entries (v0.5.91 immutable-release lockout, R5-before-R4-bakein pragmatic acceleration, R5 cache-warm short-circuit, R5 downstream-trigger bridge resolves prior R4 deferred row). - `docs/architecture/dev-flow-implementation-plan.md` — tick the final Phase 7 bake-in checkbox (deprecation shim retired, `REMOVE-AFTER: v0.5.73` satisfied at v0.5.92). - `CONTRIBUTING.md` — rewrite the Release row in the four-layer quality-gates matrix to describe the post-R5 release-plz flow. - `docs/publishing.md` — flip R3.5 / R5 / R6 status rows to landed; R4 stays 🟡 (active, bake-in pending first release-plz-driven release). - `docs/architecture/security/supply-chain-posture.md` — replace `auto-tag-release.yml` reference with the post-R5 chain. - Trailing comments in `release-plz.toml`, `Cargo.toml`, `scripts/ci-pipeline/Cargo.toml`, `.gitignore`, and `scripts/ci-pipeline/src/{version,workflow,ship,phases}.rs` rewritten to describe the post-R5 steady state and explicitly note the R5 retirement of any pre-R5 tooling they referenced. Validation: - `cargo check --workspace --locked --all-targets` green. - `cargo clippy -p uffs-ci-pipeline --locked --all-targets -- -D warnings` green. - `cargo fmt --all` green. - `actionlint` on the two modified workflow YAML files green. - `just gates-drift` — manifest + consumers agree (23 gates). R4 bake-in completes naturally on the next `feat:` / `fix:` / `perf:` / `security:` commit to `main`, which release-plz will turn into the first end-to-end release-plz-driven release (v0.5.93). At that point the R4 row in the dashboard flips to 🟢 in a follow-up commit. Refs: #148 (R4 active-mode flip), #145 (R3.5 internal-dep version requirements + R6 metadata), #151 (`release_always = false` gate), #152 (v0.5.92 manual bootstrap after v0.5.91 immutable-release lockout).
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.
Summary
Bundles two phases of
docs/architecture/release-automation-plan.mdinto one PR per the routing decision recorded in §8.1 deviations log:version =requirements (silent shadow-mode failure unblocker)[package.metadata.docs.rs]+ dry-run CI workflow + DORMANT publishing runbookR3.5 — silent shadow-mode unblocker
R3 landed on 2026-04-25 (#67) and was expected to start producing per-merge
release-plz updatesummaries. Twelve days passed with empty summaries on every push.Root cause:
release-plz updateinvokescargo packageper crate, and cargo refuses to package any crate whose[dependencies]lack aversion =requirement, even withpath =present. UFFS had:[workspace.dependencies](path-only)crates/uffs-cli/Cargo.tomlcrates/uffs-polars/Cargo.toml…all unversioned. The failure was swallowed by the workflow's tee-to-log-file step + the empty-diff branch of the summary template, masking it from any reviewer who didn't expand the inner step log.
Fix
just polarsnow updates the polarsversion =field in lockstep with the resolved git rev, so future polars major-version bumps don't drift the version requirement.R3.5 verification
12 crates enumerated cleanly.
uffs-diagexcluded (per-cratepublish = false);uffs-ci-pipeline/uffs-gen-hooks/uffs-gen-workflowexcluded (per-packagerelease = falseblocks added in this PR).R6 — crates.io metadata audit
Per-crate
[package.metadata.docs.rs]Added to all 12 publishable crates with
targets/default-targetcalibrated per-crate:targetsuffs-time,uffs-text,uffs-format,uffs-polarsuffs-mft,uffs-core,uffs-daemon,uffs-client,uffs-cli,uffs-mcp["x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]uffs-securityuffs-brokerdefault-target = "x86_64-pc-windows-msvc"(whole crate is Windows-specific)Per-package
publish/releaseoverridescrates/uffs-diag/Cargo.toml— explicitpublish = false(workspace-only diagnostic crate per plan §R6 step 2)release-plz.toml—[[package]] release = falseforuffs-ci-pipeline,uffs-gen-hooks,uffs-gen-workflow(alreadypublish = falseat the crate level; this is the surgical fix to keep them out of release-plz's per-package iteration).github/workflows/crates-io-dry-run.ymlWeekly schedule (Mondays 06:00 UTC) +
workflow_dispatch. Loops every publishable crate, runscargo publish --dry-run -p <crate>, posts a per-crate status table to the workflow summary.Currently runs in ADVISORY mode (
FAIL_ON_DRY_RUN_ERROR=false) because two known-expected failure classes exist:no matching package named uffs-X founduntil 0.0.0 stub versions are reserved on crates.io from a throwaway external workspace.uffs-polarsand any crate transitively depending on it fails withfailed to select a version for chronobecause the published-formpolars = "0.53.0"resolution conflicts with the workspacechronopin. Resolution is R8 dress rehearsal scope.Flip
FAIL_ON_DRY_RUN_ERROR=trueonce both blockers are resolved.docs/publishing.md— DORMANT runbookCovers:
publish = falseworkspace + per-package +if: falsejob + missing token)Plan dashboard updates
docs/architecture/release-automation-plan.md§8 dashboard:§8.1 deviations log: 3 new entries
docs/architecture/release-automation-baseline.md§10 R3.5 + R6 addendum (113 lines): silent-failure root cause, fix diff, validation evidence, R6 deliverables breakdown, deliberately-NOT-doing list, forward-compat assertion.Deliberately deferred (not in this PR)
publish = truestate.cargo-semver-checksintegration — needs a published baseline; deferred until post-R8.publish = falseflip — R8 scope.FAIL_ON_DRY_RUN_ERROR=true— flipped once both blockers above are resolved.Validation
cargo check --workspace --all-targetspassescargo fmt --check --allpassestaplo formatclean (formatting normalized)actionlint .github/workflows/crates-io-dry-run.ymlpassestyposcleanrelease-plz update --config release-plz.tomllists 12 crates without errorFiles
.github/workflows/crates-io-dry-run.yml,docs/publishing.md)Plan refs
docs/architecture/release-automation-plan.md§R6 (steps 1–5; step 6 explicitly deferred)docs/architecture/release-automation-plan.md§8 dashboarddocs/architecture/release-automation-plan.md§8.1 deviations log (three new entries)docs/architecture/release-automation-baseline.md§10 (new addendum)