Skip to content

Commit 5df74a1

Browse files
committed
Implement atomic version reservation in publish workflow
- Added a new `reserve-version` job to the GitHub Actions workflow, ensuring atomic reservation of the next publish version via the GitHub Git Refs API. - Rewired downstream jobs to consume outputs from `reserve-version`, replacing previous dependencies on the `validate` job. - Removed legacy `git-tag-staging` and `Calculate unified version` steps to streamline the workflow. - Updated documentation to reflect the new version reservation process and clarify the role of GHCR as image storage only. - Conducted verification on a real `alpha` run, confirming successful execution and proper tagging behavior.
1 parent 4fd3087 commit 5df74a1

9 files changed

Lines changed: 792 additions & 8 deletions

File tree

.llm/history/active/atomic-publish-version-reservation/atomic-publish-version-reservation-part-01.md renamed to .llm/history/completed/atomic-publish-version-reservation/atomic-publish-version-reservation-part-01.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ apply this plan revision to the .llm plan files, then execute Prompt 1.
1212

1313
#### Files Modified
1414

15-
- .llm/plans/active/atomic-publish-version-reservation/00-SUMMARY.md
16-
- .llm/plans/active/atomic-publish-version-reservation/01-reserve-version-job.md
17-
- .llm/plans/active/atomic-publish-version-reservation/04-docs-publish-update.md
18-
- .llm/plans/active/atomic-publish-version-reservation/05-verification.md
15+
- .llm/plans/completed/atomic-publish-version-reservation/00-SUMMARY.md
16+
- .llm/plans/completed/atomic-publish-version-reservation/01-reserve-version-job.md
17+
- .llm/plans/completed/atomic-publish-version-reservation/04-docs-publish-update.md
18+
- .llm/plans/completed/atomic-publish-version-reservation/05-verification.md
1919
- .github/workflows/publish-alpha.yml
20-
- .llm/history/active/atomic-publish-version-reservation/atomic-publish-version-reservation-part-01.md
20+
- .llm/history/completed/atomic-publish-version-reservation/atomic-publish-version-reservation-part-01.md
2121

2222
### Session 2 - 2026-04-23
2323

@@ -38,12 +38,12 @@ implement these plans. as you finish each step in the copy pasta you should mark
3838
- docs/PUBLISH.md
3939
- .cursor/rules/plan-execution-completion-tracking.mdc
4040
- .github/instructions/plan-execution-completion-tracking.instructions.md
41-
- .llm/plans/active/atomic-publish-version-reservation/COPY-PASTA.md
41+
- .llm/plans/completed/atomic-publish-version-reservation/COPY-PASTA.md
4242
- .llm/plans/completed/atomic-publish-version-reservation/01-reserve-version-job.md
4343
- .llm/plans/completed/atomic-publish-version-reservation/02-rewire-needs-and-outputs.md
4444
- .llm/plans/completed/atomic-publish-version-reservation/03-remove-git-tag-staging-and-validate-version.md
4545
- .llm/plans/completed/atomic-publish-version-reservation/04-docs-publish-update.md
46-
- .llm/history/active/atomic-publish-version-reservation/atomic-publish-version-reservation-part-01.md
46+
- .llm/history/completed/atomic-publish-version-reservation/atomic-publish-version-reservation-part-01.md
4747

4848
### Session 3 - 2026-04-23
4949

