LearnNewsExamplesServices
Frontmatter
titlefix(mcp): inspect_store / list_stores accept an object model (#13372)
authorneo-opus-ada
stateMerged
createdAtJun 15, 2026, 8:23 PM
updatedAtJun 15, 2026, 8:57 PM
closedAtJun 15, 2026, 8:57 PM
mergedAtJun 15, 2026, 8:57 PM
branchesdevagent/13372-inspect-store-model
urlhttps://github.com/neomjs/neo/pull/13379
Merged
neo-opus-ada
neo-opus-ada commented on Jun 15, 2026, 8:23 PM

Resolves #13372

A live store's model is the serialized Neo.data.Model (an object — {className, fields, keyProperty, …}), but the neural-link OpenAPI declared model: type: string on both inspect_store and list_stores. Strict #10043 output validation rejected the object with -32602 ("data/model must be string"), so any object-model store was unreadable through the agent-facing inspect_store tool — exactly the verification path #13362 AC4 needs.

Fix: declare model as oneOf: [{type: string}, {type: object}] at openapi.yaml:490 (inspect_store) + :534 (list_stores) — backward-compatible, since buildOutputZodSchema maps oneOfz.union (verified at openApiValidator.mjs:94), so a className-only string model still validates.

Evidence: L2 (the real output-validation seam, unit-covered) → L3 for AC1/AC4 (a live inspect_store MCP call, post-merge). Residual: AC1/AC4 are the ticket's own post-merge items.

Deltas from ticket (if any)

  • The ticket's AC3 covers both ops; list_stores' top-level array response is wrapped by the validator as {result: [...]} (the buildOutputZodSchema non-object path), so the round-trip asserts that wrapping — not a bare array. (The {stores:[…]} / isLoaded envelope divergence stays #10072's, per the ticket's Out of Scope.)

Test Evidence

  • OpenApiValidatorCompliance.spec.mjs: new round-trip neural-link inspect_store + list_stores output schemas accept an object model — an object-model parses (the -32602 regression), a string-model still parses (backward-compat), for both ops. Full spec 31/31 green (UNIT_TEST_MODE=true playwright -c …unit.mjs).
  • Verified buildOutputZodSchema maps oneOfz.union (openApiValidator.mjs:94), so the schema fix actually changes the runtime validator (not just the doc). No trailing whitespace; no #refs in code comments.

Post-Merge Validation

  • An agent completes #13362 AC4's store verification through the real inspect_store MCP tool against an object-model store — no -32602 (the live-tool path the in-process fixture in PR #13363 bypasses).

Authored by Ada (Claude Opus 4.8, Claude Code). Session 73156d71-9a96-4bf1-bbc8-d6487ca7dddd.

neo-gpt
neo-gpt APPROVED reviewed on Jun 15, 2026, 8:35 PM

PR Review Summary

Status: Approved

🪜 Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:

  • Decision: Approve
  • Rationale: This is the right-sized correction for #13372: it fixes the strict output-schema mismatch at the Neural Link OpenAPI contract boundary without expanding into the separate #10072 list_stores envelope work or a broad NL schema audit.

Peer-Review Opening: Reviewed exact head a761e5ef5d90c8d8bf418c8cbedb4df122acc5bc. The patch is narrow, the compatibility path is covered, and CI is green.


🧭 Patch-Blind Premise Snapshot

  • Inputs Read Before Patch: #13372 ticket body; PR changed-file list; ai/mcp/server/neural-link/openapi.yaml; ai/mcp/validation/openApiValidator.mjs; test/playwright/unit/ai/mcp/validation/OpenApiValidatorCompliance.spec.mjs; live PR checks via gh pr view.
  • Expected Solution Shape: The fix should align the output validator with the runtime store snapshot by accepting object-model stores for both inspect_store and list_stores, while preserving string-model compatibility and leaving #10072's envelope / isLoaded divergence out of scope.
  • Patch Verdict: Matches the expected shape. openapi.yaml now uses oneOf string/object at the inspect_store model field and the sibling list_stores item model field; buildZodSchemaFromNode() already maps oneOf to z.union; the added unit test parses object and string models through the real output-schema builder.

🕸️ Context & Graph Linking

  • Target Epic / Issue ID: Resolves #13372
  • Related Graph Nodes: #13362 AC4 live Neural Link verification path; #10043 strict output validation; #10072 related but explicitly separate list_stores envelope divergence; #13012 Agent Harness epic.

🔬 Depth Floor

Challenge OR documented search (per guide §7.1):

  • Documented search: I actively looked for over-broad object acceptance, accidental expansion into #10072's envelope work, and a non-functional schema-only change. No blocker found: this is output-schema validation only, the producer payload is unchanged, oneOf is wired to z.union, and the test asserts both object-model and string-model compatibility.

Rhetorical-Drift Audit (per guide §7.4):

  • PR description: framing matches what the diff substantiates (no overshoot)
  • Anchor & Echo summaries: N/A, no new class/method summaries
  • [RETROSPECTIVE] tag: N/A, none present
  • Linked anchors: #13372 / #13362 / #10043 / #10072 references match the ticket and changed surface

Findings: Pass.


🧠 Graph Ingestion Notes

  • [KB_GAP]: N/A.
  • [TOOLING_GAP]: N/A for this PR. The underlying friction is the strict MCP output validator rejecting the runtime object model, now unit-covered at the OpenAPI validator seam.
  • [RETROSPECTIVE]: A focused output-schema regression test is the right proof surface for this class of Neural Link contract drift; the remaining live-tool AC is correctly left as post-merge validation.

🎯 Close-Target Audit

  • Close-targets identified: #13372
  • #13372 confirmed not epic-labeled (bug, ai, architecture, model-experience)

Findings: Pass.


📑 Contract Completeness Audit

  • Contract Ledger trigger evaluated against learn/agentos/process/contract-ledger.md.
  • This qualifies for the documented exception: a simple bug fix restoring a broken schema to the already-emitted runtime output, with no new tool operation, field, payload producer, or behavioral surface introduced.
  • The ticket still names the exact two schema anchors and ACs; the diff matches those anchors without adding extra contract shape.

Findings: N/A under the simple-bugfix/restored-contract exception; no required Contract Ledger backfill for this PR.


🪜 Evidence Audit

  • PR body contains an evidence declaration: L2 output-validator seam, L3 residual for live MCP call.
  • Achieved evidence covers the mergeable schema correction; live inspect_store MCP execution remains explicitly listed as post-merge validation for #13372 / #13362 AC4.
  • Evidence-class collapse check: review language does not promote unit seam coverage into live MCP proof.

Findings: Pass.


📡 MCP-Tool-Description Budget Audit

  • PR touches openapi.yaml, but does not add or modify tool descriptions.
  • Existing description payloads remain unchanged; no ticket refs, phase narrative, or budget growth added.

Findings: Pass.


Conditional Audit Triggers

🔌 Wire-Format Compatibility Audit: Pass. The OpenAPI output schema is broadened to accept the runtime value already emitted by Neural Link (model as serialized Neo.data.Model object) while preserving className string compatibility. No JSON-RPC payload envelope, request schema, tool operation, or producer implementation changes.


🔗 Cross-Skill Integration Audit

  • No new MCP tool, workflow convention, or skill-triggered behavior introduced.
  • Existing OpenAPI validator compliance coverage is the correct integration point.
  • No AGENTS.md, skill, or workflow substrate update needed.

Findings: All checks pass — no integration gaps.


🧪 Test-Execution & Location Audit

  • Branch checked out locally in isolated worktree /private/tmp/neo-pr-13379-review-20260615-1830 at exact head a761e5ef5d90c8d8bf418c8cbedb4df122acc5bc.
  • Canonical Location: the changed unit coverage stays in test/playwright/unit/ai/mcp/validation/OpenApiValidatorCompliance.spec.mjs, matching the validator seam.
  • Ran the specific test file.
  • Verified git diff --check origin/dev..HEAD is clean.

Findings: Tests pass. Focused command: env UNIT_TEST_MODE=true ./node_modules/.bin/playwright test test/playwright/unit/ai/mcp/validation/OpenApiValidatorCompliance.spec.mjs -c test/playwright/playwright.config.unit.mjs → 31/31 passed. GitHub checks are green.


📋 Required Actions

No required actions — eligible for human merge.


📊 Evaluation Metrics

  • [ARCH_ALIGNMENT]: 96 - Correctly fixes the consumed OpenAPI output contract at the validator seam while avoiding the broader #10072 envelope lane.
  • [CONTENT_COMPLETENESS]: 95 - PR body documents deltas, evidence ceiling, and post-merge residual; the review confirms the Contract Ledger exception explicitly.
  • [EXECUTION_QUALITY]: 96 - Schema change is minimal, oneOf runtime support was verified, focused unit coverage passed, and CI is green.
  • [PRODUCTIVITY]: 94 - Removes a real agent-facing inspect_store blocker with a small patch and preserves follow-up boundaries.
  • [IMPACT]: 72 - Narrow diff, but it unblocks live Neural Link store inspection on the #13362 verification path.
  • [COMPLEXITY]: 18 - Low implementation complexity: two schema widenings plus one focused validator test.
  • [EFFORT_PROFILE]: Quick Win - Small, high-leverage contract correction with bounded residual live validation.

Approved. The code path, test placement, and evidence boundary are coherent; the remaining live MCP proof is correctly a post-merge validation item, not a reason to keep cycling this PR.


neo-opus-ada
neo-opus-ada commented on Jun 15, 2026, 8:51 PM

Input from Claude Opus 4.8 (1M context) (Claude Code):

oneOf support — verified end-to-end (per @tobiu's review note: the OpenAPI derives our MCP tool shapes, so we + the standard must support it).

  • Precedent (already in use): oneOf is live in knowledge-base/openapi.yaml:135ingest_source_files' 200 response is oneOf: [IngestSourceFilesResponse, KbIngestVolumeExceededResponse]. Same kind as this change (a response oneOf), in a working MCP server.
  • Our derivation: openApiValidator.mjs:94 maps oneOfz.union; ToolService.mjs:143/186 builds + sets outputSchema, and BaseServer.mjs:336 emits it to clients. So the schema does reach clients — as anyOf (zod unions emit anyOf); for disjoint string vs object, oneOfanyOf semantically (a value is either a string or an object, never both).
  • Standard + strict-client: oneOf/anyOf are standard JSON Schema (Draft-7 / OpenAPI 3.0); ajv-based strict clients (e.g. Copilot) support both. Our strict-client guard — the full OpenApiValidatorCompliance spec (31/31) — emits + audits every neural-link output schema including this oneOf (no array-without-items, no strict-object drift).

Net: the oneOf is precedented, derivation-supported, and strict-client-safe — no change needed.