fix: use parseFrontmatter instead of an unbounded title: regex in 4 more places - #578
Merged
nashsu merged 1 commit intoJul 15, 2026
Merged
Conversation
…ore places
extractEmbeddingTitle (embedding.ts), buildWikiIndex (sweep-reviews.ts),
and two sites in ingest.ts each reimplemented their own frontmatter
title extraction with:
content.match(/^---\n[\s\S]*?^title:\s*["']?(.+?)["']?\s*$/m)
Anchored only at the opening `---`, with the lazy [\s\S]*? never
required to stop at the closing `---`. A page whose frontmatter has no
title -- but whose body happens to contain a later line starting with
"title:" (plain prose, not YAML) -- gets that body line misread as the
title. This is the same bug already found and fixed in wiki-graph.ts's
extractTitle/extractType (a separate open PR).
The blast radius differs per site:
- embedding.ts: the bogus title gets prepended to every chunk's
embedding text, silently corrupting the semantic vectors sent to the
embedding model for that page.
- sweep-reviews.ts: the bogus title is added to the wiki index's
byTitle set, which pageExists() checks to decide whether a
"missing-page" review should auto-resolve -- a body line that
happens to match a still-missing page's name can falsely mark that
review as resolved, silently hiding a real gap.
- ingest.ts (x2): the bogus title is passed to embedPage(), same
corruption as the embedding.ts site.
This codebase already has a correct, actively-used frontmatter parser
(src/lib/frontmatter.ts's parseFrontmatter, built on js-yaml, used in
10+ other files including ingest.ts itself at two other call sites).
Switch all 4 buggy sites to use it instead of re-deriving frontmatter
fields with a fragile regex.
Exported extractEmbeddingTitle and buildWikiIndex (previously
module-private) so they're directly unit-testable, matching the
existing @internal-exported-for-tests pattern already used for
extractJsonObject in sweep-reviews.ts.
Added regression tests for extractEmbeddingTitle (embedding.test.ts)
and buildWikiIndex (new sweep-reviews-build-wiki-index.test.ts).
Confirmed both fail against the pre-fix regex and pass with
parseFrontmatter. Ran the full test:mocks suite (1643 passed) and
typecheck (clean).
Disclosure: I used an AI coding assistant (Claude) to help identify
this bug pattern and draft the fix. I independently confirmed
parseFrontmatter was already the established convention elsewhere in
the codebase (including inside ingest.ts itself) before choosing to
switch these sites to it rather than just patching the regex in place,
verified each site's exact blast radius, and ran the full local test
suite plus typecheck before opening this PR.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Follow-up to #577
While fixing the same bug pattern in
wiki-graph.ts(#577), I found the identical unbounded regex reimplemented in 4 more places:Anchored only at the opening
---, with the lazy[\s\S]*?never required to stop at the closing---. A page whose frontmatter has no title — but whose body happens to contain a later line starting withtitle:(plain prose, not YAML) — gets that body line misread as the title.The blast radius differs per site:
embedding.ts(extractEmbeddingTitle): the bogus title gets prepended to every chunk's embedding text, silently corrupting the semantic vectors sent to the embedding model for that page.sweep-reviews.ts(buildWikiIndex): the bogus title is added to the wiki index'sbyTitleset, whichpageExists()checks to decide whether amissing-pagereview should auto-resolve — a body line that happens to match a still-missing page's name can falsely mark that review as resolved, silently hiding a real gap from the user.ingest.ts(2 sites): the bogus title is passed toembedPage(), same corruption as theembedding.tssite.Fix
This codebase already has a correct, actively-used frontmatter parser —
src/lib/frontmatter.ts'sparseFrontmatter(), built onjs-yaml, already used in 10+ other files includingingest.tsitself at two other call sites. Rather than re-patch the regex 4 more times, I switched all 4 sites to useparseFrontmatter()instead.Exported
extractEmbeddingTitleandbuildWikiIndex(previously module-private) so they're directly unit-testable, matching the existing@internal — exported for tests onlypattern already used forextractJsonObjectinsweep-reviews.ts.Testing
extractEmbeddingTitle(embedding.test.ts) andbuildWikiIndex(newsweep-reviews-build-wiki-index.test.ts). Confirmed both fail against the pre-fix regex and pass withparseFrontmatter.npm run test:mockssuite (1643 passed) andnpm run typecheck(clean).Disclosure: I used an AI coding assistant (Claude) to help identify this bug pattern and draft the fix. I independently confirmed
parseFrontmatterwas already the established convention elsewhere in the codebase (including insideingest.tsitself) before choosing to switch these sites to it rather than just patching the regex in place, verified each site's exact blast radius, and ran the full local test suite plus typecheck before opening this PR.