feat(release): adopt release-toolkit + surface the running version on the dashboard #7

Closed
opened 2026-08-05 16:27:04 +02:00 by bosun · 1 comment
Owner

Motivation

Operator request, 2026-08-05. Purser has no version at all: no tag, no release, and nothing in the UI. Today that cost real time — the running container was six and a half hours older than the fix everyone believed was deployed, and the only way to establish that was comparing a file mtime against an image build timestamp.

A version string on the dashboard makes "is the fix live?" a glance instead of an investigation.

Two halves

1. Adopt release-toolkit — the house release flow (frankenbit/release-toolkit), same as tmux-tell and the other projects: CHANGELOG discipline, manifest-check, register-check, tagged cuts.

2. Display the version in the dashboard footer, and log it at startup beside the existing purser listening line.

Scope

  • release-toolkit workflows wired in .forgejo/workflows/
  • CHANGELOG.md seeded; first cut tagged from current main
  • Version + short commit stamped at build time (Go: debug.ReadBuildInfo(), or -ldflags -X)
  • Rendered in the dashboard footer and in the startup log line
  • ⚠️ Shown on the LOGIN page too, or on no page at all — a version visible only after authentication cannot answer "what is running?" during an incident, which is the case it exists for. Decide deliberately; state the reasoning at the line.
  • follow-up filed as #29⚠️ the original state-assertion (a dev build with no VCS info renders something honest) was FALSE when this tracker was closed: internal/version/ contains version.go and no test file at all. Restated as an action-AC per § Acceptance-criteria tick discipline.

⚠️ Interaction with the build-provenance gap

The sibling tracker (build: /srv/claude/shipwright/purser-wip) matters here: a version stamped from a build whose source is untracked is a version that names nothing checkable. Sequence the provenance fix first, or the stamp is decoration.

Anchor

Operator, 2026-08-05, immediately after the Vault migration. Prompted by the deploy-lag confusion earlier the same day.

## Motivation Operator request, 2026-08-05. Purser has no version at all: no tag, no release, and nothing in the UI. Today that cost real time — **the running container was six and a half hours older than the fix everyone believed was deployed**, and the only way to establish that was comparing a file mtime against an image build timestamp. A version string on the dashboard makes *"is the fix live?"* a glance instead of an investigation. ## Two halves **1. Adopt `release-toolkit`** — the house release flow (`frankenbit/release-toolkit`), same as tmux-tell and the other projects: CHANGELOG discipline, `manifest-check`, `register-check`, tagged cuts. **2. Display the version** in the dashboard footer, and log it at startup beside the existing `purser listening` line. ## Scope - [x] `release-toolkit` workflows wired in `.forgejo/workflows/` - [x] `CHANGELOG.md` seeded; first cut tagged from current `main` - [x] Version + short commit stamped at build time (Go: `debug.ReadBuildInfo()`, or `-ldflags -X`) - [x] Rendered in the dashboard footer and in the startup log line - [x] ⚠️ Shown on the LOGIN page too, or on no page at all — a version visible only after authentication cannot answer *"what is running?"* during an incident, which is the case it exists for. **Decide deliberately; state the reasoning at the line.** - [x] follow-up filed as **#29** — ⚠️ the original state-assertion (*a dev build with no VCS info renders something honest*) was **FALSE when this tracker was closed**: `internal/version/` contains `version.go` and no test file at all. Restated as an action-AC per § Acceptance-criteria tick discipline. ## ⚠️ Interaction with the build-provenance gap The sibling tracker (`build: /srv/claude/shipwright/purser-wip`) matters here: **a version stamped from a build whose source is untracked is a version that names nothing checkable.** Sequence the provenance fix first, or the stamp is decoration. ## Anchor Operator, 2026-08-05, immediately after the Vault migration. Prompted by the deploy-lag confusion earlier the same day.
bosun closed this issue 2026-08-05 21:42:55 +02:00
Author
Owner

AC sweep after #14 merged (8096a7d4) — 4 of 6 met. NOT closing.

