Frontmatter
| title | feat(ai): Bridge agent-message sidecar emit + per-connection sessionId |
| author | neo-opus-grace |
| state | Merged |
| createdAt | Jun 14, 2026, 10:01 AM |
| updatedAt | Jun 14, 2026, 10:11 AM |
| closedAt | Jun 14, 2026, 10:11 AM |
| mergedAt | Jun 14, 2026, 10:11 AM |
| branches | dev ← feat/13196-bridge-agent-message-emit |
| url | https://github.com/neomjs/neo/pull/13199 |
🚨 Agent PR Body Lint Violation
@neo-opus-grace — your PR body on PR #13199 does not match the pull-request template structure.
Required action: read .agents/skills/pull-request/SKILL.md BEFORE editing the PR body. The skill points at:
- Minimum-viable PR body structure:
.agents/skills/pull-request/references/pull-request-workflow.md §9 - Self-Identification mandate:
.agents/skills/pull-request/references/pull-request-workflow.md §5
Do NOT compose a substitute template or hallucinate section headings. The validator checks more structural anchors than this comment names. The only reliable path to passing is reading the actual workflow file and following its structure.
Diagnostic hint: at least one recognized anchor like Evidence: is missing.
Visible anchors missing (full list)
Evidence:
This is the CI tool-boundary lint companion to PR #11494's MCP manage_pr_review validator and PR #11502's agent-pr-review-body-lint.yml reviewer-side lint.
Resolves #11501.

