diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml index 362052341..9cf7cf234 100644 --- a/.github/workflows/release-plz.yml +++ b/.github/workflows/release-plz.yml @@ -2,17 +2,20 @@ # SPDX-License-Identifier: MPL-2.0 # ───────────────────────────────────────────────────────────────────────────── -# Release-plz — DEFERRED (manual-only, 2026-05-08) +# Release-plz — ACTIVE (registry-baseline mode, re-enabled 2026-06-10) # -# Phase R4 of `docs/architecture/release-automation-plan.md`, currently -# dormant pending an upstream-polars compat release. See the DEFERRAL -# NOTICE below for the full root-cause and re-enable trail. +# Phase R4 of `docs/architecture/release-automation-plan.md`. Runs on +# every push to `main`. The DEFERRAL NOTICE below (2026-05-08, +# polars/chrono) is HISTORICAL: that root cause and its successor +# (git-only worktree packaging, 2026-06-09) are both resolved — see the +# trigger comment above the `on:` block for the resolution trail. # # ─── DEFERRAL NOTICE (2026-05-08) ─────────────────────────────────────── # -# The `push: branches: [main]` auto-trigger is commented out below. The -# workflow runs ONLY on `workflow_dispatch` (manual `gh workflow run` -# from the maintainer). Reason: +# HISTORICAL — resolved 2026-06-10 (see "Re-enable checklist" below). +# At the time, the push auto-trigger was commented out and the workflow +# ran ONLY on `workflow_dispatch` (manual `gh workflow run` from the +# maintainer). Reason: # # release-plz `git_only = true` mode hardcodes # cargo package --allow-dirty --workspace @@ -68,7 +71,15 @@ # 4. once merged, the maintainer pushes a signed `vX.Y.Z` tag # which fires `release.yml` to build + upload binaries. # -# Re-enable when the chrono conflict goes away: +# Re-enable checklist (SUPERSEDED 2026-06-10): the chrono conflict was +# resolved by polars 0.54.4 on crates.io, but the 2026-06-09 re-activation +# then failed one layer deeper — git-only mode's hardcoded worktree +# `cargo package --workspace` (see the trigger comment above `on:`). +# The terminal fix took a different route than the items below: +# `git_only = false` in `release-plz.toml` (registry-baseline mode, +# unlocked by the R8 bootstrap publish of uffs-time + uffs-text +# v0.5.120) skips that packaging step entirely. Items kept for +# historical context: # # 1. Verify `cargo package -p uffs-polars --allow-dirty` succeeds # locally (it should once polars upstream ships). @@ -216,45 +227,37 @@ # • https://release-plz.ieni.dev/docs/usage/release # • https://github.com/release-plz/release-plz/blob/main/.github/workflows/release-plz.yml -name: "🚀 Release-plz (manual-only — re-deferred pending crates.io bootstrap)" +name: "🚀 Release-plz" on: - # ─── RE-DEFERRED 2026-06-09 (auto-trigger disabled) ────────────────── - # The 2026-06-09 activation (push: branches: [main]) was PREMATURE. - # Polars 0.54.4 on crates.io resolved the chrono conflict that was the - # FIRST blocker — but it was necessary, not sufficient. release-plz's - # git_only mode hardcodes `cargo package --allow-dirty --workspace` - # (see the DEFERRAL NOTICE above), and that step still fails one layer - # later on the crates.io BOOTSTRAP problem: + # ─── RE-ENABLED 2026-06-10 (post-R8 registry-baseline flip) ────────── + # History of this trigger: # - # cargo package failed: no matching package named `uffs-broker-protocol` - # found, location searched: crates.io index, required by `uffs-broker` + # • 2026-06-09: activated prematurely. Polars 0.54.4 resolved the + # chrono conflict (first blocker) but release-plz's git_only mode + # hardcodes `cargo package --allow-dirty --workspace` in the + # latest-tag worktree, which fails on the never-publish crates' + # versioned internal deps (uffs-broker -> uffs-broker-protocol: + # "no matching package found, location searched: crates.io + # index"). NOT fixable by `release = false` / `publish = false` + # config (both ignored by that hardcoded step, confirmed on CLI + # 0.3.158 run #79 AND re-confirmed locally on 0.3.157, + # 2026-06-10) — never-publish crates will NEVER resolve from the + # registry, so git-only mode can never work here. Trigger was + # commented out after 4 consecutive failures. # - # `cargo package` verifies each crate's *versioned* internal deps - # against crates.io. Nothing is published yet, so every member that - # carries an internal `uffs-*` dep fails (uffs-broker -> uffs-broker- - # protocol; uffs-diag -> uffs-mft + uffs-polars; the publishable - # uffs-mft/-client/-mcp/-cli -> uffs-polars/-security/-format; etc.). - # Only `uffs-time` + `uffs-text` (zero internal deps) package cleanly. - # - # This is NOT fixable by `release = false` / `publish = false` config - # (both are ignored by the hardcoded `cargo package --workspace` step, - # confirmed on release-plz CLI 0.3.158, run #79) nor by the nightly - # `-Zpackage-workspace` flag (which explicitly excludes `publish = - # false` crates — exactly our never-publish set). The workspace has - # never-publish crates with versioned internal deps (uffs-broker -> - # uffs-broker-protocol) that will NEVER be on crates.io, so the - # hardcoded `--workspace` package step can never fully succeed. - # - # Re-enable the push trigger ONLY after the crates.io bootstrap is - # complete (the dependency graph's internal crates are published, so - # `cargo package --workspace` resolves every versioned dep). Until - # then this workflow is workflow_dispatch-only and the first publish - # is driven per-crate (`cargo publish -p `), NOT via release-plz - # release-pr. See issue #241 (publish-day umbrella). - # - # push: - # branches: [main] + # • 2026-06-10: R8 bootstrap published uffs-time + uffs-text + # v0.5.120 to crates.io, unlocking the registry-baseline mode + # that `release-plz.toml`'s git_only comment block always planned + # to flip to post-R8. `git_only = false` makes release-plz diff + # local packages against the DOWNLOADED .crate files instead of + # packaging the tag worktree — the broken `cargo package + # --workspace` step is never invoked. Verified locally: + # `release-plz update` downloads uffs-text 0.5.120 as baseline, + # exits 0, proposes bumps only when the published crates' files + # change. See issue #241 (publish-day umbrella). + push: + branches: [main] workflow_dispatch: # Default to ZERO permissions; each job grants only what it needs. diff --git a/docs/architecture/release-automation-plan.md b/docs/architecture/release-automation-plan.md index fd32137e0..0055785db 100644 --- a/docs/architecture/release-automation-plan.md +++ b/docs/architecture/release-automation-plan.md @@ -2052,7 +2052,7 @@ Single source of truth for phase progress. Mirror the format of | R2 | `git-cliff` + `cliff.toml` (local validation) | 🟢 | `d49a778d6` | 2026-04-25 | [#66](https://github.com/skyllc-ai/UltraFastFileSearch/pull/66) | Final landed PR shape: 3 files (1 new, 2 modified), +495 / −3 LOC. `cliff.toml` template iterated against full history until output matches Keep-a-Changelog spacing; type → section mapping mirrors `commitlint.yml` regex (11 types). Validation captured in `release-automation-baseline.md` §8. Two iteration issues caught + fixed during template tuning (extra blank line after `## [version]`, duplicate `(#NN)` PR links). | | R3 | release-plz shadow mode | 🟢 | `1b0aa55b7` | 2026-04-25 | [#67](https://github.com/skyllc-ai/UltraFastFileSearch/pull/67) | Final landed PR shape: 2 files (1 new workflow, 1 new release-plz.toml) + ~370 LOC. Workflow runs `release-plz update` (local-only by design) on every `push: main` and posts the proposed diff to the workflow summary. Three layers of dormancy: `publish = false` in config, missing `CARGO_REGISTRY_TOKEN`, read-only workflow permissions. **Post-merge observation** revealed shadow output stayed empty across ≥12 days because `release-plz update` failed silently inside the workflow on `cargo package`'s "dependency `uffs-X` does not specify a version" error — fixed in R3.5 below by adding `version = ` requirements to internal `[workspace.dependencies]` entries. | | R3.5 | Internal-dep `version = ` requirements + polars git-pin version annotation | 🟢 | `cccf4f111` | 2026-05-07 | [#145](https://github.com/skyllc-ai/UltraFastFileSearch/pull/145) | Bundled into the R6 PR (see §8.1 deviations log first row). Adds `version = "0.5.90"` to all 8 internal workspace.dependencies, to the 2 direct path-deps in `uffs-cli/Cargo.toml`, and `version = "0.53.0"` to the polars git dep. Updates `just polars` to keep the polars version pin in lockstep with the resolved git rev. Without these, every `cargo package` invocation (release-plz `update` and any future `release-pr`) fails with "dependency `` does not specify a version". Verified locally: `release-plz update --config release-plz.toml` now lists all 12 publishable crates without error. | -| R4 | release-plz active (release PR mode) | 🟢 | `HEAD` | 2026-06-09 | (this PR) | Push trigger re-enabled after Polars 0.54.4 resolved the chrono conflict. Workflow now auto-triggers on every push to main, analyzes conventional commits, and opens release PRs when feat/fix/perf/security changes land. Added workflow_dispatch bridge to release.yml to handle GitHub's anti-loop policy (GITHUB_TOKEN-created tags don't trigger downstream workflows). First release through new flow will satisfy exit criterion. | +| R4 | release-plz active (release PR mode) | 🟢 | `HEAD` | 2026-06-10 | (this PR) | Push trigger re-enabled after Polars 0.54.4 resolved the chrono conflict. Workflow now auto-triggers on every push to main, analyzes conventional commits, and opens release PRs when feat/fix/perf changes land. Added workflow_dispatch bridge to release.yml to handle GitHub's anti-loop policy (GITHUB_TOKEN-created tags don't trigger downstream workflows). **2026-06-10 correction**: the 2026-06-09 re-enable failed 4 straight runs on git-only mode's worktree `cargo package --workspace` and was silently re-deferred the same day; the actual terminal fix is the `git_only = false` registry-baseline flip (see the §8.1 "R4 git-only baseline dead end" row), after which the trigger was re-enabled for real. First release through the new flow will satisfy the exit criterion. | | R5 | Retire bespoke tooling (incl. `scripts/ci/ci-pipeline.rs` thin wrapper per its `REMOVE-AFTER: v0.5.73` marker) | 🟢 | `HEAD` | 2026-06-09 | (this PR) | Re-applied now that Polars 0.54.4 on crates.io resolves the publishability blocker. Deleted: `build/update_all_versions.rs`, `scripts/ci/ci-pipeline.rs`, `.github/workflows/auto-tag-release.yml`, version-bump functions from `version.rs`, `STEP_VERSION_INCREMENT` from workflow. Updated: `justfile` recipes, `.gitignore` restored to blanket `build/`. Version bumps now handled entirely by release-plz when conventional commits land on `main`. | | R6 | crates.io metadata audit + dry-run CI | 🟢 | `cccf4f111` | 2026-05-07 | [#145](https://github.com/skyllc-ai/UltraFastFileSearch/pull/145) | Adds: `[package.metadata.docs.rs]` to all 12 publishable crates with appropriate `targets`/`default-target` per crate's platform surface; explicit `publish = false` to `crates/uffs-diag/Cargo.toml`; per-package `release = false` blocks for the 3 internal CI tools in `release-plz.toml`; `.github/workflows/crates-io-dry-run.yml` (advisory weekly + workflow_dispatch); `docs/publishing.md` DORMANT runbook. R6 step 6 (crate name reservations on crates.io) is intentionally **deferred** — those happen from a throwaway external workspace per plan §R6 step 6, not from this repo. | | R7 | OIDC trusted publisher (dormant, now wired) | 🟡 | `HEAD` | 2026-06-10 | (this PR) | Scaffolding complete **and publish steps now wired** (post-R8-bootstrap). Added `crates-io-publish` job with OIDC token permissions and environment protection. Originally gated `if: false`; replaced with a repo-variable gate (`if: vars.ENABLE_CRATES_IO_PUBLISH == 'true'`) after actionlint flagged the constant-false expression. The placeholder publish step is replaced by a real `rust-lang/crates-io-auth-action@v1.0.4` (pinned SHA `bbd81622…`) token mint + a dependency-ordered `cargo publish` loop over `cargo metadata` publishable crates (today: `uffs-time`, `uffs-text`). Still DORMANT: job only runs once the maintainer (1) registers trusted publishers on crates.io with environment `crates.io-publish`, (2) creates that GitHub Environment with required reviewers, and (3) sets `ENABLE_CRATES_IO_PUBLISH = true`. Flips to 🟢 on first OIDC-driven publish (R9). | @@ -2085,6 +2085,7 @@ Mirror the format of | R6 → R8 publishability resolution (crates.io polars 0.54) | 2026-06-09 | Final resolution of the `R6 → R8 publishability` / `…resolution (Path A)` rows. Polars published `0.54.4` to crates.io (edition 2024, 2026-06-04) carrying the nightly-`std::simd` / `core::unicode` patches that the abandoned Path B-i probe found missing in published `0.53.0`, and its `polars-arrow` now accepts modern `chrono` (workspace resolves `chrono 0.4.45`). Dropped the `git`+`rev` pin in `crates/uffs-polars/Cargo.toml` → plain `polars = "0.54.4"` from crates.io. Handled the 0.54 breaking changes: feature `new_streaming` → `streaming`; `LazyFrame::with_new_streaming` → `with_streaming`; `&ChunkedArray` no longer implements `IntoIterator` (replaced `.into_iter()` with `.iter()` at ~25 call sites in `uffs-core`/`uffs-diag`). Retired the track-upstream-main machinery: `update_polars_git()` + `STEP_UPDATE_POLARS` (`scripts/ci-pipeline`), the `just polars` HEAD-bump recipe (now a crates.io SemVer bump), and the `pola-rs/polars` `deny.toml` `allow-git` entry (zero git sources remain). `cargo check --workspace --all-targets` + `cargo clippy --workspace --all-targets` both clean. | The original blocker was the git-rev / published-version skew on `0.53.0` (git `polars-arrow` wanted `chrono ^0.4.42`, registry wanted `<=0.4.41`; and registry `0.53.0` was un-buildable on current nightly). A published `0.54.x` that both builds on nightly and accepts modern chrono removes the need for any git source, collapsing the divergence to zero. | `uffs-polars` now packages as a plain registry dependency, so `cargo package -p uffs-polars` is no longer blocked by the chrono clash. **Unblocks R5/R6/R8**: release-plz reactivation + the crates.io dry-run / `uffs-time` dress rehearsal can proceed without the polars publishability caveat. No release-workflow flips made in this change — gate-lift recorded here for the next release-automation pass. | | R5 re-application (post-Polars) | 2026-06-09 | R5 originally landed via PR #153 on 2026-05-08 but was rolled back same-day when the chrono conflict in `cargo package --workspace` forced release-plz deferral to `workflow_dispatch`-only (PR #157). With Polars 0.54.4 now on crates.io (see prior row), the publishability blocker is resolved and R5 can safely re-land. | The Polars git-rev / crates.io skew was the only remaining blocker preventing `cargo package` from succeeding. Once Polars 0.54.4 arrived with nightly-compatible code and modern chrono support, the path to R5 was cleared. | Re-applied R5: deleted `build/update_all_versions.rs`, `.github/workflows/auto-tag-release.yml`, `scripts/ci/ci-pipeline.rs`, version-bump functions from `version.rs`, and `STEP_VERSION_INCREMENT`. Updated justfile recipes and `.gitignore`. Dashboard R5 flips from 🔴 ROLLBACK to 🟢. | R5 now 🟢. Bespoke version tooling is retired; release-plz owns all version bumps. This is the final state — no further rollback expected. | | R8 OIDC wire-up + env-name doc fix | 2026-06-10 | After the R8 bootstrap published `uffs-time` + `uffs-text` v0.5.120 by hand (token), the dormant `crates-io-publish` job in `release-plz.yml` still carried a commented-out placeholder publish step, and §R7/§5.6 of this plan named the OIDC environment `crates-io-production` while the live workflow uses `environment: crates.io-publish` — a mismatch that would have caused trusted-publisher registration to silently fail (crates.io requires the registered environment name to match the workflow's `environment:` value exactly). | (1) Bootstrap publish had to come first (chicken-and-egg: trusted publishers can only be registered on crates that already exist), so the publish step was deliberately left dormant through R7 and only wired after R8. (2) The `crates-io-production` name was an early-draft placeholder in the plan that was never reconciled against the workflow when the job was scaffolded in R7. | Replaced the placeholder with a real publish path: `rust-lang/crates-io-auth-action@bbd81622…` (v1.0.4, SHA-pinned) mints a short-lived OIDC token, then a `cargo metadata`-derived, dependency-ordered `cargo publish --locked` loop publishes the publishable set (today `uffs-time`, `uffs-text`). Job stays dormant behind the `ENABLE_CRATES_IO_PUBLISH` repo-variable gate + the `crates.io-publish` environment (required reviewers). Renamed all `crates-io-production` → `crates.io-publish` across §R7, §5.6, §5.7 checklist, §R9, and the risk table so the doc matches the workflow exactly. | Unblocks the R9 cutover: the maintainer now only needs to register trusted publishers (env `crates.io-publish`), create the GitHub Environment with reviewers, set the repo variable, and revoke the bootstrap token — no further workflow edits required. R7 advances to "wired"; R8 marked 🟢 (bootstrap done). | +| R4 git-only baseline dead end → registry-baseline flip | 2026-06-10 | The 2026-06-09 R4 re-activation failed 4 consecutive push runs (last: run [27242337110](https://github.com/skyllc-ai/UltraFastFileSearch/actions/runs/27242337110)) with `failed to determine next versions → run cargo package → no matching package named uffs-broker-protocol found, location searched: crates.io index`; the push trigger was re-commented out (workflow_dispatch-only), so the #387/#388 merges to `main` triggered nothing — discovered when the expected post-R9-arming release PR never appeared. | In `git_only = true` mode release-plz hardcodes `cargo package --allow-dirty --workspace` inside the latest-tag worktree, packaging ALL members regardless of `release = false` config (confirmed CLI 0.3.158 run #79; re-confirmed locally 0.3.157 with `RUST_LOG=debug`). Never-publish crates with versioned internal deps (`uffs-broker` → `uffs-broker-protocol`) can never resolve from the crates.io index; dropping the `version =` instead fails `cargo package` with "all dependencies must have a version requirement" (both directions tested locally) — git-only mode is structurally incompatible with this workspace, and the workflow header's old "re-enable after bootstrap publishes the internal crates" condition was unsatisfiable (those crates are never-publish by design). | Flipped `git_only = false` in `release-plz.toml` — the registry-baseline mode its own R4 comment block planned for post-R8. With `uffs-time`/`uffs-text` v0.5.120 live on crates.io (R8 bootstrap), release-plz downloads the published `.crate` files as baseline and never invokes the worktree packaging step. Verified locally: `release-plz update` downloads uffs-text 0.5.120, exits 0, proposes bumps only when the published crates' files change. Push trigger re-enabled in the same PR; both deferral notices in the workflow header rewritten as historical records. | R4's auto-trigger is genuinely live for the first time. The R4 dashboard row's 2026-06-09 note ("push trigger re-enabled") was true for ~hours then silently regressed — corrected by this row per append-only discipline. First release-plz release PR (→ first OIDC publish, R9) now fires on the next `feat:`/`fix:`/`perf:` commit touching `crates/uffs-time` or `crates/uffs-text` files. | | R8 prep — publishable set narrowed (12 → 2) + credential path | 2026-06-10 | Pre-publish audit for R8 found the "12/13 publishable crates" figure used throughout this plan and `release-automation-baseline.md` (R0/R3.5/R6 entries) is no longer the live state. `cargo metadata --no-deps` (authoritative, resolves workspace inheritance) shows exactly **2** members with `publish = ANY`: `uffs-time` and `uffs-text`. All 17 others resolve to `publish = []` (false) — `uffs-broker`, `uffs-broker-protocol`, and `uffs-security` were flipped back to `publish.workspace = true` (= false) during the publishability deep-dive (name-squat reservations / internal-only; see `docs/refactor/crates-io-publishability-deep-dive.md` §7.3–7.5), and the root-manifest comment lagged behind (corrected in PR [#385](https://github.com/skyllc-ai/UltraFastFileSearch/pull/385)). | The strategic publish scrub happened incrementally across the deep-dive without a single "recount" pass; historical plan/baseline entries are point-in-time records and stay unedited per append-only discipline — this row is the correction of record. | **Publish sequence for R8/R9 (dependency-ordered):** both publishable crates are dependency-free leaves with zero internal deps, so the bootstrap is simply (1) `cargo publish -p uffs-time`, (2) `cargo publish -p uffs-text` (order interchangeable); dry-runs verified green for both, names available on crates.io. No other crate can join the set without first flipping its never-publish internal deps (`uffs-polars`/`uffs-security`/`uffs-format` → blocking `uffs-mft` → blocking `uffs-client`/`uffs-mcp`/`uffs-cli`) — a deliberate architecture decision, not a gap. **Credential path:** crates.io Trusted Publishing is configured per-crate in the crate's settings page and therefore requires the crate to already exist — no pending-publisher flow exists — so the **first** publish of each crate must use a maintainer `CARGO_REGISTRY_TOKEN` (manual `cargo publish` or repo secret); after bootstrap, configure the trusted publisher for both crates and flip the dormant R7 OIDC job (`vars.ENABLE_CRATES_IO_PUBLISH`), then revoke the token. | R8's dress-rehearsal target (`uffs-time` only) is unchanged and now fully unblocked. R9 "full workspace" should be re-read as "the publishable set" (currently 2 crates). | ## 9. Cross-references diff --git a/release-plz.toml b/release-plz.toml index 1a24f8e73..a576ffb0a 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -76,22 +76,29 @@ # WARN Package `uffs-security@*.*.*` not found # ... (12 crates, all "not found") # -# `git_only = true` flips release-plz into a tag-based baseline mode: it -# scans `git tag` output for tags matching `git_tag_name` (set below to -# `v{{ version }}` to match the existing UFFS tag scheme), picks the -# latest semver-ordered tag, checks out that tag's worktree, and uses its -# Cargo.toml + file content as the baseline. Required while crates.io is -# empty. -# -# Forward-compat note for R8: -# -# When R8 publishes the first crate to crates.io, `git_only = true` and -# `publish = true` cannot both be true on the same package — release-plz -# refuses that combination by design (see release-plz docs §git_only). -# The R8 PR will either (a) flip `git_only = false` workspace-wide once -# ≥1 crate is published, or (b) carry per-package `git_only` overrides -# for the remaining unpublished crates during the staggered rollout. -git_only = true +# HISTORY — `git_only = true` (R4, 2026-04-25 → 2026-06-10): tag-based +# baseline mode. release-plz scanned `git tag` for `v*`, checked out the +# latest tag's worktree, and used its content as the baseline. Required +# while crates.io was empty — but it carried a fatal side effect found in +# the 2026-06-09 active runs (run #79 + 3 retries): git-only mode +# hardcodes `cargo package --allow-dirty --workspace` inside that +# worktree, packaging ALL members regardless of the `release = false` +# blocks below. Never-publish crates with versioned internal deps +# (`uffs-broker` → `uffs-broker-protocol`) can never resolve from the +# crates.io index, so the step can never succeed — catch-22 confirmed +# locally (versioned dep → "no matching package found"; versionless → +# "all dependencies must have a version requirement"). +# +# CURRENT — `git_only = false` (post-R8, 2026-06-10): registry baseline. +# The R8 bootstrap published `uffs-time` + `uffs-text` v0.5.120, so +# release-plz now downloads the published .crate files and diffs local +# packages against them — exactly the forward-compat flip the R4 note +# here always planned. The broken worktree `cargo package --workspace` +# step is never invoked in this mode (verified locally on 0.3.157: +# update downloads uffs-text 0.5.120, exits 0, proposes bumps only when +# the published crates' files change). The 15 non-published members +# stay out of scope via their `release = false` blocks below. +git_only = false # ───────────────────────────────────────────────────────────────────────────── # Tag & GitHub Release naming (R4 — workspace style)