Skip to content

Reject a Backtick in a Backtick-Fence Info String - #904

Merged
ptr727 merged 1 commit into
developfrom
fix/523-fence-edge-cases
Aug 22, 2026
Merged

Reject a Backtick in a Backtick-Fence Info String#904
ptr727 merged 1 commit into
developfrom
fix/523-fence-edge-cases

Conversation

@ptr727

@ptr727 ptr727 commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to #903, addressing a finding raised on the #900 -> #901 promotion PR review (CodeRabbit).

Per CommonMark, a backtick-fenced opener's info string may not itself contain a backtick (the spec's own reasoning: otherwise inline code spans could be misread as a new fence). `_fence_step()` accepted an opener like ```md` regardless, so a heading right after it was hidden from the scan. Verified independently against the actual code before fixing. A tilde fence has no such restriction and is unaffected.

Also split the two over-25-word docstring sentences flagged in the same review round.

Verification

  • python3 spec/audit.py --selftest -> SELFTEST PASS, including 3 new regression cases and the full pre-existing suite unchanged
  • python3 spec/validate.py -> Spec validation OK
  • ruff check . / ruff format --check . -> clean
  • python3 scripts/prose_lint.py --diff origin/develop spec/audit.py -> clean

A note on scope

This is the fourth follow-up PR (#901 -> #902 -> #903 -> this one) chasing progressively deeper CommonMark fence-parsing edge cases that CodeRabbit's automated review keeps finding one round at a time against _fence_step(). Each one has been real and independently verified, but I want to flag the pattern rather than silently keep going: CommonMark has more edge cases than these four (unterminated fences at EOF, tab expansion in indentation, and others), and a sufficiently persistent automated reviewer may keep surfacing them. Worth a decision on where "correct enough" is for a fleet-internal audit tool versus a full CommonMark implementation.

CodeRabbit, on PR #901: per CommonMark, a backtick-fenced opener's
info string may not itself contain a backtick (the restriction
exists so inline code spans are not misread as a new fence).
_fence_step() accepted ```md` as a valid opener regardless, so a
heading after it was hidden. Verified against the actual code before
fixing. A tilde fence has no such restriction and is unaffected.
2 regression cases added to unfenced_text, 1 to undeclared_h2_headings.

Also split the two over-25-word docstring sentences CodeRabbit
flagged in the same round.
Copilot AI lite review requested due to automatic review settings August 22, 2026 03:16
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9970d88d-7bb8-4346-a9fb-8bbe91aa262f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Reject backticks in backtick-fence info strings per CommonMark

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Reject backtick-fenced openers whose info strings contain backticks, per CommonMark.
• Prevent headings after invalid fences from being incorrectly hidden during section scanning.
• Add regression selftests for backtick/tilde fence edge cases and tighten docstrings.
Diagram

graph TD
A["Markdown text"] --> B["extract_section()"] --> C["_fence_step()"] --> D{"Fence boundary?"} --> E["Section scan"]
F["_selftest()"] --> B
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Adopt a CommonMark-compliant Markdown parser library
  • ➕ Reduces long-tail edge-case maintenance in custom parsing logic
  • ➕ Leverages battle-tested compliance and future spec nuance handling
  • ➖ Adds dependency and potential runtime/packaging complexity for an internal audit tool
  • ➖ May require adapting AST output to current section/heading semantics
2. Define and enforce an explicit “supported Markdown subset” for audits
  • ➕ Sets clear scope boundaries and stops iterative edge-case churn
  • ➕ Allows simpler, more predictable parsing rules tied to audit needs
  • ➖ May diverge from CommonMark expectations in real-world docs
  • ➖ Requires documentation and buy-in from users of the audit tool

Recommendation: The PR’s targeted fix is the right near-term approach: it aligns _fence_step() with CommonMark and adds regressions to prevent reintroduction. Given the repeated edge-case follow-ups, consider either adopting a parser library or formally documenting a supported subset to cap future correctness work.

Files changed (1) +23 / -5

Bug fix (1) +23 / -5
audit.pyAlign fence opener parsing with CommonMark and add regression coverage +23/-5

Align fence opener parsing with CommonMark and add regression coverage

• Updates '_fence_step()' to treat backtick-fenced openers whose info string contains a backtick as invalid boundaries, preventing headings after such lines from being skipped. Splits overly long docstring sentences for clarity and adds three selftest regressions covering backtick/tilde fence edge cases and heading visibility.

spec/audit.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change aligns _fence_step() with CommonMark, and the added selftests demonstrate the corrected behavior without introducing new risk.

Pull request overview

Tightens the Markdown fence parser used by spec/audit.py to match CommonMark’s restriction on backtick-fenced info strings, preventing invalid openers (e.g., `````md` ``) from hiding subsequent headings during scans.

Changes:

  • Update _fence_step() so a backtick-fence opener is rejected when its info string contains a backtick.
  • Add regression selftests covering the invalid-backtick opener case (and confirming tildes are unaffected).
  • Split previously overlong docstring sentences while updating the fence-parsing explanation.
File summaries
File Description
spec/audit.py Enforces the CommonMark backtick-in-info-string restriction in _fence_step() and adds regression coverage to prevent heading-hiding regressions.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ptr727
ptr727 merged commit 7321cd5 into develop Aug 22, 2026
9 checks passed
@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (1)

Grey Divider


Remediation recommended

1. _fence_step docstring wraps sentences 📜 Skill insight ✧ Quality
Description
The updated _fence_step() docstring wraps sentences across lines and also places multiple
sentences on a single line. This violates the requirement that multi-line comments/docstrings use
exactly one sentence per line without mid-sentence line wraps.
Code

spec/audit.py[R398-401]

+    A mismatched or shorter marker does not close it, such as a ~~~ example inside a ``` block, or a
+    ``` inside a longer ````. Trailing text does not close it either, since an opening fence's language
+    tag has no closing counterpart. A backtick fence's info string may not itself contain a backtick,
+    per CommonMark, so such an opener is not a boundary either.
Relevance

●●● Strong

Deterministic docstring style fix; team consistently accepts prose/comment clarity corrections in
spec/audit.py.

PR-#555
PR-#635

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2826725 requires multi-line comments/docstrings to have one sentence per line and
forbids wrapping a sentence across multiple lines. The updated _fence_step() docstring contains
wrapped and multi-sentence lines in the edited portion.

spec/audit.py[395-401]
Skill: comment-and-doc-style

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `_fence_step()` docstring is multi-line prose that wraps mid-sentence and combines multiple sentences on one line, which violates the comment-structure rule.

## Issue Context
This docstring was edited in this PR and now contains several sentences that are split across lines and/or share a line with another sentence.

## Fix Focus Areas
- spec/audit.py[395-401]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 67 rules
✅ Skills: 5 invoked
  comment-and-doc-style
  dotnet-codestyle
  python-codestyle
  shell-codestyle
  workflow-ci-contract
Review mode: ⚖️ Balanced: This changes runtime fence-parsing behavior in a CommonMark edge case and adds tests/docs; the logic is localized, but it is behaviorally consequential and not clearly trivial enough for lite.

Grey Divider

Tip of the day
💡 Did you know, you can commit Qodo's fix in one click with committable suggestions (GitHub & GitLab)

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread spec/audit.py
Comment on lines +398 to +401
A mismatched or shorter marker does not close it, such as a ~~~ example inside a ``` block, or a
``` inside a longer ````. Trailing text does not close it either, since an opening fence's language
tag has no closing counterpart. A backtick fence's info string may not itself contain a backtick,
per CommonMark, so such an opener is not a boundary either.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. _fence_step docstring wraps sentences 📜 Skill insight ✧ Quality

The updated _fence_step() docstring wraps sentences across lines and also places multiple
sentences on a single line. This violates the requirement that multi-line comments/docstrings use
exactly one sentence per line without mid-sentence line wraps.
Agent Prompt
## Issue description
The `_fence_step()` docstring is multi-line prose that wraps mid-sentence and combines multiple sentences on one line, which violates the comment-structure rule.

## Issue Context
This docstring was edited in this PR and now contains several sentences that are split across lines and/or share a line with another sentence.

## Fix Focus Areas
- spec/audit.py[395-401]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

ptr727 added a commit that referenced this pull request Aug 22, 2026
## Summary

Follow-up to #904, addressing a suppressed Copilot finding raised on the
#900 -> #901 promotion PR review.

`undeclared_h2_headings()`'s docstring read as if a bare \`##\`-prefixed
shell comment is never misread as a heading anywhere, when that only
holds inside a fenced code sample, the same as the heading-syntax
example right beside it. Reworded so both read as one example of fenced
content rather than two independent claims.

## Verification

- \`python3 spec/audit.py --selftest\` -> \`SELFTEST PASS\`
- \`python3 spec/validate.py\` -> \`Spec validation OK\`
- \`ruff check .\` / \`ruff format --check .\` -> clean
- \`python3 scripts/prose_lint.py --diff origin/develop spec/audit.py\`
-> clean
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants