Why
The current versioning model (auto-bump on PR via the n3ary/actions/.github/actions/version-bump composite) causes every PR branch to fall out of sync with main. The bot pushes a commit on the PR branch after validate passes, which forces a rebase on every main advance, which re-triggers the auto-bump, which lands in the action_required gate because github-actions[bot] is treated as a first-time contributor. The cycle is documented in the n3ary-pr-automation agent memory and has bitten every active consumer repo in the org.
The current per-consumer pr-validation.yml has permissions: contents: write solely to support the auto-bump. With auto-bump gone, that privilege can drop to contents: read — a real security tightening.
The current workflow naming is freestyle. gtfs-publisher alone has Build ghcr.io/..., Daily multi-feed pipeline → R2, gtfs-rt recovery (VM reboot), gtfs-rt uptime, Rebuild gtfs-rt VM, an empty name field in publish-spec.yml, and a lowercase inconsistency that makes the Actions tab unreadable.
Concrete evidence: Dependabot missed the v12 case
n3ary/gtfs-adapters has been on version-bump@v12 while the rest of the org is on @v22. Dependabot opened and merged PR #44 (build(deps): bump n3ary/actions from 14 to 22) on 2026-07-06, but the diff only touched 2 of 3 n3ary/actions references in the same file:
- uses: n3ary/actions/.github/actions/setup-pnpm-gh-packages-auth@v14
+ uses: n3ary/actions/.github/actions/setup-pnpm-gh-packages-auth@v22
- uses: n3ary/actions/.github/actions/package/publish@v21
+ uses: n3ary/actions/.github/actions/package/publish@v22
The third reference, n3ary/actions/.github/actions/version-bump@v12, was not touched and remains stale in main. So: Dependabot is necessary but not sufficient. The per-consumer action reference is fragile in a way that wasn't visible until this exact case landed. The release bot eliminates the per-consumer action reference for versioning entirely, so this class of bug cannot recur for the version-bump concern.
What we're building
1. The release bot (n3ary/release-bot, new repo)
A Cloudflare Worker that runs as a GitHub App installed at the n3ary org level. On every merged PR, the bot:
- Receives the
pull_request: closed webhook.
- Reads the repo's
package.json#version on main (and any sub-package package.jsons — e.g. libs/spec/, adapters/*/).
- Computes the next CalVer version:
YY.M.D-N in Europe/Bucharest timezone, counter resets at day boundary, counter starts at 1.
- If the merge commit already changed the version (dev manually edited it), no-op. Otherwise, write the new version, commit with
chore(release): <version>, push to main.
No per-consumer workflow file references the bot. No pr-validation.yml edit is required to enable it. No branch protection change is required per repo (one org-level bypass rule for the app's identity).
2. The new standards docs
Four docs in n3ary/standards/standards/:
version-management.md (rewrite) — CalVer with daily counter, the release bot does the post-merge bump, the n3ary/actions/version-bump action stays for the version-input publish path only.
workflow-naming.md (new) — the [<type>] <subject> (<trigger>) format, file naming convention, type and trigger vocabularies, examples from the org.
workflow-conventions.md (new) — the description block at the top of every workflow file, the principle of least privilege for permissions:, the head.sha checkout for post-merge workflows that consume the version, the "what belongs in a workflow vs. what belongs in the release bot" decision boundary.
org-automation.md (new) — what the release bot is, install steps, org-level bypass rule, Worker deploy process, on-call expectations, secret rotation cadence.
The standards auto-sync workflow (n3ary/standards/.github/workflows/sync-standards.yml) will vendor these into every consumer repo on the next push.
3. The consumer cleanup
Five PRs, one per consumer repo, each a focused cleanup that:
- Deletes the
auto-bump job from pr-validation.yml (where it exists).
- Drops
permissions: contents: write to contents: read in pr-validation.yml (where it's currently set solely for auto-bump).
- Renames every workflow file to the new standard (
pr-validation.yml → pr-check.yml, build-gtfs-rt.yml stays, daily.yml → release-daily-multi-feed.yml, etc.).
- Sets the new
name: field on every workflow to the [<type>] <subject> (<trigger>) format.
- Adds the standardized description block header to every workflow file.
- Sets the initial CalVer version (
26.7.11-1 for repos with today's date as the first ever CalVer version).
- Cleans up any per-repo
github-actions[bot] bypass-actor rules (moved to the org-level rule for the new app).
Token / permission drops
| Current |
New |
Why |
contents: write in every pr-validation.yml |
contents: read |
Auto-bump job is deleted; nothing else in the workflow needs push. |
NPM_TOKEN in the auto-bump's pnpm setup |
(gone, auto-bump deleted) |
NPM_TOKEN is still needed by the validate job's pnpm install (via setup-pnpm-gh-packages-auth). Stays. |
github-actions[bot] bypass-actor per repo on main |
Removed per repo; one org-level rule for n3ary-release-bot[bot] |
Single identity across the org; bypass set once. |
version-bump action's pr-bump mode |
Deprecated in the action's README; no consumer calls it anymore |
The publish paths still use version-input mode. |
gtfs-adapters reference to version-bump@v12 |
Deleted (auto-bump job goes away) |
The "stale v12" case cannot recur. |
Migration order
- This issue (open).
- PR in
n3ary/standards: the four standards docs (reviewable in one PR).
- PR in
n3ary/release-bot (new repo): the Worker, the CalVer logic, the GitHub App manifest, the smoke test workflow. Reviewable in one PR.
- Pause for review of (2) and (3). These are the new pieces. Get them right; the rest is mechanical.
- PR per consumer repo (
n3ary/app, n3ary/gtfs-publisher, n3ary/gtfs-adapters, n3ary/website, n3ary/branding): delete auto-bump, drop contents: write, rename workflows, add description blocks, set initial CalVer version. Five small PRs, opened in parallel.
- Org-level steps (one-time, by hand, in the GH UI):
- Register the GitHub App (manifest-based, links provided in the bot README).
- Install the app on the n3ary org.
- Add the org-level bypass rule for
n3ary-release-bot[bot] on main.
- Cutover: from this point, every PR merge in any n3ary repo produces a
chore(release): 26.7.11-N commit on that repo's main, automatically, with the app's identity, no action_required gate.
What's NOT in scope
- Switching to release-please or any other external tool. The release bot is n3ary-specific on purpose.
- Adopting Conventional Commits. The release bot uses CalVer + daily counter, not commit-message-driven bump type.
- Renaming any repos.
- Touching
n3ary/standards or n3ary/actions consumer surfaces (those are source repos, not application repos).
Tracking checklist
Related
- Agent memory:
~/.mavis/agents/mavis/memory/n3ary-pr-automation.md — the action_required cycle this issue is closing
- Agent memory:
~/.mavis/agents/mavis/memory/MEMORY.md — "Never merge your own PRs" + the github-actions[bot] bypass-actor notes
- Existing standard:
standards/version-management.md (current "bump on PR" rule, to be rewritten)
Why
The current versioning model (
auto-bump on PRvia then3ary/actions/.github/actions/version-bumpcomposite) causes every PR branch to fall out of sync withmain. The bot pushes a commit on the PR branch aftervalidatepasses, which forces a rebase on everymainadvance, which re-triggers the auto-bump, which lands in theaction_requiredgate becausegithub-actions[bot]is treated as a first-time contributor. The cycle is documented in then3ary-pr-automationagent memory and has bitten every active consumer repo in the org.The current per-consumer
pr-validation.ymlhaspermissions: contents: writesolely to support the auto-bump. With auto-bump gone, that privilege can drop tocontents: read— a real security tightening.The current workflow naming is freestyle.
gtfs-publisheralone hasBuild ghcr.io/...,Daily multi-feed pipeline → R2,gtfs-rt recovery (VM reboot),gtfs-rt uptime,Rebuild gtfs-rt VM, an empty name field inpublish-spec.yml, and a lowercase inconsistency that makes the Actions tab unreadable.Concrete evidence: Dependabot missed the v12 case
n3ary/gtfs-adaptershas been onversion-bump@v12while the rest of the org is on@v22. Dependabot opened and merged PR #44 (build(deps): bump n3ary/actions from 14 to 22) on 2026-07-06, but the diff only touched 2 of 3n3ary/actionsreferences in the same file:The third reference,
n3ary/actions/.github/actions/version-bump@v12, was not touched and remains stale inmain. So: Dependabot is necessary but not sufficient. The per-consumer action reference is fragile in a way that wasn't visible until this exact case landed. The release bot eliminates the per-consumer action reference for versioning entirely, so this class of bug cannot recur for the version-bump concern.What we're building
1. The release bot (
n3ary/release-bot, new repo)A Cloudflare Worker that runs as a GitHub App installed at the n3ary org level. On every merged PR, the bot:
pull_request: closedwebhook.package.json#versiononmain(and any sub-packagepackage.jsons — e.g.libs/spec/,adapters/*/).YY.M.D-NinEurope/Bucharesttimezone, counter resets at day boundary, counter starts at1.chore(release): <version>, push tomain.No per-consumer workflow file references the bot. No
pr-validation.ymledit is required to enable it. No branch protection change is required per repo (one org-level bypass rule for the app's identity).2. The new standards docs
Four docs in
n3ary/standards/standards/:version-management.md(rewrite) — CalVer with daily counter, the release bot does the post-merge bump, then3ary/actions/version-bumpaction stays for theversion-inputpublish path only.workflow-naming.md(new) — the[<type>] <subject> (<trigger>)format, file naming convention, type and trigger vocabularies, examples from the org.workflow-conventions.md(new) — the description block at the top of every workflow file, the principle of least privilege forpermissions:, thehead.shacheckout for post-merge workflows that consume the version, the "what belongs in a workflow vs. what belongs in the release bot" decision boundary.org-automation.md(new) — what the release bot is, install steps, org-level bypass rule, Worker deploy process, on-call expectations, secret rotation cadence.The standards auto-sync workflow (
n3ary/standards/.github/workflows/sync-standards.yml) will vendor these into every consumer repo on the next push.3. The consumer cleanup
Five PRs, one per consumer repo, each a focused cleanup that:
auto-bumpjob frompr-validation.yml(where it exists).permissions: contents: writetocontents: readinpr-validation.yml(where it's currently set solely for auto-bump).pr-validation.yml→pr-check.yml,build-gtfs-rt.ymlstays,daily.yml→release-daily-multi-feed.yml, etc.).name:field on every workflow to the[<type>] <subject> (<trigger>)format.26.7.11-1for repos with today's date as the first ever CalVer version).github-actions[bot]bypass-actor rules (moved to the org-level rule for the new app).Token / permission drops
contents: writein everypr-validation.ymlcontents: readNPM_TOKENin the auto-bump's pnpm setupNPM_TOKENis still needed by the validate job'spnpm install(viasetup-pnpm-gh-packages-auth). Stays.github-actions[bot]bypass-actor per repo onmainn3ary-release-bot[bot]version-bumpaction'spr-bumpmodeversion-inputmode.gtfs-adaptersreference toversion-bump@v12Migration order
n3ary/standards: the four standards docs (reviewable in one PR).n3ary/release-bot(new repo): the Worker, the CalVer logic, the GitHub App manifest, the smoke test workflow. Reviewable in one PR.n3ary/app,n3ary/gtfs-publisher,n3ary/gtfs-adapters,n3ary/website,n3ary/branding): delete auto-bump, dropcontents: write, rename workflows, add description blocks, set initial CalVer version. Five small PRs, opened in parallel.n3ary-release-bot[bot]onmain.chore(release): 26.7.11-Ncommit on that repo'smain, automatically, with the app's identity, noaction_requiredgate.What's NOT in scope
n3ary/standardsorn3ary/actionsconsumer surfaces (those are source repos, not application repos).Tracking checklist
n3ary/standards— four standards docsn3ary/release-bot(new repo) — Worker + App + manifest. Repo created, initial commit onmain(tagv0.1.0). Awaiting App registration on the org. PR in docs(standards): CalVer model + workflow naming/conventions + org-automation #21 has the four standards docs.n3ary/app— consumer cleanupn3ary/gtfs-publisher— consumer cleanupn3ary/gtfs-adapters— consumer cleanupn3ary/website— consumer cleanupn3ary/branding— consumer cleanupn3ary-release-bot[bot]main(cutover moment)Related
~/.mavis/agents/mavis/memory/n3ary-pr-automation.md— theaction_requiredcycle this issue is closing~/.mavis/agents/mavis/memory/MEMORY.md— "Never merge your own PRs" + thegithub-actions[bot]bypass-actor notesstandards/version-management.md(current "bump on PR" rule, to be rewritten)