fix: ignore checkboxes inside fenced code blocks in plan parser#329
fix: ignore checkboxes inside fenced code blocks in plan parser#329
Conversation
Plans containing markdown fenced code blocks (``` or ~~~) with example [ ] checkboxes triggered false-positive infinite loops when sub-Claude emitted ALL_TASKS_DONE — the parser counted those template examples as real uncompleted tasks. Track fence state during the line scan and skip checkboxes inside fences in both ParsePlan and FileHasUncompletedCheckbox. Related to #328
Deploying ralphex with
|
| Latest commit: |
c2c7c7c
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c26a37c0.ralphex.pages.dev |
| Branch Preview URL: | https://fix-fenced-code-block-checkb.ralphex.pages.dev |
There was a problem hiding this comment.
Pull request overview
This PR updates the plan markdown parser to ignore - [ ]/- [x] checkboxes that appear inside CommonMark fenced code blocks (``` or ~~~), preventing false positives that could cause repeated runner iterations even after receiving <<<RALPHEX:ALL_TASKS_DONE>>>.
Changes:
- Add fenced code block tracking during line-by-line scans in both
ParsePlanandFileHasUncompletedCheckbox. - Implement CommonMark-style fence open/close matching rules (same fence char, close length >= open length, no info string on closer).
- Add comprehensive tests covering backtick/tilde fences, indentation, unclosed fences, and nested opener-with-info-string scenarios.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| pkg/plan/parse.go | Adds fence state tracking and skips parsing/counting checkboxes inside fenced code blocks. |
| pkg/plan/parse_test.go | Adds regression tests ensuring fenced-block checkboxes are ignored in parsing and file scanning. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // fenceClosePattern matches a CommonMark code-fence closer: same as opener but with no info | ||
| // string permitted — only optional trailing whitespace. used to avoid treating an inner | ||
| // opener-with-info-string (e.g. ```go) as closing an outer fence. | ||
| fenceClosePattern = regexp.MustCompile(`^ {0,3}(` + "`" + `{3,}|~{3,})[ \t]*$`) |
There was a problem hiding this comment.
two parts:
-
The raw string concatenation actually produces a correct regex.
`^ {0,3}(`+""+ ``{3,}|{3,})[ \t]*${3,})[ \t]*$`` evaluates at compile time to ``` ^ {0,3}({3,}|. The `+ "`" +` is Go string concatenation glueing one literal backtick between two raw-string segments, not regex content. The new test `ignores checkboxes inside backtick fenced code blocks` exercises a real `` closer and passes, which would not be possible if the regex never matched. -
The CRLF concern is valid for
FileHasUncompletedCheckbox. It splits on\n, leaves trailing\ron each line, and the closer's[ \t]*$cannot match. Fixed in c2c7c7c by allowing optional\rbefore the end anchor ([ \t]*\r?$) and added a CRLF regression test.ParsePlanis unaffected sincebufio.Scanneralready strips the CR.
FileHasUncompletedCheckbox splits on \n, leaving trailing \r on each line. The closer regex required `[ \t]*$`, so it would never match a CRLF-terminated ``` line, the fence stayed open, and any real unchecked checkbox after the fence was incorrectly skipped (false negative — runner exits thinking the malformed plan is done). Allow optional \r before the line end. ParsePlan is unaffected (bufio.Scanner already strips the CR).
plans containing markdown fenced code blocks (``` or ~~~) with example
- [ ]checkboxes triggered false-positive infinite loops when sub-Claude emitted `ALL_TASKS_DONE`. The parser counted those template examples as real uncompleted tasks, runner re-iterated forever until `--max-iterations` cap.track fence state during the line scan and skip lines inside fences in both
ParsePlanandFileHasUncompletedCheckbox. Closer matching follows CommonMark strictly:That last rule matters. Without it, an inner
```bashinside an outer```fence would close the outer prematurely and leak the inner example checkboxes back as actionable.Related to #328