Filed by @neo-opus-vega. Two findings with one causal link, both measured today: the sanctioned tool is unavailable to at least one seat, and the fallback everyone reaches for reports superseded failures as live.
Context — the tool that exists for this refuses
get_conversation({pr_number, projection: 'merge-readiness'}) is the governed surface for "is this PR merge-eligible". For @neo-opus-vega it returns no verdict at all:
{"verdict": "unavailable",
"principals": {"agentIdentity": "@neo-opus-vega", "githubLogin": "neo-opus-vega", "memoryCoreIdentity": null},
"blockers": [{"code": "IDENTITY_BINDING_MISSING",
"message": "The merge-readiness projection requires bound AgentIdentity, GitHub, and Memory Core principals."}],
"audit": [{"source": "identity-assertion", "outcome": "failed"}]}Two of three principals resolve. memoryCoreIdentity is null, and the projection is all-or-nothing on the triple — so the seat gets unavailable rather than a partial verdict.
The Problem
Because the projection is unavailable, the seat hand-rolls merge-eligibility from gh pr view --json statusCheckRollup — and that field reports the FIRST failed attempt per check name, not the latest run per workflow. A head whose every workflow ultimately passed reads red.
Three instances today, three different PRs, and one of them is a merge decision:
| PR |
rollup says |
the head's actual runs |
| #16865 |
lint-pr-body FAILURE |
@neo-gpt: "The older failed PR-body attempt is superseded by a successful rerun on the same head." |
| #16891 |
lint-pr-body FAILURE |
later success on the same head |
| #16889 |
lint-pr-body and lint-pr-review-body FAILURE |
both latest runs success — see below |
#16889 @ 4a6ac93bdf, queried per workflow filtered to that exact SHA:
agent-pr-body-lint : success 16:01:07 · success 15:38:53 · FAILURE 15:35:45 · success 15:33:45
agent-pr-review-body-lint : success 16:08:05 · success 15:56:31 · FAILURE 15:48:13
Zero live failures. Two red entries in the rollup. That PR is operator-approved at exact head and reads as having two failing checks.
Why this is worse than a cosmetic display bug. Merge-eligibility broadcasts to @tobiu are assembled by agents from this field. A false red costs a held merge and an investigation; the same habit inverted — learning that reds on this repo are probably stale — is how a real red gets waved through. The failure mode is not the wrong answer, it is the erosion of the signal.
It also produces exactly the wrong reviewer behaviour: I have now told two peers "your check is red" and had to follow up with "actually the latest run passed", which spends the credibility that makes a genuine red actionable.
The Architectural Reality
get_conversation's merge-readiness projection exists precisely so agents do not hand-assemble this. It gates on a bound {AgentIdentity, GitHub, MemoryCore} triple and returns IDENTITY_BINDING_MISSING when any is absent.
agentIdentity and githubLogin both resolve for this seat; only memoryCoreIdentity is null. Whether that is a per-seat registration gap or a resolution bug in the projection is not established — I have not read the binding resolver, and a mechanism inferred from one symptom is a guess.
statusCheckRollup is GitHub's per-check-name summary. For a workflow re-run on the same head it retains an earlier conclusion rather than the latest; the authoritative read is per-workflow, filtered by headSha, taking the newest run.
- Adjacent but distinct: #16888 (
list_messages truncation) is the same class — a summary surface that cannot express its own incompleteness — filed separately and already claimed.
The Fix
Two independent halves; either alone is an improvement.
- Make the projection degrade instead of refusing. An unbound
memoryCoreIdentity blocks identity-scoped content, not a checks verdict. Return a partial verdict naming what it could not evaluate, rather than unavailable with no data — a tool that answers nothing guarantees the caller hand-rolls it.
- Compute checks as latest-run-per-workflow-per-head, never the rollup entry, and say so in the projection's own contract so a reader knows which it got.
- Root-cause the null binding for at least this seat: per-seat registration gap, or resolver defect. State which; do not fix by widening the gate.
- Document the manual discriminator in the pr-review skill for as long as (1) is outstanding, since agents will keep hand-rolling until the tool answers.
Contract Ledger
| Target surface |
Source of authority |
Behavior |
Failure / fallback |
Evidence |
get_conversation merge-readiness |
GitHub-workflow MCP server |
returns a checks verdict when GitHub principals bind, naming any identity-scoped fields it omitted |
never a bare unavailable when checks are readable |
this seat's unavailable payload above |
| its checks computation |
same |
latest run per workflow per head |
a workflow with no run for the head reports unknown, never inherits an older head's conclusion |
the #16889 run tables above |
memoryCoreIdentity binding |
identity/registration surface |
resolves for a registered seat |
absent binding reduces scope, never the whole verdict |
{agentIdentity, githubLogin} resolve while it does not |
Acceptance Criteria
Out of Scope
- Changing what
statusCheckRollup means. It is GitHub's field; the defect is our consumption of it.
- #16888. Same class, different surface, already claimed.
- Required-vs-optional check policy. Both lints here are non-required; that is why #16889 still reads
CLEAN. A required check with a stale red would be strictly worse and is the reason not to wait for one.
Avoided Traps
- Filing this as discipline. I did read the runs and catch all three — and I also told two peers their check was red before checking. A rule that must be applied by hand on every read, against a field that looks authoritative, is a surface problem.
- Inferring the binding mechanism. I have not read the resolver; the AC asks for the cause to be established rather than assuming a registration gap.
Related
#16888 (summary surfaces that cannot express incompleteness) · #16865, #16891, #16889 (the three instances).
Live latest-open sweep: latest 8 open issues created-descending at 2026-08-10T16:44:16Z; A2A claim sweep over the latest messages, all read-states, at 2026-08-10T16:45Z. No equivalent open ticket and no competing claim.
Origin Session ID: 4131135d-1b20-487f-9d23-d7213914246b
Retrieval Hint: query_raw_memories("merge-readiness unavailable statusCheckRollup superseded rerun") · IDENTITY_BINDING_MISSING
Filed by @neo-opus-vega. Two findings with one causal link, both measured today: the sanctioned tool is unavailable to at least one seat, and the fallback everyone reaches for reports superseded failures as live.
Context — the tool that exists for this refuses
get_conversation({pr_number, projection: 'merge-readiness'})is the governed surface for "is this PR merge-eligible". For@neo-opus-vegait returns no verdict at all:{"verdict": "unavailable", "principals": {"agentIdentity": "@neo-opus-vega", "githubLogin": "neo-opus-vega", "memoryCoreIdentity": null}, "blockers": [{"code": "IDENTITY_BINDING_MISSING", "message": "The merge-readiness projection requires bound AgentIdentity, GitHub, and Memory Core principals."}], "audit": [{"source": "identity-assertion", "outcome": "failed"}]}Two of three principals resolve.
memoryCoreIdentityisnull, and the projection is all-or-nothing on the triple — so the seat getsunavailablerather than a partial verdict.The Problem
Because the projection is unavailable, the seat hand-rolls merge-eligibility from
gh pr view --json statusCheckRollup— and that field reports the FIRST failed attempt per check name, not the latest run per workflow. A head whose every workflow ultimately passed reads red.Three instances today, three different PRs, and one of them is a merge decision:
lint-pr-bodyFAILURElint-pr-bodyFAILUREsuccesson the same headlint-pr-bodyandlint-pr-review-bodyFAILUREsuccess— see below#16889@4a6ac93bdf, queried per workflow filtered to that exact SHA:Zero live failures. Two red entries in the rollup. That PR is operator-approved at exact head and reads as having two failing checks.
Why this is worse than a cosmetic display bug. Merge-eligibility broadcasts to @tobiu are assembled by agents from this field. A false red costs a held merge and an investigation; the same habit inverted — learning that reds on this repo are probably stale — is how a real red gets waved through. The failure mode is not the wrong answer, it is the erosion of the signal.
It also produces exactly the wrong reviewer behaviour: I have now told two peers "your check is red" and had to follow up with "actually the latest run passed", which spends the credibility that makes a genuine red actionable.
The Architectural Reality
get_conversation'smerge-readinessprojection exists precisely so agents do not hand-assemble this. It gates on a bound{AgentIdentity, GitHub, MemoryCore}triple and returnsIDENTITY_BINDING_MISSINGwhen any is absent.agentIdentityandgithubLoginboth resolve for this seat; onlymemoryCoreIdentityis null. Whether that is a per-seat registration gap or a resolution bug in the projection is not established — I have not read the binding resolver, and a mechanism inferred from one symptom is a guess.statusCheckRollupis GitHub's per-check-name summary. For a workflow re-run on the same head it retains an earlier conclusion rather than the latest; the authoritative read is per-workflow, filtered byheadSha, taking the newest run.list_messagestruncation) is the same class — a summary surface that cannot express its own incompleteness — filed separately and already claimed.The Fix
Two independent halves; either alone is an improvement.
memoryCoreIdentityblocks identity-scoped content, not a checks verdict. Return a partial verdict naming what it could not evaluate, rather thanunavailablewith no data — a tool that answers nothing guarantees the caller hand-rolls it.Contract Ledger
get_conversationmerge-readinessunavailablewhen checks are readableunavailablepayload aboveunknown, never inherits an older head's conclusionmemoryCoreIdentitybinding{agentIdentity, githubLogin}resolve while it does notAcceptance Criteria
merge-readinessreturns a usable checks verdict for a seat whosememoryCoreIdentityis unbound, naming the identity-scoped fields it could not evaluate. Proven by a fixture with an unbound principal — today's response is the RED witness.unknownrather than inheriting a prior head's conclusion — the sibling of the same defect, and untested here.memoryCoreIdentity: nullcause is stated — registration gap or resolver defect — not papered over by relaxing the gate.Out of Scope
statusCheckRollupmeans. It is GitHub's field; the defect is our consumption of it.CLEAN. A required check with a stale red would be strictly worse and is the reason not to wait for one.Avoided Traps
Related
#16888 (summary surfaces that cannot express incompleteness) · #16865, #16891, #16889 (the three instances).
Live latest-open sweep: latest 8 open issues created-descending at
2026-08-10T16:44:16Z; A2A claim sweep over the latest messages, all read-states, at2026-08-10T16:45Z. No equivalent open ticket and no competing claim.Origin Session ID: 4131135d-1b20-487f-9d23-d7213914246b
Retrieval Hint:
query_raw_memories("merge-readiness unavailable statusCheckRollup superseded rerun")·IDENTITY_BINDING_MISSING