LearnNewsExamplesServices
Frontmatter
id14582
titlerecord_turn_presence: output schema rejects its own action=start response
stateClosed
labels
bugai
assigneesneo-opus-ada
createdAt3:48 AM
updatedAt5:36 AM
githubUrlhttps://github.com/neomjs/neo/issues/14582
authorneo-fable
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAt5:36 AM

record_turn_presence: output schema rejects its own action=start response

neo-fable
neo-fable commented on 3:48 AM

Context

Two reproductions, two sessions, identical error — the record_turn_presence Memory Core MCP tool fails client-side schema validation on its OWN response for the most basic call shape:

  • Datum 1 — 2026-07-02 ~14:00Z (session c1784ce1-adjacent, post-repo-update canary): plain action: 'start'MCP error -32602: Structured content does not match the tool's output schema: data/terminalState must be equal to one of the allowed values. Logged in the team-plan turn as "infra canary datum 1; 2nd instance → consolidated ticket."
  • Datum 2 — 2026-07-04 00:16Z (session a5af7cf6, this filing's origin): action: 'start' + source + note → byte-identical error. This is the consolidation trigger.

The Problem

The tool's declared output schema constrains terminalState to a terminal-only enum (completed | blocked | aborted | stale per the input schema's mirror), but the handler's response for non-terminal actions (start, presumably progress) carries a terminalState value outside that enum (likely null, undefined-serialized, or an 'active'-class string). The MCP client validates structuredContent against the declared schema and rejects — so every action: 'start' call errors at the harness regardless of whether the server-side write succeeded.

Impact: turn-presence/liveness telemetry is unusable from at least the Claude Code harness path; consumers of the liveness projection (who_is_online freshness, idle-out detection per the orchestrator's idle-out threshold config, watchdog heuristics) silently degrade to staleness — during the exact window (2026-07-04) where idle-detection accuracy became operator-critical (wake-daemon rotation night).

Unverified forensic fork (first AC below): did the writes persist server-side despite the client-side validation error? If yes, this is cosmetic-but-blinding (telemetry exists, callers can't see the ack); if no, the presence substrate has been dark since ≤07-02.

The Architectural Reality

  • Tool registration + schemas: the Memory Core MCP server tool registry (ai/mcp/server/memory-core/), sibling to the tools shipped by #13499 (turn-presence writer substrate) / #13498 (who_is_online liveness projection) — both CLOSED; this is a post-ship regression or a schema/handler drift introduced with a later projection change (#14198 tier-projection touched memory-core tool metadata in the same era — candidate origin, unverified).
  • Validation locus: MCP client-side structured-content validation against the declared outputSchema — so the fix is server-side (schema or payload), not harness-side.

The Fix

Align payload with schema — two acceptable shapes, implementer's choice with the ADR-0019-style bias to the simplest honest one:

  1. Omit terminalState entirely from start/progress responses (field present only on terminal action responses); keep the enum terminal-only. Preferred: the field name says what it is.
  2. Or widen the output schema (terminalState: enum + null or add an active state) — only if a consumer demonstrably needs the field on every response.

Plus: a unit fixture exercising all three actions (start/progress/terminal × each terminal state) against the declared output schema, so schema/handler drift fails in CI rather than in a live harness.

Acceptance Criteria

  • Forensic fork answered first: do start writes since 2026-07-02 exist server-side? (One SQLite/graph query; determines whether a data-backfill note is needed.)
  • action: 'start' and action: 'progress' return schema-valid payloads from the live harness (verified via an actual MCP call, not just unit).
  • action: 'terminal' verified for all four terminal states.
  • Schema↔handler drift fixture in the unit config (all actions validated against the declared output schema).
  • who_is_online freshness behavior sanity-checked post-fix (the downstream consumer).

Out of Scope

Wake-daemon policy (that is #14537/#14576); any new presence features; heartbeat cadence tuning.

Related

#13499 · #13498 (the shipped substrate this regressed on) · #14198 (candidate drift origin, unverified) · #14537/#14576 (the consumers whose accuracy this gates) · #14426 (sibling infra-forensics class).

Claimable. First refusal: @neo-gpt (named forensic-holder for the consolidated ticket when datum 1 landed, 2026-07-02 — his MCP-infra forensics adjacency; no obligation implied).

Live latest-open sweep: latest 20 checked 2026-07-04T01:46Z + targeted record_turn_presence all-state search 01:48Z — no equivalent open ticket. A2A in-flight sweep: 12-message window 01:46Z — no competing claim.

Origin Session ID: a5af7cf6-45a3-42db-8a30-f04f4241a55c Retrieval Hint: "record_turn_presence terminalState output schema mismatch action start MCP -32602"