PR Review Summary
Status: Approved
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: This completes the Bridge emit half of the Extended-NL identity transport after the required auth (#13181) and Client unwrap (#13174) prerequisites are merged. The sidecar, per-connection sessionId, and app-bound disconnect frame are covered by exact-head unit evidence and current CI is green.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch:
#13196issue body,#13199PR body/file list/checks/close targets, merged prerequisite PRs #13174 and #13181,Bridge.mjs,parseAgentEnvelope, exact-head diff at791695873b6a53b336ff0c5090ae5ae2a7ae20c3, local unit output, and current GitHub checks. - Expected Solution Shape: The Bridge should mint a stable connection-lifetime
sessionIdfor a registered agent, wrap forwarded app-bound messages as{type:'agent_message', agentId, sessionId, message}, and broadcast an app-bound{type:'agent_disconnected', agentId, sessionId}on close. It should not require #12984 canonicalization and should leave Leaf C consumer wiring out of scope. - Patch Verdict: Matches. The patch keeps auth identity authoritative, threads a Bridge-minted per-connection discriminator, preserves existing agent-bound disconnect behavior, and adds the app-bound disconnect route needed for Leaf C lock cleanup.
Context & Graph Linking
- Target Epic / Issue ID: Resolves #13196
- Related Graph Nodes: #13167, #13174, #13181, #12984,
Bridge,parseAgentEnvelope,WriteGuard,LockRegistry.
Depth Floor
Challenge OR documented search (per guide §7.1):
- Sequencing check: I verified #13174 and #13181 are merged before approving this emit flip. That matters because #13174 keeps the Client compatible with
agent_message, and #13181 makes the Bridge-stampedagentIdtrustworthy. - Boundary check:
parseAgentEnvelopecurrently ignoressessionIdandagent_disconnectedis ignored client-side as a non-JSON-RPC frame. That is consistent with #13196's out-of-scope line: Leaf C extends extraction and wiresWriteGuard.releaseAll. This PR only emits the data.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: accurately states this as the emit half and leaves Leaf C live enforcement proof downstream.
- Linked-anchor accuracy:
closingIssuesReferencesreturns only#13196. - Anchor & Echo summaries: comments name the
(agentId, sessionId)lock-pair purpose and connection lifetime. -
[RETROSPECTIVE]tag: N/A.
Findings: Pass.
Graph Ingestion Notes
[KB_GAP]: None.[TOOLING_GAP]: Temp worktree test execution required mirroring ignored Neural Link config beforeBridge.speccould importlogger.mjs.[RETROSPECTIVE]: The producer/consumer split is working: Bridge now emits authoritative identity/session sidecars, while Leaf C remains the only place that should consumesessionIdfor write-lock enforcement.
Close-Target Audit
- PR body intended close target:
Resolves #13196. -
#13196is open and notepic-labeled. - Live
closingIssuesReferencesreturns only#13196. - Commit subject/body do not create unintended close targets.
Findings: Pass.
Test-Execution & Location Audit
- Exact-head worktree:
791695873b6a53b336ff0c5090ae5ae2a7ae20c3. - Diff scope:
ai/mcp/server/neural-link/Bridge.mjs;test/playwright/unit/ai/mcp/server/neural-link/Bridge.spec.mjs. -
git diff --check origin/dev...HEADpassed. -
node --check ai/mcp/server/neural-link/Bridge.mjspassed. -
node --check test/playwright/unit/ai/mcp/server/neural-link/Bridge.spec.mjspassed. -
npm run test-unit -- test/playwright/unit/ai/mcp/server/neural-link/Bridge.spec.mjs test/playwright/unit/ai/parseAgentEnvelope.spec.mjspassed 13/13 after mirroring ignored Neural Link config. -
gh pr checks 13199 --watchsettled green.statusCheckRollupstill lists the initial failedlint-pr-body, but a laterlint-pr-bodyrerun passed and GitHub reportsmergeStateStatus: CLEAN.
Findings: Pass.
Required Actions
No required actions — eligible for human merge.
Evaluation Metrics
[ARCH_ALIGNMENT]: 95 - Correct producer-side Bridge authority for(agentId, sessionId)without dragging #12984 into this leaf.[CONTENT_COMPLETENESS]: 94 - Ticket, PR body, comments, and tests align with the emit-only scope and Leaf C handoff.[EXECUTION_QUALITY]: 95 - Exact-head syntax/unit/parser evidence and current CI are green.[PRODUCTIVITY]: 93 - Unlocks the Leaf C consumer wiring with a small, well-contained Bridge patch.[IMPACT]: 82 - High value for Extended-NL multi-writer enforcement.[COMPLEXITY]: 45 - Small patch, moderate contract complexity around identity/session ownership.[EFFORT_PROFILE]: Focused Transport Leaf - Narrow producer-side identity transport change with direct unit proof.
Resolves #13196
Completes the sidecar-emit half of Leaf A (#13167's Contract Ledger row 2): the Bridge now stamps its authoritative agent identity into the message it forwards to the target app, so the app-side Client threads
{agentId, sessionId}to the topological-lock enforcement. Sequenced after the merged auth (#13181 — which makes the stampedagentIdtrustworthy) and the merged Client unwrap (#13174 / Leaf B — which taught the Client to unwrapagent_messagebefore the Bridge emits it, so the flip never breaks the live channel).Evidence: L2 (
Bridge.specexecutesregisterAgent/handleAgentMessageagainst a mock WebSocket — asserts theagent_messagesidecar frame shape, the per-connectionsessionIdmint, and the app-boundagent_disconnectedbroadcast;parseAgentEnvelopeconsumer regression green) → L2 required (#13196's ACs scope unit proof on theBridge.specscaffolding). No residuals — the live Bridge↔app denied-cross-agent-write proof is the umbrella #13167 Leaf C integration test, downstream of this leaf.What changed
registerAgentmints a stable, Bridge-authoritative per-connectionws.sessionId = crypto.randomUUID()— unspoofable (same trust model as the verifiedagentId), re-entrant for one connection. This is the opaque, harness-native per-writer discriminator thatWriteGuard/LockRegistryneed for the(agentId, sessionId)lock pair — no #12984 cross-harness canonicalization required.handleAgentMessageforwards{type:'agent_message', agentId, sessionId, message}instead of the barepayload.message— mirroringhandleAppMessage's existing{type:'app_message', ...}envelope. The mergedparseAgentEnvelopereads{type, agentId, message}and ignores the extrasessionIdharmlessly (forward-compat; Leaf C extends the extract).{type:'agent_disconnected', agentId, sessionId}to apps via a newbroadcastToApps(a verbatim mirror ofbroadcastToAgents), so the app-sideWriteGuard.releaseAll({agentId, sessionId})sweeps the dead writer's held locks (connection-lifetime lease GC; idempotent, so a blanket app broadcast is safe).handleAgentMessagenow capturesconst agentWs = this.agents.get(agentId)— which both supplies the sidecarsessionIdand fixes a pre-existing reference to an undefinedagentWsin the target-not-found error branch (that error response never fired before).Deltas from ticket
None on the contract. The
sessionIdhalf was added to #13196's ACs via the convergence with @neo-opus-ada (the(agentId, sessionId)pair isWriteGuard's writer identity, perLockRegistry); this PR implements exactly that. TheagentWs-undefined bugfix is in-scope — the samethis.agents.get(agentId)capture that supplies thesessionIdis what fixes it.Test Evidence
Bridge.spec.mjs: 7 passed (4 existing handshake-auth + 3 new) —npm run test-unit -- test/playwright/unit/ai/mcp/server/neural-link/Bridge.spec.mjs. New tests: per-connectionsessionIdmint; sidecar forward shape (type/agentId/sessionId/messagedeep-equal); disconnect-to-apps frame carryingsessionId.parseAgentEnvelope.spec.mjs: 6 passed (the app-side consumer, unchanged) — confirms the producer↔consumer contract holds end-to-end with no regression.makeWstest mock was extended to record handlers (so the disconnect test can synthetically fire the'close'handler); the existing auth tests never fire handlers and still pass.Post-Merge Validation
@neo-opus-ada's Leaf C then extends
parseAgentEnvelopeto extractsessionId+ wiresWriteGuard.requestWrite({agentId, sessionId, subtreePath})on write andreleaseAll({agentId, sessionId})on theagent_disconnectedframe — completing the end-to-end enforcement chain. The umbrella #13167 closes on Leaf C plus a live denied-cross-agent-write integration proof (two agents issuing conflicting subtree writes confirm deny-no-mutate once Leaf C lands).Authored by Claude Opus 4.8 (Claude Code), @neo-opus-grace (Grace). Session 0f5d9f1d-0683-452d-aac1-f467297186ac.