Skip to content

Commit 1987581

Browse files
phernandezclaude
andcommitted
docs: update v0.19.0 release notes and apply formatting fixes
Add #634 (stale schema metadata) to bug fixes section. Apply ruff formatting to schema.py, write_note.py, test files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 59134af commit 1987581

5 files changed

Lines changed: 40 additions & 26 deletions

File tree

docs/releases/v0.19.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ making all major CLI commands scriptable for CI pipelines and automation.
255255
- **#31**: `search_notes` returns cluttered observation/relation-level results — now defaults to entity-level results
256256
- **#28**: `schema_infer` and `schema_diff` return raw Pydantic models as "undefined" in LLM output — added markdown formatters
257257
- Fix `schema_validate` identifier resolution (now uses LinkResolver) and text rendering (markdown formatter)
258+
- **#634**: `schema_validate` and `schema_diff` use stale database metadata instead of reading schema definitions from file — now reads frontmatter directly from the file with fallback to database metadata
258259
- Fix `Post(**metadata)` crash when frontmatter contains `content` or `handler` keys
259260
- Fix list-valued frontmatter fields (`title`, `type`) crashing on `.strip()` — now coerced to strings
260261
- Cap sqlite-vec knn `k` parameter at 4096 to prevent backend errors

src/basic_memory/mcp/tools/schema.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ def _format_inference_report(report: InferenceReport) -> str:
8484
req_marker = "required" if f.name in report.suggested_required else "optional"
8585
samples = ", ".join(f.sample_values[:3]) if f.sample_values else ""
8686
sample_str = f" (e.g. {samples})" if samples else ""
87-
lines.append(f"- **{f.name}** ({f.source}) — {pct} ({f.count}/{f.total}) "
88-
f"[{req_marker}]{sample_str}")
87+
lines.append(
88+
f"- **{f.name}** ({f.source}) — {pct} ({f.count}/{f.total}) "
89+
f"[{req_marker}]{sample_str}"
90+
)
8991
lines.append("")
9092

9193
# --- Excluded fields ---

