fix: only toggle %% comment state at line boundaries#51
Merged
Conversation
findTrailingCommentBlockStart counts every %% on every line via /%%/g, but Obsidian only treats %% as a comment delimiter at line boundaries. A stray %% in card text (e.g. "100%%") toggles comment state; an odd count leaves the parser open, misidentifying the actual kanban:settings block. Marked as it.fails — flip to it() when the fix lands. 4 new tests: 2 it.fails (stray %%, odd count), 2 passing (large board, inline comment with even count). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
findTrailingCommentBlockStart counted every %% substring per line via /%%/g, but Obsidian treats %% as a comment delimiter only at line boundaries. A stray %% inside card text (e.g. 100%%) toggled the parser's comment state spuriously; an odd count left the parser in "open" state when it reached the real %% kanban:settings opener, misidentifying it as a closer and skipping trailing block detection — so append to the final Kanban lane landed AFTER the settings block. Fix: new countCommentToggles helper counts toggles only when %% appears at the start and/or end of the trimmed line. Mid-line %% no longer affects detection. Flipped 2 it.fails -> it (now passing). Added 5 focused unit tests against findTrailingCommentBlockStart locking down the line-boundary rule at the helper level.
The large-board test fixture leaked a real production tunnel hostname in one of the sample Done items. The test only needs the structural shape (indented sub-item, backticks, arrow); the specific hostname adds no coverage. Replaced with tunnel.example.com.
…fixture
The three wikilinks in the doneItems fixture referenced real vault
paths under `Code Projects/vault-cortex/task-notes/` along with one
display-text mention of `About Me/`. The test exercises wikilink
structural patterns (escaped pipe, display text, block ID); the
specific paths add no coverage. Replaced with `Notes/projects/sample-*`
plus matching `^sample-{a,b,c}` block IDs.
The doneItems list mirrored the real project history, including security-related items (secret scan, port closure, SSH hardening, DNS provider, CI secret handling) and project-specific tool/file names. The test only needs structural variety — escaped pipes, block IDs, backticks, indented sub-items, long lines, escaped quotes — none of which depend on the specific task text. Rewrote the list with fictional task content, generalising security items (e.g. "SSH Tailscale hardening" → "Restrict admin access to private overlay network"; "gitleaks + CI workflow" → "Add static analysis to CI pipeline"; "secrets for deploy vars, IP masking" → "secrets pulled from secret store, sensitive logs masked"), and renamed real tool/file references (`vault_search` → "full-text search backend", `verifyAccessToken` → "token verification", etc.). Block IDs renamed to generic equivalents (`^cf-tunnel` → `^ingress`, `^ssh-tailscale` → `^admin-net`, `^props-tool` → `^props`, `^config-oss` → `^config-ext`). Title and comment updated to reflect that all task text is fictional.
The first round of unit tests for the mid-line %% rule used small line
arrangements where the buggy per-substring counter and the fixed
line-boundary rule happened to produce the same return value — they
passed under both implementations, so they did not actually verify the
fix.
Rewrote the three "ignores mid-line %%" tests with line arrangements
that include a real multi-line trailing block (with a code fence
inside). Under the buggy counter, the stray mid-line %% misdirects
the parser and the detected block start shifts; under the fixed rule
it does not. Each test now fails under the buggy implementation and
passes under the fixed one (verified by temporarily reverting the
countCommentToggles call).
Removed the two contract tests ("`%%` alone as single toggle",
"`%%` at end of line as closer") — they verified preserved behaviors
that hold under both buggy and fixed code, so they only added noise
to a bug-fix PR. Those behaviors are covered implicitly by existing
tests like "finds a multi-line trailing comment block".
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.
Summary
vault_patch_notemis-located the trailing%% kanban:settings %%block on TASKS.md when any card contained a stray%%in its text (e.g.100%%,50%% off). When that happened, anappendto theDonelane landed after the settings block, corrupting the board'skanban-pluginconfig position.Root cause:
findTrailingCommentBlockStartcounted every%%substring on every line via/%%/g, but Obsidian treats%%as a comment delimiter only at line boundaries. A mid-line%%toggled the parser'scommentstate spuriously; an odd total count left the parser in the "open" state when it reached the real%% kanban:settingsopener, which the parser then misinterpreted as a closer — so no trailing block was detected andparseHeadingsreportedbodyEndLinepast the settings block.Fix: new private
countCommentToggles(line)helper returns 0, 1, or 2 toggles based on whether the trimmed line starts and/or ends with%%. Mid-line%%is now ignored. The existing fence/comment state machine infindTrailingCommentBlockStartis preserved — only the per-line toggle count changes.Test plan
it.failsintegration tests (added in 936e7bf) toit— both now pass.findTrailingCommentBlockStartlocking down the line-boundary rule at the helper level (ignores a mid-line %%,ignores multiple mid-line %% on separate lines (odd substring count),ignores %% embedded mid-word,treats a line that is exactly %% as a single toggle,toggles for a line that ends with %% (multi-line closer)).patchNoteintegration tests).npm run lintclean.npm run buildclean.vault_patch_noteagainst a real TASKS.md with a stray-%%card; confirm the appended card lands above%% kanban:settings.Closes the bug tracked as
^bug-kanban-stray-pcton the project board.Generated by Claude Code