Skip to content

feat(meta): CTL-2266 — Mergify merge queue config + labels for catalyst - #4079

Merged
ryanrozich merged 3 commits into
mainfrom
CTL-2266
Aug 28, 2026
Merged

feat(meta): CTL-2266 — Mergify merge queue config + labels for catalyst#4079
ryanrozich merged 3 commits into
mainfrom
CTL-2266

Conversation

@ryanrozich

Copy link
Copy Markdown
Contributor

Summary

Phases 2–3 of the CTL-2266 plan — extends the catalyst-cloud Mergify merge-queue trial to coalesce-labs/catalyst. Phase 1 (the monotonic version guard) already merged as #4077, so AC2's silent version-collision case is already covered by check-versions on main — this PR does not touch that logic again.

  • Phase 2queue:ready and hold:hand-steps labels created on the repo (colors/descriptions match the catalyst-cloud trial); AGENTS.md documents queue-merge as the PR default once activated.
  • Phase 3.mergify.yml, validated and simulated against real open PRs below.

This PR does not activate the queue and is not merged by the queue itself (it touches .mergify.yml, which the config's own path exclusion routes to hand-merge). The coordinator merges this by hand, then runs the live @Mergifyio probe per plan Phase 4 — Ryan has already activated the repo in the Mergify dashboard.

One deliberate deviation from the plan: max_parallel_checks: 3

The plan as researched specified max_parallel_checks: 1 (in-place checks, matching the catalyst-cloud shape). Per Ryan's direction from today's catalyst-cloud experience, this PR ships with max_parallel_checks: 3 instead.

Measured caveat, not fixed by this PR: gh api repos/coalesce-labs/catalyst/rulesets/13503799 still reports the "main branch protection" ruleset's required_status_checks.strict_required_status_checks_policy: true (verbatim, re-checked just before opening this PR). Mergify computes allow_inplace_checks automatically, and only enables it when max_parallel_checks == 1 + batch_size == 1 + merge_conditions == queue_conditions for every queue — setting max_parallel_checks: 3 opts OUT of in-place checks, so Mergify will run CI on temporary merge-queue branches instead of pushing update commits onto the PR branch. Separately, with strict_required_status_checks_policy: true, each queued PR's required checks are only valid against the exact current main, so real parallel throughput still needs that ruleset setting turned off — otherwise batches serialize behind rebase-and-recheck regardless of the configured slot count.

I have not touched branch protection — that's explicitly out of scope for me per the dispatch instructions; it's a call for Ryan. The config comments in .mergify.yml spell this out inline so it isn't only in this PR description.

Validation

mergify config validate

$ mergify config validate -f .mergify.yml
Fetching schema from https://docs.mergify.com…
Configuration file '.mergify.yml' is valid.

mergify config simulate — real open PRs, both polarities

#4070 (CTL-2240, Ryan's own PR, all required + non-required checks green) — real state, no queue:ready label:

### Rule: enqueue when a lane marks a PR ready (queue)
- [ ] `label=queue:ready`
- [ ] any of: [🔀 queue conditions]
  - [ ] all of: [📌 queue conditions of queue rule `default`]
    - [ ] `#review-threads-unresolved = 0` [🛡 GitHub repository ruleset rule `main branch protection`]
    ...
    - [X] `-check-failure=quality`
    - [X] `-draft`
    - [X] `-files~=^\.github/workflows/publish-`
    - [X] `-files~=^\.mergify\.yml$`
    - [X] `-files~=^plugins/dev/scripts/db-migrations/`
    - [X] `-head~=^release-please--`
    - [X] `base=main`
    - [X] all six required checks (success/neutral/skipped)
    - [X] all three non-required always-on gates

Every guard is TRUE except the label — as expected for an unlabeled PR. While testing this (toggling queue:ready on and off on #4070 to get the positive-polarity read, see below), I discovered #4070 genuinely has unresolved Codex P1 review threads right now (#review-threads-unresolved = 0 reads [ ] false) — real, not caused by my testing. That's a live negative-polarity data point for that specific condition, not a config defect: the guard correctly refuses to admit a PR with unresolved review threads. Ryan/coordinator: #4070 is not actually queue:ready-eligible today for that reason, independent of this PR.

#4066 (dependabot/bun/eslint-10.9.1) — I temporarily applied queue:ready (removed immediately after, confirmed back to ["dependencies","javascript"]), to get the positive polarity on a real PR:

$ mergify config simulate -f .mergify.yml https://github.com/coalesce-labs/catalyst/pull/4066
1 rule matches

### ✅ Rule: enqueue when a lane marks a PR ready (queue)
- [X] `-closed` [📌 queue requirement]
- [X] `-conflict` [📌 queue requirement]
- [X] `-draft` [📌 queue requirement]
- [X] `base=main`
- [X] `label=queue:ready`
- [X] any of: [🔀 queue conditions]
  - [X] all of: [📌 queue conditions of queue rule `default`]
    - [X] `#review-threads-unresolved = 0` [🛡 GitHub repository ruleset rule `main branch protection`]
    - [X] all path exclusions, all six required checks, all three non-required gates, all TRUE

Full green — this dependabot PR would actually enter the queue with the label applied. This is the genuine positive control the plan's Phase 3 step 3 asks for (not a list of ticks on a PR that was never going to queue).

#4028 (release-please--branches--main) — real state, read-only, no label change — negative control for the outward-facing exclusion:

- [ ] `-head~=^release-please--`

Confirms the head-branch regex correctly refuses a real release-please PR (this repo has one live right now, since CTL-2263 reinstated release-please — landed on main between this branch's original cut and this rebase; the -head~=^release-please-- exclusion already covers it, no config change needed, matching the plan's "correct under both futures" claim in decision 3).

Required-check population, re-confirmed live

gh api .../commits/<sha>/check-runs on both #4070 and #4066 shows all six ruleset-required contexts plus packaging-gate, skills-gate, check-plugin-manifest-parity, and quality present and green on both — consistent with the plan's check-population table.

What's not in this PR

  • Queue activation (Ryan's one Mergify-dashboard click, plan Phase 4).
  • The first end-to-end live merge and post-merge trigger verification (Phase 4, after activation).
  • Negative-control drills (Phase 5) — path-exclusion refusal, hold:hand-steps refusal, pause behavior — run live after activation.
  • Any change to branch-protection / the ruleset's strict_required_status_checks_policy — that's Ryan's call, not made here.

Linear

CTL-2266 → In Review.

queue:ready is the review attestation (CTC-1200); hold:hand-steps is the
escape hatch. Both labels created on coalesce-labs/catalyst via the API
(colors/descriptions match the catalyst-cloud trial).
Extends the catalyst-cloud merge-queue trial (CTC-1196) to coalesce-labs/catalyst.
Mirrors the ruleset's own skip-tolerant check shape (success|neutral|skipped) for
the six required contexts plus the three always-on non-required gates, excludes
quality via the negative -check-failure form (it is path-filtered and often
absent), and excludes publish-* workflows, db-migrations, .mergify.yml itself,
and release-please branches from unattended merge.

max_parallel_checks: 3 per Ryan's direction — the live ruleset still has
strict_required_status_checks_policy: true, so real parallel throughput needs
that turned off separately (not done here; see the PR description).

Validated: `mergify config validate` clean; `mergify config simulate` against
#4070 and dependabot #4066 in both polarities, plus #4028 (release-please) as
a real negative control for the head-branch exclusion.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 28, 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-08-28T22:09:41.494447Z c7003e0 PR opened
ℹ️ 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.

@mergify

mergify Bot commented Aug 28, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@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: c7003e00d5

ℹ️ 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 .mergify.yml
… pending

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ryanrozich
ryanrozich merged commit 3c6cba4 into main Aug 28, 2026
17 checks passed
@ryanrozich
ryanrozich deleted the CTL-2266 branch August 28, 2026 22:19
ryanrozich added a commit that referenced this pull request Aug 29, 2026
…platform-enforced (#4089)

## Summary

Adds `merge_protections` rules to `.mergify.yml`, extending the
catalyst-cloud config-as-code adoption ([Mergify feature-suite
evaluation](https://github.com/coalesce-labs/catalyst-cloud/blob/main/thoughts/shared/research/2026-08-28-mergify-feature-suite-evaluation.md),
"Merge Protections rules — ADOPT NOW") to this repo: two checks that
hold even for a PR merged **by hand**, outside the Mergify queue.

1. **No unresolved review threads before merge** —
`#review-threads-unresolved=0`, active on every non-draft PR against
`main`.
2. **Title follows the Conventional-Commit convention** — `type(scope):
...`, active on every non-draft PR against `main` except automation:
`dependabot[bot]`, Mergify's own queue-train/dashboard-config branches
(`head~=^mergify/`), and release-please (`head~=^release-please--` — it
opens PRs under a human GitHub identity in this repo, not a bot login,
so it can't be author-exempted).

**This does not touch `queue_rules`/`pull_request_rules`.** The
auto-queue rule CTC-1231 also asks for (`label=queue:ready` +
`#review-threads-unresolved=0` + the required-check set → `queue`)
already shipped today via CTL-2266 (#4079) — re-checked, unchanged,
still correct.

**Not required yet.** A failing active `merge_protections` rule surfaces
as a non-required `Mergify Merge Protections` check — this PR does not
mark it required in the `main branch protection` ruleset, so nothing is
newly blocking. That flip is Ryan's call, same restraint #4079 took with
branch protection.

**Note on `.mergify.yml`'s own path exclusion:** this repo's
`queue_conditions`/`merge_conditions` already hard-exclude
`-files~=^\.mergify\.yml$`, so this PR (and any future `.mergify.yml`
change) can never enter the queue regardless of labeling — hand-merge
only, by design, already in place before this PR.

Explicitly **not** in this PR (per the sibling catalyst-cloud evaluation
and the dispatch instructions): CI Insights auto-retry, any Test
Insights config.

## Validation

### `mergify config validate`

```
$ mergify config validate -f .mergify.yml
Fetching schema from https://docs.mergify.com…
Configuration file '.mergify.yml' is valid.
```

### `mergify config simulate` — scope limitation, documented

`mergify config simulate <PR_URL>` only previews
`pull_request_rules`/`queue_rules` evaluation. Ran it against #4066
(real Dependabot PR) to confirm the pre-existing queue rule is
unaffected by this diff — it evaluated correctly (all conditions still
resolve as before). It never surfaced the new `merge_protections` rules
on any PR — that's a CLI/product scope limit (I found no documented way
to preview `merge_protections` outside the dashboard), not a config
defect.

In place of `simulate` for the new rules, I verified both directly:

- **Review-threads condition** — the exact same
`#review-threads-unresolved=0` attribute the existing `queue_conditions`
already gates on; unchanged in this diff, and I didn't need to re-derive
its correctness.
- **Title regex** — scripted the exact YAML-parsed pattern against real
titles pulled from `gh pr list` history for this repo, both polarities:
- **Match:** `feat(meta): CTL-2266 — ...`, `perf(ci): CTC-1229 — ...`,
`ci(runner-image): CTC-1228 — ...`, `chore(deps): Bump ...`
(Dependabot), `ci: Bump actions/checkout from 4 to 7` (Dependabot, no
scope), `chore: release main` (release-please).
- **No-match, correctly flagged:** `CTC-746: A ticket's agent session
should still show its plan after th` (a real, old, merged PR using a
pre-convention title shape — historical, not currently open, so nothing
bricks).

## Local gate

No unified `bun run check`-equivalent here; ran `mergify config
validate` (pass) and `make lint`/`make test` locally. `make lint`'s
`trunk check` currently fails on a pre-existing `fmt`/prettier
formatting complaint about `.mergify.yml` — **reproduced identically
against the unmodified `origin/main` copy of the same file**, so it
predates this PR and isn't something this diff introduced or should fix
(touching those pre-existing lines was explicitly avoided to keep the
live, already-proven queue config untouched). `make test` surfaced one
unrelated pre-existing failure (`catalyst-config.test.sh`, a
config-fingerprint test with no relation to `.mergify.yml`) before my
own `timeout 180` truncated the (very large) suite; nothing in this diff
touches that test or its dependencies.

## Linear

CTC-1231 stays in Implement — dispatched with `--phase implement`; not
moving it to In Review myself per the dispatch instructions (report
only, don't merge).

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant