Skip to content

Commit

The docs say how the merge queue blames a failure: a state is held while entries ahead of it are still being tested, smaller combinations narrow down which entries ahead a change breaks with within three builds, who is told and with what (the timeline, the issue, the session, an integration_failure decision and integration.failed), and that a fixed pull request rejoins the queue by itself once its checks pass. Sessions and why-blame gains decision records (their kinds and confidences, what g1t records itself, record_decision and list_decisions) and why over the API; the webhooks guide lists integration.failed, integration.passed and decision.recorded; the MCP reference, bring your own agent and llms.txt name the new actions.

syntaqxcommitted Parentc9e737fBrowse files
6 files+192−130/6 viewed
+10−0
107107 into the fork and push. The pull request can then be merged, or joins the
108108 [merge queue](/guides/merge-queue/) when the repository uses one.
109109
110+When the merge queue takes an agent's pull request out because it fails
111+combined with the pull requests ahead of it, g1t
112+[says which ones and which check failed](/guides/merge-queue/#who-is-told):
113+in the pull request's session, as an `integration_failure` decision
114+(`pull_request` `list_decisions`), and as the `integration.failed` event.
115+The agent reads the other pull request's changes, fixes its own, and
116+pushes; once the checks pass, the pull request rejoins the queue by
117+itself. It can say what it changed with `pull_request` `record_decision`
118+(`kind` `fix`), and `repository` `why` explains any line it is unsure of.
119+
110120 ### Repository instructions
111121
112122 Each agent reads a repository's instructions from a file at its root:
+86−10
134134 An entry fails when its `merge_group` workflows or required checks fail
135135 on the combined state, when it does not merge cleanly with what is ahead of it, or
136136 when the state cannot be built.
137−It leaves the queue, and:
138137
139−1. Its pull request records the failure, saying why: which workflow failed
140− on the state, which required check did not report, or, for a conflict,
141− the pull request ahead it collided with and the files.
142−2. Its conversation records that it was taken out of the queue, and why: a
143− conflict links the pull request it collided with and each conflicting
144− file, which opens in the pull request's changes.
145−3. The entries that were tested on top of it are tested again without it.
138+### Who answers for it
139+
140+A state that fails while an entry ahead of it is still being tested is
141+held until those ahead are settled. If one of them fails too, the held
142+entry is tested again without it and is not blamed. Once every entry ahead
143+has passed, the held entry answers for the failure. So when #41 is
144+broken, it leaves the queue, and #44 and #46, which were tested with #41
145+in them, are tested again without it rather than taken out with it.
146+
147+The entry that answers for a failure leaves the queue, and g1t works out
148+what it failed with:
149+
150+| What happened | Who it failed with (`suspects`) |
151+| --- | --- |
152+| Tested on `main` alone | Nobody: the change is the cause. |
153+| Its own checks fail on its head too | Nobody: the change is the cause. |
154+| It conflicts with an entry ahead | That entry, and the conflicting files. |
155+| A required check did not report, or the state could not be built | Nobody: the note says what to fix. |
156+| Its own checks pass, one entry ahead | That entry. |
157+| Its own checks pass, several entries ahead | Found by building smaller combinations, below. |
158+
159+### Narrowing it down
160+
161+An entry whose own checks pass but which fails combined with several
162+entries ahead breaks *with* some of them. g1t builds `main` with the first
163+half of those entries and the failing one, and runs the `merge_group`
164+workflows on it, as for any queued state. If that fails, the cause is in
165+that half; if it passes, in the other half. It halves again until one entry
166+is left, or it has built three extra combinations. With the default four
167+entries to a batch, at most three are ahead of a failing entry, and two
168+builds always find the one it breaks with; three builds find one among up
169+to eight.
170+
171+These combinations are built in sandboxes as the queue's states are, on
172+`g1t-queue/<id>` branches that are deleted afterwards, and never land. They
173+do not hold up the queue: the entries behind are tested again at once. When
174+a combination cannot be built or checked, or its checks are still running
175+past the rule's timeout when the queue next moves, g1t stops and reports
176+the entries still suspected.
177+
178+The halving assumes one entry ahead is the cause. When the failure needs
179+two of them together, what is reported is the half that still failed, and
180+can name more than one pull request.
181+
182+### Who is told
183+
184+1. Its pull request records the failed check, saying why: which workflow
185+ failed on the state, which required check did not report, or, for a
186+ conflict, the pull request ahead it collided with and the files.
187+2. Its conversation records that it was taken out of the queue, then what
188+ g1t found: the pull requests it fails with, whether that was narrowed
189+ down, and the check that failed.
190+3. Its issue's conversation says the same in one line, and so does the
191+ pull request's [session](/guides/why-blame/#sessions), so the agent
192+ working on it reads it there.
193+4. A [decision record](/guides/why-blame/#decision-records) of kind
194+ `integration_failure`, confidence `tested`, keeps it, with the
195+ combination, the check and the suspects as evidence.
196+5. The `integration.failed` [event](/guides/webhooks/#events) carries the
197+ same to webhooks and to anyone following the repository's events:
198+ `pull` (the entry that failed, also `number`), `issue`, `combination`
199+ (the pull requests tested together, in order), `check` (`name`,
200+ `conclusion`, `url`), `bisected`, `suspects`, `other_pulls` and `commit`.
201+6. The entries that were tested on top of it are tested again without it.
202+
203+A combined state that passes is recorded too: an `integration_passed`
204+decision and the `integration.passed` event, with `pull` and `combination`.
205+
206+### Getting back in the queue
207+
208+The merge stays asked for. Push a fix to the pull request, starting from
209+`main` as it is now: once every check on the new commit has finished, none
210+failed and every required check passed, g1t merges it again as whoever
211+queued it, which puts it back in the queue. Everything a merge needs is
212+checked again then, so if an approval was dismissed by the push, the
213+conversation says so and you merge it again once it is approved. Until a
214+new commit's checks pass, merging it again is refused: "It failed in the
215+merge queue; push a fix to try again."
146216
147−Its author fixes it, starting from `main` as it is now, and merges it
148−again to put it back in the queue.
217+A pull request whose checks are not reported by workflows (none run on its
218+pushes) is not put back by itself: merge it again once it is fixed.
149219
150220 ## The Merge queue page
151221
209279 | `results` | What building the state recorded, each with `command`, `passed` and `output`. The workflow runs on it are on its commit, `combined_commit`. |
210280 | `error` | Why it failed: a conflict, a workflow that failed on it, a required check that did not report, or what could not be built. |
211281 | `enqueued_by` | Who added it: a username, or `g1t` when it was merged automatically. |
282+
283+An agent working on a pull request learns of a failure without polling the
284+queue: from the `integration.failed` event, from the note in the pull
285+request's session (`pull_request` `read_session`), or from its decisions
286+(`pull_request` `list_decisions`, or
287+`GET /repos/{owner}/{name}/pulls/{number}/decisions`).
+4−1
111111 | `deployment_status.created` | A deployment got a status, from any source. `data.repo_id`, `data.deployment` without its `payload`, and `data.deployment_status`. |
112112 | `release.created`, `.published`, `.released`, `.prereleased`, `.edited`, `.unpublished`, `.deleted` | A [release](/guides/releases/) changed; one change can send several, as the [release activity types](/guides/actions/#releases) say. `data.release_id`, `data.tag_name`, and `data.release` (`tag_name`, `target`, `name`, `body`, `draft`, `prerelease`, `author`, `created_at`, `published_at`), as it was for `release.deleted`. On `release.edited`, `data.changes` holds the old `name` and `body`. |
113113 | `queue.changed` | The merge queue gained, lost or settled an entry. |
114−| `session.appended` | A pull request's [session](/guides/why-blame/#sessions) grew: a coding agent recorded entries with `record_session`. Busy: choose it only if you need it. |
114+| `integration.failed` | A pull request failed in the [merge queue](/guides/merge-queue/#when-an-entry-fails) combined with the ones ahead of it. `pull` (also `number`) is the one that answers for it, `issue` its issue, `combination` the pull requests tested together, `check` the check that failed (`name`, `conclusion`, `url`), `suspects` the pull requests ahead it fails with, `bisected` whether smaller combinations were built to find them, and `other_pulls` the rest of the combination. |
115+| `integration.passed` | A pull request's combined state passed in the merge queue: `pull` and `combination`. |
116+| `decision.recorded` | A [decision record](/guides/why-blame/#decision-records) was kept on an issue or pull request: `decision`, with `number` and `issue`. |
117+| `session.appended` | A pull request's [session](/guides/why-blame/#sessions) grew: a coding agent recorded entries with `record_session`, or g1t noted a merge queue failure. Busy: choose it only if you need it. |
115118
116119 [Managing a repository](/guides/managing-repositories/) says what each of
117120 the `repo.` and `branch.` changes does.
+73−0
8686 request when it caught up with `main` is credited to whoever wrote it on
8787 `main`, not to the merge.
8888
89+### Why over the API
90+
91+The `repository` tool's `why` action, or
92+`GET /repos/{owner}/{name}/why?path=&line=&ref=`, answers the same for one
93+line, with the decision records too. `ref` is a branch, tag or commit; the
94+default branch when left out.
95+
96+```sh
97+curl "https://api.g1t.sh/repos/acme/web/why?path=src/config.rs&line=42" \
98+ -H "Authorization: Bearer $G1T_TOKEN"
99+```
100+
101+| Field | |
102+| --- | --- |
103+| `commit` | The commit that last changed the line: `hash`, `message`, `author`, `parents`, `authored_at`. |
104+| `pull` | The merged pull request it arrived in: `number`, `title`, `author`, `agent`, `merged_by`, `merged_at`. Absent when it did not arrive through one. |
105+| `issue` | That pull request's issue: `number`, `title`, `state` and `body` (cut at 900 characters). |
106+| `decisions` | The [decision records](#decision-records) on the pull request, oldest first. |
107+| `sessions` | Up to eight entries of the pull request's session behind that commit: the messages, and the tool calls that touched the file. |
108+
109+A pull request is found for a commit as on the site: the one whose head it
110+is, or the one whose stretch of the default branch's last 300 commits holds
111+it. It is public for a public repository, and needs the `code:read` scope
112+otherwise.
113+
114+## Decision records
115+
116+A decision record is a reason kept on an issue or pull request, with how
117+sure it is. Sessions say what happened; decisions say why the result is
118+the way it is, in a sentence, with what it rests on.
119+
120+| Confidence | Meaning |
121+| --- | --- |
122+| `claimed` | Someone said so: an agent or a person recorded it. |
123+| `tested` | A check or the merge queue proved it. |
124+| `approved` | A person approved it. |
125+
126+g1t keeps these itself:
127+
128+| Kind | When | Confidence |
129+| --- | --- | --- |
130+| `integration_failure` | The [merge queue](/guides/merge-queue/#when-an-entry-fails) found a combination of pull requests fails: which ones, and the check. | `tested` |
131+| `integration_passed` | A combined state passed in the merge queue. | `tested` |
132+| `approval` | Someone approved the pull request. | `approved` for a person, `claimed` for an agent's token |
133+| `merge` | It was merged. | `tested` through the queue or a repository's own auto-merge, `approved` when a person merged it, `claimed` for an agent's token |
134+
135+Agents and people record their own, of kind `proposal` (why the change is
136+made this way), `claim` (something true of it), `fix` (what fixed a
137+failure) or `note`, always as `claimed`, with the `pull_request` tool's
138+`record_decision` action or
139+`POST /repos/{owner}/{name}/pulls/{number}/decisions`:
140+
141+```sh
142+curl -X POST https://api.g1t.sh/repos/acme/web/pulls/14/decisions \
143+ -H "Authorization: Bearer $G1T_TOKEN" \
144+ -H "Content-Type: application/json" \
145+ -d '{"kind": "fix",
146+ "summary": "Renamed the config key #12 also introduced, so both read retry_limit.",
147+ "evidence": {"commit": "7d3e9a1c"}}'
148+```
149+
150+`summary` is at most 2,000 characters and `evidence` an object of at most
151+8 KB. Whoever opened the pull request can record one, and so can anyone
152+who may comment on it, once their email address is confirmed. Each is
153+attributed to whoever recorded it, carries
154+the issue the pull request is for, and is published as `decision.recorded`.
155+
156+Read them with the `pull_request` tool's `list_decisions` action, with
157+`GET /repos/{owner}/{name}/pulls/{number}/decisions`, or for an issue and
158+all its pull requests with
159+`GET /repos/{owner}/{name}/issues/{number}/decisions`. A decision is as
160+visible as the repository, so do not put secrets in one.
161+
89162 ## Commit pages
90163
91164 Every commit has a page of its own, `g1t.sh/<workspace>/<repo>/commit/<hash>`,
+6−1
300300 | [`security_alerts`](/reference/api/security/list-security-alerts/) | Its security alerts: secrets found in pushes and history (`kind` `secret`) and dependencies with known vulnerabilities (`dependency`), each `open`, `dismissed` or `fixed`. `state` and `kind` filter them. Write role. | `repo` | `repo:read` |
301301 | [`dismiss_alert`](/reference/api/security/dismiss-security-alert/) | Dismiss one by `id` with a `reason` and an optional `comment`. A secret takes `false_positive`, `used_in_tests`, `revoked` or `wont_fix`, and needs the Admin role, since a dismissed secret is let through push protection; a dependency takes `fix_started`, `no_bandwidth`, `tolerable_risk`, `inaccurate` or `not_used`, and needs Write. | `repo`, `id`, `reason` | `repo:admin` |
302302 | [`reopen_alert`](/reference/api/security/reopen-security-alert/) | Open a dismissed alert again. The same roles as dismissing. | `repo`, `id` | `repo:admin` |
303+| [`why`](/reference/api/decisions-and-why/why/) | Why a line is the way it is: the `commit` that last changed `line` of `path` (at `ref`, or the default branch), the merged `pull` request it arrived in, its `issue`, the `decisions` recorded on the pull request, and the `sessions` entries behind the commit. | `repo`, `path`, `line` | `code:read` |
303304
304305 `update_settings` takes `required_checks` (at most 20 names),
305306 `required_approvals`, `allow_ignoring_checks`, `require_up_to_date`,
351352 | [`update`](/reference/api/pull-requests/update-pull-request/) | Change its `base` (the branch it merges into; Write role), `labels`, `milestone`, `assignees` or `reviewers`. `state` `open` reopens it and `closed` closes it. | `repo`, `number` | `pull_requests:write` |
352353 | [`record_session`](/reference/api/sessions/record-session/) | Append entries to a pull request's session. Each has `kind` and `text`, and `tool` for tool entries. | `repo`, `number`, `entries` | `pull_requests:write` |
353354 | [`read_session`](/reference/api/sessions/read-session/) | The recorded session, oldest first. `after` skips to entries after a sequence number. | `repo`, `number` | `pull_requests:read` |
355+| [`record_decision`](/reference/api/decisions-and-why/record-decision/) | Record a decision on a pull request, kept as `claimed`: a `kind` (`proposal`, `claim`, `fix` or `note`), a `summary`, and optional `evidence` (an object) and `session_id`. | `repo`, `number`, `kind`, `summary` | `pull_requests:write` |
356+| [`list_decisions`](/reference/api/decisions-and-why/list-decisions/) | The decision records on a pull request, or on an issue and its pull requests, oldest first, each with its `kind`, `confidence` (`claimed`, `tested` or `approved`), `summary` and `evidence`. | `repo`, `number` | `pull_requests:read` |
354357 | [`ready`](/reference/api/pull-requests/mark-pull-request-ready/) | Mark a draft ready for review. The summary becomes its description. | `repo`, `number`, `summary` | `pull_requests:write` |
355358 | [`draft`](/reference/api/pull-requests/convert-pull-request-to-draft/) | Turn a pull request that is ready for review back into a draft. It leaves the merge queue. Its author, or the Triage role. | `repo`, `number` | `pull_requests:write` |
356359 | [`request_reviewers`](/reference/api/pull-requests/request-reviewers/) | Ask more people (`reviewers`, by username) or teams (`team_reviewers`, as `workspace/team` or a slug of the repository's workspace) to review it, added to whoever is asked already. Its author, or the Triage role. | `repo`, `number` | `pull_requests:write` |
364367 `record_session` takes a list of `entries`, each with a `kind` (`prompt`,
365368 `message`, `tool_call`, `tool_result` or `note`) and `text`, and `tool` for
366369 tool entries. See [sessions and why-blame](/guides/why-blame/) and the
367−[merge queue](/guides/merge-queue/).
370+[merge queue](/guides/merge-queue/). g1t records `integration_failure`,
371+`integration_passed`, `approval` and `merge` decisions itself; see
372+[decision records](/guides/why-blame/#decision-records).
368373
369374 ## `memory`
370375
+13−1
212212 into the fork, push, and merge again.
213213 With the merge queue on, merging adds the pull request to the queue
214214 instead; `GET {repo}/queue` shows it being tested with the pull requests
215− ahead of it, and it lands only if that combination passes.
215+ ahead of it, and it lands only if that combination passes. When it fails
216+ combined with them, g1t says which pull requests ahead it breaks with
217+ and which check failed: in its conversation, its issue's, its session,
218+ `GET {repo}/pulls/{number}/decisions` (an `integration_failure`
219+ decision) and the `integration.failed` event. Read the other pull
220+ request's changes, fix yours, and push: once its checks pass, it rejoins
221+ the queue by itself.
222+- **Record a decision**: why the change is made this way, or what fixed a
223+ failure: `POST {repo}/pulls/{number}/decisions` with `kind` (`proposal`,
224+ `claim`, `fix` or `note`) and `summary`, and `evidence` (an object).
225+- **Why is a line the way it is:** `GET {repo}/why?path=src/a.rs&line=42`
226+ answers with its commit, the pull request it arrived in, that pull
227+ request's issue, decisions and session.
216228
217229 ## Where work runs
218230