The Handwriting Font Matcher changelog had an entry that read “Push 8 unpushed commits: handwriting font matcher overhaul + blog drafts + memory sync.” That’s not a commit about the font matcher. It’s a sync summary from one of my Klaus agents, bundling several unrelated things that got pushed together. It mentioned the font matcher. That was enough for the filter.
I built per-tool changelogs for ricoordonio.com. Each tool page shows an auto-generated list of changes, pulled from git log and filtered for commits whose subject mentions the tool by name. The filter looked like this:
if (!/handwriting\s+font\s+matcher/i.test(subject)) continue;
Substring match. Commit mentions the tool anywhere in the subject? It’s in the changelog. Seemed like a reasonable starting point.
The problem is “anywhere.” My sync agents write bundled subjects when they batch multiple changes. A subject like “Push 8 unpushed commits: handwriting font matcher overhaul + blog drafts + memory sync” mentions multiple tools in one line. Each tool in that summary was getting the commit added to its own changelog, even though the commit wasn’t really about any of them. The Handwriting Font Matcher page looked complete and accurate. Real dates, real descriptions, real entries. It was just including noise that looked exactly like signal.
The fix is three characters. Add ^ to anchor the regex to the start of the subject:
if (!/^(?:tools:\s*(?:add\s+)?)?handwriting(?:\s+font)?\s+matcher\b/i.test(subject)) continue;
The tool name now has to start the commit subject, with an optional Tools: prefix for commits that use a namespaced convention. “Push 8 unpushed commits: handwriting font matcher overhaul…” starts with “Push” and gets filtered out. “Handwriting Font Matcher: add CLIP fallback” starts with the tool name and stays in.
Applied the same fix across all five tools. Five regexes, three characters each.
What bothers me isn’t that the bug existed. It’s that the output looked correct while it was wrong.
The changelog was generating entries, formatting dates, cleaning subjects. No errors. The entries had legitimate text. If I hadn’t looked at that particular entry the day after a big sync push, I wouldn’t have known. The changelog was confidently presenting a history that was real in its structure and slightly inaccurate in its scope.
Automated output that looks right when it’s wrong doesn’t give you a reason to go check it. Manual documentation at least carries the friction of writing it. A script has no friction. It generates and moves on.
Tell your past self: substring matching says “this commit mentioned the tool.” Anchored matching says “this commit is about the tool.” Those are different filters. The output looks the same either way.