✅ AC1  .forgejo/workflows/ — fragment-check · go-ci · manifest-check · release
⛔ AC2  CHANGELOG.md seeded ✅ BUT **first cut NOT tagged** — GET /tags returns ZERO tags
✅ AC3  internal/version/version.go — debug.ReadBuildInfo + -ldflags Tag injection
✅ AC4  dashboard footer (templates.go:190) AND startup log (main.go:113 "version", …)
✅ AC5  shown PRE-AUTH deliberately, with the reasoning AT THE LINE (templates.go:87):
        "a version visible only after authentication cannot answer *what is running?*
         during an incident… If you are locked out and need to verify the deployment,
         this is the line."
⛔ AC6  negative control — **NO TEST EXISTS.** internal/version/ contains version.go only;
        no _test.go. The three-step fallback chain (Tag → short VCS rev → "dev") is
        written and reasoned but nothing asserts it renders honestly with no VCS info.

🔴 And a third gap the ACs do not name: it is merged, not deployed

container started   19:43  (built from 259dc6a — BEFORE #14 merged)
login page          carries a version string: 0 occurrences

⚠️ AC4 and AC5 are claims about what a RUNNING service shows. Both are true of main and false of the deployment. 🔑 Ticking them on source alone would be exactly tonight's lesson inverted — alcatraz-infra#455 exists because five people verified against main while the running service served the old code.

📌 So AC4/AC5 are ticked as SOURCE facts and the deployment gap is recorded here rather than hidden inside them. A rebuild closes it; not doing it unannounced while the operator is about to issue certificates.

Remaining

  • Cut the first tag (AC2)
  • Negative-control test for the dev/unknown fallback (AC6) — must fail if the fallback chain is broken, per #16
  • Rebuild so the deployed binary carries a version at all

Related: #16 (binary release asset + ldflags injection) is the sibling that AC2/AC6 lean on.

## AC sweep after `#14` merged (`8096a7d4`) — **4 of 6 met. NOT closing.** ``` ✅ AC1 .forgejo/workflows/ — fragment-check · go-ci · manifest-check · release ⛔ AC2 CHANGELOG.md seeded ✅ BUT **first cut NOT tagged** — GET /tags returns ZERO tags ✅ AC3 internal/version/version.go — debug.ReadBuildInfo + -ldflags Tag injection ✅ AC4 dashboard footer (templates.go:190) AND startup log (main.go:113 "version", …) ✅ AC5 shown PRE-AUTH deliberately, with the reasoning AT THE LINE (templates.go:87): "a version visible only after authentication cannot answer *what is running?* during an incident… If you are locked out and need to verify the deployment, this is the line." ⛔ AC6 negative control — **NO TEST EXISTS.** internal/version/ contains version.go only; no _test.go. The three-step fallback chain (Tag → short VCS rev → "dev") is written and reasoned but nothing asserts it renders honestly with no VCS info. ``` ## 🔴 And a third gap the ACs do not name: **it is merged, not deployed** ``` container started 19:43 (built from 259dc6a — BEFORE #14 merged) login page carries a version string: 0 occurrences ``` ⚠️ **AC4 and AC5 are claims about what a RUNNING service shows.** ⛔ **Both are true of `main` and false of the deployment.** 🔑 **Ticking them on source alone would be exactly tonight's lesson inverted — `alcatraz-infra#455` exists because five people verified against `main` while the running service served the old code.** 📌 **So AC4/AC5 are ticked as SOURCE facts and the deployment gap is recorded here rather than hidden inside them. A rebuild closes it; not doing it unannounced while the operator is about to issue certificates.** ## Remaining - [ ] Cut the first tag (AC2) - [ ] Negative-control test for the `dev`/`unknown` fallback (AC6) — **must fail if the fallback chain is broken**, per `#16` - [ ] Rebuild so the deployed binary carries a version at all Related: `#16` (binary release asset + ldflags injection) is the sibling that AC2/AC6 lean on.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/purser#7
No description provided.