Skip to content

fix(ci): a fence opened inside a blockquote must close with the quote - #170

Merged
tucktuck101 merged 1 commit into
launchpadfrom
fix/blockquoted-fence-consumes-body
Aug 16, 2026
Merged

tucktuck101 merged 1 commit into
launchpadfrom
fix/blockquoted-fence-consumes-body

Conversation

@serina-mcfall

Copy link
Copy Markdown

Summary

_strip_fences in launchpad/scripts/pr_body_check.py kept no record of whether a fence opened inside a blockquote, so one opened with > and never explicitly closed stayed open past the quote's own end — silently consuming a Refs #<n> GitHub renders as ordinary prose, and blocking a compliant PR for appearing to have no issue reference.

Related issue

Closes #145

Issue type

Bug


Agent provenance

Field Value
Harness / provider Claude Code
Model claude-sonnet-5
Session reference N/A - harness does not expose a run id/URL
Initiating human @serina-mcfall

Objective

Make _strip_fences close a fence when the blockquote that contains it ends, so prose after the quote is no longer swallowed as leftover fence content.

Impacted components

  • launchpad/scripts/pr_body_check.py (_strip_fences)
  • launchpad/scripts/test_pr_body_check.py

Approach and rejected alternatives

Track whether the currently-open fence started inside a quote (fence_in_quote). On each subsequent line, if that flag is set and the raw line no longer carries a blockquote marker, force-close the fence before evaluating the line — so it falls through to ordinary prose handling instead of being swallowed.

Rejected: tracking full blockquote depth (nesting level) rather than a simple in-quote boolean. The issue's own converse case ("a quoted ``` closing an unquoted fence") is explicitly out of scope, and #145 only needs to know "did this fence open inside any quote, and has that quote now ended" — a boolean is sufficient and simpler to reason about than tracking depth for a case not being fixed here.

Verification

Command run:

python3 -m unittest test_pr_body_check

Raw output:

...............................................
----------------------------------------------------------------------
Ran 47 tests in 0.004s

OK

Confirmed the two new core tests fail against the pre-fix code with the exact symptom the issue describes:

FAIL: test_blockquoted_unterminated_fence_closes_on_a_bare_top_level_blank_line_too
FAIL: test_blockquoted_unterminated_fence_does_not_consume_prose_after_the_quote_ends
AssertionError: 'Refs #116' not found in '### Issue type\nTask\n\n'
FAILED (failures=2)

and that the regression guard (a fence that closes explicitly while still inside the quote must still close there) already held before the fix — confirming it guards against over-correction rather than duplicating the core fix's own assertion.

  • Tests or checks were run and the raw output is pasted above
  • The diff is confined to the scope of the linked issue
  • No secrets, keys, tokens or hostnames were added to tracked files

Not verified

  • Did not check this against a reference CommonMark parser — the fix follows CommonMark's stated lazy-continuation rule for block quotes, but wasn't cross-checked against commonmark.js or similar.
  • The issue's own "converse leak" (a quoted ``` closing an unquoted fence) is explicitly out of scope per the issue text and is not addressed here.
  • Did not test interaction with nested quotes (a quote inside a quote, each potentially containing a fence) — the issue's repro and scope are single-level.

Security implications

None. This only affects which lines of a PR body are treated as prose vs. code for the purpose of finding an issue-closing reference; it has no effect on repository content, secrets, or access.

Escalations

None — the fix follows directly from CommonMark's documented lazy-continuation rule, and the issue's own scope notes (bare > in-scope, quoted-fence-closing-unquoted-fence out-of-scope) left no ambiguity to resolve.

_strip_fences in launchpad/scripts/pr_body_check.py strips blockquote
markers before matching a fence, but kept no record of the container a
fence opened in. A fence opened with `> ` and never explicitly closed
stayed open past the blockquote's own end, consuming every remaining
line — including a `Refs #<n>` GitHub renders as ordinary prose once
the quote ends, blocking a compliant PR for appearing to have no issue
reference at all.

CommonMark ends a block quote lazily: a line with no `>` marker (a
blank line included, since a bare `>` strips to empty) closes it, the
same way a blank line ends one at the top level. A fence carries no
memory of its container, so one opened inside a quote must close when
the quote does — it cannot lazily continue past the boundary the way a
paragraph can't either.

_strip_fences now tracks whether the currently-open fence started
inside a quote. On each line, if that's true and the raw line no longer
carries a blockquote marker, the fence is force-closed before the line
is evaluated — so it falls through to ordinary prose handling (or a new
fence opening) instead of being silently swallowed as leftover fence
content.

Three new tests: the core fix (issue's own repro), the same defect with
a bare blank line instead of an omitted one, and a regression guard — a
fence that closes explicitly while still inside the quote must still
close there, not run to the quote's end regardless. Confirmed the first
two fail against the pre-fix code with the exact symptom described (the
Refs line vanishes) and the regression guard already held.

Verified:

$ python3 -m unittest test_pr_body_check
Ran 47 tests in 0.004s
OK

Closes #145

Signed-off-by: Serina Mcfall <serina.mcfall@gmail.com>
@serina-mcfall serina-mcfall added the by:agent Filed or authored by an AI agent, not a human label Aug 14, 2026
@serina-mcfall
serina-mcfall marked this pull request as ready for review August 14, 2026 22:03
@tucktuck101
tucktuck101 merged commit 72c6442 into launchpad Aug 16, 2026
25 checks passed
@serina-mcfall
serina-mcfall deleted the fix/blockquoted-fence-consumes-body branch August 31, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

by:agent Filed or authored by an AI agent, not a human

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: a blockquoted unterminated fence deletes the rest of the PR body, blocking a compliant PR

2 participants