@@ -65,4 +65,4 @@ https://github.com/podverse/metaboost/actions/runs/24857171910 thanks to this ru
6565
- .llm/plans/completed/atomic-publish-version-reservation/00-SUMMARY.md (moved)
6666
- .llm/plans/completed/atomic-publish-version-reservation/05-verification.md (moved then updated)
6767
- .llm/plans/completed/atomic-publish-version-reservation/COPY-PASTA.md (moved then updated)
68-
- .llm/history/active/atomic-publish-version-reservation/atomic-publish-version-reservation-part-01.md
68+
- .llm/history/completed/atomic-publish-version-reservation/atomic-publish-version-reservation-part-01.md
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Execution Order — Atomic Publish Version Reservation (metaboost)
2+
3+
This plan reworks `.github/workflows/publish-alpha.yml` so that the publish version
4+
`X.Y.Z-{suffix}.N` is selected and reserved **atomically** via the GitHub Git Refs API
5+
**before** any Docker image is pushed. GHCR is no longer the source of truth for the
6+
next `N`; Git tags are.
7+
8+
All phases are **sequential**. Do not start phase N+1 until phase N is fully complete
9+
and verified.
10+
11+
## Phase 1 — Add `reserve-version` and rewire downstream jobs
12+
13+
Single PR / branch. After this phase the workflow has both the new `reserve-version`
14+
job and the old `validate` version-calculation step + `git-tag-staging` job (the old
15+
ones are removed in Phase 2 to keep the diff reviewable).
16+
17+
1. `01-reserve-version-job.md` — Add the new `reserve-version` job between `validate`
18+
and `publish-docker`.
19+
2. `02-rewire-needs-and-outputs.md` — Update every downstream job to depend on
20+
`reserve-version` and consume `needs.reserve-version.outputs.*`.
21+
22+
## Phase 2 — Remove the legacy version-calculation and tag job
23+
24+
3. `03-remove-git-tag-staging-and-validate-version.md` — Delete the `git-tag-staging`
25+
job and the `Calculate unified version` step from `validate`. Update remaining
26+
`needs:` lists.
27+
28+
## Phase 3 — Documentation
29+
30+
4. `04-docs-publish-update.md` — Update [docs/PUBLISH.md](../../../../docs/PUBLISH.md)
31+
to describe atomic reservation via Git ref API; clarify GHCR is image storage only.
32+
33+
## Phase 4 — Verify on a real run
34+
35+
5. `05-verification.md` — Push to `alpha`, walk through the verification checklist,
36+
and only then move on to the podverse plan set.
37+
38+
```mermaid
39+
flowchart TD
40+
p1["Phase 1: reserve-version + rewire"] --> p2["Phase 2: remove legacy version + tag job"]
41+
p2 --> p3["Phase 3: docs"]
42+
p3 --> p4["Phase 4: verify on alpha"]
43+
p4 --> pv["Then start podverse plan set"]
44+
```
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Summary — Atomic Publish Version Reservation (metaboost)
2+
3+
## Why this keeps failing
4+
5+
Run [24852065873](https://github.com/podverse/metaboost/actions/runs/24852065873)
6+
failed with `Refusing to move tag 0.1.9-staging.0` even after the previous "GHCR +
7+
Git tags" combined-discovery change. That means the `Calculate unified version` step
8+
in `validate` still picked `.0`, almost certainly because:
9+
10+
- `git ls-remote --tags origin "refs/tags/${BASE_VERSION}-${SUFFIX}.*"` returned
11+
nothing (errors are swallowed by trailing `|| true`), or
12+
- the GHCR tag list was empty / `404` and we treated it as bootstrap.
13+
14+
Even when the increment **is** correct, the current ordering is unsafe:
15+
16+
- `publish-docker` pushes images first; `git-tag-staging` runs after and can fail.
17+
GHCR tags are mutable, so a duplicate `N` already overwrote images by the time the
18+
Git tag check rejects.
19+
- Two concurrent runs can both compute the same `N` (race).
20+
21+
## Goal
22+
23+
A single, atomic source of truth for `N`: **the Git tag
24+
`refs/tags/X.Y.Z-{suffix}.N`**, reserved before publish via
25+
the GitHub Git Refs API (`POST /repos/{owner}/{repo}/git/refs`).
26+
27+
```mermaid
28+
flowchart TD
29+
validateNode["validate (build, lint, type-check, audit)"] --> reserveNode["reserve-version (compute N + create tag at workflow SHA)"]
30+
reserveNode --> publishNode["publish-docker (uses reserved version)"]
31+
publishNode --> verifyNode["verify-published-tags"]
32+
verifyNode --> releaseNode["github-prerelease-create + changelog-pr-to-develop"]
33+
```
34+
35+
## Decisions
36+
37+
- **Git ref API is source of truth.** The GitHub `POST /repos/{owner}/{repo}/git/refs`
38+
endpoint is atomic: HTTP 201 = we won the race; HTTP 422 = "Reference already
39+
exists". For computed prerelease tags we bump `N` and retry; for exact-tag
40+
reservations (`version_override` and `main`) we resolve the existing tag and only
41+
accept 422 if it already points at `github.sha`.
42+
- **GHCR is image storage only.** No more GHCR tag discovery for selecting `N`.
43+
Verification of pushed tags continues to use GHCR after the fact.
44+
- **No silent failure in the authoritative reservation path.** All shell uses
45+
`set -euo pipefail`. Git Refs API failures other than 201/422 fail immediately;
46+
non-authoritative discovery fallbacks are explicit and logged.
47+
- **Smart start hint, not source of truth.** `git ls-remote --tags` is only used to
48+
pick a starting `N` so we don't loop linearly from 0. If it fails or returns
49+
nothing, we still walk from 0; the create-ref race detection guarantees
50+
correctness.
51+
- **Two-phase rollout in this workflow.** Phase 1 adds `reserve-version` and rewires
52+
consumers (the old version step still runs but is unused). Phase 2 deletes the
53+
legacy version step and the `git-tag-staging` job. This keeps the diff reviewable
54+
and lets us bail back to the old behaviour if Phase 1 misbehaves.
55+
56+
## Plan files
57+
58+
- `00-EXECUTION-ORDER.md`
59+
- `00-SUMMARY.md` (this file)
60+
- `01-reserve-version-job.md`
61+
- `02-rewire-needs-and-outputs.md`
62+
- `03-remove-git-tag-staging-and-validate-version.md`
63+
- `04-docs-publish-update.md`
64+
- `05-verification.md`
65+
- `COPY-PASTA.md`
66+
67+
## Out of scope
68+
69+
- Podverse alignment lives in
70+
`podverse/.llm/plans/active/ci-atomic-version-reservation/`. Do not touch podverse
71+
until metaboost Phase 4 verification is green.
72+
- `main` (RTM) tag handling stays as today (no suffix, single `X.Y.Z`).

0 commit comments

Comments
 (0)