Repository navigation
fix(wiki): drop a leading BOM on a page with no frontmatter - #663
Merged
akitaonrails merged 1 commit intoSep 7, 2026
Merged
akitaonrails merged 1 commit into
akitaonrails merged 1 commit into
Conversation
`markdown::parse` strips a leading UTF-8 BOM before it looks for the
frontmatter fence, but the no-frontmatter path returned the untouched
`input` as the body rather than the stripped `trimmed`
(crates/ai-memory-wiki/src/markdown.rs:48-51). A page a Windows editor
saved with a BOM and no frontmatter therefore kept the mark in front of
its first line, where it is no longer a byte-order mark.
Two things follow. `derive_title` scans body lines for `# `, so the H1
stopped being a heading and the page was indexed under its filename
instead of its title. And the OKF v0.2 file pass, whose contract is
"conform every wiki `.md` in place (body untouched)", re-emitted the
mark after the closing `---` fence: `conform_file` parses, fills the
frontmatter and writes `emit(&md)` back, so the file lands on disk as
`---\ntype: Note\n...\n---\n\u{feff}# Hand written`.
Return `trimmed` on both paths, which is what the frontmatter path
already did. Two regression tests: one at the parse boundary, covering
the body and the derived title, and one driving `conform_file` over a
BOM-prefixed page with no frontmatter.
MaxFreedomPollard
force-pushed
the
fix/bom-in-frontmatterless-page-body
branch
from
September 6, 2026 22:47
6385c22 to
54a933f
Compare
akitaonrails
added a commit
that referenced
this pull request
Sep 8, 2026
Bump workspace 2.1.0 -> 2.1.1 (all crates + Cargo.lock). CHANGELOG [Unreleased] becomes [2.1.1] - 2026-09-07 with a fresh [Unreleased]; compare links updated. 2.1.1 is a patch collecting the fixes on main since 2.1.0: BOM on frontmatter- less pages (#663), wiki commits no longer re-hash the whole tree (#665), typed relations preserved in multi-page batches (#667), serve stops re-archiving the data dir every start (#669), promptless sessions no longer synthesize wiki pages (#662), a capture-only marker no longer resets scope across shell/native/ TS (#668), and a routing-snippet note that ai-memory is the cross-harness memory of record (#671). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
This was referenced Sep 25, 2026
akitaonrails
pushed a commit
that referenced
this pull request
Sep 29, 2026
parse_markdown found the frontmatter fence only as "---\n" at byte zero and "\n---\n" to close it. A wiki checked out on Windows with core.autocrlf=true has CRLF throughout, and one saved as "UTF-8 with BOM" opens with U+FEFF, so either missed the fence: kind, tier, tags and pinned were dropped, the title came from the body's H1 instead of the frontmatter, and the whole YAML block was imported as the top of the page body. The fence is now found the way ai_memory_wiki::markdown::parse finds it since #663 and #908: past a leading BOM, with LF or CRLF fence lines, and the YAML's trailing CR trimmed. The body keeps its own line endings. Co-Authored-By: Claude Opus 5.5 <[email protected]>
7 of 8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
markdown::parsestrips a leading UTF-8 BOM before it looks for the frontmatter fence, but the no-frontmatter path returned the untouchedinputas the body instead of the strippedtrimmed(crates/ai-memory-wiki/src/markdown.rs:34-52). A page with a BOM and no frontmatter therefore kept the mark in front of its first line, where it is not a byte-order mark any more. It now returnstrimmedon both paths, which is what the frontmatter path already did.Before:
parse("\u{FEFF}# Hand written\n\nBody.\n").body == "\u{FEFF}# Hand written\n\nBody.\n". After:"# Hand written\n\nBody.\n". A page that already had frontmatter is unchanged, and so is every page with no BOM.Why
Two observable consequences.
derive_titlepicks a title by scanning body lines for a#prefix. With the mark sitting in front of the#the H1 stops matching, soreindex_pageandrestore_page_from_checkpointindex the page under its filename stem rather than its heading. A hand-editednotes/hand-written.mdstarting# Hand writtencame back as "hand-written".The OKF v0.2 file pass is worse, because it writes. Its contract is "conform every wiki
.mdin place (body untouched)" (crates/ai-memory-wiki/src/migrations/m2026_09_okf_conformance.rs:8), andconform_fileimplements that by parsing, filling the frontmatter, and writingemit(&md)back through an atomic rename. Fed a BOM-prefixed page with no frontmatter it produced:The mark is now after the closing fence, inside the body, where it is a stray zero-width no-break space ahead of the H1 rather than a byte-order mark. That is a permanent edit to the source of truth, and the migration is one-shot.
The wiki is meant to be hand-editable and the project supports Windows, where a BOM is what several editors and PowerShell write by default. The CLI hook path already handles this deliberately (
crates/ai-memory-cli/src/commands/hook.rs:822,docs/windows.md:512); this is the same class of input reaching the wiki parser.Test plan
cargo fmt --all -- --checkpassesgit diff --checkpassescargo clippy --workspace --all-targets -- -D warningspassescargo test --workspace --all-targetspassesai-memory-wiki158 of them. With the two new tests kept and the one-word fix reverted,parses_bom_prefixed_body_without_frontmatterfails withleft: "\u{feff}# Hand written\n\nBody.\n"andconforming_a_bom_prefixed_page_does_not_move_the_mark_into_the_bodyfails printing the conformed file with the mark after the fence. The pre-existingparses_bom_prefixed_frontmatterpasses either way, so the frontmatter path is untouched.Commit attribution
Release impact
CHANGELOG (merge gate)
CHANGELOG.md[Unreleased]entry under### Fixed.Notes for reviewers
The tests live in the two modules that own the two symptoms: the parse-boundary one next to the existing
parses_bom_prefixed_frontmatterinmarkdown.rs, and the file-pass one in the migration's own test module, callingconform_filedirectly rather than standing up a store.One knock-on worth naming: a store that already indexed a BOM-prefixed frontmatter-less page will supersede it once on the next reindex, because the body sha256 changes when the mark leaves. That is the fix landing, and it corrects the title on the same pass.
I did not touch the
---\r\ncase. A CRLF file is not recognised as having frontmatter at all today, which is a separate decision about what "the canonical---\n<yaml>\n---\nblock" means, and it would change what parses rather than what a parsed body contains.