fix(vault): tolerate BOM and leading blank lines in frontmatter parsing

A note saved by Notepad/PowerShell carries a leading UTF-8 BOM (and
sometimes leading blank lines) before the opening `---`. The old
\A-anchored regex treated that as "no frontmatter", dumping the whole
YAML block into the body -- which then hits the destructive
no-valid-ULID path in index.py. parse() now strips a leading BOM and
tolerates leading whitespace before the delimiter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139vHnNpS2sLNELjrAHX5Cu
This commit is contained in:
MarkusandClaude Opus 5 committed 2026-09-12 14:33:13 +00:00
1 parent 9f976c54ea
commit 6c5531da98
2 files changed
+19 -2

No files matched your search

+5 -2
View File
@@ -19,7 +19,7 @@ from ruamel.yaml.comments import CommentedMap
from mdmem.config import NOTE_TYPES
from mdmem.ids import filename_for, new_id, nfc
_FM_RE = re.compile(r"\A---[ \t]*\r?\n(.*?)\r?\n---[ \t]*\r?\n?", re.DOTALL)
_FM_RE = re.compile(r"\A\s*---[ \t]*\r?\n(.*?)\r?\n---[ \t]*\r?\n?", re.DOTALL)
_WIKILINK_RE = re.compile(r"\[\[([^\[\]|#]+?)(?:#[^\[\]|]*)?(?:\|[^\[\]]*)?\]\]")
_HEADING_RE = re.compile(r"^(#{1,6})\s+(.*?)\s*#*\s*$", re.MULTILINE)
@@ -62,7 +62,10 @@ def parse(text: str, *, strict: bool = False) -> tuple[CommentedMap, str]:
strict=True re-raises broken YAML — used where a human just typed it. The
scanner stays lenient so one bad file cannot stop the whole vault indexing.
"""
text = nfc(text.replace("\r\n", "\n"))
text = text.replace("\r\n", "\n")
if text.startswith(""): # BOM left by Notepad/PowerShell
text = text[1:]
text = nfc(text)
m = _FM_RE.match(text)
if not m:
return CommentedMap(), text
+14
View File
@@ -82,6 +82,20 @@ def test_missing_frontmatter_is_tolerated():
assert body.strip() == "just a body"
def test_parse_tolerates_leading_utf8_bom():
"""A note saved by Notepad/PowerShell carries a leading BOM (finding 2)."""
fm, body = parse("" + SAMPLE)
assert fm["title"].startswith("llama-swap")
assert body.startswith("llama-swap routes models")
assert "---" not in body
def test_parse_tolerates_leading_blank_lines_before_delimiter():
fm, body = parse("\n\n \n" + SAMPLE)
assert fm["title"].startswith("llama-swap")
assert body.startswith("llama-swap routes models")
def test_wikilinks_with_alias_and_heading():
n = Note.new(title="T", body="see [[target|alias]] and [[other#Head]]", type="note")
assert n.wikilinks == ["target", "other"]