LearnNewsExamplesServices
Frontmatter
id10437
titleAuto-invoke wake subscription bootstrap on MCP server boot
stateClosed
labels
bugaiarchitecture
assigneesneo-opus-4-7
createdAtApr 27, 2026, 8:21 PM
updatedAtApr 27, 2026, 9:21 PM
githubUrlhttps://github.com/neomjs/neo/issues/10437
authorneo-opus-4-7
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtApr 27, 2026, 9:21 PM

Auto-invoke wake subscription bootstrap on MCP server boot

Closedbugaiarchitecture
neo-opus-4-7
neo-opus-4-7 commented on Apr 27, 2026, 8:21 PM

Context

Closes a missed AC from #10402 (Phase 1 wake substrate self-healing). The merged implementation (#10404 + #10412) delivered the bootstrap mechanism — idempotent, restart-safe, identity-template-driven — but never wired up the auto-trigger. Every new agent session today silently has zero WAKE_SUBSCRIPTION nodes until someone manually calls manage_wake_subscription({action: 'bootstrap'}). Without the auto-invoke, the bridge daemon polls but has nothing active to deliver to → no [WAKE] events → silent wake-substrate degradation.

The original #10402 ticket explicitly scoped this auto-trigger:

"AGENTS_STARTUP.md boot sequence invokes bootstrap so new sessions self-heal to a known-good subscription" "Post-merge validation: new session boots auto-bootstrap their subscription... Verify by terminating + restarting both harnesses; both wake substrates should self-heal without manual scratch-script intervention."

Empirical reproducer (2026-04-27 session b3c0bfb8-44e1-4646-9c62-110ef16b0fad): post-#10433 merge + harness restart, my MCP server bound @neo-opus-4-7 and ran for ~2 hours with zero WAKE_SUB for the bound identity. Bridge daemon (PID 12039) was running healthy in canonical, polling, but had nothing to deliver to. A2A read/write paths verified working; wake delivery silently broken.

The Problem

WakeSubscriptionService.bootstrap() is reachable only via the manage_wake_subscription({action: 'bootstrap'}) MCP tool dispatch path. There is no auto-invocation anywhere:

  • WakeSubscriptionService.init() (line 77) only initializes liveCursor from GraphLog — does NOT call bootstrap()
  • StdioIdentityResolver resolves identity at MCP-server startup but does not chain into wake-substrate seeding
  • No identity-bind hook, no first-call interceptor, no boot-time auto-trigger
  • The original #10402 AC item "AGENTS_STARTUP.md boot sequence invokes bootstrap" was never wired

The wake substrate has the lever to self-heal but nothing to pull it. Every new session needs an agent to remember to call bootstrap manually — a discipline burden that won't survive context-pruning. This affects every new session on both Claude Code and Antigravity sides.

The Architectural Reality

  • ai/mcp/server/memory-core/services/WakeSubscriptionService.mjs — owns the bootstrap() action (line 207). Idempotent + raw-SQL-safe per #10412.
  • ai/mcp/server/memory-core/server.mjs — the MCP server entry point; identity is bound here in stdio mode via StdioIdentityResolver.
  • ai/mcp/server/shared/services/StdioIdentityResolver.mjs — resolves the bound identity once at server boot for stdio transport.
  • ai/mcp/server/shared/services/RequestContextService.mjs — per-request identity binding (OIDC mode).
  • AgentIdentity nodes for both @neo-opus-4-7 and @neo-gemini-3-1-pro already carry valid subscriptionTemplate properties (verified empirically) — the data substrate for auto-bootstrap is already in place.

Precedent for the right substrate placement: #10181/#10182 (April 22) fixed identity-binding self-heal at server-side dispatch level, NOT via documentation discipline. Same problem class (lifecycle gap that requires per-session re-derivation otherwise); same right answer (substrate-level auto-trigger). Doc-layer mandates depend on agent compliance + survive context-pruning poorly; code-layer guarantees fire regardless.

The Fix

Primary path: server-side auto-invoke after identity bind.

In stdio mode (the dominant path for the swarm today), the seam is in server.mjs after StdioIdentityResolver resolves identity. Pseudo-code:

// In server boot sequence, after identity is bound:
if (resolvedIdentity?.agentIdentityNodeId) {
    // Fire-and-forget; failure must not gate boot
    WakeSubscriptionService.bootstrap()
        .then(result => logger.info(`[WakeSubBootstrap] ${result.action}: ${result.subscriptionId}`))
        .catch(err => logger.warn(`[WakeSubBootstrap] auto-invoke failed: ${err.message}`));
}

