From 60176e7c2e2a135217abdcc7dbe976374332712d Mon Sep 17 00:00:00 2001 From: rob thijssen Date: Tue, 19 May 2026 13:36:53 +0300 Subject: [PATCH] ci: monotonic prerelease versions + serialize CI on shared runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two CI hygiene fixes uncovered while validating against the live fleet. 1. Same-day prerelease packages were being ordered by RPM-vercmp's alpha-vs-digit precedence on the git SHA fragment, not by commit chronology. With release stamps like "0.1.${YYYYMMDD}git${SHA}", two commits on the same day produce the same numeric prefix and rpmvercmp falls back to comparing the alphanumeric SHA suffixes, where digit-leading SHAs are ranked above alpha-leading ones — completely unrelated to which commit landed first. Verified with rpmdev-vercmp: gitabc1234 < gitdef5678 (old scheme — purely lexicographic) Bumping the timestamp prefix to second-precision (%Y%m%d%H%M%S) makes the numeric prefix strictly monotonic for any chronologically- ordered commits, so the SHA fragment becomes a debug identifier only — never participates in version ordering. 2. ci.yml and build-prerelease.yml both target the `rust` runner label and both auto-trigger on push to main. The act-based runner reuses /root/.cache/act//hostexecutor/ across concurrent jobs, so ci.yml's clippy and build-prerelease.yml's build-cortex were racing each other's checkout/cleanup steps and corrupting in-flight compile artifacts. Real fix is in gongfoo; workflow-level workaround is a shared concurrency group with cancel-in-progress=false so the two workflows queue sequentially on the same ref. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/build-prerelease.yml | 38 +++++++++++++++++++-------- .gitea/workflows/ci.yml | 10 +++++++ rpm/cortex-prerelease.spec | 6 ++++- rpm/helexa-neuron-prerelease.spec | 6 ++++- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/.gitea/workflows/build-prerelease.yml b/.gitea/workflows/build-prerelease.yml index 422e8c1..0f4871d 100644 --- a/.gitea/workflows/build-prerelease.yml +++ b/.gitea/workflows/build-prerelease.yml @@ -8,8 +8,13 @@ name: build-prerelease # Optionally provide a `ref` to build from a non-default branch. # # The published packages are versioned as e.g. -# helexa-neuron-blackwell-0.1.16-0.1.20260518gitabcdef0.fc43.x86_64 -# so they sort BELOW the eventual 0.1.16-1 stable release. +# helexa-neuron-blackwell-0.1.16-0.1.20260518T140530.gitabcdef0.fc43.x86_64 +# ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ +# commit time (s) commit sha +# so they sort BELOW the eventual 0.1.16-1 stable release, and so two +# commits on the same day are still strictly ordered by their commit +# timestamps (rather than by RPM-vercmp's alpha-vs-digit precedence +# on the SHA fragment). on: # Auto-build on every push to main so the unstable channel tracks @@ -25,10 +30,14 @@ on: default: "" concurrency: - # Coalesce on branch+event so successive pushes don't pile up; the - # latest push wins. - group: prerelease-build-${{ github.ref }} - cancel-in-progress: true + # Share the group with ci.yml so the two workflows can't run + # concurrently on the same `rust` runner (act reuses the workspace + # cache and races destroy each other's build files mid-compile). + # cancel-in-progress=false → workflows queue; if a newer push lands, + # the older run is still picked up by ci.yml's own ref-keyed + # concurrency (same group, queued). + group: cortex-runner-pool-${{ github.ref }} + cancel-in-progress: false env: CARGO_INCREMENTAL: "0" @@ -41,7 +50,7 @@ jobs: version: ${{ steps.info.outputs.version }} release: ${{ steps.info.outputs.release }} short_sha: ${{ steps.info.outputs.short_sha }} - commit_date: ${{ steps.info.outputs.commit_date }} + commit_timestamp: ${{ steps.info.outputs.commit_timestamp }} steps: - uses: actions/checkout@v4 with: @@ -53,13 +62,20 @@ jobs: set -eux VERSION=$(awk -F\" '/^version[[:space:]]*=/ { print $2; exit }' Cargo.toml) SHORT_SHA=$(git rev-parse --short=7 HEAD) - COMMIT_DATE=$(git log -1 --format=%cd --date=format:%Y%m%d HEAD) - # Prerelease release stamp sorts before "1" (the stable release). - RELEASE="0.1.${COMMIT_DATE}git${SHORT_SHA}" + # Second-precise commit timestamp gives the release stamp a + # strictly monotonic numeric prefix. The earlier %Y%m%d-only + # form let same-day builds be ordered by RPM's rpmvercmp + # rules over the SHA, which is non-chronological — e.g. + # "git602e8e1" sorts newer than "gitf9f5fa4" purely because + # rpmvercmp ranks digit-prefixed segments above alpha ones. + # The SHA stays only as a debug identifier; sort order is + # decided entirely by the timestamp. + COMMIT_TIMESTAMP=$(git log -1 --format=%cd --date=format:%Y%m%d%H%M%S HEAD) + RELEASE="0.1.${COMMIT_TIMESTAMP}.git${SHORT_SHA}" echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "release=${RELEASE}" >> "$GITHUB_OUTPUT" echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT" - echo "commit_date=${COMMIT_DATE}" >> "$GITHUB_OUTPUT" + echo "commit_timestamp=${COMMIT_TIMESTAMP}" >> "$GITHUB_OUTPUT" build-cortex: name: Build cortex binary diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 5917fce..35670db 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -7,6 +7,16 @@ on: pull_request: branches: [main] +# Share a concurrency group with build-prerelease.yml so the two +# workflows don't race on the same `rust` runner workspace (act's +# /root/.cache/act//hostexecutor/ is shared across concurrent +# jobs and one job's checkout step nukes another's in-flight build +# files). cancel-in-progress=false → they queue; same-ref pushes +# coalesce per workflow via cancel-in-progress on each. +concurrency: + group: cortex-runner-pool-${{ github.ref }} + cancel-in-progress: false + env: CARGO_INCREMENTAL: "0" RUSTC_WRAPPER: sccache diff --git a/rpm/cortex-prerelease.spec b/rpm/cortex-prerelease.spec index 9a49c52..f2934b4 100644 --- a/rpm/cortex-prerelease.spec +++ b/rpm/cortex-prerelease.spec @@ -6,7 +6,11 @@ # # Required defines at rpmbuild time: # cortex_version e.g. "0.1.16" -# cortex_prerelease e.g. "0.1.20260518gitabcdef0" (used as Release) +# cortex_prerelease e.g. "0.1.20260518140530.gitabcdef0" +# ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ +# commit time (sec) commit sha +# (used as Release; the timestamp prefix +# keeps same-day builds strictly ordered.) %global _build_id_links none %global debug_package %{nil} diff --git a/rpm/helexa-neuron-prerelease.spec b/rpm/helexa-neuron-prerelease.spec index 8e874d6..21a1e8d 100644 --- a/rpm/helexa-neuron-prerelease.spec +++ b/rpm/helexa-neuron-prerelease.spec @@ -9,7 +9,11 @@ # neuron_version e.g. "0.1.16" # neuron_flavour e.g. "ada", "blackwell" — matches the CI build # matrix's compute_cap label. -# neuron_prerelease e.g. "0.1.20260518gitabcdef0" (used as Release) +# neuron_prerelease e.g. "0.1.20260518140530.gitabcdef0" +# ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ +# commit time (sec) commit sha +# (used as Release; the timestamp prefix +# keeps same-day builds strictly ordered.) # # One flavour can be installed at a time on a given host; flavour # packages Conflict with each other.