Skip to content

fix(review): strip inline code spans delimiter-aware in the decline re-check - #702

Merged
devops-thiago merged 4 commits into
mainfrom
fix/697-delimiter-aware-spans
Aug 13, 2026
Merged

fix(review): strip inline code spans delimiter-aware in the decline re-check#702
devops-thiago merged 4 commits into
mainfrom
fix/697-delimiter-aware-spans

Conversation

@devops-thiago

Copy link
Copy Markdown
Owner

What type of PR is this?

  • 🐛 Bug fix

Description

RebuttalContradiction.assertedText stripped inline code spans with two regexes (DOUBLE_BACKTICK_SPAN, SINGLE_BACKTICK_SPAN) that missed two CommonMark-valid span shapes, so quoted claim text could be matched as the maintainer's own assertion and reopen a correct decline:

  1. A span whose body carries a backtick run longer than its delimiter ( `ab` `` is one single-backtick span per CommonMark, but the regex body class stopped at the interior backticks).
  2. A span containing a line ending (both patterns excluded \n).

This PR replaces the regex passes with a small delimiter-aware scanner (stripInlineSpans): an opening run of N backticks closes at the next run of exactly N (the CommonMark rule), an unclosed run is literal text, the closer must sit within a 1000-character bound so a stray backtick cannot swallow the reply, and the body may cross at most one line ending. Anything the scan cannot classify stays in place — under-fire is the safe, keep-the-decline direction.

Blockquote lines are still dropped before span stripping; that ordering can now only leave a span unstripped (an opener whose closer lived on a dropped blockquote line no longer closes), which is again the under-fire direction.

Related Issues

Closes #697

How Has This Been Tested?

  • Unit tests
  • Integration tests
  • Manual testing

New tests: backtick-run-in-body span stripped whole, one-newline span stripped, two-newline pair stays literal, unclosed run stays literal (mid-text and at end of reply), closer beyond the length bound does not swallow the reply. All existing #652/#686-round span tests (bridging probe, blockquote-tail probe, double-backtick unit strip, half-strip guard) stay green. ./mvnw verify clean; JaCoCo shows zero missed lines/branches on the changed file.

Checklist

  • My code follows the project's coding standards
  • I have performed a self-review of my own code
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated the documentation accordingly
  • My changes generate no new warnings or errors

Screenshots / Logs

N/A

Additional Notes

CHANGELOG.md gains a [Unreleased] Fixed entry referencing #697. This mirrors the delimiter-aware direction #651 sets for the diff-line comment scan.

…e-check

Replace the DOUBLE_BACKTICK_SPAN / SINGLE_BACKTICK_SPAN regex passes in
RebuttalContradiction.assertedText with a small delimiter-aware scanner:
an opening run of N backticks closes at the next run of exactly N (per
CommonMark), an unclosed run stays literal text, the closer must sit
within a 1000-character bound, and the body may cross at most one line
ending. Spans whose body carries a longer backtick run and spans holding
one newline are now stripped whole, so quoted claim text no longer
reopens a correct decline. Anything the scan cannot classify is left in
place — under-fire, the keep-the-decline direction. Blockquote lines are
still dropped before span stripping.

Closes #697
@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@thrillhousebot

Copy link
Copy Markdown
Contributor

🤖 ThrillhouseBot PR Summary

What this PR does

Replaces the DOUBLE_BACKTICK_SPAN/SINGLE_BACKTICK_SPAN regex passes in RebuttalContradiction.assertedText with a delimiter-aware scanner (stripInlineSpans) that closes an N-backtick span at the next run of exactly N backticks, permits one line ending in the span body, treats unclosed runs as literal text, and bounds the closer search at 1000 characters; adds six tests covering the new span shapes and a CHANGELOG entry.

⚠️ Description vs. Implementation

Every mismatch found between the description and the change is reported as a finding below, so it is not repeated here.

Control-Flow Diagram

🔀 Show diagram
flowchart TD
  A["assertedText(rebuttal)"] --> B["FENCED_BLOCK pairs replaced with space"]
  B --> C["blockquote lines dropped, kept lines joined with newline"]
  C --> D["stripInlineSpans(joined)"]
  D --> E{"char is a backtick?"}
  E -- no --> F["append char"]
  F --> D
  E -- yes --> G["delimiter = length of maximal backtick run"]
  G --> H["closingRunStart: scan for next run of exactly delimiter"]
  H --> I{"closer within 1000 chars and body has at most one newline?"}
  I -- no --> J["run kept literal"]
  J --> D
  I -- yes --> K["span replaced with one newline"]
  K --> D
Loading

Changes Overview

  • Files changed: 3
  • Lines added: +175
  • Lines removed: -35

Changed Files

File Change Summary
CHANGELOG.md Modified Adds an [Unreleased] Fixed entry describing the delimiter-aware span stripping change for #697.
src/main/java/dev/thiagogonzaga/thrillhousebot/review/RebuttalContradiction.java Modified Replaces the two inline-span regex passes with delimiter-aware stripInlineSpans and helpers closingRunStart/endOfBacktickRun
src/test/java/dev/thiagogonzaga/thrillhousebot/review/RebuttalContradictionTest.java Modified Adds six tests: longer-run-in-body span stripped, one-newline span stripped, two-newline/unclosed/end-of-reply runs literal, distant closer beyond bound does not swallow.

Risk Assessment

