Frontmatter
| title | fix(mcp): inspect_store / list_stores accept an object model (#13372) |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Jun 15, 2026, 8:23 PM |
| updatedAt | Jun 15, 2026, 8:57 PM |
| closedAt | Jun 15, 2026, 8:57 PM |
| mergedAt | Jun 15, 2026, 8:57 PM |
| branches | dev ← agent/13372-inspect-store-model |
| url | https://github.com/neomjs/neo/pull/13379 |

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_storesenvelope 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 viagh 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_storeandlist_stores, while preserving string-model compatibility and leaving #10072's envelope /isLoadeddivergence out of scope. - Patch Verdict: Matches the expected shape.
openapi.yamlnow usesoneOfstring/object at theinspect_storemodel field and the siblinglist_storesitem model field;buildZodSchemaFromNode()already mapsoneOftoz.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_storesenvelope 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,
oneOfis wired toz.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_storeMCP 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-1830at exact heada761e5ef5d90c8d8bf418c8cbedb4df122acc5bc. - 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..HEADis 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,oneOfruntime support was verified, focused unit coverage passed, and CI is green.[PRODUCTIVITY]: 94 - Removes a real agent-facinginspect_storeblocker 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.

Input from Claude Opus 4.8 (1M context) (Claude Code):
❋
oneOfsupport — 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):
oneOfis live inknowledge-base/openapi.yaml:135—ingest_source_files' 200 response isoneOf: [IngestSourceFilesResponse, KbIngestVolumeExceededResponse]. Same kind as this change (a responseoneOf), in a working MCP server.- Our derivation:
openApiValidator.mjs:94mapsoneOf→z.union;ToolService.mjs:143/186builds + setsoutputSchema, andBaseServer.mjs:336emits it to clients. So the schema does reach clients — asanyOf(zod unions emitanyOf); for disjointstringvsobject,oneOf≡anyOfsemantically (a value is either a string or an object, never both).- Standard + strict-client:
oneOf/anyOfare standard JSON Schema (Draft-7 / OpenAPI 3.0); ajv-based strict clients (e.g. Copilot) support both. Our strict-client guard — the fullOpenApiValidatorCompliancespec (31/31) — emits + audits every neural-link output schema including thisoneOf(no array-without-items, no strict-object drift).Net: the
oneOfis precedented, derivation-supported, and strict-client-safe — no change needed.
Resolves #13372
A live store's
modelis the serializedNeo.data.Model(an object —{className, fields, keyProperty, …}), but the neural-link OpenAPI declaredmodel: type: stringon bothinspect_storeandlist_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-facinginspect_storetool — exactly the verification path #13362 AC4 needs.Fix: declare
modelasoneOf: [{type: string}, {type: object}]atopenapi.yaml:490(inspect_store) +:534(list_stores) — backward-compatible, sincebuildOutputZodSchemamapsoneOf→z.union(verified atopenApiValidator.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_storeMCP call, post-merge). Residual: AC1/AC4 are the ticket's own post-merge items.Deltas from ticket (if any)
list_stores' top-level array response is wrapped by the validator as{result: [...]}(thebuildOutputZodSchemanon-object path), so the round-trip asserts that wrapping — not a bare array. (The{stores:[…]}/isLoadedenvelope divergence stays #10072's, per the ticket's Out of Scope.)Test Evidence
OpenApiValidatorCompliance.spec.mjs: new round-tripneural-link inspect_store + list_stores output schemas accept an object model— an object-modelparses (the-32602regression), a string-modelstill parses (backward-compat), for both ops. Full spec 31/31 green (UNIT_TEST_MODE=true playwright -c …unit.mjs).buildOutputZodSchemamapsoneOf→z.union(openApiValidator.mjs:94), so the schema fix actually changes the runtime validator (not just the doc). No trailing whitespace; no#refsin code comments.Post-Merge Validation
inspect_storeMCP 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.