* fix(release): keep notes anchored and cap the release body
The v0.21.2 publish failed at "Create GitHub Release and Tag" with
HTTP 422 "body is too long (maximum is 125000 characters)", after every
npm package had already been published.
Stable releases are tagged on their own release/* branch and merged back
to main only afterwards, so the previous stable tag is never an ancestor
of the branch being released. The ancestor guard therefore dropped
--notes-start-tag on every stable release, and without an anchor GitHub
generates notes across the entire branch history (8000+ commits), which
overruns the body limit.
Always pass the previous tag instead: GitHub diffs it through the merge
base, which is how v0.21.1 produced a 27KB body from a tag that was
equally divergent. Generate the body through the generate-notes API
first so an oversized changelog is truncated on a UTF-8 boundary, and
degrade to an unanchored body and then a minimal one, rather than
aborting a release whose packages are already on npm.
* test(release): pin the anchored release-notes contract
The workflow test asserted the ancestor guard that dropped
--notes-start-tag on every stable release. Assert the replacement
instead: the previous tag is always passed to generate-notes, the body
is capped, and ancestry no longer decides whether notes are anchored.
* refactor(release): extract release-notes capping into a tested helper
The degradation chain lived inline in the workflow bash, so nothing
pinned that a capped body plus its footer stays under GitHub's 125000
character limit, that truncation never splits a multi-byte character, or
that the chain always yields a non-empty body. Move it to
.github/scripts/cap-release-notes.mjs with a collocated node:test suite,
matching the other workflow helpers.
Capping on code points rather than bytes drops the head/iconv dance and
makes the surrogate-pair case testable. The helper also absorbs the
empty-body fallback, which caught a real defect: gh writes the API error
payload to stdout when generate-notes fails, so a doubly failed call
would have published `{"message":"Not Found",...}` as the release body.
Discard a failed attempt's output instead.
* test(release): exercise the surrogate-pair cut and footer-overflow branch (#8199)
---------
Co-authored-by: Qwen Code Bot <qwen-code-bot@alibabacloud.com>
* fix(release): raise model timeouts and shrink batch size for slow networks
The AI release-notes generator timed out on every batch in the v0.21.1
finalize run on a GitHub-hosted runner (US, Azure westus3) hitting a
remote LLM endpoint. The 60s per-request timeout was too close to the
edge: two successful requests took 54.2s and 56.7s, and every other
batch hit the 60s abort. The 12-minute total budget was consumed by
retries on those timeouts, and the circuit breaker opened after 3
consecutive failures, skipping highlights entirely.
- timeoutMs: 60s -> 180s — give the model enough headroom to generate
a full JSON response over a high-RTT cross-region connection.
- totalTimeoutMs: 12min -> 30min — ~140 PRs at 8 per batch is ~18
batches; at ~90s each that's ~27 minutes of model time.
- batchSize: 12 -> 8 — fewer entries per prompt means the model
generates less per request, returning faster and reducing the
chance of a single slow request dragging the whole batch.
- workflow timeout-minutes: 15 -> 35 — match the new 30min budget
plus a margin for git/npm setup.
No changes to retry logic, circuit breaker, or prompt shape.
* fix(release): sync timeout workflow test
* test(release): assert step timeout exceeds script budget
The workflow `timeout-minutes` and the script's `totalTimeoutMs` are
defined in separate files with no shared constant. If they drift apart
silently and the budget exceeds the step timeout, the runner SIGKILLs
the step and even the fallback release notes are lost.
Add a cross-file assertion so any future change to either value that
breaks the invariant fails the test immediately.
Suggested-by: wenshao in PR review.
* test(release): parse release notes timeout expression
* fix(release): skip notes-start-tag when previous release diverges from target (#7969)
* style(release): fix prettier formatting in release workflow (#7969)
* fix(release): warn when notes-start-tag is skipped for a divergent tag (#7969)
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* ci(release): comment released-in version on merged PRs
After a stable release is published, comment on each merged PR in the
release range with a link to the release tag, so contributors can find
which version shipped their change directly from the PR timeline.
Collects PR numbers from squash-merge commit subjects between the
previous and current stable tags, posts a marker-tagged comment, and
skips PRs that already carry the marker (re-run safety). Nightly and
preview releases are out of scope, since finalize only handles stable
tags.
* fix(ci): narrow release PR extraction
* test(ci): cover release comment safety checks
* feat(release): generate AI-assisted release notes
* docs(release): remove AI release notes planning docs
* fix(release): preserve complete AI release notes
* refactor(release): trim AI notes generator surface
* ci: Open autofix issues for main CI failures
* fix(release): harden AI notes review feedback
* fix(release): close AI notes review gaps