Risk Count
🔴 Critical 0
🟠 High 0
🟡 Medium 0
🔵 Low 2

Key Findings

  • LOW: SPAN_BODY_BOUND is off by one: a closer exactly 1000 chars from the opener is never found (body max 999, old regex stripped 1000) (src/main/java/dev/thiagogonzaga/thrillhousebot/review/RebuttalContradiction.java:463)

Things to double-check

1 lower-confidence finding
  • LOW: Ordering Javadoc overclaims: the filter can also make a span close, and the "under-fire, keep-the-decline" label is inverted (src/main/java/dev/thiagogonzaga/thrillhousebot/review/RebuttalContradiction.java:386) (low confidence — verify before acting)

⚠️ Required CI Checks Status

Some required checks are still pending or have failed:

Check Type Status Detail
test check-run ⏳ Pending -
trivy check-run ⏳ Pending -
frontend check-run ⏳ Pending -
format check-run ⏳ Pending -
dependency-review check-run ⏳ Pending -

Automated review by ThrillhouseBot. Reply with /review to re-run.

@thrillhousebot thrillhousebot Bot 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.

ThrillhouseBot noted 1 lower-confidence item(s) under Things to double-check in the PR summary (not posted as inline threads):

  • LOW: Ordering Javadoc overclaims: the filter can also make a span close, and the "under-fire, keep-the-decline" label is inverted (src/main/java/dev/thiagogonzaga/thrillhousebot/review/RebuttalContradiction.java:386)
    The new Javadoc states: "The order can only leave a span unstripped in the other direction — an opener whose closer lived on a dropped blockquote line no longer closes and stays literal — which is the under-fire, keep-the-decline direction." Both halves are contradicted by the code in this diff and by the PR's own tests. (1) The scanner closes a span whose body has at most one line ending (if (c == '\n' && ++newlines > 1) { return -1; }). When a dropped blockquote line sat BETWEEN an opener and its closer — e.g. the original reply "a\n> quote\nb" — the filter drops the middle line and the join produces "a\nb", i.e. one line ending, so the span now CLOSES and is stripped (and a dropped middle line can likewise bring a distant closer inside the 1000-char bound). That is the opposite of "can only leave a span unstripped", and before this PR the regexes never crossed a newline, so such text was never stripped. (2) An unstripped span leaves the quoted claim text in assertedText, and that text is exactly what makes the re-check fire and reopen a correct decline — the over-fire direction per the linked issue. The PR's own test shouldTreatAnUnclosedBacktickRunAsLiteralText asserts contradiction.isPresent() for an unclosed run left literal, demonstrating the re-check fires in the "stays literal" configuration the comment calls "under-fire, keep-the-decline". The direction label in both this Javadoc and the PR description is therefore backwards. Verify the blockquote filter drops whole lines (not just the '>' prefix) in the assertedText loop above this hunk.

@thrillhousebot thrillhousebot Bot added bug Something isn't working java Pull requests that update java code labels Aug 13, 2026
…ing javadoc

A closer exactly SPAN_BODY_BOUND characters past the opener is now found,
matching the {0,1000} body the replaced regexes stripped, with a boundary
test. The assertedText ordering javadoc no longer claims the blockquote
drop can only leave a span unstripped, and drops the inverted under-fire
label from the stays-in-place direction.
@devops-thiago

Copy link
Copy Markdown
Owner Author

@thrillhousebot resolved src/main/java/dev/thiagogonzaga/thrillhousebot/review/RebuttalContradiction.java:386 — Ordering Javadoc overclaims: the filter can also make a span close, and the "under-fire, keep-the-decline" label is inverted

@thrillhousebot

Copy link
Copy Markdown
Contributor

The next review will close every previous finding this comment names by its path:line and title; anything it does not name stays open.

@thrillhousebot

Copy link
Copy Markdown
Contributor

🤖 ThrillhouseBot — changes since the last review

  • New findings this round: 1
  • Previous findings resolved: 2
  • Previous findings still open: 0

Comment thread src/main/java/dev/thiagogonzaga/thrillhousebot/review/RebuttalContradiction.java Outdated
…avadoc

FENCED_BLOCK only pairs fences within its 10000-character bound and runs
before the blockquote filter, so a paired triple run can still reach the
span scan and be closed there; say so instead of claiming every paired
fence was consumed.
@thrillhousebot

Copy link
Copy Markdown
Contributor

🤖 ThrillhouseBot — changes since the last review

  • New findings this round: 0
  • Previous findings resolved: 1
  • Previous findings still open: 0

@thrillhousebot thrillhousebot Bot 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.

ThrillhouseBot found no issues in this PR, but some checks are still pending or failed:

  • Check format is pending
  • Check test is pending
  • Check frontend is pending
  • Check trivy is pending
  • Check dependency-review is pending

@sonarqubecloud

Copy link
Copy Markdown

@thrillhousebot thrillhousebot Bot 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.

ThrillhouseBot found no issues in this PR, but some checks are still pending or failed:

  • Check format is pending
  • Check test is pending
  • Check frontend is pending
  • Check trivy is pending
  • Check dependency-review is pending

@devops-thiago
devops-thiago merged commit f1c9151 into main Aug 13, 2026
17 checks passed
@devops-thiago
devops-thiago deleted the fix/697-delimiter-aware-spans branch August 13, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working java Pull requests that update java code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(review): delimiter-aware inline span stripping in the decline re-check

1 participant