Skip to content

feat(rulesets): pilot a merge queue on playtester - #102

Merged
zoeyrose merged 4 commits into
mainfrom
feat/merge-queue-pilot
Oct 18, 2026
Merged

zoeyrose merged 4 commits into
mainfrom
feat/merge-queue-pilot

Conversation

@zoeyrose

@zoeyrose zoeyrose commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Summary

This pilots GitHub's merge queue on playtester and adds merge_queue support to the desired state, publisher, validation and audit. The owner approved the pilot on 2026-10-18; other repositories follow later.

  • Config. A new merge_queue list in config/repositories.json holds only playtester. A new config/rulesets/merge-queue.json template defines 08 - Merge queue:
    • SQUASH merges and ALLGREEN grouping;
    • build concurrency 5 and groups of 1 to 5 PRs, with no minimum-group wait, so a single green PR merges at once;
    • a 60-minute check timeout;
    • the usual pull-request-only owner bypass.
  • Publisher. GitHub accepts merge_queue only in repository rulesets; the org rulesets API rejects it. So 08 - Merge queue is repository-owned in both policy scopes, like 06 - CodeQL security. The publisher only writes on drift (KEEP when converged) and refuses to overwrite a same-name rule with foreign ownership. A queued repository's 03 - Required CI rule gets strict_required_status_checks_policy: false, because the queue tests each merged result. Every other repository stays strict. Ordering:
    • the queue is installed before required CI is relaxed. When applying, the publisher re-reads the queue right before publishing required CI and relaxes it only if the exact repository-owned queue is in place; otherwise required CI stays strict with a SKIP;
    • on removal from the list, strict CI is restored first, then only an unmodified, repository-owned queue is deleted. An identity fence and a final re-read run immediately before the DELETE; any other case is SKIP ... retained;
    • a listed active repository that is private on Team fails before any write;
    • an inactive entry is skipped, as security gates are, and its required CI stays strict.
  • Validation. Queued repositories must be in required_ci, and must never be a Dependency review gate, which has no merge-group trigger. Queue parameters must stay within GitHub's API ranges and use the organization's only allowed merge method. A wait is allowed only with a minimum group size above 1. The 03 - Required CI template is pinned to strict.
  • Audit. Queued repositories must have the exact repository-owned queue, matching effective merge_queue rules, and non-strict required CI. A queue retained on any other repository is reported for manual review.
  • Docs. README gains "Enabling a merge queue"; CONTRIBUTING and AGENTS.md describe the new contract.

Owner steps (in order)

  1. Merge ci: report required checks on the merge queue playtester#66 first. It makes both required checks (Playtester validation, Conventional PR title) report on merge_group. Without it, queued merges stall until the 60-minute timeout.
  2. Merge this PR.
  3. Run bin/publish in plan mode from main and confirm the diff below. Then run bin/publish --apply. That step is the owner's; nothing was applied from this branch.

Plan diff (bin/publish, plan mode only, never --apply)

Organization atrinik, plan team, policy scope organization. Run on head 0c2dc23: the branch plan has 50 operations and the main baseline has 49. I compared every payload of the two runs. Exactly two differ:

+PLAN POST /repos/atrinik/playtester/rulesets            # new "08 - Merge queue"
 PLAN PUT  /orgs/atrinik/rulesets/20669522               # "03 - Required CI - playtester"
-          "strict_required_status_checks_policy": true
+          "strict_required_status_checks_policy": false

The new 08 - Merge queue payload:

{
  "name": "08 - Merge queue",
  "target": "branch",
  "enforcement": "active",
  "bypass_actors": [{"actor_id": 1, "actor_type": "OrganizationAdmin", "bypass_mode": "pull_request"}],
  "conditions": {"ref_name": {"include": ["~DEFAULT_BRANCH"], "exclude": []}},
  "rules": [{"type": "merge_queue", "parameters": {
    "check_response_timeout_minutes": 60,
    "grouping_strategy": "ALLGREEN",
    "max_entries_to_build": 5,
    "max_entries_to_merge": 5,
    "merge_method": "SQUASH",
    "min_entries_to_merge": 1,
    "min_entries_to_merge_wait_minutes": 0
  }}]
}