src/basic_memory/mcp/tools/write_note.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ async def write_note(
144144
# Trigger: caller omitted the parameter (None)
145145
# Why: lets users set a global default without breaking per-call overrides
146146
effective_overwrite = (
147-
overwrite if overwrite is not None
148-
else ConfigManager().config.write_note_overwrite_default
147+
overwrite if overwrite is not None else ConfigManager().config.write_note_overwrite_default
149148
)
150149

151150
async with get_project_client(project, workspace, context) as (client, active_project):
@@ -230,9 +229,7 @@ async def write_note(
230229
"action": "conflict",
231230
"error": "NOTE_ALREADY_EXISTS",
232231
}
233-
return _format_overwrite_error(
234-
title, entity.permalink, active_project.name
235-
)
232+
return _format_overwrite_error(title, entity.permalink, active_project.name)
236233

237234
logger.debug(f"Entity exists, updating instead permalink={entity.permalink}")
238235
try:

tests/markdown/test_date_frontmatter_parsing.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
def test_file_with_date(tmp_path):
1717
"""Create a test file with date fields in frontmatter."""
1818
test_file = tmp_path / "test_note.md"
19-
test_file.write_text(dedent("""\
19+
test_file.write_text(
20+
dedent("""\
2021
---
2122
title: Test Note
2223
date: 2025-10-24
@@ -29,15 +30,17 @@ def test_file_with_date(tmp_path):
2930
# Test Content
3031
3132
This file has date fields in frontmatter that PyYAML will parse as datetime.date objects.
32-
"""))
33+
""")
34+
)
3335
return test_file
3436

3537

3638
@pytest.fixture
3739
def test_file_with_date_in_tags(tmp_path):
3840
"""Create a test file with a date value in tags (edge case)."""
3941
test_file = tmp_path / "test_note_date_tags.md"
40-
test_file.write_text(dedent("""\
42+
test_file.write_text(
43+
dedent("""\
4144
---
4245
title: Test Note with Date Tags
4346
tags: 2025-10-24
@@ -46,15 +49,17 @@ def test_file_with_date_in_tags(tmp_path):
4649
# Test Content
4750
4851
This file has a date value as tags, which will be parsed as datetime.date.
49-
"""))
52+
""")
53+
)
5054
return test_file
5155

5256

5357
@pytest.fixture
5458
def test_file_with_dates_in_tag_list(tmp_path):
5559
"""Create a test file with dates in a tag list (edge case)."""
5660
test_file = tmp_path / "test_note_dates_in_list.md"
57-
test_file.write_text(dedent("""\
61+
test_file.write_text(
62+
dedent("""\
5863
---
5964
title: Test Note with Dates in Tags List
6065
tags:
@@ -66,7 +71,8 @@ def test_file_with_dates_in_tag_list(tmp_path):
6671
# Test Content
6772
6873
This file has date values mixed into tags list.
69-
"""))
74+
""")
75+
)
7076
return test_file
7177

7278

@@ -141,7 +147,8 @@ async def test_parse_file_with_list_frontmatter_fields(tmp_path):
141147
to be strings, causing 'list' object has no attribute 'strip'.
142148
"""
143149
test_file = tmp_path / "test_list_fields.md"
144-
test_file.write_text(dedent("""\
150+
test_file.write_text(
151+
dedent("""\
145152
---
146153
title:
147154
- Week 2 Discussion Post
@@ -160,7 +167,8 @@ async def test_parse_file_with_list_frontmatter_fields(tmp_path):
160167
# Content
161168
162169
Some body text.
163-
"""))
170+
""")
171+
)
164172

165173
parser = EntityParser(tmp_path)
166174
entity_markdown = await parser.parse_file(test_file)
@@ -192,14 +200,16 @@ async def test_parse_file_with_list_frontmatter_fields(tmp_path):
192200
async def test_parse_file_with_list_title_single_item(tmp_path):
193201
"""Test that a single-item list title is coerced to a plain string."""
194202
test_file = tmp_path / "test_single_list_title.md"
195-
test_file.write_text(dedent("""\
203+
test_file.write_text(
204+
dedent("""\
196205
---
197206
title:
198207
- My Single Title
199208
---
200209
201210
# Content
202-
"""))
211+
""")
212+
)
203213

204214
parser = EntityParser(tmp_path)
205215
entity_markdown = await parser.parse_file(test_file)
@@ -218,7 +228,8 @@ async def test_parse_file_with_various_yaml_types(tmp_path):
218228
when code expects strings and calls .strip().
219229
"""
220230
test_file = tmp_path / "test_yaml_types.md"
221-
test_file.write_text(dedent("""\
231+
test_file.write_text(
232+
dedent("""\
222233
---
223234
title: Test YAML Types
224235
date: 2025-10-24
@@ -235,7 +246,8 @@ async def test_parse_file_with_various_yaml_types(tmp_path):
235246
# Test Content
236247
237248
This file has various YAML types that need to be normalized.
238-
"""))
249+
""")
250+
)
239251

240252
parser = EntityParser(tmp_path)
241253
entity_markdown = await parser.parse_file(test_file)
@@ -282,7 +294,8 @@ async def test_parse_file_with_datetime_objects(tmp_path):
282294
with time components (as parsed by PyYAML), ensuring they're converted to ISO format strings.
283295
"""
284296
test_file = tmp_path / "test_datetime.md"
285-
test_file.write_text(dedent("""\
297+
test_file.write_text(
298+
dedent("""\
286299
---
287300
title: Test Datetime
288301
created_at: 2025-10-24 14:30:00
@@ -292,7 +305,8 @@ async def test_parse_file_with_datetime_objects(tmp_path):
292305
# Test Content
293306
294307
This file has datetime values in frontmatter that PyYAML will parse as datetime objects.
295-
"""))
308+
""")
309+
)
296310

297311
parser = EntityParser(tmp_path)
298312
entity_markdown = await parser.parse_file(test_file)
@@ -322,7 +336,8 @@ async def test_parse_file_with_reserved_frontmatter_field_content(tmp_path):
322336
the 'content' positional argument.
323337
"""
324338
test_file = tmp_path / "topic-note-template.md"
325-
test_file.write_text(dedent("""\
339+
test_file.write_text(
340+
dedent("""\
326341
---
327342
title: Topic Note Template
328343
content: Template for topic notes
@@ -332,7 +347,8 @@ async def test_parse_file_with_reserved_frontmatter_field_content(tmp_path):
332347
# Template Body
333348
334349
Actual body content here.
335-
"""))
350+
""")
351+
)
336352

337353
parser = EntityParser(tmp_path)
338354
entity_markdown = await parser.parse_file(test_file)

tests/mcp/test_project_context.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,7 @@ async def fake_factory():
515515

516516
# Patch workspace resolution to fail if called — factory mode should skip it
517517
async def fail_if_called(**kwargs): # pragma: no cover
518-
raise AssertionError(
519-
"resolve_workspace_parameter must not be called in factory mode"
520-
)
518+
raise AssertionError("resolve_workspace_parameter must not be called in factory mode")
521519

522520
monkeypatch.setattr(
523521
"basic_memory.mcp.project_context.resolve_workspace_parameter",

0 commit comments

Comments
 (0)