Repository navigation
[BUG] OpenClaw schema tools misread response fields: valid notes render as undefined - invalid #1997
Description
Bug Description
The OpenClaw plugin's schema_validate, schema_infer and schema_diff tools read response properties that the Basic Memory backend does not return. Consequently, valid notes are displayed as undefined - invalid, note-type labels are undefined or missing, and dropped fields are described using an undefined schema location.
This is reproducible with @basicmemory/openclaw-basic-memory@1.0.0 and Basic Memory 1.0.0. The affected renderers and schema client methods are unchanged on upstream main at 77f40181f35418e6792999751aa196d7d7e0b1b3 (checked October 30, 2026). The backend returns correct structured data; the defect is in the adapter's response interfaces and text rendering.
Steps To Reproduce
Live OpenClaw tool path
- Use the OpenClaw plugin 1.0.0 with Basic Memory 1.0.0 and an accessible local project containing a schema and at least one note which passes it.
- Call the plugin's
schema_validatetool with that note'sidentifierand explicitproject. - Compare its rendered output with the backend result for the same note:
bm tool schema validate --identifier '<existing-note>' --project '<project>' --local --json
- The backend reports
passed: truewith the note's identifier, while the plugin displays that note asundefined - invalid.
I executed this against an existing schema-covered note, not an empty/no-schema case. The project's name and note identifier are omitted here; the relevant result fields and all rendered output below retain their observed values.
Deterministic reproduction of all three renderers
Save the following as schema-rendering-repro.mjs, then run it against an already-installed plugin package directory (the directory containing its package.json and dist/):
node schema-rendering-repro.mjs /path/to/node_modules/@basicmemory/openclaw-basic-memoryThis invokes the actual compiled registration functions and renderers, with synthetic response objects matching the backend's published response models. It does not start MCP, require credentials, or modify notes. I executed this exact script against the installed 1.0.0 package. The fixture route isolates rendering; it is separate from the live reproduction above.
import { resolve } from "node:path";
import { pathToFileURL } from "node:url";
const root = resolve(process.argv[2] ?? ".");
const note = (identifier, passed, errors = []) => ({
note_identifier: identifier, schema_entity: "schema/adapter-audit", passed,
field_results: [], unmatched_observations: {}, unmatched_relations: [],
warnings: [], errors,
});
const fixtures = {
schemaValidate: {
note_type: "AdapterAudit", total_notes: 2, total_entities: 2,
valid_count: 1, warning_count: 0, error_count: 1,
results: [note("adapter-audit/valid", true),
note("adapter-audit/invalid", false, ["Missing required field: fact"])],
type_summaries: [],
},
schemaInfer: {
note_type: "AdapterAudit", notes_analyzed: 2,
field_frequencies: [{name: "fact", source: "observation", count: 2,
total: 2, percentage: 1, sample_values: ["checked"],
is_array: false, target_type: null}],
suggested_schema: {fact: "string"}, suggested_required: ["fact"],
suggested_optional: [], excluded: [],
},
schemaDiff: {
note_type: "AdapterAudit", schema_found: true, new_fields: [],
dropped_fields: [{name: "obsolete", source: "observation", count: 0,
total: 2, percentage: 0}], cardinality_changes: [], notes_compared: 2,
},
};
for (const [file, method, registration] of [
["schema-validate", "schemaValidate", "registerSchemaValidateTool"],
["schema-infer", "schemaInfer", "registerSchemaInferTool"],
["schema-diff", "schemaDiff", "registerSchemaDiffTool"],
]) {
const module = await import(pathToFileURL(resolve(root, "dist/tools", file + ".js")));
let tool;
module[registration]({registerTool(t) { tool = t; }},
{[method]: async () => fixtures[method]});
const result = await tool.execute("schema-renderer-repro",
{noteType: "AdapterAudit", project: "fixture"});
console.log(`\n${file}:\n${result.content[0].text}`);
}Expected Behavior
- Validation identifies each note using
note_identifierand displays its actualpassedresult. The passing fixture must beadapter-audit/valid - valid; the failing fixture must beadapter-audit/invalid - invalid, retaining its error. - Type headings use
note_typefor validation, inference and drift. - Drift output describes dropped fields using fields the backend supplies (
name,source,count,total,percentage), without inventing adeclared_invalue. - Rendered per-note outcomes agree with aggregate counts and structured results.
Actual Behavior
Observed live tool output
**Notes:** 1 | **Valid:** 1 | **Warnings:** 0 | **Errors:** 0
- **undefined** — invalid
For the same note, the direct CLI JSON returned valid_count: 1, warning_count: 0, error_count: 0, and a result with a populated note_identifier, passed: true, warnings: [], and errors: [].
Output from the deterministic script
schema-validate:
**Notes:** 2 | **Valid:** 1 | **Warnings:** 0 | **Errors:** 1
- **undefined** — invalid
- **undefined** — invalid
- error: Missing required field: fact
schema-infer:
**Type:** undefined
**Notes analyzed:** 2
**Required fields:** fact
### Field Frequencies
- **fact** — 100% (2 notes)
### Suggested Schema
```json
{
"fact": "string"
}
```
schema-diff:
**Type:** undefined
### Dropped Fields (in schema, not in notes)
- **obsolete** — declared in undefined
Both validation fixtures are rendered as unnamed invalid notes, even though only one failed. Inference and drift also lose the type name. Drift's dropped-field description is declared in undefined.
Environment
- OS: Ubuntu 26.04.1 LTS, x86_64.
- Python: 3.14.10.
- Basic Memory backend: 1.0.0, local stdio MCP and SQLite.
- Backend installation: uv-managed
basic-memory[litellm]==1.0.0. - OpenClaw plugin:
@basicmemory/openclaw-basic-memory@1.0.0, enabled in the running host and installed through OpenClaw's npm-managed plugin installation. - OpenClaw: 2026.10.9, source build
5f6f15fed0d. - Node: v26.13.0.
- Claude Desktop: not applicable; this is the OpenClaw integration.
Additional Context
Version and verification boundaries
- npm latest was 1.0.0 when checked, published October 29, 2026 at 23:49 UTC.
- I verified the registry tarball's integrity and compared its schema renderer and client source/compiled files with the installed package; those files match.
- Upstream main's three schema renderer source files are byte-identical to the installed 1.0.0 files. The three schema client methods are unchanged too. Other client startup code has changed on main; I am not claiming the whole client is identical.
- The installed backend response-model file matches main. Upstream main was source-inspected, not deployed and live-tested.
- The live reproduction covers validation. The nonempty inference, dropped-field drift, and mixed valid/invalid cases were exercised through the actual compiled renderers using the synthetic backend-shaped fixtures above.
Impact and workaround
The text presented to the agent can contradict a successful validation result and conceal which note was checked. Drift output also loses useful evidence. The mismatch is deterministic for these nonempty response shapes; a zero-note or no-schema check would miss it.
Raw result details and direct CLI JSON preserve the backend's correct fields. Those are workarounds. This evidence does not indicate stored-note corruption or a need to reindex.
Related reports checked
I searched open/closed issues and PRs using the tool names, undefined, declared_in, note_identifier/passed, and schema-rendering terms. I found no report of this adapter field-mapping defect. In particular:
- [BUG] schema_validate with no identifier or note_type defaults to validating type 'unknown' instead of all types #1013 concerns no-argument validation scope, not incorrect rendering of a returned note.
- bm_* tools: six issues found while verifying the manual examples #1843's schema item concerns stale no-schema guidance.
- refactor(mcp): fold schema tools into bm_schema #1959 consolidates backend schema tools; it does not fix these OpenClaw renderers.
- Schema fields should be satisfiable by frontmatter, not only observations #1973 concerns whether frontmatter satisfies schema fields. Here the backend already says the note passed.
- [BUG] OpenClaw 2026.10.6 degrades Basic Memory context engine to legacy; auto-capture never runs #1880 / fix(integrations): make the OpenClaw plugin work on OpenClaw 2026.10 #1966 concern OpenClaw host compatibility; the published 1.0.0 plugin still reproduces this separate problem.
Possible Solution
Align the adapter's TypeScript response interfaces and consumers with the existing backend contract:
| Area | Adapter reads | Backend supplies |
|---|---|---|
| Validation/inference/drift type | entity_type |
note_type |
| Validation note identity | identifier |
note_identifier |
| Validation outcome | valid |
passed |
| Drift dropped-field description | declared_in |
No such field; use source, count, total, percentage |
The client casts the structured payload to the declared interfaces; it does not translate these fields, so the stale declarations hide the mismatch from TypeScript.
Pinned source references:
- Backend response models.
- Adapter response interfaces and schema methods returning casts.
- Validation renderer.
- Inference renderer.
- Drift renderer.
Regression coverage should include a passing note, a failing note, warning/error preservation, a nonempty inferred type, and at least one dropped field, using response objects derived from the backend contract. The existing aggregate counts should remain correct. A passing empty-result test would not cover this defect.
Activity
fix(integrations): read bm_schema fields the backend actually returns (…