feat(changelog): PR numbers as source of truth — stamp at merge + verify in CI (0203) - #192
Merged
Merged
Conversation
Successor to 0202. Diagnoses why the changelog keeps *seeming* broken even though production resolves 35/35: the PR number is a deploy-time side-channel (absent from committed source, absent from PR CI/previews, self-healing only at deploy). Recommends stamping the number at merge from the event payload (bot write-back, no human second commit) + a PR-CI validate/dry-resolve so an entry can never silently look broken, with deploy-time resolve-prs kept as the net. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…203) - resolve-prs.mjs gains a --check mode: dry-run resolution for PR CI that never writes and exits non-zero when a fragment introduced by the PR can't be resolved to a PR number (pre-existing gaps stay warnings). Scoped via CHANGELOG_BASE_REF. - loadPrGallery() bounds its build-time fetch with AbortSignal.timeout(5s) so a slow/hung visuals host can't stall the production deploy. - changelog.ts header documents the stamp-at-merge + dry-run flow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New stamp-pr-number.yml: on a merged PR that touched a changelog fragment, write the PR number (from the merge event) into any fragment lacking one and commit it back to main with [skip ci]. Degrades to a warning if the token can't push to a protected main; resolve-prs.mjs stays the deploy-time net. - ci.yml gains a lightweight `changelog` PR job: validate-changelog + resolve-prs --check, so a malformed/numberless entry fails the PR, not the prod deploy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Preview removed for PR #192. |
crs48
added a commit
that referenced
this pull request
Jun 18, 2026
Follow-up to #192. Switches `stamp-pr-number.yml` from a long-lived PAT to a **GitHub App** installation token, the more secure way to let the merge-time stamp push land in `main`. ## What - `stamp-pr-number.yml` mints a short-lived token via `actions/create-github-app-token`, gated on the `CHANGELOG_APP_ID` repo **variable** (usable in `if`), with `continue-on-error` and a `secrets.CHANGELOG_BOT_TOKEN || github.token` fallback chain. So it **never hard-fails**: unconfigured → falls back → existing graceful `::warning`; configured → token can bypass the `main` ruleset and the PR number persists to source. - Doc + in-file setup notes updated. ## One-time ops to activate (after merge) 1. Create a GitHub App with repository **Contents: write**; install it on `crs48/xNet`. 2. Set repo **variable** `CHANGELOG_APP_ID` and **secret** `CHANGELOG_APP_PRIVATE_KEY`. 3. Add the App to the **`main` ruleset bypass list**. Until then, behaviour is unchanged (deploy-time `resolve-prs.mjs` keeps the live site correct). No user-facing change → `skip-changelog`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
crs48
added a commit
that referenced
this pull request
Jun 18, 2026
Adds [`docs/changelog-pr-stamping-setup.md`](https://github.com/crs48/xNet/blob/docs/changelog-stamping-runbook/docs/changelog-pr-stamping-setup.md) — the one-time GitHub-App setup that activates the merge-time changelog PR-number stamping shipped in #192/#193: 1. Create a GitHub App (Contents: write), install it on the repo. 2. Set the `CHANGELOG_APP_ID` variable + `CHANGELOG_APP_PRIVATE_KEY` secret. 3. Add the App to the `main` ruleset bypass list. Includes verification steps, troubleshooting, and the PAT alternative. Docs-only → `skip-changelog`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.
Implements exploration 0203 (
docs/explorations/0203_[_]_CHANGELOG_PR_NUMBERS_AS_SOURCE_OF_TRUTH.md), the successor to 0202.Why
The changelog isn't actually broken — production resolves every entry's PR number. But the number is a deploy-time side-channel: it's absent from committed source (8/34 fragments had no
prin the repo), absent from PR CI and previews, and self-heals only at deploy. So it keeps looking broken (kebab-case "branch-name" fragments with no number), and a malformed fragment would fail the production deploy — freezing the whole live changelog — rather than the PR.This makes the PR number a first-class, visible, verified property of the fragment, with no second human commit.
What
.github/workflows/stamp-pr-number.yml): when a merged PR touched a changelog fragment, write the PR number (straight from the merge event — no heuristics) into any fragment lacking one and commit it back tomainwith[skip ci]. The author still commits once; the bot does the "second commit". The merge's own deploy already published the number viaresolve-prs, so[skip ci]avoids a redundant deploy. Degrades to a::warningif the token can't push to a protectedmain.ci.ymlchangelogjob): runsvalidate-changelog.ts+ a newresolve-prs.mjs --checkdry run. A malformed or numberless-and-unresolvable entry now fails the PR, not the prod deploy. Lightweight (plain Node + on-the-flytsx, no workspace install).resolve-prs.mjsstill fills any gap at deploy (direct pushes, etc.).loadPrGallerybounds its build-time fetch withAbortSignal.timeout(5s)so a hung host can't stall the deploy.Verified locally
--check: 28 baked, 6 resolve via git subject, exit 0, zero files written.--checkwithCHANGELOG_BASE_REF: a PR-new unresolvable fragment →::error+ exit 1.validate-changelog.ts: exit 1 on a malformed fragment.Follow-up (ops, can't be done in-PR)
CHANGELOG_BOT_TOKEN(GitHub App / PAT) withmainruleset bypass so C persists to source. Until then C degrades to a warning and the deploy-time net keeps the live site correct.stamp-pr-number.ymlruns from the base branch's copy, so it can't stamp its own introducing PR — this PR's fragment is filled by the deploy-time net; the stamp takes effect for subsequent PRs.🤖 Generated with Claude Code