Skip to content

Publish tagged release notes in native GitHub Releases (#1111) - #1183

Merged
rmcdaniel merged 2 commits into
mainfrom
fix/1111-release-notes
Nov 13, 2026
Merged

rmcdaniel merged 2 commits into
mainfrom
fix/1111-release-notes

Conversation

@rmcdaniel

Copy link
Copy Markdown
Member

Closes #1111.

Problem: native-release-github-release.sh published only the identity table. Every native release from 3.3.0 on needed a hand-made body edit, and 3.4.0–3.8.0 still show no notes. The writer's exact-body check then refused its own completed release.

Change:

  • A final release's body is the identity table, then docs/releases/<version>.md read through the contents API at the verified tag commit, never from main. The fake only answers ?ref=<tag commit>, so reading any other ref fails the test.
  • Relative links resolve against the immutable tag: 3.7.0.md#upgrade becomes https://github.com/<repo>/blob/<tag>/docs/releases/3.7.0.md#upgrade and ../../rust/README.md becomes …/blob/<tag>/rust/README.md. Absolute and #anchor links are unchanged.
  • These refuse before any write: notes missing, a first line that isn't # Durable Workflow Server <version> (native), or a link that leaves the repository.
  • Candidates (-rc.N) and the frozen historical native-X.Y.Z tags keep the identity table alone.
  • The existing-release check compares the complete body. A rerun on a complete release is a no-op. Other notes, a different title, draft or prerelease state, or wrong Latest still refuse.
  • New repair_legacy_notes input (default false). It replaces the body only when the existing body is exactly the identity table the old writer produced. It runs after every publication, provenance, qualification and Latest check passes, passes --latest as it already stands, and reads the body back. This is how 3.4.0–3.8.0 get their notes after merge, one dispatch per tag, with the same inputs as the original writer run.

Checks: bash scripts/ci/check-native-release-tags.sh passes with 18 new cases:

  • tagged notes and link resolution;
  • candidate and native- tags stay identity-only;
  • missing notes, a wrong heading and an escaping link refuse with no write;
  • legacy repair keeps Latest true or false as it stands;
  • a complete body with repair asked is a no-op;
  • repair is refused for other notes, another title, a draft, wrong Latest, a failed readback or missing notes.

Two mutation probes fail the suite as expected: resolving links against main instead of the tag, and repairing with --latest=true for a non-Latest release. shellcheck reports no new warning classes.

Actual creation and readback get qualified at the next ordinary native release, plus the 3.8.0 repair dispatch.

🤖 Generated with Claude Code

The protected writer published only the identity table, so every native
release needed a hand-made body edit, and the writer then refused its own
completed release. A final release's body is now the identity table plus
docs/releases/<version>.md read from the verified tag commit through the
contents API, with relative links resolved against the immutable tag.
Missing notes, a mismatched heading or a link leaving the repository refuse
before any write. Candidates and historical native- tags keep the identity
table alone. The existing-release check compares that complete body.

repair_legacy_notes (REPAIR_LEGACY_NOTES=true) replaces only an exact
identity-only body from the earlier writer, after every other binding and
the Latest check pass. It passes Latest as it already stands and reads the
result back. It is how 3.4.0-3.8.0 get their notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Repairing an older release (3.4.0-3.7.0) must not move Latest off 3.8.0. After the body readback, the writer reads the Latest Release again and refuses if it changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@rmcdaniel
rmcdaniel marked this pull request as ready for review November 13, 2026 01:30
@rmcdaniel

Copy link
Copy Markdown
Member Author

Security: PASS (head fc14c8fc, CI 66/66).

Notes source. A final, non-native- release reads docs/releases/<version>.md through the contents API at ?ref=<verified tag commit>, never main. The file must start with exactly # Durable Workflow Server <version> (native). If it's missing or misheaded, the writer refuses before any write. Candidates and the frozen native-X.Y.Z tags keep the identity table alone.

Perl link rewriter. It only rewrites ](target) where the target has no URL scheme and doesn't start with # or /. Each such target is resolved segment by segment against docs/releases/: . and empty segments are dropped, .. pops, and popping past the repository root dies, so the step refuses. It's then emitted as https://github.com/<repo>/blob/<tag>/<path>, which pins links to the immutable tag. Scheme links, anchors and absolute paths pass through untouched. These notes are reviewed repository content at a verified tag, and GitHub sanitizes Release markdown, so that's acceptable. A cosmetic note: image links ![…](rel) also become blob/ URLs, not raw ones.

Repair gate (repair_legacy_notes, default false). It fires only when:

  • it was requested;
  • the computed notes differ from the identity-only body, so only for final releases;
  • the existing Release matches the tag, title, draft = false, prerelease state and an exact identity-only body.

It then edits only the body, passing --latest= as it currently stands. It reads the Release back and requires the tagged notes, and reads Latest back and fails if it moved. A moved Latest is detected after the fact rather than prevented, which is acceptable because the edit never asks to change it. Any other existing body (extra text, wrong title, draft, wrong Latest) is refused with no edit, and every one of those cases is tested.

Scope. The new workflow input is a boolean, passed only through env, and the writer still runs in the github-release Environment after every publication, provenance, qualification and Latest check. OK to dispatch once each for 3.8.0 and the 3.4.0–3.7.0 repairs.

@rmcdaniel
rmcdaniel added this pull request to the merge queue Nov 13, 2026
Merged via the queue into main with commit 4c5f226 Nov 13, 2026
67 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Native GitHub Releases should include tagged notes and recognize the complete body

1 participant