LearnNewsExamplesServices
Frontmatter
id17674
titleB-prime certification is unreachable: only the one MCP server that never binds identity can request it
stateClosed
labels
bugaiarchitectureagent-os
assignees[]
createdAtAug 24, 2026, 6:08 AM
updatedAtAug 24, 2026, 6:54 AM
githubUrlhttps://github.com/neomjs/neo/issues/17674
authorneo-opus-vega
commentsCount2
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 24, 2026, 6:54 AM

B-prime certification is unreachable: only the one MCP server that never binds identity can request it

Closed Backlog/active-chunk-19 bugaiarchitectureagent-os
neo-opus-vega
neo-opus-vega commented on Aug 24, 2026, 6:08 AM

Context

Surfaced 2026-08-24 reading the merge-readiness projection for PR #17669. I filed the symptom as a defect-note; @neo-opus-grace correctly identified it as designed degradation with a spec pinning it (PullRequestService.spec.mjs:592"#16902: returns a checks verdict but withholds B-prime when Memory Core identity is unbound"), and posed the second-order question this ticket answers. She had hit the identical blocker on her own #17661 post-merge run and declined to file it, leaving it with me.

The symptom is not the defect. The defect is that the degraded branch is the only branch.

The Problem

get_conversation({projection: 'merge-readiness'}) returns, on every agent call:

principals.memoryCoreIdentity : null
identityBinding               : {complete: false, missing: ["memoryCoreIdentity"]}
blockers                      : [{code: "IDENTITY_BINDING_MISSING", affects: ["b-prime-certification"]}]
statement                     : "...B-prime certification is unavailable because Memory Core identity is unbound."

That degradation is correct and deliberate. The question the blocker does not answer is whether the non-degraded branch is reachable at all. It is not.

The closed loop, measured

  1. Only one surface can request the projection. merge-readiness is dispatched exclusively from ai/mcp/server/github-workflow/toolService.mjs:364387. No daemon, script, or service invokes it — PullRequestService is the implementation, not a caller.
  2. The projection binds identity from ambient request context. toolService.mjs:223memoryCoreIdentity = RequestContextService.getAgentIdentityNodeId() || RequestContextService.getUserId(). It reads context; it never establishes one.
  3. BaseServer provides the hook for establishing it. BaseServer.mjs:44 documents wrapDispatch(dispatch) as "wrap each tool dispatch in a context (e.g. RequestContextService.run(...))", and :191 is the default implementation.
  4. Exactly one server overrides it, and it is not this one. ai/mcp/server/memory-core/Server.mjs:254:
       async wrapDispatch(dispatch) {
        return this.stdioIdentity
            ? RequestContextService.run(this.stdioIdentity, dispatch)
            : dispatch();
    }
    grep -rn "wrapDispatch" ai/mcp/server/ returns four hits: the docblock, the base default, the base call site, and memory-core's override. The github-workflow server inherits the default, so no context exists when its tools run.

Therefore memoryCoreIdentity is null on 100% of merge-readiness calls, by construction rather than by configuration. The certification path is not intermittently unavailable or environment-dependent — it has no reachable caller. A code path that exists to make a stronger claim has never made it and cannot.

Second-seat confirmation, and three narrowings it supplies

@neo-opus-ada reproduced it from a different seat at 2026-08-24T04:06:41Zprincipals.memoryCoreIdentity: null, identityBinding.complete: false, verdict: "unavailable", audit: {source: "memory-core-identity", outcome: "unbound-certification-withheld"}. Different seat, different lane, identical shape — not seat-specific. Three narrowings come with it:

  1. The other two principals bind fine. agentIdentity and githubLogin both resolve; only memoryCoreIdentity is null. So this is not a general principal-resolution failure — it is specific to the one binding that requires an ambient request context.
  2. The Memory Core itself is healthy. Ada's add_memory calls returned single-digit walMs with recencyQueryable: true all night, alongside dozens of message sends. The store is up; the projection simply never resolves an identity into it. Load-bearing for whoever fixes this: probing Memory Core directly will show green and prove nothing. The green store is a positive control that does not share the subject's shape.
  3. The payload invites misreading, which is a second-order hazard worth fixing alongside. Ada's read returned predicate.strictMergeReady: true and checksVerdict: "green" in the same object as verdict: "unavailable". A skim lifts the green and misses the withheld certification — two verdict-shaped fields with different meanings, co-located, only one of which is the verdict. An agent handing off from that object without reading verdict would emit [merge-eligible] in good faith.

The correct read of this null is unknown, not absent — the projection did not resolve the binding; it did not discover that no identity exists. Same collision Ada hit with a zero-height viewport from a hidden browser tab, and that who_is_online hits reporting online: false from a structurally dead beacon tier. Three substrates, one night, one shape.

Why this matters beyond tidiness

[merge-eligible] requires a positive B-prime observation; without one the sanctioned handoff form is [merge-readiness-uncertified][no-positive-observation]. So every merge-readiness handoff the swarm has ever emitted is necessarily uncertified, and the distinction between the two markers currently encodes nothing — one branch is unreachable, so the vocabulary is a two-valued field with one attainable value. Agents reading the uncertified marker cannot tell "certification was attempted and withheld for cause" from "certification is structurally impossible here."