Live 03 - Required CI - playtester (id 20669522) is still strict today, and playtester is public, so the Team limitation does not apply. The repository has no repository-level rulesets yet.

Unrelated pending changes that the same apply would also perform. These operations appear identically in the main baseline. They come from already-merged changes that have not been applied yet:

Verification

  • bin/validate: valid. New tests/validate-merge-queue.sh checks that validation rejects:
    • 8 bad inventories;
    • 25 bad queue templates, including each range bound, other merge methods, and a wait with a minimum of 1;
    • 3 bad required-CI templates;
    • a Dependency review gate on a queued repository.
  • New tests/publish-merge-queue.sh covers:
    • creation on the repository, never as an organization rule;
    • required CI relaxed only behind a freshly verified queue: one verified state and five unverified states, plan mode, and an inactive entry;
    • a converged rerun with no write;
    • six kinds of drift converged by PUT, and plan mode with no writes;
    • four foreign-ownership refusals, inactive skip and ambiguous-inventory failure;
    • advisory always bypass;
    • retirement of the exact managed rule, and six modified or foreign variants retained;
    • the retirement identity fence, concurrent edits caught by the final read, and an unreadable final read;
    • install-before-relax and restore-before-retire ordering;
    • the private-repository preflight.
  • tests/audit.sh adds a playtester fixture with nine assertions over six queue scenarios: pass, missing queue, parameter drift, organization ownership, strict drift, and a queue retained on observatory.
  • All 28 tests/*.sh pass on 0c2dc23. ShellCheck is clean on bin/* and tests/*.sh. git diff --check is clean.

Related work

Checklist

  • The title uses Conventional Commits style.
  • Repository-specific instructions have been followed.
  • Tests, documentation, and dependency inventory are updated where needed.
  • No confidential or unreleased information is exposed.

🤖 Generated with Claude Code

@zoeyrose

Copy link
Copy Markdown
Member Author

@codex review

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T09:35:22.864736Z 0c2dc23 Manual request
🔒 Security Review ✅ Completed 2026-10-18T10:01:09.959842Z 0c2dc23 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Add a merge_queue inventory to config/repositories.json and a
repository-owned "08 - Merge queue" ruleset template. GitHub accepts the
merge_queue rule only in repository rulesets, so both policy scopes
install it on each listed repository, like the CodeQL gate. The template
squash-merges with ALLGREEN grouping, builds up to 5 entries, merges
groups of 1 to 5 and gives required checks 60 minutes to report.

A queued repository's required CI no longer requires an up-to-date
branch, because the queue tests each merged result. The publisher
installs the queue before relaxing that rule. On removal it restores the
strict policy first, then deletes only an unmodified repository-owned
queue. It fails before any write if a listed active repository is
private on Team, and skips an inactive one as it does security gates.

Validation keeps queued repositories in required CI and out of the
Dependency review gate. It also bounds the queue parameters to GitHub's
API ranges and the organization's merge method. The audit expects the
exact repository-owned queue and non-strict required CI on queued
repositories, and reports a queue retained anywhere else.

playtester is the pilot. Apply only after atrinik/playtester#66 merges,
so both required checks report on merge_group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 2198a42d99

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@zoeyrose
zoeyrose force-pushed the feat/merge-queue-pilot branch from 2198a42 to 12474e4 Compare October 18, 2026 08:29
@zoeyrose

Copy link
Copy Markdown
Member Author

Review round 1

  • Codex code review: completed on 2198a42 with no findings.
  • Behind main: rebased onto 4d920c1 (chore: record owner decisions from the editor and renderer transfer #101) with no conflicts. The new head is 12474e4. bin/validate and the affected suites pass: publish-merge-queue, publish-maintenance-branch, verify-manual-settings, validate-crate-trusted-publishing, check-project-health, validate-manual-credentials, validate-planning-health. chore: record owner decisions from the editor and renderer transfer #101 does not touch the publisher or the ruleset templates, so the plan diff in the description still holds.
  • Codex security review: it had not started on the old head, so it is re-requested on 12474e4 along with the code review.

🤖 Generated with Claude Code

@zoeyrose

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12474e4414

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/publish Resolved
The retirement path matched the live queue once and then deleted it, so
an owner edit made between that read and the DELETE would be removed.
Like security-gate retirement, it now checks the repository's identity
and archive state, re-reads the rule and repeats the ownership and
payload match immediately before deleting. A changed rule or repository
is retained with a SKIP, and a failed final read stops the publisher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zoeyrose

Copy link
Copy Markdown
Member Author

Review round 2

  • Recheck the queue before deleting it (bin/publish, P2). Fixed in beb2fce. Retirement now fences the repository's identity and archive state, then re-reads the rule and repeats the ownership and payload match immediately before the DELETE, as security-gate retirement does. Changed rules or repositories are retained with a SKIP, and a failed final read stops the publisher. New tests cover identity drift, concurrent edits on the final read, and an unreadable final read. README, CONTRIBUTING and AGENTS.md now state the fence.

The plan diff in the description is unchanged: this fix touches only the retirement path, which has nothing to retire today.

🤖 Generated with Claude Code

@zoeyrose

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: beb2fcecab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/publish Resolved
The required-CI payload dropped the up-to-date requirement for every
repository named in merge_queue. The queue publisher skips an inactive
entry, so such a repository would lose strict CI without gaining a
queue, and the gap would become live if it were later reactivated.
Required CI now relaxes only for listed repositories that are active in
this run, which are exactly the ones the queue publisher installs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zoeyrose

Copy link
Copy Markdown
Member Author

Review round 3

  • Keep inactive queue repositories strict (bin/publish, P2). Fixed in d5e1d38. Required CI drops the up-to-date requirement only for listed repositories that are active in this run, which are exactly the ones whose queue the publisher installs. A listed but inactive repository stays strict. A new test covers both scopes. README and AGENTS.md now state the rule.

The plan diff in the description is unchanged, because playtester is active: the same two payloads differ from main.

🤖 Generated with Claude Code

@zoeyrose

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d5e1d388b8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/publish Resolved
Comment thread config/rulesets/merge-queue.json Resolved
When applying, required CI dropped the up-to-date requirement for every
active queued repository, even if the queue had been deleted, disabled
or scoped away after the queue publisher ran. Both scopes now re-read
the queue just before publishing required CI. They relax it only when
that read shows the exact repository-owned queue, and otherwise keep it
strict with a SKIP. A plan still reports the planned installation.

The pilot queue also waited 5 minutes for a minimum group size of 1,
which the first queued pull request already meets, so the wait did
nothing. It is now 0, and validation allows a wait only with a minimum
above one. A new schema test covers the inventory, queue template,
required-CI template and Dependency review constraints. The CONTRIBUTING
paragraph is moved back after the Classic CodeQL example it split.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zoeyrose

Copy link
Copy Markdown
Member Author

Review round 4

  • Reverify the queue before relaxing required CI (bin/publish, P2). Fixed in 0c2dc23. When applying, both scopes re-read the queue immediately before publishing required CI, and relax it only if the exact repository-owned queue is in place. Otherwise required CI stays strict with a SKIP. Plans report the planned installation.
  • Align the wait time with a minimum larger than one (config/rulesets/merge-queue.json, P2). Fixed in 0c2dc23. The wait is now 0 with a minimum of 1, so a single green PR merges at once. Validation allows a wait only with a minimum above one, and a new tests/validate-merge-queue.sh adds schema negative tests.
  • Also in 0c2dc23: the CONTRIBUTING merge-queue paragraph no longer splits the Classic CodeQL example from its sentence.

All 28 tests/*.sh pass, and ShellCheck and git diff --check are clean. I am rerunning the plan and will update the description's payload (wait 0).

🤖 Generated with Claude Code

@zoeyrose

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 0c2dc23938

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@zoeyrose

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 0c2dc23938

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@zoeyrose
zoeyrose marked this pull request as ready for review October 18, 2026 10:02
@zoeyrose zoeyrose self-assigned this Oct 18, 2026
@zoeyrose
zoeyrose merged commit 9e5aa0c into main Oct 18, 2026
9 checks passed
@zoeyrose
zoeyrose deleted the feat/merge-queue-pilot branch October 18, 2026 16:30
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 2.25.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant