Skip to content

Migrate to org-level release bot + apply workflow naming/permissions standard #20

Description

@ciotlosm

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:

  1. Receives the pull_request: closed webhook.
  2. Reads the repo's package.json#version on main (and any sub-package package.jsons — e.g. libs/spec/, adapters/*/).
  3. Computes the next CalVer version: YY.M.D-N in Europe/Bucharest timezone, counter resets at day boundary, counter starts at 1.
  4. 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.ymlpr-check.yml, build-gtfs-rt.yml stays, daily.ymlrelease-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

  1. This issue (open).
  2. PR in n3ary/standards: the four standards docs (reviewable in one PR).
  3. PR in n3ary/release-bot (new repo): the Worker, the CalVer logic, the GitHub App manifest, the smoke test workflow. Reviewable in one PR.
  4. Pause for review of (2) and (3). These are the new pieces. Get them right; the rest is mechanical.
  5. 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.
  6. 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.
  7. 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

  • This issue (open)
  • PR in n3ary/standards — four standards docs
  • PR in n3ary/release-bot (new repo) — Worker + App + manifest. Repo created, initial commit on main (tag v0.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.
  • PR in n3ary/app — consumer cleanup
  • PR in n3ary/gtfs-publisher — consumer cleanup
  • PR in n3ary/gtfs-adapters — consumer cleanup
  • PR in n3ary/website — consumer cleanup
  • PR in n3ary/branding — consumer cleanup
  • GitHub App registered + installed on org
  • Org-level bypass rule for n3ary-release-bot[bot]
  • First CalVer commit lands on every consumer's main (cutover moment)

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions