LearnNewsExamplesServices
Frontmatter
id11819
titleAllow null `from` in mailbox latestPreview schema for system messages
stateClosed
labels
bugaimodel-experience
assigneesneo-opus-4-7
createdAtMay 23, 2026, 6:40 AM
updatedAtMay 23, 2026, 10:19 AM
githubUrlhttps://github.com/neomjs/neo/issues/11819
authorneo-opus-4-7
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 23, 2026, 10:19 AM

Allow null from in mailbox latestPreview schema for system messages

Closedbugaimodel-experience
neo-opus-4-7
neo-opus-4-7 commented on May 23, 2026, 6:40 AM

Context

Empirical anchor (this session, 2026-05-23): add_memory MCP tool repeatedly rejected with schema validation error when the mailbox preview pointed at a system-sent heartbeat message:

MCP error -32602: Structured content does not match the tool's output schema:
data/mailbox/latestPreview/from must be string,
data/mailbox/latestPreview must be null,
data/mailbox/latestPreview must match a schema in anyOf

Four observed occurrences this session, each blocked end-of-turn add_memory consolidation until the heartbeat message was manually marked-read first. Workaround discovered: mark_read on the null-from message clears the preview to null (which the schema accepts), then add_memory succeeds.

The Problem

ai/mcp/server/memory-core/openapi.yaml:1816-1818 defines latestPreview.from as:

from:
  type: string
  description: The sender's AgentIdentity node id
  example: "@neo-gemini-3-1-pro"

No nullable: true. The schema rejects any from: null value.

But ai/services/memory-core/MemoryService.mjs:126-129 legitimately returns null for the from field when no SENT_BY edge exists on the message:

(
    SELECT se.target FROM Edges se
    WHERE se.source = messageId AND se.type = 'SENT_BY'
    LIMIT 1
) AS "from"

For system-generated messages (heartbeats, idle-out nudges) there is no SENT_BY edge — the system is the sender, and that's structurally distinct from agent-sender messages. The current behavior is correct at the data layer (null = no agent-sender) but incorrect at the schema layer (rejects the data layer's legitimate null).

The Architectural Reality

Surface Behavior Status
MemoryService.mjs mailbox-delta query Returns from: null for system messages Correct
list_messages MCP tool output Already accepts/returns from: null for system messages (empirically verified by list_messages returning heartbeat preview rows without error) Correct
add_memory mailbox-preview block schema Rejects from: null because latestPreview.from is not nullable: true Bug

list_messages and add_memory mailbox-preview blocks both surface the same data shape, but list_messages is permissive while add_memory is strict. Inconsistency.

The Fix

Single-line nullable: true addition to ai/mcp/server/memory-core/openapi.yaml:1816-1818:

from:
  type: string
  nullable: true
  description: The sender's AgentIdentity node id; `null` for system-sent messages (heartbeats, idle-out nudges) that have no SENT_BY edge in the graph
  example: "@neo-gemini-3-1-pro"

Updated description preserves the empirical reality for future schema readers.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
latestPreview.from field in add_memory mailbox-preview block This ticket + MemoryService.mjs:126-129 legitimately-null behavior Schema accepts from: null for system messages; description updated to name the empirical cause None (single-line nullability addition) Inline JSDoc / schema description Reproducer: send mailbox preview block from add_memory while mailbox contains a system-sent heartbeat — current fails, post-fix passes

Decision Record Impact

none. Inline schema-shape correction matching the legitimately-permissive list_messages surface; no ADR consultation needed.

Acceptance Criteria

  • AC1: ai/mcp/server/memory-core/openapi.yaml:1816-1818 latestPreview.from carries nullable: true.
  • AC2: Description updated to document the system-message null case.
  • AC3: add_memory succeeds when the mailbox preview points at a system-sent heartbeat (no manual mark_read prerequisite).
  • AC4: list_messages permissive behavior unchanged.
  • AC5: No service-side code change required — MemoryService.mjs:126-129 already returns the correct shape; schema is the sole drift surface.

Out of Scope

  • Filtering system messages from latestPreview entirely (would hide information from agents; the current shape correctly surfaces "this is a system message with no agent sender").
  • Adding a sentinel "from": "@system" instead of null (loses the structural "no SENT_BY edge" signal; muddles data layer).
  • Broader schema audit of other potentially-null fields (separate sweep if more drift surfaces emerge; this is the only one empirically observed this session).

Avoided Traps

Trap Why rejected
Coalesce null to "@system" in service code Muddles data layer; loses structural distinction; breaks the from: null → "no SENT_BY edge" graph-level invariant
Filter system messages out of latestPreview Hides legitimate information from agents (they'd not see heartbeats in the preview); harms observability
Add nullable only at latestPreview level (the object), not at from field Wouldn't address the actual rejection — the strictness is on the field, not the parent

Related

  • Empirical anchor: 4 observed add_memory rejections this session in b08bd969-3a3b-49a1-9bfe-9941820e7fbd (current) + the earlier session segments
  • Schema surface: ai/mcp/server/memory-core/openapi.yaml:1805-1823
  • Service surface (correct, no change needed): ai/services/memory-core/MemoryService.mjs:126-129
  • Consistency sibling: list_messages MCP tool already accepts/returns from: null for system messages

Origin Session ID: b08bd969-3a3b-49a1-9bfe-9941820e7fbd

Pre-Flight reasoning per ticket-create-workflow.md §1d: Will attach to Project 12 per §4 (v13 Release board), per the mandate currently in PR #11818 (still pending @tobiu merge but already operator-direction).

tobiu referenced in commit 3a44d5f - "fix(mcp): allow null from in mailbox latestPreview schema for system messages (#11819) (#11820) on May 23, 2026, 10:19 AM
tobiu closed this issue on May 23, 2026, 10:19 AM