Proximal trigger: metanorma/ci#342 rolling drift-audit report (2026-07-29 run) — automerge.yml surfaced as the largest remaining drift class at 62 consumers, following the 2026-07-27 to 2026-07-30 rake.yml sweep that cleared its class (31 consumers merged + cimas.yml unmap landed at metanorma/ci@0b4623e). This ticket is the design-first response to the shape of the next-class conversion.
Related: metanorma/cimas#68 (rake.yml conversion arc precedent) + metanorma/ci#372 (v1.1.0 immutable + three-tier tagging discipline).
Problem
The cimas-managed automerge.yml template is the largest drift class in the current audit report: 62 consumers mapped to master/automerge.yml, spanning flavour gems (15), model repos (14), sample repos (~18), plus basicdoc-models, requirements-models, and various project repos (ogc, csa, hk, bipm-si-brochure, eccma).
Unlike the rake.yml conversion arc — where consumers just needed uses: metanorma/ci/.github/workflows/generic-rake.yml@v1 to point at an existing reusable — the current master/automerge.yml template is a full inline workflow (triggers + permissions + pascalgn/automerge-action@v0.16.4 steps), and there is no metanorma/ci/.github/workflows/generic-automerge.yml reusable to point consumers at.
Consequences of the current shape:
- 62 places to update when
pascalgn/automerge-action bumps a major.
- 62 places to drift silently when consumers hand-edit or when the master template changes.
- 62 places for the (e.2) audit warning to accumulate.
Concrete example — the current drift class (as of the 2026-07-29 audit)
Spot-checked master template + consumer files show they all agree on pascalgn/automerge-action@v0.16.4 — the action-version pin is NOT the drift source. The actual drift is the permissions: block that metanorma/ci#339 added to the master template on 2026-07-12 (least-privilege contents: write + pull-requests: write) that has not yet been synced out to the 62 consumers. All 62 automerge.yml files are on the pre-#339 shape, missing the block.
That's the shape of every template update in this class: master gets a change, consumers await a sync wave to catch up, and in the meantime the (e.2) audit accumulates the drift count. A reusable-workflow reference obviates the sync-wave requirement entirely for future template updates — consumers pinned at @v1 pick up permission changes, action-version bumps, and step-shape changes transparently on the next workflow run.
Proposal
Create metanorma/ci/.github/workflows/generic-automerge.yml as a workflow_call reusable. Consumers then adopt a small uses: stub referencing it at @v1 (per the three-tier discipline landed in ci#372 — moving major, moving minor, immutable patch).
Reusable shape
# metanorma/ci/.github/workflows/generic-automerge.yml
name: automerge (reusable)
on:
workflow_call:
secrets:
# No secrets input needed — automerge uses GITHUB_TOKEN which is
# available via secrets.GITHUB_TOKEN in the caller context.
# If a consumer needs to pass a PAT with wider permissions,
# add a `pat_token` optional secret later.
permissions:
contents: write
pull-requests: write
jobs:
automerge:
runs-on: ubuntu-latest
steps:
- id: automerge
name: automerge
uses: pascalgn/automerge-action@v0.16.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Consumer stub shape
# In each consumer repo: .github/workflows/automerge.yml
name: automerge
on:
pull_request:
types: [labeled, unlabeled, synchronize, opened, edited, ready_for_review, reopened, unlocked]
pull_request_review:
types: [submitted]
check_suite:
types: [completed]
status: {}
permissions:
contents: write
pull-requests: write
jobs:
automerge:
uses: metanorma/ci/.github/workflows/generic-automerge.yml@v1
secrets: inherit
Triggers stay at the caller level (that's a reusable-workflow structural requirement — the caller decides what fires it). Workflow-level permissions at the caller must declare what the reusable's job needs, since job-level permissions can't exceed the caller's ceiling. secrets: inherit passes GITHUB_TOKEN through.
Versioning
Same three-tier discipline as ci#372 established: immutable patch tag (v1.2.0), moving minor (v1.2), moving major (v1). Consumers pin @v1 for auto-track by default.
Bumping pascalgn/automerge-action
One reusable-side change instead of 62 consumer PRs. This is the whole point of the conversion.
Non-scope for this issue
- The 62-consumer sweep is a follow-up conversion arc (would mirror the
rake.yml cimas#68 pattern: batches by ownership, direct-to-main cimas.yml unmap after PRs merge). Not proposing that here — this issue is only for the reusable design.
- Any change to what triggers automerge on consumer side — that stays out of scope; the reusable just executes the merge attempt on invocation.
- Special-cases where a consumer needs a broader-permission PAT (rare in the automerge context) — can be added as an optional
pat_token secret in a follow-up if a real consumer needs it.
Ask
@ronaldtse — happy to open the PR against metanorma/ci implementing the reusable shape above once you've had a chance to look at this design. If you have a different shape preference (different trigger scope on the reusable, different permissions posture, different action-version pin than the current v0.16.4), name it and I'll draft accordingly.
🤖
Proximal trigger:
metanorma/ci#342rolling drift-audit report (2026-07-29 run) —automerge.ymlsurfaced as the largest remaining drift class at 62 consumers, following the 2026-07-27 to 2026-07-30rake.ymlsweep that cleared its class (31 consumers merged +cimas.ymlunmap landed atmetanorma/ci@0b4623e). This ticket is the design-first response to the shape of the next-class conversion.Related:
metanorma/cimas#68(rake.yml conversion arc precedent) +metanorma/ci#372(v1.1.0 immutable + three-tier tagging discipline).Problem
The cimas-managed
automerge.ymltemplate is the largest drift class in the current audit report: 62 consumers mapped tomaster/automerge.yml, spanning flavour gems (15), model repos (14), sample repos (~18), plus basicdoc-models, requirements-models, and various project repos (ogc, csa, hk, bipm-si-brochure, eccma).Unlike the
rake.ymlconversion arc — where consumers just neededuses: metanorma/ci/.github/workflows/generic-rake.yml@v1to point at an existing reusable — the currentmaster/automerge.ymltemplate is a full inline workflow (triggers + permissions +pascalgn/automerge-action@v0.16.4steps), and there is nometanorma/ci/.github/workflows/generic-automerge.ymlreusable to point consumers at.Consequences of the current shape:
pascalgn/automerge-actionbumps a major.Concrete example — the current drift class (as of the 2026-07-29 audit)
Spot-checked master template + consumer files show they all agree on
pascalgn/automerge-action@v0.16.4— the action-version pin is NOT the drift source. The actual drift is thepermissions:block thatmetanorma/ci#339added to the master template on 2026-07-12 (least-privilegecontents: write+pull-requests: write) that has not yet been synced out to the 62 consumers. All 62 automerge.yml files are on the pre-#339 shape, missing the block.That's the shape of every template update in this class: master gets a change, consumers await a sync wave to catch up, and in the meantime the (e.2) audit accumulates the drift count. A reusable-workflow reference obviates the sync-wave requirement entirely for future template updates — consumers pinned at
@v1pick up permission changes, action-version bumps, and step-shape changes transparently on the next workflow run.Proposal
Create
metanorma/ci/.github/workflows/generic-automerge.ymlas aworkflow_callreusable. Consumers then adopt a smalluses:stub referencing it at@v1(per the three-tier discipline landed in ci#372 — moving major, moving minor, immutable patch).Reusable shape
Consumer stub shape
Triggers stay at the caller level (that's a reusable-workflow structural requirement — the caller decides what fires it). Workflow-level
permissionsat the caller must declare what the reusable's job needs, since job-level permissions can't exceed the caller's ceiling.secrets: inheritpassesGITHUB_TOKENthrough.Versioning
Same three-tier discipline as ci#372 established: immutable patch tag (
v1.2.0), moving minor (v1.2), moving major (v1). Consumers pin@v1for auto-track by default.Bumping
pascalgn/automerge-actionOne reusable-side change instead of 62 consumer PRs. This is the whole point of the conversion.
Non-scope for this issue
rake.ymlcimas#68 pattern: batches by ownership, direct-to-main cimas.yml unmap after PRs merge). Not proposing that here — this issue is only for the reusable design.pat_tokensecret in a follow-up if a real consumer needs it.Ask
@ronaldtse — happy to open the PR against
metanorma/ciimplementing the reusable shape above once you've had a chance to look at this design. If you have a different shape preference (different trigger scope on the reusable, different permissions posture, different action-version pin than the current v0.16.4), name it and I'll draft accordingly.🤖