Skip to content

fix(deploy): guard the CHANGELOG version heading, and correct the v0.7.28 token it misquoted - #305

Merged
argszero merged 1 commit into
mainfrom
fix/changelog-carries-the-version-it-declares
Sep 27, 2026
Merged

argszero merged 1 commit into
mainfrom
fix/changelog-carries-the-version-it-declares

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The release chain states its version in four places, and until now only three of them 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 .github/workflows/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 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: forgetting Dockerfile / docker-compose.yml is caught, a mismatched tag is caught, and forgetting CHANGELOG.md was 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 in CHANGELOG.md must equal the version Cargo.toml declares.

    • The expectation is derived (declared_version() reads Cargo.toml's [package].version; no snapshot constant).
    • include_str!("../CHANGELOG.md") — zero new files, zero new dependencies.
    • It is a separate file constant, not a new entry in FILES: the first two rules and the module's "prose is out of scope" statement are untouched.
    • Why the heading is not prose (and so is in scope): it sits at a machine-readable structural position, in a file whose whole job is to state versions. The body stays out of scope — in particular the asset-token enumeration below is not gated, by design.
  • CHANGELOG.md: corrected the v0.7.28 entry, which paired data.js with style.css at the same ?v=20260914-11.

    The release tree disagrees: git show 63f5975:ui/index.html has style.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) pushed style.css alone to 20260924-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 --check rc=0, cargo clippy --all-targets -- -D warnings rc=0.

  • 新增/更新了单元测试(如适用)

    Two companions, each owning one claim:

    • positive control — the scanner really sees the heading it guards (non-empty, first heading near the top, the scanned line really starts with ## 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.
    • teeth — on synthetic input, not on the live file (rule and "is the file currently fixed" are two different readings): a correct heading passes, a stale one is reported, and a file with no heading is reported too, so "scanned zero headings" can never masquerade as "compliant".

    Verified by mutation: renaming the top heading to v9.9.9 turns exactly one test red —

    CHANGELOG.md:5: 最新条目标题是 v9.9.9,而 Cargo.toml 声明的是 0.7.28(发行链上的版本副本没跟上)
    

    and restoring it turns the suite green again.

Checklist

  • 分支命名符合约定(fix/)
  • Commit message 使用 Conventional Commits 格式(fix(deploy): …)
  • 单一职责,改动最小化 — one fact ("the CHANGELOG heading's version comes from Cargo.toml") and the one literal it caught being wrong.

Not changed on purpose

…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.
@argszero
argszero merged commit 231b4d3 into main Sep 27, 2026
2 checks passed
@argszero
argszero deleted the fix/changelog-carries-the-version-it-declares branch September 27, 2026 01:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant