OpenClaw Changelog Update
Use this for changelog rewrites and GitHub release-note source text. For regular
beta/stable, prepare complete notes before final-source qualification when
possible; Code SHA may then also be Release SHA. Editorial work may overlap
Code validation. If notes change afterward, a genuine CHANGELOG-only descendant
may use the existing product-evidence reuse policy. For
extended-stable, run it before final exact-head validation and tagging. Do not
rerun it for tooling retries, resumed publication, or promotion.
Use it with release-openclaw-maintainer; this skill owns changelog content,
ordering, grouping, and attribution discipline.
Goal
Rebuild the target CHANGELOG.md version section from a complete, generated
history manifest, not stale draft notes. Produce grouped user-facing release
notes sorted by user interest while preserving every relevant issue/PR ref and
every human Thanks @... attribution.
Inputs
- Target base version:
YYYY.M.PATCH, without beta suffix.
- Base tag: last reachable shipped release tag, usually the previous stable or
the previous beta train requested by the operator. It must be an ancestor of
the target; a newer but divergent tag is not a valid history boundary. Use
an explicit shipped/main-closeout SHA only when it is also reachable from the
target.
- Target ref: the exact product-complete history being documented. Its
contribution-record target must be an ancestor of the final release target;
it need not name a not-yet-created changelog commit. Include any later fixes
before finalizing notes. Final notes may be committed before qualification,
or afterward as a CHANGELOG-only descendant of a green Code SHA.
- Canonical main ref: current
origin/main, fetched before verification. Release
notes cite the original merged main PR when the same work is carried by a
backport. A release-branch PR is used only while no forward-port exists on
current main.
Workflow
Confirm the release branch and exact history target:
git fetch --tags origin
- confirm clean
git status -sb
- record
git rev-parse HEAD as the history target
- record the Full Release Validation run id and attempt when qualification already exists
- finish pending product/version/backport changes before freezing final source; refresh the inventory for actual changes
Audit history, including direct commits:
git log --topo-order --date=iso-strict --pretty=format:'%h%x09%ad%x09%s' <base-tag>..<target-ref>
git log --topo-order --grep='(#' --date=short --pretty=format:'%h%x09%ad%x09%s' <base-tag>..<target-ref>
- Include every commit reachable from the target but not the base, including merged side branches. Resolve PR associations before deduplicating and subtracting shipped records; retain the existing revert exclusions.
- also inspect
--since='24 hours ago' when main moved during the release.
Generate the complete contribution record and editorial manifest before
writing grouped prose:
node --import tsx .agents/skills/openclaw-changelog-update/scripts/verify-release-notes.mjs \
--base <base-tag> \
--target <target-ref> \
--main-ref origin/main \
--version <YYYY.M.PATCH> \
--manifest /tmp/openclaw-release-<YYYY.M.PATCH>.json \
--write-ledger
Add repeatable --release-provenance '<40sha> -> #PR[, #PR]' inputs when
release commits cannot carry provenance metadata. These use the same exact
marker grammar and current-main validation as commit-body markers.
The verifier automatically reuses public GitHub GraphQL responses from an
exact base/target SHA snapshot under the worktree's git metadata. Iterative
rewrites at the same target avoid repeated network discovery. Use
--refresh-github-snapshot after suspect API data, `--github-snapshot
for an explicit artifact, or--no-github-snapshotfor a live-only audit. GitHub release bodies are always read live. ExplicitCI #, CI run #, Actions run #, and workflow run #references in active source are classified separately only when issue/PR resolution fails and a live same-repository Actions lookup confirms the exact run ID. Any ordinary occurrence of that number in active source, notes, or the contribution record remains a strict issue/PR requirement. Confirmed runs appear asworkflowRuns` in verification output and the manifest, never as
PR associations or contributor credit.
- the manifest is the required input to the rewrite, not an after-the-fact
audit; it contains every referenced PR, eligible contributor credit,
inline issue context, every direct commit, and an editorial-eligibility
classification for PRs and direct commits
- schema version 3 is the required ephemeral manifest contract. Regenerate
older manifests; version 2 is not a supported downstream-reader boundary
- for a historical backfill, add
--seed-ref <pre-backfill-ref> once so
contribution records from the prior changelog are retained even when an
older merged commit omitted its PR number; the verifier excludes records
for work reverted after the base tag, including beta work reverted before
the stable release
- generated provenance reports in-range PRs separately from retained
seed-only PRs, then states the unique row total. A PR present in both
inventories counts as in-range; never describe the seed-inclusive total
as work merged in the current release range
- add repeatable
--shipped-ref <prior-shipped-tag> when the reachable main
closeout differs from the shipped tag or later forward-port commits
re-associate PRs that were already released. Each tag is a cumulative
shipped boundary: the verifier unions explicit PR rows from complete
contribution records in numbered release sections, excludes only overlapping PRs,
and ignores Unreleased. Never infer this boundary from the base SHA,
target prose, or target record. The manifest and generated provenance retain
each tag plus the exact excluded PR inventory and count for deterministic
candidate validation
- source PR discovery bounds GitHub commit associations to the selected target
history, or the frozen main history for canonical carriers. A contextual
source reference becomes a contribution only when its merged commit is
reachable in the target history and its merge time is within the target.
Keep all references resolvable, but do not promote unrelated PRs merely
because they merge while release preparation continues. Explicit seeds
retain their historical membership and remain seed-only unless independently
proven in-range. Resolve every association page; existing canonical,
cherry-pick, and provenance contracts remain authoritative.
- explicit multi-commit reverts require a revert subject and one standalone
Reverts <full SHA> and <full SHA>. declaration (comma-separated lists
with final and also work). The exact ending to restore the previous behavior.
is accepted. Duplicate, abbreviated, embedded, or repeated declarations do
not establish reversal. Each named commit must be a single-parent ancestor,
and reverse-applying all named patches must reproduce the complete revert
tree. Recognized declarations that fail this proof stop verification. Proof
uses private Git index/object storage without hooks or external diffs;
canonical single-revert and revert-of-revert accounting stays intact.
- canonicalize backports to the original merged PR on
main: explicit
cherry-pick origins win, then a unique normalized-subject match requires
the same author and an overlapping changed path. Suppress release/backport
PRs whenever the corresponding main PR exists on current origin/main.
Keep a release-branch PR only when that change landed there first and has
not yet been forward-ported to main
- read the manifest before editing
### Highlights, ### Changes, or
### Fixes; do not carry old grouped prose forward without re-auditing it
- inspect linked PRs/issues or diffs for ambiguous commits. Direct commits
are editorial input, not public ledger rows; infer material user outcomes
from subject, body, touched files, tests, and nearby commits
- Rewrite one stable-base section only:
- use
## YYYY.M.PATCH
- do not create beta-specific headings
- do not leave a stale
## Unreleased section above the target release
- if
Unreleased contains release-bound notes, fold them into the target
section instead of deleting them
- Section shape:
### Highlights: 5-8 bullets, broad user wins first
- include only a clear user-visible capability or workflow unlock, a
material reliability/safety fix, a broad cross-surface improvement, or
a release-defining integration/compatibility milestone
- every highlight must say what changed for a user in one sentence; use
one user story per bullet and group its supporting PRs
- exclude tests, CI, refactors, docs, catalog churn, and implementation
detail unless the outcome is a material install/update, data-safety, or
widely visible user improvement
### Changes: new capabilities and behavior changes
### Fixes: user-facing fixes first, grouped by impact and surface
- group related changes/fixes by surface and user impact; avoid one bullet
per tiny commit when several commits tell one user-facing story
### Complete contribution record: generated PR-first record after the
grouped prose; it is the exhaustive accounting surface, not a second
release summary
- Preserve attribution:
- keep
#issue, (#PR), Fixes #..., and Thanks @...
- every human-authored merged PR represented by a user-facing entry needs
its PR ref and
Thanks @author, even when the PR had no linked issue
- every human issue reporter for a
Fixes #... or referenced bug issue
represented by a user-facing entry needs Thanks @reporter unless the
same handle is already thanked in that bullet
- every human
Co-authored-by contributor on represented user-facing work
needs Thanks @handle when a GitHub handle is known
- when grouping multiple PRs/issues in one bullet, include every relevant
PR/issue ref and every human contributor handle in that same bullet
- multiple
Thanks @... handles in one bullet are expected; do not drop or
collapse contributor credit just because the note is grouped
- if one grouped bullet covers both direct commits and PRs, keep all PR refs
and thanks, plus any issue refs and human credit from the direct work
- issues remain normal inline
#NNN references. Do not add a separate
linked-issues inventory. The generated PR record keeps source issues
inline as Related #NNN on the PR that shipped them
- when backfilling an older linked-issues inventory, preserve reporter
credit inline for every GitHub-confirmed closing PR relationship. Do not
infer a PR relationship from a generic cross-reference event, invent an
unrelated PR link for a standalone report, or recreate the retired
inventory
- the complete contribution record lists every verified in-range PR and
explicitly retained seed-only PR exactly once as
**PR #NNN**. Discovery
preserves canonical/cherry-pick provenance and requires frozen-history
membership for contextual references; inline context alone cannot create a
contribution row. It preserves author/co-author credit and any issue
references in the original title
- the provenance arithmetic and unique total must match the rendered PR
rows exactly; candidate validation rejects malformed or forged counts
- direct commits remain in the manifest with GitHub-resolved author,
co-author, issue, and editorial-eligibility data. They inform grouped
prose but are never rendered as a public
#### Direct commits dump. Add
direct-commit credit to a grouped bullet only when it shares an explicit
closing issue reference or at least two distinctive subject terms
- the verifier rejects ordinary
docs, test, refactor, ci, build,
chore, and style PRs in Highlights, Changes, or Fixes. An explicit
Conventional Commits ! marker makes any type editorial-eligible; include
its verified user-facing breaking change and migration guidance with the
original PR ref and credit. Keep other internal contributions only in the
complete PR record
- classify conventional titles from their declared type and scope, not
incidental words such as
doc or build in their descriptions. For
untyped titles, retain internal-work signals such as QA, test, docs,
refactor, lint, or CI; eligibility never replaces the source audit
that establishes a user-visible outcome
- do not add GHSA references, advisory IDs, or security advisory slugs to
changelog entries or GitHub release-note text unless explicitly requested
- never thank bots,
@claude, @codex, @openclaw, @clawsweeper, or @steipete
- do not use GitHub's release contributor count as the source of truth; the
changelog must carry the complete human credit set itself
- Sorting preference:
- security/data-loss and content-boundary fixes
- transcript/replay/reply delivery correctness
- channels and mobile integrations
- providers/Codex/local model reliability
- install/update/release path reliability
- performance and observability
- docs and contributor-only/internal details last or omitted
- Keep bullets single-line unless existing file style forces otherwise. Avoid
internal release-process noise unless it changes user install/update safety.
- Check release-note side conditions:
- inspect
src/plugins/compat/registry.ts
- inspect
src/commands/doctor/shared/deprecation-compat.ts
- if a deprecated compatibility record reaches
removeAfter, remove it when
proven safe or move it to removal-pending and record the blocker; keep a
due removal-pending record only until its documented conditions are met
- Validate and ship:
- after the manifest-driven rewrite, regenerate and verify the complete
contribution record before committing:
node --import tsx .agents/skills/openclaw-changelog-update/scripts/verify-release-notes.mjs \
--base <base-tag> \
--target <target-ref> \
--main-ref origin/main \
--version <YYYY.M.PATCH> \
--manifest /tmp/openclaw-release-<YYYY.M.PATCH>.json \
--write-ledger
- the command fails when any
#NNN reference in release history or the
rendered release section cannot resolve, when reverted work is presented
as shipped, when a source PR is absent from the contribution record, when
direct commits are rendered as a public record dump, when non-editorial
PRs appear in grouped prose, or when an eligible PR author or known
co-author is missing from that PR's Thanks @... credit. It also fails
before history collection when --base is not an ancestor of --target,
when ### Highlights has fewer than five or more than eight top-level
bullets, or when the existing prose/record names a PR outside the source
range. Only an explicit --seed-ref may add historical PR inventory; an
explicit repeatable --shipped-ref may subtract PRs proven present in a
prior shipped tag
- when grouped prose names a PR, that same bullet must retain every
contributor and linked-reporter credit from its generated PR record
- unqualified
#NNN references resolve against openclaw/openclaw;
cross-repository references such as openclaw/imsg#141 remain literal
text and must not be rewritten as local issue links
- after the GitHub release or prerelease is published, verify every matching
release page against the same source section:
node --import tsx .agents/skills/openclaw-changelog-update/scripts/verify-release-notes.mjs \
--base <base-tag> \
--target <target-ref> \
--version <YYYY.M.PATCH> \
--release-tag v<YYYY.M.PATCH> \
--check-github
- add one
--release-tag for every beta and stable page in the train; a
### Release verification tail is permitted, but any other body drift
fails the check
scripts/render-github-release-notes.mts is the canonical release-body
renderer used by candidate validation, publish, and verification. When the
complete ## YYYY.M.PATCH section fits GitHub's 125,000-character limit and
the renderer's matching 125,000-byte safety ceiling, the body must contain
that exact section including its heading
- when the complete source section exceeds either limit, the renderer keeps the exact
grouped editorial notes through the line before
### Complete contribution record, then emits that heading with a stable
link to the full contribution record in the tag-pinned CHANGELOG.md.
Never truncate a bullet or partial record, and never hand-author a different
compact form
- append
### Release verification only when it fits after the canonical full
or compact body is chosen. If it does not fit, omit the body tail and retain
the immutable attached release evidence; never compact a fitting full
contribution record just to preserve the optional tail
pnpm release:candidate performs this deterministic render check from the
exact target before it dispatches Full Release Validation, including when local
generated checks are explicitly skipped
git diff --check
- for docs/changelog-only changes, no broad tests are required
- stage
CHANGELOG.md and commit with git commit -m "docs(changelog): refresh YYYY.M.PATCH notes"
- push the release branch without rebasing it onto moving
main
- when all fixes and final notes are committed before fresh full qualification,
record that commit as both Code SHA and Release SHA; use the same successful
full parent/attempt and its exact publication bytes for both roles
- only when notes change after Code qualification, require
git diff --name-only <code-sha>..<release-sha> to print exactly
CHANGELOG.md before optionally using changelog-only-release-v1. That path
retains green Code proof and qualifies new Release SHA package bytes. Any
other changed path requires fresh product qualification
Extended-Stable Variant
Extended-stable has one release commit and no GitHub Release body. After version
prep and approved backports, regenerate ## YYYY.M.P with the regular manifest
and original-main-PR provenance rules. Land it by PR, then validate the final
branch tip before tagging. Re-audit after a product backport; a tooling-only
repair needs no changelog entry. Never rewrite a published tag or changelog.
Quota / API Outage Rule
If GitHub API quota is exhausted, do not idle. Continue work that does not need
GitHub API:
- local changelog rewrite and release-note extraction
- local pretag checks and package/build sanity
- git push/tag checks over git protocol
- npm registry
npm view checks
- exact workflow-dispatch command preparation
Only GitHub Release creation, workflow dispatch, run polling, artifact download,
and issue/PR mutation need API quota.
1---2name: openclaw-changelog-update3description: Regenerate OpenClaw release changelog sections from git history before beta, stable, or extended-stable releases.4---5
6# OpenClaw Changelog Update
7
8Use this for changelog rewrites and GitHub release-note source text. For regular
9beta/stable, prepare complete notes before final-source qualification when
10possible; Code SHA may then also be Release SHA. Editorial work may overlap
11Code validation. If notes change afterward, a genuine CHANGELOG-only descendant
12may use the existing product-evidence reuse policy. For
13extended-stable, run it before final exact-head validation and tagging. Do not
14rerun it for tooling retries, resumed publication, or promotion.
15Use it with `release-openclaw-maintainer`; this skill owns changelog content,
16ordering, grouping, and attribution discipline.
17
18## Goal
19
20Rebuild the target `CHANGELOG.md` version section from a complete, generated
21history manifest, not stale draft notes. Produce grouped user-facing release
22notes sorted by user interest while preserving every relevant issue/PR ref and
23every human `Thanks @...` attribution.
24
25## Inputs
26
27- Target base version: `YYYY.M.PATCH`, without beta suffix.
28- Base tag: last reachable shipped release tag, usually the previous stable or
29 the previous beta train requested by the operator. It must be an ancestor of
30 the target; a newer but divergent tag is not a valid history boundary. Use
31 an explicit shipped/main-closeout SHA only when it is also reachable from the
32 target.
33- Target ref: the exact product-complete history being documented. Its
34 contribution-record target must be an ancestor of the final release target;
35 it need not name a not-yet-created changelog commit. Include any later fixes
36 before finalizing notes. Final notes may be committed before qualification,
37 or afterward as a CHANGELOG-only descendant of a green Code SHA.
38- Canonical main ref: current `origin/main`, fetched before verification. Release
39 notes cite the original merged main PR when the same work is carried by a
40 backport. A release-branch PR is used only while no forward-port exists on
41 current main.
42
43## Workflow
44
451. Confirm the release branch and exact history target:
46 - `git fetch --tags origin`
47 - confirm clean `git status -sb`
48 - record `git rev-parse HEAD` as the history target
49 - record the Full Release Validation run id and attempt when qualification already exists
50 - finish pending product/version/backport changes before freezing final source; refresh the inventory for actual changes
512. Audit history, including direct commits:
52 - `git log --topo-order --date=iso-strict --pretty=format:'%h%x09%ad%x09%s' <base-tag>..<target-ref>`
53 - `git log --topo-order --grep='(#' --date=short --pretty=format:'%h%x09%ad%x09%s' <base-tag>..<target-ref>`
54 - Include every commit reachable from the target but not the base, including merged side branches. Resolve PR associations before deduplicating and subtracting shipped records; retain the existing revert exclusions.
55 - also inspect `--since='24 hours ago'` when main moved during the release.
563. Generate the complete contribution record and editorial manifest before
57 writing grouped prose:
58
59 ```bash
60 node --import tsx .agents/skills/openclaw-changelog-update/scripts/verify-release-notes.mjs \
61 --base <base-tag> \
62 --target <target-ref> \
63 --main-ref origin/main \
64 --version <YYYY.M.PATCH> \
65 --manifest /tmp/openclaw-release-<YYYY.M.PATCH>.json \
66 --write-ledger
67 ```
68
69 Add repeatable `--release-provenance '<40sha> -> #PR[, #PR]'` inputs when
70 release commits cannot carry provenance metadata. These use the same exact
71 marker grammar and current-main validation as commit-body markers.
72
73 The verifier automatically reuses public GitHub GraphQL responses from an
74 exact base/target SHA snapshot under the worktree's git metadata. Iterative
75 rewrites at the same target avoid repeated network discovery. Use
76 `--refresh-github-snapshot` after suspect API data, `--github-snapshot
77<path>` for an explicit artifact, or `--no-github-snapshot` for a live-only
78 audit. GitHub release bodies are always read live.
79 Explicit `CI #`, `CI run #`, `Actions run #`, and `workflow run #` references
80 in active source are classified separately only when issue/PR resolution
81 fails and a live same-repository Actions lookup confirms the exact run ID.
82 Any ordinary occurrence of that number in active source, notes, or the
83 contribution record remains a strict issue/PR requirement. Confirmed runs
84 appear as `workflowRuns` in verification output and the manifest, never as
85 PR associations or contributor credit.
86 - the manifest is the required input to the rewrite, not an after-the-fact
87 audit; it contains every referenced PR, eligible contributor credit,
88 inline issue context, every direct commit, and an editorial-eligibility
89 classification for PRs and direct commits
90 - schema version 3 is the required ephemeral manifest contract. Regenerate
91 older manifests; version 2 is not a supported downstream-reader boundary
92 - for a historical backfill, add `--seed-ref <pre-backfill-ref>` once so
93 contribution records from the prior changelog are retained even when an
94 older merged commit omitted its PR number; the verifier excludes records
95 for work reverted after the base tag, including beta work reverted before
96 the stable release
97 - generated provenance reports in-range PRs separately from retained
98 seed-only PRs, then states the unique row total. A PR present in both
99 inventories counts as in-range; never describe the seed-inclusive total
100 as work merged in the current release range
101 - add repeatable `--shipped-ref <prior-shipped-tag>` when the reachable main
102 closeout differs from the shipped tag or later forward-port commits
103 re-associate PRs that were already released. Each tag is a cumulative
104 shipped boundary: the verifier unions explicit PR rows from complete
105 contribution records in numbered release sections, excludes only overlapping PRs,
106 and ignores `Unreleased`. Never infer this boundary from the base SHA,
107 target prose, or target record. The manifest and generated provenance retain
108 each tag plus the exact excluded PR inventory and count for deterministic
109 candidate validation
110 - source PR discovery bounds GitHub commit associations to the selected target
111 history, or the frozen main history for canonical carriers. A contextual
112 source reference becomes a contribution only when its merged commit is
113 reachable in the target history and its merge time is within the target.
114 Keep all references resolvable, but do not promote unrelated PRs merely
115 because they merge while release preparation continues. Explicit seeds
116 retain their historical membership and remain seed-only unless independently
117 proven in-range. Resolve every association page; existing canonical,
118 cherry-pick, and provenance contracts remain authoritative.
119 - explicit multi-commit reverts require a revert subject and one standalone
120 `Reverts <full SHA> and <full SHA>.` declaration (comma-separated lists
121 with final `and` also work). The exact ending ` to restore the previous behavior.`
122 is accepted. Duplicate, abbreviated, embedded, or repeated declarations do
123 not establish reversal. Each named commit must be a single-parent ancestor,
124 and reverse-applying all named patches must reproduce the complete revert
125 tree. Recognized declarations that fail this proof stop verification. Proof
126 uses private Git index/object storage without hooks or external diffs;
127 canonical single-revert and revert-of-revert accounting stays intact.
128 - canonicalize backports to the original merged PR on `main`: explicit
129 cherry-pick origins win, then a unique normalized-subject match requires
130 the same author and an overlapping changed path. Suppress release/backport
131 PRs whenever the corresponding main PR exists on current `origin/main`.
132 Keep a release-branch PR only when that change landed there first and has
133 not yet been forward-ported to `main`
134 - read the manifest before editing `### Highlights`, `### Changes`, or
135 `### Fixes`; do not carry old grouped prose forward without re-auditing it
136 - inspect linked PRs/issues or diffs for ambiguous commits. Direct commits
137 are editorial input, not public ledger rows; infer material user outcomes
138 from subject, body, touched files, tests, and nearby commits
139
1404. Rewrite one stable-base section only:
141 - use `## YYYY.M.PATCH`
142 - do not create beta-specific headings
143 - do not leave a stale `## Unreleased` section above the target release
144 - if `Unreleased` contains release-bound notes, fold them into the target
145 section instead of deleting them
1465. Section shape:
147 - `### Highlights`: 5-8 bullets, broad user wins first
148 - include only a clear user-visible capability or workflow unlock, a
149 material reliability/safety fix, a broad cross-surface improvement, or
150 a release-defining integration/compatibility milestone
151 - every highlight must say what changed for a user in one sentence; use
152 one user story per bullet and group its supporting PRs
153 - exclude tests, CI, refactors, docs, catalog churn, and implementation
154 detail unless the outcome is a material install/update, data-safety, or
155 widely visible user improvement
156 - `### Changes`: new capabilities and behavior changes
157 - `### Fixes`: user-facing fixes first, grouped by impact and surface
158 - group related changes/fixes by surface and user impact; avoid one bullet
159 per tiny commit when several commits tell one user-facing story
160 - `### Complete contribution record`: generated PR-first record after the
161 grouped prose; it is the exhaustive accounting surface, not a second
162 release summary
1636. Preserve attribution:
164 - keep `#issue`, `(#PR)`, `Fixes #...`, and `Thanks @...`
165 - every human-authored merged PR represented by a user-facing entry needs
166 its PR ref and `Thanks @author`, even when the PR had no linked issue
167 - every human issue reporter for a `Fixes #...` or referenced bug issue
168 represented by a user-facing entry needs `Thanks @reporter` unless the
169 same handle is already thanked in that bullet
170 - every human `Co-authored-by` contributor on represented user-facing work
171 needs `Thanks @handle` when a GitHub handle is known
172 - when grouping multiple PRs/issues in one bullet, include every relevant
173 PR/issue ref and every human contributor handle in that same bullet
174 - multiple `Thanks @...` handles in one bullet are expected; do not drop or
175 collapse contributor credit just because the note is grouped
176 - if one grouped bullet covers both direct commits and PRs, keep all PR refs
177 and thanks, plus any issue refs and human credit from the direct work
178 - issues remain normal inline `#NNN` references. Do not add a separate
179 linked-issues inventory. The generated PR record keeps source issues
180 inline as `Related #NNN` on the PR that shipped them
181 - when backfilling an older linked-issues inventory, preserve reporter
182 credit inline for every GitHub-confirmed closing PR relationship. Do not
183 infer a PR relationship from a generic cross-reference event, invent an
184 unrelated PR link for a standalone report, or recreate the retired
185 inventory
186 - the complete contribution record lists every verified in-range PR and
187 explicitly retained seed-only PR exactly once as `**PR #NNN**`. Discovery
188 preserves canonical/cherry-pick provenance and requires frozen-history
189 membership for contextual references; inline context alone cannot create a
190 contribution row. It preserves author/co-author credit and any issue
191 references in the original title
192 - the provenance arithmetic and unique total must match the rendered PR
193 rows exactly; candidate validation rejects malformed or forged counts
194 - direct commits remain in the manifest with GitHub-resolved author,
195 co-author, issue, and editorial-eligibility data. They inform grouped
196 prose but are never rendered as a public `#### Direct commits` dump. Add
197 direct-commit credit to a grouped bullet only when it shares an explicit
198 closing issue reference or at least two distinctive subject terms
199 - the verifier rejects ordinary `docs`, `test`, `refactor`, `ci`, `build`,
200 `chore`, and `style` PRs in Highlights, Changes, or Fixes. An explicit
201 Conventional Commits `!` marker makes any type editorial-eligible; include
202 its verified user-facing breaking change and migration guidance with the
203 original PR ref and credit. Keep other internal contributions only in the
204 complete PR record
205 - classify conventional titles from their declared type and scope, not
206 incidental words such as `doc` or `build` in their descriptions. For
207 untyped titles, retain internal-work signals such as `QA`, `test`, `docs`,
208 `refactor`, `lint`, or `CI`; eligibility never replaces the source audit
209 that establishes a user-visible outcome
210 - do not add GHSA references, advisory IDs, or security advisory slugs to
211 changelog entries or GitHub release-note text unless explicitly requested
212 - never thank bots, `@claude`, `@codex`, `@openclaw`, `@clawsweeper`, or `@steipete`
213 - do not use GitHub's release contributor count as the source of truth; the
214 changelog must carry the complete human credit set itself
2157. Sorting preference:
216 - security/data-loss and content-boundary fixes
217 - transcript/replay/reply delivery correctness
218 - channels and mobile integrations
219 - providers/Codex/local model reliability
220 - install/update/release path reliability
221 - performance and observability
222 - docs and contributor-only/internal details last or omitted
2238. Keep bullets single-line unless existing file style forces otherwise. Avoid
224 internal release-process noise unless it changes user install/update safety.
2259. Check release-note side conditions:
226 - inspect `src/plugins/compat/registry.ts`
227 - inspect `src/commands/doctor/shared/deprecation-compat.ts`
228 - if a deprecated compatibility record reaches `removeAfter`, remove it when
229 proven safe or move it to `removal-pending` and record the blocker; keep a
230 due `removal-pending` record only until its documented conditions are met
23110. Validate and ship:
232
233- after the manifest-driven rewrite, regenerate and verify the complete
234 contribution record before committing:
235 ```bash
236 node --import tsx .agents/skills/openclaw-changelog-update/scripts/verify-release-notes.mjs \
237 --base <base-tag> \
238 --target <target-ref> \
239 --main-ref origin/main \
240 --version <YYYY.M.PATCH> \
241 --manifest /tmp/openclaw-release-<YYYY.M.PATCH>.json \
242 --write-ledger
243 ```
244- the command fails when any `#NNN` reference in release history or the
245 rendered release section cannot resolve, when reverted work is presented
246 as shipped, when a source PR is absent from the contribution record, when
247 direct commits are rendered as a public record dump, when non-editorial
248 PRs appear in grouped prose, or when an eligible PR author or known
249 co-author is missing from that PR's `Thanks @...` credit. It also fails
250 before history collection when `--base` is not an ancestor of `--target`,
251 when `### Highlights` has fewer than five or more than eight top-level
252 bullets, or when the existing prose/record names a PR outside the source
253 range. Only an explicit `--seed-ref` may add historical PR inventory; an
254 explicit repeatable `--shipped-ref` may subtract PRs proven present in a
255 prior shipped tag
256- when grouped prose names a PR, that same bullet must retain every
257 contributor and linked-reporter credit from its generated PR record
258- unqualified `#NNN` references resolve against `openclaw/openclaw`;
259 cross-repository references such as `openclaw/imsg#141` remain literal
260 text and must not be rewritten as local issue links
261- after the GitHub release or prerelease is published, verify every matching
262 release page against the same source section:
263 ```bash
264 node --import tsx .agents/skills/openclaw-changelog-update/scripts/verify-release-notes.mjs \
265 --base <base-tag> \
266 --target <target-ref> \
267 --version <YYYY.M.PATCH> \
268 --release-tag v<YYYY.M.PATCH> \
269 --check-github
270 ```
271- add one `--release-tag` for every beta and stable page in the train; a
272 `### Release verification` tail is permitted, but any other body drift
273 fails the check
274- `scripts/render-github-release-notes.mts` is the canonical release-body
275 renderer used by candidate validation, publish, and verification. When the
276 complete `## YYYY.M.PATCH` section fits GitHub's 125,000-character limit and
277 the renderer's matching 125,000-byte safety ceiling, the body must contain
278 that exact section including its heading
279- when the complete source section exceeds either limit, the renderer keeps the exact
280 grouped editorial notes through the line before
281 `### Complete contribution record`, then emits that heading with a stable
282 link to the full contribution record in the tag-pinned `CHANGELOG.md`.
283 Never truncate a bullet or partial record, and never hand-author a different
284 compact form
285- append `### Release verification` only when it fits after the canonical full
286 or compact body is chosen. If it does not fit, omit the body tail and retain
287 the immutable attached release evidence; never compact a fitting full
288 contribution record just to preserve the optional tail
289- `pnpm release:candidate` performs this deterministic render check from the
290 exact target before it dispatches Full Release Validation, including when local
291 generated checks are explicitly skipped
292- `git diff --check`
293- for docs/changelog-only changes, no broad tests are required
294- stage `CHANGELOG.md` and commit with `git commit -m "docs(changelog): refresh YYYY.M.PATCH notes"`
295- push the release branch without rebasing it onto moving `main`
296- when all fixes and final notes are committed before fresh full qualification,
297 record that commit as both Code SHA and Release SHA; use the same successful
298 full parent/attempt and its exact publication bytes for both roles
299- only when notes change after Code qualification, require
300 `git diff --name-only <code-sha>..<release-sha>` to print exactly
301 `CHANGELOG.md` before optionally using `changelog-only-release-v1`. That path
302 retains green Code proof and qualifies new Release SHA package bytes. Any
303 other changed path requires fresh product qualification
304
305## Extended-Stable Variant
306
307Extended-stable has one release commit and no GitHub Release body. After version
308prep and approved backports, regenerate `## YYYY.M.P` with the regular manifest
309and original-main-PR provenance rules. Land it by PR, then validate the final
310branch tip before tagging. Re-audit after a product backport; a tooling-only
311repair needs no changelog entry. Never rewrite a published tag or changelog.
312
313## Quota / API Outage Rule
314
315If GitHub API quota is exhausted, do not idle. Continue work that does not need
316GitHub API:
317
318- local changelog rewrite and release-note extraction
319- local pretag checks and package/build sanity
320- git push/tag checks over git protocol
321- npm registry `npm view` checks
322- exact workflow-dispatch command preparation
323
324Only GitHub Release creation, workflow dispatch, run polling, artifact download,
325and issue/PR mutation need API quota.