diff --git a/scripts/pr_review.py b/scripts/pr_review.py index 636708668..dce7f1ef4 100755 --- a/scripts/pr_review.py +++ b/scripts/pr_review.py @@ -2941,7 +2941,7 @@ def heading_of(block: str) -> str: # `
(.*?)
` lazily pairs each open with the *next* close, which is the innermost one once a shape nests, silently losing everything the outer wrapper still carries after it. # CodeRabbit's outside-diff section does exactly that: a file wrapper nested inside the section heading, itself wrapping a per-finding "Prompt for AI Agents" block three levels deep. DETAILS_TAG = re.compile( - r"]*|/)?>|" + r"]*|/)?>|" r"|(?\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029]*|/)>", re.IGNORECASE, ) diff --git a/tests/test_pr_review.py b/tests/test_pr_review.py index ff5d835bc..e0e2457ce 100755 --- a/tests/test_pr_review.py +++ b/tests/test_pr_review.py @@ -60,7 +60,7 @@ def flowed_text(text: str) -> str: # The shape 28 of the 333 measured bodies carry: an overview, and no count of what was read. # A body of no text at all is not one of the shapes, and the reader now says so, correctly. OVERVIEW = "## Pull request overview\n\nThe change is narrow.\n" -# The wall-clock ceiling the two backtracking cases read, stated once so they cannot drift apart. +# The wall-clock ceiling the backtracking cases read, stated once so they cannot drift apart. # Each case sizes its own input so that a regression finishes and trips this rather than running long enough to hang the suite. # Three seconds against readings of microseconds and milliseconds, which is the margin that makes a loaded runner a non-issue rather than the clock being trusted. BACKTRACK_BOUND = 3.0 @@ -3347,6 +3347,7 @@ def test_a_tag_is_bounded_by_html_s_own_syntax(self) -> None: """A tail reaching another line or another tag swallowed the opener or heading after it.""" cases = { "": ["
"], + "
": ["
"], "
": [], "": [], "": [], @@ -3359,6 +3360,16 @@ def test_a_tag_is_bounded_by_html_s_own_syntax(self) -> None: found = [m.group() for m in pr_review.DETAILS_TAG.finditer(text)] self.assertEqual(tags, found) + def test_a_body_of_unclosed_openers_is_read_in_linear_time(self) -> None: + """An opener with no closing `>` ends its scan at the next `<`, so a body of such openers reads in linear time.""" + body = "
None: """The section readers pair on the same tags, so their regions end where HTML ends them.""" body = "
\na\n
\nb\n
\nc\n
\n"