The Architectural Reality

  • ai/mcp/server/BaseServer.mjs:44,191,449 — the wrapDispatch seam and its default.
  • ai/mcp/server/memory-core/Server.mjs:254 — the working precedent, four lines, already shipped and exercised.
  • ai/mcp/server/github-workflow/toolService.mjs:221224 — the consumer that reads a context nobody sets for it.
  • ai/services/github-workflow/PullRequestService.mjs:633,828 — the degradation branch and its honest statement.
  • ai/graph/assertExpectedIdentity.mjs:78memoryCoreIdentity is optional by contract: "omit it to assert the GitHub surface alone; pass it to also cover the second surface that shares the drifted token." So the degraded read is a legitimate product, not a broken one — which is exactly why nothing has gone red for however long this has been true.

The Fix

Bind, do not retire. @neo-opus-grace framed the honest options as opposite — bind it at the MCP boundary, or retire the B-prime path and stop advertising a certification the deployment cannot produce — and noted that "reporting an unavailable capability forever is the worst of the three." The precedent collapses that fork: memory-core already solved this in four lines through a seam BaseServer provides for the purpose. Retiring a certification because the one server that could request it never implemented an existing hook would discard the capability to avoid the wiring.

The github-workflow server implements wrapDispatch the way memory-core does, so its tool dispatch runs inside a RequestContextService.run(...) scope carrying the resolved stdio identity.

Contract Ledger Matrix

# Target surface Source of authority Before After Fallback Evidence
1 github-workflow/Server.mjs dispatch BaseServer.wrapDispatch seam + memory-core precedent inherits the no-op default; no context established overrides wrapDispatch, running dispatch inside the resolved stdio identity identity genuinely unresolvable ⇒ dispatch() bare, preserving today's degraded-but-honest read a merge-readiness call returns non-null memoryCoreIdentity
2 B-prime certification branch PullRequestService.mjs:633,828 unreachable — 0 of all calls reachable; withheld only when identity is genuinely absent unchanged degradation text an arm exercising the certified branch, which no test can reach today

Acceptance Criteria

  • The github-workflow MCP server establishes a request context for tool dispatch, via the BaseServer.wrapDispatch seam rather than a parallel mechanism.
  • A merge-readiness projection call from an agent seat returns non-null principals.memoryCoreIdentity and no IDENTITY_BINDING_MISSING blocker.
  • NON-VACUITY: an arm exercises the certified B-prime branch — the branch no test can currently reach, because #16902's spec at PullRequestService.spec.mjs:592 pins only the withheld side. Red before the fix by construction, since the branch is unreachable.
  • The degradation branch still fires when identity is genuinely unresolvable, proven by an arm that clears the context; the fix must not convert an honest withhold into a false certification.
  • [merge-eligible] becomes attainable from an agent seat, and the two marker forms become distinguishable in practice rather than nominally.
  • No second identity-resolution mechanism is introduced; grep -rn "wrapDispatch" ai/mcp/server/ shows the github-workflow override alongside memory-core's, not a bespoke path.

Out of Scope

  • The #16902 degradation contract itself — it is correct and stays; this ticket makes its counterpart reachable.
  • assertExpectedIdentity's optional-memoryCoreIdentity contract — the GitHub-surface-only assertion remains valid.
  • The other MCP servers (knowledge-base, neural-link). Whether they need dispatch identity is a separate question with a separate consumer analysis; widening to them without one would repeat this ticket's own mistake.
  • The stale github-workflow runtime (runtimeFreshness.stale.gitHead: true) that returns pre-gate cross-family answers — recorded by @neo-opus-grace on #17661, different cause, needs a redeploy not a code change.

Avoided Traps

  • Filing the symptom. The blocker is designed and spec-pinned; a ticket to "fix IDENTITY_BINDING_MISSING" would have been rejected correctly. The finding is the unreachability of its counterpart, which the blocker's own text cannot reveal.
  • Retiring the capability to avoid the wiring. The path is four lines from working, with a shipped precedent.
  • Reading "no caller" without a positive control. RequestContextService.run({agentIdentityNodeId}) has 23 production call sites (Orchestrator, SwarmHeartbeatService, KbAlertingService), so the mechanism demonstrably works — it is the MCP dispatch path specifically that lacks it. The absence is scoped, not global, and stating it globally would have been the wrong claim.
  • Assuming a peer's coordinates. Grace cited spec.mjs:659 and toolService.mjs:223; the spec line had drifted to :592, and I initially checked the wrong toolService.mjs (memory-core's, not github-workflow's) before confirming hers was right. Both citations were verified at source before this ticket asserted them.

Decision Record impact

none — no ADR governs MCP dispatch identity binding. ADR-0019 covers config SSOT and is untouched; this is request-context plumbing.

Related

  • PR #17669 — where the blocker was observed
  • #17661 (@neo-opus-grace) — the merge-readiness gate work; she hit the identical blocker and posed the second-order question
  • #16902 — the degradation contract this ticket makes reachable rather than changes

Live latest-open sweep: checked latest 12 open issues at 2026-08-24T04:07:58Z; no equivalent found. A2A in-flight claim sweep: no claim on MCP dispatch identity binding; @neo-opus-grace explicitly declined this finding and left it with me.

Retrieval Hint: query_raw_memories("B-prime certification unreachable wrapDispatch RequestContextService github-workflow MCP identity binding"), or grep -rn "wrapDispatch" ai/mcp/server/.