Every release on Gitea was a list of binaries and nothing else. Gitea makes
an empty release for each pushed tag, and the workflow only ever attached
files to it, so what had changed was written in CHANGELOG.md and nowhere a
release was looked at.
A job after the build now copies the tag's section of the changelog onto its
release, and fails if there is none — a version nobody described should say
so where it is seen. Run by hand, it syncs every version the changelog has,
which is how the releases made before this get their notes. The changelog
stays the one place notes are written; this copies it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
23:59:59Z renders as the following day in any positive-offset timezone, so
every due date showed up a day late in the UI.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Versions track the phases in the plan: a phase is released once its exit
criterion is met, not when its code lands. That keeps "released" meaning
something — v0.1.0 ships sim-engine and the routing libraries, and says plainly
that the gateway does not serve traffic yet.
scripts/gitea/milestones.py creates the matching Gitea milestones. Idempotent
and never destructive, so it can be re-run after the roadmap shifts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>