merge-steward 0.19.0 → 0.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -347
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,397 +1,99 @@
|
|
|
1
1
|
# merge-steward
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
GitHub pull requests. It admits approved PRs whose required checks are green,
|
|
5
|
-
builds cumulative speculative branches, waits for CI on those exact integrated
|
|
6
|
-
SHAs, and then fast-forwards `main` to the tested result. On failure, it evicts
|
|
7
|
-
with a durable incident record and GitHub check run so an agent or human can
|
|
8
|
-
repair the branch and re-queue it.
|
|
3
|
+
Self-hosted serial merge queue for bot-managed and human-managed GitHub pull requests. Admits approved PRs whose required checks are green, builds speculative branches on top of the latest `main`, waits for CI on those integrated SHAs, and fast-forwards `main` to the tested result.
|
|
9
4
|
|
|
10
|
-
|
|
11
|
-
checks, labels, branches.
|
|
5
|
+
Independent of PatchRelay. Communicates through GitHub only — PRs, reviews, checks, labels, branches. Pairs with `review-quill`; neither requires the other.
|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
## Why this matters
|
|
14
8
|
|
|
15
|
-
-
|
|
9
|
+
PRs delivered through the queue are tested against `main` as it was at admission time, and re-validated if `main` advances during validation. No more "CI was green yesterday, breaks on merge today" — the queue catches the integration bug before `main` ever sees it.
|
|
16
10
|
|
|
17
11
|
## How it works
|
|
18
12
|
|
|
19
|
-
1. A PR becomes eligible when GitHub says it is approved and its required checks are green
|
|
20
|
-
2. The steward notices
|
|
21
|
-
3. It
|
|
22
|
-
4.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
6. If the queue head's speculative SHA is still a fast-forward from current `main`, the steward pushes that exact SHA to `main`
|
|
27
|
-
7. On failure: retry (gated on base SHA change), then evict with a durable incident record and GitHub check run
|
|
28
|
-
8. PatchRelay (or any agent) sees the check run failure and can fix the branch
|
|
29
|
-
9. When the branch is fixed and CI passes again, the PR can be re-admitted
|
|
13
|
+
1. A PR becomes eligible when GitHub says it is approved and its required checks are green.
|
|
14
|
+
2. The steward notices through webhook wakeups or startup reconcile scans, and admits the PR to the queue.
|
|
15
|
+
3. It builds a speculative branch — `main + PR` at the head, cumulative downstream (`main + A + B`, `main + A + B + C`).
|
|
16
|
+
4. CI runs on that speculative SHA.
|
|
17
|
+
5. If the head's speculative SHA is still a fast-forward from current `main`, the steward pushes that SHA to `main`; otherwise it retries.
|
|
18
|
+
6. On CI failure: retry (gated on base SHA change), then evict with a durable incident record and GitHub check run.
|
|
19
|
+
7. PatchRelay, the `ship-pr` skill, or any agent sees the check run failure and fixes the branch; when CI passes again the PR can be re-admitted.
|
|
30
20
|
|
|
31
|
-
##
|
|
21
|
+
## Use with your own agent
|
|
32
22
|
|
|
33
|
-
|
|
23
|
+
For an agent that drives PRs through the queue and reacts to evictions / failing checks without running PatchRelay's full harness, install the [`ship-pr`](https://github.com/krasnoperov/patchrelay-agents) skill from the companion Claude Code marketplace:
|
|
34
24
|
|
|
35
|
-
- Node.js 24+
|
|
36
|
-
- `gh` CLI available in `PATH`
|
|
37
|
-
- `git` binary
|
|
38
|
-
|
|
39
|
-
### Bootstrap
|
|
40
|
-
|
|
41
|
-
Initialize the machine-level steward home once:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
merge-steward init https://queue.example.com
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
That creates:
|
|
48
|
-
|
|
49
|
-
- `~/.config/merge-steward/runtime.env`
|
|
50
|
-
- `~/.config/merge-steward/service.env`
|
|
51
|
-
- `~/.config/merge-steward/merge-steward.json`
|
|
52
|
-
- `~/.config/merge-steward/repos/`
|
|
53
|
-
- `/etc/systemd/system/merge-steward.service`
|
|
54
|
-
|
|
55
|
-
Add one repo-scoped steward instance:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
merge-steward attach owner/repo
|
|
59
25
|
```
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
If you also use `review-quill`, its `review-quill/verdict` check can be added to
|
|
64
|
-
the repository's required checks if you want machine review to be part of the
|
|
65
|
-
merge gate. Steward will naturally follow whatever required checks the repo
|
|
66
|
-
configuration uses, but its primary admission gate is still GitHub's formal
|
|
67
|
-
review state plus those required checks.
|
|
68
|
-
|
|
69
|
-
Validate the setup:
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
merge-steward doctor --repo repo
|
|
73
|
-
merge-steward service status
|
|
74
|
-
merge-steward queue status --repo repo
|
|
26
|
+
/plugin marketplace add krasnoperov/patchrelay-agents
|
|
27
|
+
/plugin install ship-pr@patchrelay
|
|
75
28
|
```
|
|
76
29
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Keep only non-secret identifiers in:
|
|
30
|
+
The skill wraps `merge-steward pr status --wait` and `review-quill pr status --wait` into a blocking-gate workflow with stable exit codes, so the agent only wakes on terminal outcomes.
|
|
80
31
|
|
|
81
|
-
|
|
32
|
+
## Quick start
|
|
82
33
|
|
|
83
|
-
|
|
34
|
+
Prerequisites: Node.js 24+, `gh` CLI in `PATH`, `git`.
|
|
84
35
|
|
|
85
36
|
```bash
|
|
86
|
-
|
|
87
|
-
MERGE_STEWARD_GITHUB_APP_INSTALLATION_ID=12345678
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Store secrets in encrypted systemd credentials:
|
|
91
|
-
|
|
92
|
-
- `/etc/credstore.encrypted/merge-steward-webhook-secret.cred`
|
|
93
|
-
- `/etc/credstore.encrypted/merge-steward-github-app-pem.cred`
|
|
94
|
-
|
|
95
|
-
The running service resolves the webhook secret in this order:
|
|
96
|
-
|
|
97
|
-
1. `$CREDENTIALS_DIRECTORY/<name>`
|
|
98
|
-
2. `${ENV_KEY}_FILE`
|
|
99
|
-
3. `${ENV_KEY}`
|
|
100
|
-
|
|
101
|
-
The running service resolves GitHub auth in this order:
|
|
102
|
-
|
|
103
|
-
1. `MERGE_STEWARD_GITHUB_APP_ID` + `merge-steward-github-app-pem` / `MERGE_STEWARD_GITHUB_APP_PRIVATE_KEY`
|
|
104
|
-
|
|
105
|
-
In practice, use:
|
|
106
|
-
|
|
107
|
-
- `merge-steward-webhook-secret` for validating incoming GitHub webhooks
|
|
108
|
-
- `MERGE_STEWARD_GITHUB_APP_ID` plus `merge-steward-github-app-pem` for production GitHub auth
|
|
109
|
-
- `MERGE_STEWARD_GITHUB_APP_INSTALLATION_ID` if you want to pin a single installation instead of resolving one per repo
|
|
110
|
-
|
|
111
|
-
When GitHub App auth is configured, Merge Steward mints short-lived installation tokens and uses them for both `gh` API calls and `git clone/fetch/push` over HTTPS. In multi-repo setups it resolves the installation per repository, so repos in different GitHub App installations can still coexist.
|
|
112
|
-
|
|
113
|
-
Recommended GitHub App repository permissions:
|
|
114
|
-
|
|
115
|
-
- `Contents: Read and write`
|
|
116
|
-
- `Pull requests: Read and write`
|
|
117
|
-
- `Checks: Read and write`
|
|
118
|
-
- `Metadata: Read-only`
|
|
119
|
-
- `Administration: Read-only`
|
|
120
|
-
|
|
121
|
-
`Contents: Read and write` is the important merge-path permission because the
|
|
122
|
-
steward lands tested speculative SHAs by fast-forward pushing `main`.
|
|
123
|
-
`Administration: Read-only` is not required for merging itself, but it lets the
|
|
124
|
-
doctor and attach/refresh flows discover branch rules and required checks
|
|
125
|
-
without falling back to a local `gh` user token.
|
|
126
|
-
|
|
127
|
-
The machine-level env files created by `merge-steward init` are:
|
|
128
|
-
|
|
129
|
-
- `~/.config/merge-steward/runtime.env`
|
|
130
|
-
- `~/.config/merge-steward/service.env`
|
|
131
|
-
|
|
132
|
-
`runtime.env` is for non-secret runtime settings.
|
|
133
|
-
`service.env` is for non-secret machine-level service config like `MERGE_STEWARD_GITHUB_APP_ID`.
|
|
134
|
-
The CLI is a thin local client and does not need direct access to secret credentials.
|
|
135
|
-
|
|
136
|
-
### Repo Config
|
|
137
|
-
|
|
138
|
-
`merge-steward attach` writes a repo-scoped config like:
|
|
139
|
-
|
|
140
|
-
```json
|
|
141
|
-
{
|
|
142
|
-
"repoId": "app",
|
|
143
|
-
"repoFullName": "owner/repo",
|
|
144
|
-
"baseBranch": "main",
|
|
145
|
-
"clonePath": "~/.local/state/merge-steward/repos/app",
|
|
146
|
-
"maxRetries": 2,
|
|
147
|
-
"flakyRetries": 1,
|
|
148
|
-
"pollIntervalMs": 30000,
|
|
149
|
-
"admissionLabel": "queue",
|
|
150
|
-
"mergeQueueCheckName": "merge-steward/queue",
|
|
151
|
-
"server": {
|
|
152
|
-
"bind": "127.0.0.1",
|
|
153
|
-
"port": 8790
|
|
154
|
-
},
|
|
155
|
-
"database": {
|
|
156
|
-
"path": "~/.local/state/merge-steward/app.sqlite"
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
| Field | Description |
|
|
162
|
-
|-|-|
|
|
163
|
-
| `repoId` | Internal ID for this repo (used in DB keys) |
|
|
164
|
-
| `repoFullName` | GitHub `owner/repo` |
|
|
165
|
-
| `baseBranch` | Target branch for merges (usually `main`) |
|
|
166
|
-
| `clonePath` | Local clone directory (created on first run) |
|
|
167
|
-
| `maxRetries` | Rebase/CI retry attempts before eviction |
|
|
168
|
-
| `flakyRetries` | CI-only retries before counting toward maxRetries |
|
|
169
|
-
| `pollIntervalMs` | Reconciliation loop interval |
|
|
170
|
-
| `admissionLabel` | Optional GitHub label used as a manual/operator admission nudge |
|
|
171
|
-
| `mergeQueueCheckName` | GitHub check run name emitted on eviction |
|
|
172
|
-
|
|
173
|
-
`attach` discovers these values from GitHub when possible:
|
|
174
|
-
|
|
175
|
-
- `repoId` defaults to the repo name portion of `owner/repo`
|
|
176
|
-
- `baseBranch` defaults to the GitHub default branch
|
|
177
|
-
|
|
178
|
-
Pass `--refresh` to re-discover the base branch for an existing repo config. `merge-steward doctor --repo <id>` reports the GitHub-required checks currently enforced for that branch.
|
|
179
|
-
|
|
180
|
-
### GitHub Webhook
|
|
181
|
-
|
|
182
|
-
Configure one webhook on the repository pointing to the steward:
|
|
183
|
-
|
|
184
|
-
- **Payload URL:** `https://queue.example.com/webhooks/github`
|
|
185
|
-
- **Content type:** `application/json`
|
|
186
|
-
- **Secret:** same as `MERGE_STEWARD_WEBHOOK_SECRET` or the `merge-steward-webhook-secret` systemd credential
|
|
187
|
-
- **Events:** Pull requests, Pull request reviews, Check suites, Pushes, Branch protection rules, Repository rulesets
|
|
188
|
-
|
|
189
|
-
The steward uses a single multi-repo webhook endpoint and routes events by `repository.full_name`.
|
|
190
|
-
|
|
191
|
-
It can wake up on:
|
|
192
|
-
|
|
193
|
-
- PR label changes
|
|
194
|
-
- review approvals
|
|
195
|
-
- successful check-suite completion
|
|
196
|
-
- pushes to the base branch
|
|
197
|
-
- branch protection edits
|
|
198
|
-
- repository ruleset edits
|
|
199
|
-
|
|
200
|
-
On startup, the steward reconciles GitHub protection for every attached repo. Policy changes are normally learned from GitHub policy webhooks. If a merge is rejected unexpectedly, the steward performs a guarded one-shot policy refresh to recover from a missed webhook without polling GitHub continuously.
|
|
201
|
-
|
|
202
|
-
The dashboard project view and `merge-steward queue status --repo <id>` also show the live GitHub-required checks and the last policy refresh, so an operator can tell whether a queue pause came from a policy change or from the branch state itself.
|
|
203
|
-
|
|
204
|
-
Current policy decision: Merge Steward uses the same GitHub-required check names for both PR/spec admission and current-`main` drift detection. For example, if branch protection requires `Tests`, the steward treats `Tests` as both the merge gate for candidate commits and the signal that current `main` is still in-policy. This is an explicit simplification for now and may be split into separate merge-gate and main-health signals later.
|
|
205
|
-
|
|
206
|
-
### Running
|
|
207
|
-
|
|
208
|
-
```bash
|
|
209
|
-
# Happy path
|
|
37
|
+
npm install -g merge-steward
|
|
210
38
|
merge-steward init https://queue.example.com
|
|
211
|
-
merge-steward attach owner/repo
|
|
39
|
+
merge-steward attach owner/repo --base-branch main
|
|
212
40
|
merge-steward doctor --repo repo
|
|
213
41
|
merge-steward service status
|
|
214
42
|
merge-steward queue status --repo repo
|
|
215
|
-
merge-steward queue show --repo repo --pr 123
|
|
216
|
-
merge-steward dashboard
|
|
217
|
-
|
|
218
|
-
# Manual foreground start
|
|
219
|
-
merge-steward serve
|
|
220
|
-
|
|
221
|
-
# Open one project directly in the dashboard
|
|
222
|
-
merge-steward dashboard --repo app
|
|
223
43
|
```
|
|
224
44
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
The first screen shows all configured projects with:
|
|
230
|
-
|
|
231
|
-
- project-level queue health
|
|
232
|
-
- readable queue stats
|
|
233
|
-
- a compact queue chain like `#123 ● #124 ○`
|
|
234
|
-
- clear bad states such as blocked, stuck, or needs attention
|
|
235
|
-
- explicit startup states such as `Initializing` and `Init failed` for repo-local boot problems
|
|
236
|
-
|
|
237
|
-
Press `Enter` on a project to open the second screen. That project detail view shows:
|
|
238
|
-
|
|
239
|
-
- the same top-level queue stats for that project
|
|
240
|
-
- a readable list of PRs in the queue
|
|
241
|
-
- recent queue activity in plain language
|
|
242
|
-
- incidents for evicted PRs
|
|
243
|
-
- direct actions like reconcile and dequeue
|
|
244
|
-
- live GitHub-required checks plus the last policy refresh
|
|
245
|
-
|
|
246
|
-
Use `merge-steward dashboard --repo <id>` to open the project detail screen directly. Use `--pr <number>` to preselect a PR when you already know what you need to inspect.
|
|
247
|
-
|
|
248
|
-
Controls:
|
|
45
|
+
- `init` writes config files, a systemd unit, and a generated webhook secret.
|
|
46
|
+
- `attach` discovers the default branch from GitHub and stores a per-repo config.
|
|
47
|
+
- Required checks are learned from GitHub branch protection at runtime — the steward does not keep a local copy.
|
|
249
48
|
|
|
250
|
-
|
|
251
|
-
- `Enter` — open the selected project from overview
|
|
252
|
-
- `Esc` — return to the overview
|
|
253
|
-
- `a` — toggle `active` vs `all` in project view
|
|
254
|
-
- `r` — run a reconcile tick for the selected project
|
|
255
|
-
- `d` — dequeue the selected PR in project view
|
|
256
|
-
- `q` — quit
|
|
49
|
+
Full setup (GitHub App permissions, secrets, webhook events, systemd, HTTP API): [docs/merge-steward.md](../../docs/merge-steward.md).
|
|
257
50
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
The gateway binds its HTTP port before repo initialization finishes. Each repo then initializes independently in the background, so a bad clone or GitHub discovery problem stays local to that repo instead of taking down the whole dashboard.
|
|
261
|
-
|
|
262
|
-
These are the first commands to reach for after setup or when a queue looks wrong:
|
|
51
|
+
## Everyday commands
|
|
263
52
|
|
|
264
53
|
```bash
|
|
265
|
-
merge-steward
|
|
266
|
-
merge-steward
|
|
267
|
-
merge-steward
|
|
268
|
-
merge-steward
|
|
269
|
-
merge-steward
|
|
270
|
-
merge-steward queue status --repo app
|
|
271
|
-
merge-steward queue show --repo app --pr 123
|
|
54
|
+
merge-steward dashboard # operator UI across all projects
|
|
55
|
+
merge-steward pr status # one-PR verdict (inside a git checkout)
|
|
56
|
+
merge-steward queue status --repo <id> # quick text snapshot
|
|
57
|
+
merge-steward queue show --pr <num> # one PR's queue events and incidents
|
|
58
|
+
merge-steward queue reconcile --repo <id> # force one reconcile tick
|
|
272
59
|
merge-steward service logs --lines 100
|
|
273
60
|
```
|
|
274
61
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
- `doctor` checks config, GitHub auth, branch rules, and required checks.
|
|
278
|
-
- `dashboard` is the best live operator view across all configured projects.
|
|
279
|
-
- `pr status` gives a single agent-friendly verdict on one PR (queue entry when it exists, GitHub state otherwise) with a stable exit code so scripts can chain with `&&`. Supports `--wait` to poll until a terminal state is reached.
|
|
280
|
-
- `queue status` is the fastest text snapshot when you need one repo in a shell script or over SSH.
|
|
281
|
-
- `queue show --pr <number>` is the most direct way to inspect one PR's queue events and incidents.
|
|
282
|
-
- `service logs` helps when the queue is not reacting to webhooks, GitHub auth is failing, or reconcile ticks are erroring.
|
|
283
|
-
|
|
284
|
-
### Resolving --repo and --pr from the current checkout
|
|
285
|
-
|
|
286
|
-
`pr status`, `queue status`, `queue show`, and `queue reconcile` accept `--repo` and `--pr` but you can omit them when running from inside a git checkout. `merge-steward` reads `origin`'s remote URL, matches it to an attached repoId, and uses `gh pr view` to find the PR for the current branch. Pass `--cwd <path>` to resolve from a different directory.
|
|
62
|
+
`pr status`, `queue status`, `queue show`, and `queue reconcile` auto-resolve `--repo` and `--pr` from the current git checkout. `pr status` supports `--wait --timeout <s> --poll <s>` for blocking until a terminal state. Exit codes:
|
|
287
63
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
| code | meaning |
|
|
64
|
+
| Code | Meaning |
|
|
291
65
|
|-|-|
|
|
292
66
|
| 0 | merged / approved with green required checks |
|
|
293
67
|
| 2 | changes_requested / failing required checks / evicted / closed |
|
|
294
68
|
| 3 | still in flight (queued, preparing, validating, merging, pending) |
|
|
295
|
-
| 4 | `--wait` timed out
|
|
69
|
+
| 4 | `--wait` timed out |
|
|
296
70
|
| 1 | usage or configuration error |
|
|
297
71
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
```ini
|
|
301
|
-
[Unit]
|
|
302
|
-
Description=merge-steward
|
|
303
|
-
After=network-online.target
|
|
304
|
-
Wants=network-online.target
|
|
305
|
-
|
|
306
|
-
[Service]
|
|
307
|
-
Type=simple
|
|
308
|
-
EnvironmentFile=-/home/your-user/.config/merge-steward/runtime.env
|
|
309
|
-
EnvironmentFile=-/home/your-user/.config/merge-steward/service.env
|
|
310
|
-
LoadCredentialEncrypted=merge-steward-webhook-secret:/etc/credstore.encrypted/merge-steward-webhook-secret.cred
|
|
311
|
-
LoadCredentialEncrypted=merge-steward-github-app-pem:/etc/credstore.encrypted/merge-steward-github-app-pem.cred
|
|
312
|
-
ExecStart=/usr/bin/env merge-steward serve
|
|
313
|
-
Restart=on-failure
|
|
314
|
-
RestartSec=5s
|
|
315
|
-
|
|
316
|
-
[Install]
|
|
317
|
-
WantedBy=multi-user.target
|
|
318
|
-
```
|
|
72
|
+
## Merge gate
|
|
319
73
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
| Endpoint | Method | Description |
|
|
323
|
-
|-|-|-|
|
|
324
|
-
| `/health` | GET | Liveness check |
|
|
325
|
-
| `/repos/:repoId/queue/status` | GET | All queue entries for one configured repo |
|
|
326
|
-
| `/repos/:repoId/queue/watch` | GET | Queue snapshot used by the dashboard |
|
|
327
|
-
| `/repos/:repoId/queue/enqueue` | POST | Manually enqueue a PR |
|
|
328
|
-
| `/repos/:repoId/queue/reconcile` | POST | Trigger one reconcile tick immediately |
|
|
329
|
-
| `/repos/:repoId/queue/entries/:id/detail` | GET | Entry detail with recent events and incidents |
|
|
330
|
-
| `/repos/:repoId/queue/entries/:id/dequeue` | POST | Remove from queue (non-destructive) |
|
|
331
|
-
| `/repos/:repoId/queue/entries/:id/update-head` | POST | Update head SHA (force-push) |
|
|
332
|
-
| `/repos/:repoId/queue/incidents/:id` | GET | Get incident details |
|
|
333
|
-
| `/repos/:repoId/queue/entries/:id/incidents` | GET | List incidents for an entry |
|
|
334
|
-
| `/webhooks/github` | POST | GitHub webhook receiver for all configured repos |
|
|
335
|
-
|
|
336
|
-
## Queue state machine
|
|
337
|
-
|
|
338
|
-
```
|
|
339
|
-
queued → preparing_head → validating → merging → merged
|
|
340
|
-
→ evicted (on failure after retries)
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
- **queued**: waiting in line
|
|
344
|
-
- **preparing_head**: fetching + rebasing onto base branch
|
|
345
|
-
- **validating**: CI running
|
|
346
|
-
- **merging**: revalidation + merge
|
|
347
|
-
- **merged**: done
|
|
348
|
-
- **evicted**: failed after retry budget, incident created
|
|
349
|
-
- **dequeued**: manually removed
|
|
350
|
-
|
|
351
|
-
## Merge Gate
|
|
352
|
-
|
|
353
|
-
For the steward path, the real gate is:
|
|
74
|
+
The real gate is:
|
|
354
75
|
|
|
355
76
|
- GitHub says the PR review state is approved
|
|
356
|
-
-
|
|
77
|
+
- configured required checks are green
|
|
357
78
|
- the steward's speculative integrated branch also passes CI
|
|
358
79
|
|
|
359
|
-
`review-quill/verdict` only matters if you
|
|
360
|
-
required checks.
|
|
361
|
-
|
|
362
|
-
GitHub branch protection is still useful as defense in depth, but steward does
|
|
363
|
-
not merge by pressing GitHub's merge button. It fast-forwards `main` to the
|
|
364
|
-
already-tested speculative SHA, so successful queue merges also depend on the
|
|
365
|
-
steward App being allowed to push that result to the protected branch.
|
|
80
|
+
`review-quill/verdict` only matters if you include it in the repo's required checks. Branch protection is useful as defense in depth, but the steward merges by fast-forwarding `main` to the already-tested speculative SHA — not by pressing GitHub's merge button. Successful merges therefore depend on the steward App being allowed to push to the protected branch. See [docs/merge-steward.md](../../docs/merge-steward.md) for the full App permission set.
|
|
366
81
|
|
|
367
82
|
## Interaction with PatchRelay
|
|
368
83
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
- PatchRelay adds the `queue` label when an issue reaches `awaiting_queue`
|
|
372
|
-
- The steward merges the PR or evicts it (creating the configured queue eviction check run, default `merge-steward/queue`)
|
|
373
|
-
- PatchRelay watches for that check run failure and triggers `queue_repair`
|
|
374
|
-
- After repair, PatchRelay re-adds the `queue` label
|
|
375
|
-
- The steward re-admits the PR
|
|
84
|
+
Independent services, GitHub as the shared bus:
|
|
376
85
|
|
|
377
|
-
|
|
86
|
+
1. PatchRelay adds the `queue` label when an issue reaches `awaiting_queue`.
|
|
87
|
+
2. The steward merges the PR, or evicts and creates the eviction check run (default `merge-steward/queue`).
|
|
88
|
+
3. PatchRelay watches for that check run failure and triggers `queue_repair`.
|
|
89
|
+
4. After repair, PatchRelay re-adds the `queue` label; the steward re-admits.
|
|
378
90
|
|
|
379
|
-
|
|
91
|
+
Neither service calls the other's API.
|
|
380
92
|
|
|
381
|
-
|
|
382
|
-
- **Speculative execution**: cumulative branches (`main+A`, `main+A+B`, `main+A+B+C`) tested in parallel. Configurable depth (default 10, set `speculativeDepth: 1` for serial mode).
|
|
383
|
-
- **Speculative consistency**: when head merges, downstream entries that already passed don't re-test.
|
|
384
|
-
- **Cascade invalidation**: when mid-chain entry fails, downstream speculative branches are rebuilt without it.
|
|
385
|
-
- Non-spinning conflict retry: gated on base SHA change
|
|
386
|
-
- Flaky CI retry budget (separate from retry budget)
|
|
387
|
-
- Revalidation before merge (approval, SHA, external merge)
|
|
388
|
-
- Durable incident records on eviction
|
|
389
|
-
- GitHub check run as eviction signal
|
|
390
|
-
- Label-based admission and re-admission
|
|
391
|
-
- Structured reconciler event stream for observability
|
|
93
|
+
## Reference
|
|
392
94
|
|
|
393
|
-
|
|
394
|
-
-
|
|
395
|
-
-
|
|
396
|
-
-
|
|
397
|
-
-
|
|
95
|
+
- [docs/merge-steward.md](../../docs/merge-steward.md) — operator reference: GitHub App permissions, secrets, webhook, repo config, full CLI, HTTP API, queue state machine, systemd, troubleshooting
|
|
96
|
+
- [docs/merge-queue.md](../../docs/merge-queue.md) — the two-service delivery story
|
|
97
|
+
- [docs/github-queue-contract.md](../../docs/github-queue-contract.md) — shared GitHub artifacts
|
|
98
|
+
- [docs/design-docs/merge-steward.md](../../docs/design-docs/merge-steward.md) — design rationale
|
|
99
|
+
- [../../README.md](../../README.md) — the three-service stack overview
|