On 2026-08-24, PR #17670 became conflicted after later dev merges while its head stayed unchanged. The first live recheck returned head 65aed8d3a2, mergeable=CONFLICTING, and mergeStateStatus=DIRTY; the author then rebased to dda802a337, which restored mergeable=MERGEABLE and let the remaining CI gate surface normally. Review work should have waited for that author repair.
The existing admission contract catches only head-scoped CI:
.agents/skills/pull-request/references/ci-green-review-routing.md runs gh pr checks before reviewer assignment.
.agents/skills/pr-review/audits/ci-security-audit.md holds reviewers on pending or red checks.
PullRequestService.managePrReviewers() currently enters the reviewer mutation without a live mergeability preflight.
GitHub's event contract creates a blind spot: ordinary pull_request workflows do not run while a PR has a merge conflict, whereas pull_request_target still runs. GitHub also documents mergeable: null as an asynchronous computation state that must be polled, not interpreted as either clean or conflicting.
Live latest-open sweep: checked the newest 20 open issues immediately before creation on 2026-08-24; no equivalent ticket or recent A2A claim existed. Closed #11467 is the exact author-admission predecessor and explicitly excluded a mechanical status gate. Open #16136 is adjacent PR-state instrumentation, not this gate. Open #17171 owns required-context/ruleset policy, which this ticket does not change.
The Problem
CI is primarily a function of the PR head. Mergeability is a function of the PR head and the moving base. A merge into dev can therefore make an unchanged, previously green head conflicting without generating a new head-scoped CI result.
The current review-admission flow asks a human or agent to remember a second query after gh pr checks. That query is easy to skip, and an ordinary PR workflow cannot repair the omission because GitHub suppresses that workflow precisely in the state it needs to report.
The predicate must remain narrow:
confirmed mergeable === false is a merge conflict;
mergeable === null is unresolved and must not become success;
BEHIND, BLOCKED, and UNSTABLE can coexist with positive mergeability and are not conflicts;
review approval, required checks, base-update policy, and human merge authority remain separate gates.
The Architectural Reality
.github/workflows/ owns the repository-local controller that can react both to PR-head events and dev movement.
pull_request_target runs trusted default-branch workflow code even for conflicted PRs. It is admissible here only with no checkout or execution of PR code, no repository secrets, and least-privilege pull-requests: read plus statuses: write.
GitHub commit statuses attach a named result to the exact PR head SHA, so the existing gh pr checks admission instrument can see it.
ai/services/github-workflow/PullRequestService.mjs#managePrReviewers owns the active reviewer-invitation mutation and is the defense-in-depth gate for callers that bypass workflow prose.
test/playwright/unit/ai/buildScripts/util/WorkflowConcurrency.spec.mjs already establishes the pattern for parsing an actions/github-script block from YAML and executing it against mocked GitHub/runtime objects.
test/playwright/unit/ai/services/github-workflow/PullRequestServiceReviewers.spec.mjs owns reviewer-mutation preflight and no-mutation evidence.
The author and reviewer CI payloads are already conditionally loaded; a compact mergeability clause belongs there, with no SKILL.md router growth and no new skill.
The mandatory Agent OS structure-map command was attempted during creation and failed with Cannot create a string longer than 0x1fffffe8 characters. Direct sibling inspection established the existing-file placement above. No new .mjs file or directory role is introduced.
pull_request_target for opened, reopened, synchronize, and ready_for_review PRs targeting dev;
push on dev, which enumerates every open dev-target PR and is the load-bearing response to later base merges;
workflow_dispatch as a recovery path;
no checkout and no execution of PR-controlled code;
event-only discovery for active pull_request_target events; board discovery for merged-close, push: dev, trusted Data Sync completion, and recovery;
per-PR serialized evaluation, with a declared safe board cap.
For each live PR coordinate:
leave a new head without the named status while GitHub computes, which is itself an admission hold;
GET the PR and poll a declared, bounded number of times while mergeable === null;
re-read head and base before publishing; restart on movement already observed, while the serialized successor/live tool gate corrects any post-read movement;
publish success / failure / error only when the named terminal state changes, avoiding append-only status exhaustion.
Before manage_pr_reviewers(action: 'add') mutates:
perform the same bounded live mergeability read;
refuse confirmed conflict and unresolved exhaustion with distinct structured codes;
keep remove available without the preflight.
Update the MCP description/schema for the new refusal envelopes.
Fold one compact named-status clause into each existing author/reviewer CI payload. Missing, failing, or error status is an author-side hold; only success admits formal review routing. The controller activation PR substitutes a named live mergeability read.
Execute the workflow script in a focused unit harness and extend the reviewer-service suite with no-mutation controls.
Contract Ledger Matrix
Target Surface
Source of Authority
Proposed Behavior
Fallback
Docs
Evidence
review-admission/mergeability on PR head
live GitHub PR mergeable plus exact head/base coordinates
absent while computing; terminal success / failure / error only on state transition
source unresolved after a known coordinate becomes error; target discovery failure is a loud workflow failure and the reviewer-tool live gate stays authoritative
existing gh pr checks gate requires the mergeability context to be successful
missing/pending/red/error routes to author repair/retry
two existing conditional payloads
byte-bounded diff + trigger-path assertions
Decision Record impact
none — additive repository workflow, status context, and existing-tool preflight. No API break, merge-policy change, or new subsystem.
Unresolved Liveness
revalidationTrigger: open dev PR count approaches 32, observed board-trigger rate × worst-case reads approaches 800 requests/hour, an overflow invalidation reports any failure, GitHub returns the first status-limit/rate-limit refusal, or a new [skip ci] dev producer appears outside Data Sync. The live reviewer-tool preflight remains authoritative; any changed bound or mechanism goes into a new successor ticket.
Same-state terminal writes are skipped, so the append-only 1,000-status limit is consumed by state transitions rather than routine dev movement.
Acceptance Criteria
review-admission/mergeability is written to the live PR head SHA, never the base SHA.
A conflicting PR produces failure; a positive PR produces success; exhausted null or an unreadable source after a known coordinate produces error; absence while computing never reads as success.
pull_request_target covers opened/reopened/synchronize/ready-for-review events targeting dev, and the controller never checks out or executes PR code.
Within the declared safe board cap, merged-close, ordinary dev push, and trusted Data Sync completion re-evaluate open dev-target PRs, including [skip ci] sync commits; an unchanged formerly-green head can turn red after a base move.
The safe board cap is justified as a per-trigger burst bound (hourly safety still includes event rate); discovery/overflow failure refuses a partial matrix, reports invalidation failures, and leaves manage_pr_reviewers(add) as the live authority.
Head/base movement observed before publication restarts on the new coordinate; a post-read movement is corrected by the serialized successor and authoritative live reviewer-tool preflight.
Workflow permissions are limited to the reads and commit-status write actually required; no repository secret is consumed.
manage_pr_reviewers(action: 'add') performs no reviewer mutation for a confirmed conflict or unresolved mergeability, and returns distinct structured refusal codes.
manage_pr_reviewers(action: 'remove') performs no mergeability preflight and preserves current removal verification.
Positive mergeability remains admissible alongside BEHIND, BLOCKED, or UNSTABLE; those states are not reclassified as conflicts.
The author and reviewer CI payloads require the named status to be successful before actionable/formal review, with no new skill or router growth.
Workflow-runtime tests fail if pull_request_target is replaced by pull_request, if push: dev is removed, if the status targets the base SHA, or if unresolved mergeability becomes success.
Out of Scope
Making the status a required ruleset context or changing branch protection; #17171 owns that operator/settings decision.
Merge queues, auto-rebase, automatic conflict resolution, or requiring a merely BEHIND branch to update.
Approval freshness, cross-family approval, or the human-only merge gate.
A scheduled poller. Add one only if missed-event evidence appears.
Generalizing the repository-local workflow across the Neo organization in this first leaf; the reviewer-tool guard still applies to every repository target it accepts.
Avoided Traps
Ordinary pull_request CI: absent on the conflict state it must report.
Executing PR code under pull_request_target: turns a status helper into a privileged-code-execution surface.
Tool preflight only: correct but invisible in gh pr checks, and cannot proactively turn red when dev moves.
Branch protection or merge queue as review admission: governs merge, not when reviewer attention should be spent, and changes the human merge flow.
Schedule as the primary trigger: slower and noisier than the exact push: dev cause.
A new skill or MCP tool: additive capability belongs in the existing status and reviewer-invitation surfaces.
Substrate-accretion rationale: only compact clauses enter two already-conditional payloads. Retire the manual prose if a future organization-wide controller plus mechanically exclusive reviewer-invitation path makes the named context unavoidable without agent discipline.
Context
On 2026-08-24, PR
#17670became conflicted after laterdevmerges while its head stayed unchanged. The first live recheck returned head65aed8d3a2,mergeable=CONFLICTING, andmergeStateStatus=DIRTY; the author then rebased todda802a337, which restoredmergeable=MERGEABLEand let the remaining CI gate surface normally. Review work should have waited for that author repair.The existing admission contract catches only head-scoped CI:
.agents/skills/pull-request/references/ci-green-review-routing.mdrunsgh pr checksbefore reviewer assignment..agents/skills/pr-review/audits/ci-security-audit.mdholds reviewers on pending or red checks.PullRequestService.managePrReviewers()currently enters the reviewer mutation without a live mergeability preflight.GitHub's event contract creates a blind spot: ordinary
pull_requestworkflows do not run while a PR has a merge conflict, whereaspull_request_targetstill runs. GitHub also documentsmergeable: nullas an asynchronous computation state that must be polled, not interpreted as either clean or conflicting.Official constraints:
Live latest-open sweep: checked the newest 20 open issues immediately before creation on 2026-08-24; no equivalent ticket or recent A2A claim existed. Closed #11467 is the exact author-admission predecessor and explicitly excluded a mechanical status gate. Open #16136 is adjacent PR-state instrumentation, not this gate. Open #17171 owns required-context/ruleset policy, which this ticket does not change.
The Problem
CI is primarily a function of the PR head. Mergeability is a function of the PR head and the moving base. A merge into
devcan therefore make an unchanged, previously green head conflicting without generating a new head-scoped CI result.The current review-admission flow asks a human or agent to remember a second query after
gh pr checks. That query is easy to skip, and an ordinary PR workflow cannot repair the omission because GitHub suppresses that workflow precisely in the state it needs to report.The predicate must remain narrow:
mergeable === falseis a merge conflict;mergeable === nullis unresolved and must not become success;BEHIND,BLOCKED, andUNSTABLEcan coexist with positive mergeability and are not conflicts;The Architectural Reality
.github/workflows/owns the repository-local controller that can react both to PR-head events anddevmovement.pull_request_targetruns trusted default-branch workflow code even for conflicted PRs. It is admissible here only with no checkout or execution of PR code, no repository secrets, and least-privilegepull-requests: readplusstatuses: write.gh pr checksadmission instrument can see it.ai/services/github-workflow/PullRequestService.mjs#managePrReviewersowns the active reviewer-invitation mutation and is the defense-in-depth gate for callers that bypass workflow prose.test/playwright/unit/ai/buildScripts/util/WorkflowConcurrency.spec.mjsalready establishes the pattern for parsing anactions/github-scriptblock from YAML and executing it against mocked GitHub/runtime objects.test/playwright/unit/ai/services/github-workflow/PullRequestServiceReviewers.spec.mjsowns reviewer-mutation preflight and no-mutation evidence.SKILL.mdrouter growth and no new skill.The mandatory Agent OS structure-map command was attempted during creation and failed with
Cannot create a string longer than 0x1fffffe8 characters. Direct sibling inspection established the existing-file placement above. No new.mjsfile or directory role is introduced.The Fix
.github/workflows/review-admission-mergeability.ymlwith:pull_request_targetforopened,reopened,synchronize, andready_for_reviewPRs targetingdev;pushondev, which enumerates every opendev-target PR and is the load-bearing response to later base merges;workflow_dispatchas a recovery path;pull_request_targetevents; board discovery for merged-close,push: dev, trusted Data Sync completion, and recovery;mergeable === null;success/failure/erroronly when the named terminal state changes, avoiding append-only status exhaustion.manage_pr_reviewers(action: 'add')mutates:removeavailable without the preflight.Contract Ledger Matrix
review-admission/mergeabilityon PR headmergeableplus exact head/base coordinatessuccess/failure/erroronly on state transitionerror; target discovery failure is a loud workflow failure and the reviewer-tool live gate stays authoritativedevpushes plusData Sync Pipelinecompletion re-evaluate the board within the safe capworkflow_dispatchrecovery; discovery/overflow failure refuses a partial matrix and reports best-effort invalidation failuresmanage_pr_reviewers(add)manage_pr_reviewers(remove)gh pr checksgate requires the mergeability context to be successfulDecision Record impact
none— additive repository workflow, status context, and existing-tool preflight. No API break, merge-policy change, or new subsystem.Unresolved Liveness
revalidationTrigger: opendevPR count approaches 32, observed board-trigger rate × worst-case reads approaches 800 requests/hour, an overflow invalidation reports any failure, GitHub returns the first status-limit/rate-limit refusal, or a new[skip ci]dev producer appears outside Data Sync. The live reviewer-tool preflight remains authoritative; any changed bound or mechanism goes into a new successor ticket.devmovement.Acceptance Criteria
review-admission/mergeabilityis written to the live PR head SHA, never the base SHA.failure; a positive PR producessuccess; exhaustednullor an unreadable source after a known coordinate produceserror; absence while computing never reads as success.pull_request_targetcovers opened/reopened/synchronize/ready-for-review events targetingdev, and the controller never checks out or executes PR code.devpush, and trusted Data Sync completion re-evaluate opendev-target PRs, including[skip ci]sync commits; an unchanged formerly-green head can turn red after a base move.manage_pr_reviewers(add)as the live authority.manage_pr_reviewers(action: 'add')performs no reviewer mutation for a confirmed conflict or unresolved mergeability, and returns distinct structured refusal codes.manage_pr_reviewers(action: 'remove')performs no mergeability preflight and preserves current removal verification.BEHIND,BLOCKED, orUNSTABLE; those states are not reclassified as conflicts.pull_request_targetis replaced bypull_request, ifpush: devis removed, if the status targets the base SHA, or if unresolved mergeability becomes success.Out of Scope
BEHINDbranch to update.list_pull_requests; #16136 retains board-projection work.Avoided Traps
pull_requestCI: absent on the conflict state it must report.pull_request_target: turns a status helper into a privileged-code-execution surface.gh pr checks, and cannot proactively turn red whendevmoves.push: devcause.Substrate-accretion rationale: only compact clauses enter two already-conditional payloads. Retire the manual prose if a future organization-wide controller plus mechanically exclusive reviewer-invitation path makes the named context unavoidable without agent discipline.
Related
Origin Session ID: 0dc1379e-5329-4fba-80ca-f6466822f7c9
Retrieval Hint:
review admission mergeability commit status pull_request_target dev push conflicted PR reviewer assignmentAuthored by Emmy (GPT-5.6 Sol Ultra, Codex).