Failure modes the auto-invoke must handle gracefully:

  • No subscriptionTemplate on AgentIdentity — bootstrap throws; auto-invoke logs and continues. Boot must not gate on this (some identities legitimately don't need wake subs).
  • GraphService not ready — bootstrap awaits GraphService.ready() per existing logic; auto-invoke must fire AFTER that.
  • Already-existing sub — bootstrap is idempotent per #10412's raw-SQL fix; returns the existing sub.

For OIDC mode (per-request identity), the right shape is dispatch-time self-heal mirroring #10182's pattern: on first identity-bound request, check if WAKE_SUB exists for the bound identity; if not, fire-and-forget bootstrap. Defer OIDC-mode wiring if scope warrants — stdio is the load-bearing path for the swarm today.

Why NOT the doc-only fix (AGENTS_STARTUP.md mandate alone):

  • Discipline-layer mandates depend on agent compliance + survive context-pruning poorly
  • Future agents won't know to call it; the substrate must self-heal regardless
  • Per #10181/#10182 precedent, the right answer for lifecycle-gap class problems is server-side self-heal

The AGENTS_STARTUP.md note from the original #10402 AC is fine as defense-in-depth complement, but cannot be the sole mechanism.

Acceptance Criteria

  • On MCP server boot in stdio mode, after StdioIdentityResolver binds identity, WakeSubscriptionService.bootstrap() is auto-invoked
  • Auto-invoke is fire-and-forget — boot does not gate on bootstrap success/failure
  • Missing subscriptionTemplate does not crash boot — logged and skipped gracefully
  • Already-existing subscription is detected (idempotent per #10412); auto-invoke returns the existing sub without creating a duplicate
  • After fresh server boot from clean state, SELECT * FROM Nodes WHERE label='WAKE_SUBSCRIPTION' shows the auto-seeded sub for the bound identity
  • Permanent test in WakeSubscriptionService.spec.mjs (or server.spec.mjs if such a surface exists) asserting auto-invoke fires post-identity-bind without manual call
  • Post-merge validation: terminate + restart harnesses + bridge daemon. Without any manual manage_wake_subscription call, both @neo-opus-4-7 and @neo-gemini-3-1-pro get auto-seeded WAKE_SUB nodes. Bridge daemon delivers wake events on next A2A message — verify [WAKE] injection in receiver harness.

Out of Scope

  • OIDC-mode dispatch-time self-heal (defer; stdio is the dominant swarm path today; file as follow-up if/when OIDC mode is exercised)
  • AGENTS_STARTUP.md mandate (the original #10402 AC item) — this can be added as defense-in-depth in a tiny follow-up, but the substrate-level auto-invoke is the load-bearing fix per #10181/#10182 precedent. Mentioning here for completeness; not blocking.
  • Architectural restructuring of WakeSubscriptionService.bootstrap() itself (already correct + idempotent + restart-safe per the merged work)
  • Cross-clone topology coordination (already addressed by #10433 + #10436 — granular symlinks + canonical-root flag)

Avoided Traps

  • Trap: Add the AGENTS_STARTUP.md boot mandate (the original #10402 wording) and call it done. Avoided: discipline-layer fix for a lifecycle gap is not robust per #10181/#10182 precedent — depends on agent compliance, survives context-pruning poorly, fails silently if agent skips boot read.
  • Trap: Have WakeSubscriptionService.init() call bootstrap() directly. Avoided: init() runs at service initialization time (no identity context yet); the auto-invoke must fire AFTER StdioIdentityResolver binds. Wrong lifecycle hook.
  • Trap: Make boot synchronously await bootstrap completion. Avoided: bootstrap can fail (no template, GraphService not ready, etc.); fire-and-forget with try/catch + log keeps boot resilient.
  • Trap: Re-derive subscription metadata from env vars / IDE-detection inside the auto-invoke. Avoided: that's exactly the footgun #10402 closed by introducing subscriptionTemplate as canonical. Auto-invoke should ONLY consume the template; if absent, log + skip.

Related

  • Predecessor (closed prematurely): #10402 (Phase 1 wake substrate self-healing — original scope included this auto-trigger)
  • Implementation PR that closed #10402 without this AC: #10404 (feat(memory-core): stabilize wake subscription bootstrap and resolve test regressions)
  • Idempotency fix on top: #10412 (fix(memory-core): bootstrap idempotency uses raw SQL) — makes auto-invoke safe to repeat
  • Architectural precedent for substrate-level auto-heal: #10181/#10182 (identity-binding self-heal on dispatch)
  • Cross-process coherence root cause that exposed this gap: #10424
  • Substrate-level fix that restored coherence: #10433 (granular per-subdir symlinking)

Origin Session ID: b3c0bfb8-44e1-4646-9c62-110ef16b0fad

Retrieval Hint: "wake subscription auto-bootstrap server boot stdio identity resolved missing AC #10402 phase 1 completion"

tobiu referenced in commit 09984a9 - "fix(memory-core): auto-invoke wake subscription bootstrap on MCP server boot (#10437) (#10438) on Apr 27, 2026, 9:21 PM
tobiu closed this issue on Apr 27, 2026, 9:21 PM
tobiu referenced in commit b38ef32 - "fix(graph): set Gemini's identity-root appName to 'Antigravity' (#10440) (#10441) on Apr 27, 2026, 9:42 PM
tobiu referenced in commit 2405528 - "feat(ai): migrate memory-core/Server to extend BaseServer + beforeToolDispatch hook (#10965) (#10977) on May 8, 2026, 6:45 PM