fix(deploy): guard the CHANGELOG version heading, and correct the v0.7.28 token it misquoted - #305
Merged
Conversation
…7.28 token it misquoted The release chain states its version in four places, and until now only three had an executor: `Cargo.toml` is the runtime truth (`/healthz` reports `CARGO_PKG_VERSION`), the copies in `Dockerfile` / `docker-compose.yml` are guarded by the second rule in `src/deploy_gate.rs`, and the release tag is guarded by `docker-publish.yml`. The fourth — the latest `## v<semver>` heading in `CHANGELOG.md` — had none. It happened to be correct on all 23 tags (v0.7.6…v0.7.28), which is exactly the shape of a claim with consumers and no executor (the same shape R76 found for the MSRV and R80 for the tag). After the deploy-artifact rule landed a release PR touches five files: forgetting `Dockerfile`/`docker-compose.yml` is caught, a mismatched tag is caught, and forgetting `CHANGELOG.md` was not. Add a third rule to `src/deploy_gate.rs`: the latest `## v<semver>` heading in `CHANGELOG.md` must equal the version `Cargo.toml` declares. The expectation is derived (`declared_version()`, no snapshot), `include_str!` keeps it dependency-free, and it is a separate file constant rather than an entry in `FILES` — so the deploy-artifact rule and its "prose is out of scope" statement are untouched. The heading is guarded because it sits at a machine-readable structural position in a file whose job is to state versions; the body stays out of scope. While instrumenting this, the one place the entry already got wrong surfaced: the v0.7.28 entry lists the front-end asset tokens and pairs `data.js` with `style.css` at `?v=20260914-11`, but the release tree (63f5975) has `style.css?v=20260924-1`. The two shared that value before #292 (c2f047d) pushed `style.css` alone to `20260924-1`, so the entry was written from memory rather than from the tree. Correct it in place with the repo's existing convention for a false CHANGELOG claim (strikethrough plus a note, as v0.7.10 / #267 did). Tests: two companions — a positive control proving the scanner really sees the heading it guards, and a teeth check on synthetic input (a stale heading and a heading-less file both turn it red). Verified by mutation: a stale heading makes exactly one test fail and names the line. `cargo test` 399 → 402, `cargo fmt --check` and `clippy --all-targets -- -D warnings` clean.
9 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The release chain states its version in four places, and until now only three of them had an executor:
Cargo.tomlis the runtime truth (/healthzreportsCARGO_PKG_VERSION), the copies inDockerfile/docker-compose.ymlare guarded by the second rule insrc/deploy_gate.rs, and the release tag is guarded by.github/workflows/docker-publish.yml. The fourth — the latest## v<semver>heading inCHANGELOG.md— had none. It happened to be correct on all 23 tags (v0.7.6…v0.7.28), which is exactly the shape of a claim that has consumers and no executor (the same shape the MSRV had before R76 and the tag had before R80). Since the deploy-artifact rule landed, a release PR touches five files: forgettingDockerfile/docker-compose.ymlis caught, a mismatched tag is caught, and forgettingCHANGELOG.mdwas not.So this adds the missing executor, and while instrumenting it, the one place the entry had already got wrong surfaced and was corrected.
Related Issue
None — no tracking issue exists for this; it was found while auditing the version-fact carriers left unguarded after #303 / #304.
Changes
src/deploy_gate.rs(third rule): the latest## v<semver>heading inCHANGELOG.mdmust equal the versionCargo.tomldeclares.declared_version()readsCargo.toml's[package].version; no snapshot constant).include_str!("../CHANGELOG.md")— zero new files, zero new dependencies.FILES: the first two rules and the module's "prose is out of scope" statement are untouched.CHANGELOG.md: corrected the v0.7.28 entry, which paireddata.jswithstyle.cssat the same?v=20260914-11.The release tree disagrees:
git show 63f5975:ui/index.htmlhasstyle.css?v=20260924-1(the other four refs in that sentence are correct). The two shared that value before feat(ui): let the transactions trend card switch between four metrics #292 (c2f047d) pushedstyle.cssalone to20260924-1, so the sentence was written from memory rather than from the tree. It is corrected in place with this repository's existing convention for a false CHANGELOG claim — strikethrough plus a note, the way v0.7.10's "raised to 70MB" was corrected by fix(gateway): apply the body limit where axum reads it (per-route DefaultBodyLimit) #267. (No gate for this half: the axis decision for a wrong claimed value is fix the data, do not gate the prose.)No config / data-structure change.
Tests
cargo test全部通过 — 402 passed / 0 failed (399 → 402; the three new tests are the rule plus its two companions).cargo fmt --checkrc=0,cargo clippy --all-targets -- -D warningsrc=0.新增/更新了单元测试(如适用)
Two companions, each owning one claim:
## v, and the token parsed is version-shaped). It deliberately does not re-assert equality with the manifest: the claim "heading == declared version" has exactly one owner, so a stale heading fails one test and names the line rather than two.Verified by mutation: renaming the top heading to
v9.9.9turns exactly one test red —and restoring it turns the suite green again.
Checklist
fix/)fix(deploy): …)Cargo.toml") and the one literal it caught being wrong.Not changed on purpose
?v=in the body againstui/index.htmlwould be gating prose, and contradicts the deploy-artifact rule's own scope statement.CHANGELOG.md:104(v0.7.22) attributes a cache-bust bullet to fix(ui): add the global reset layer and align form/button geometry with the prototype #159 when the real jump was split across fix(ui): add the global reset layer and align form/button geometry with the prototype #159 / fix(ui): define the orphan .mono class and restore the .nb nowrap span #161; its endpoint value is correct, so it is left alone.