Fold Typographic Punctuation in pr_review.py reply --match - #1878
Conversation
A --match string copied verbatim from a rendered finding fails to select the thread it was copied from when the finding's typographic quotes, dashes, or ellipsis don't survive the copy in ASCII, and NO_MATCH reads identically to the thread being missing or already resolved. matching_threads() now folds both the pattern and each candidate body through an ASCII table before the substring compare, and NO_MATCH now states how many unresolved threads exist so a zero and a several no longer read the same. A parameterized test checks each of the issue's seven characters independently of the fold table itself, so dropping one from the table still fails the test that covers it. Closes on promotion: #1299 Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The functional change is small and well-covered by new tests, with only a minor test-robustness improvement suggested.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
This pull request improves scripts/pr_review.py reply --match so it can reliably select threads even when the thread text or the copied --match pattern differs only by typographic punctuation (curly quotes, en/em dashes, ellipsis), and it makes NO_MATCH refusals more actionable by including the total unresolved-thread count.
Changes:
- Add a typographic-to-ASCII folding table and apply it to both the
--matchneedle and candidate thread bodies before case-insensitive substring matching. - Extend the
NO_MATCHmessage to include the total number of unresolved threads on the PR. - Add targeted tests covering the fold behavior per character and the improved
NO_MATCHmessage.
| File | Description |
|---|---|
| scripts/pr_review.py | Folds typographic punctuation on both sides of --match comparisons; includes unresolved-thread count in NO_MATCH. |
| scripts/tests/test_pr_review.py | Adds regression tests for typographic folding and the updated NO_MATCH output. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
test_every_documented_character_selects_across_the_ascii_boundary captures stdout once in setUp and ran all seven fold checks against that same buffer, so a later iteration's assertIn found an earlier iteration's leftover REPLIED_AND_RESOLVED output rather than its own. Clearing the buffer at the start of each subTest makes the assertion specific to its own iteration. Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
Re: the stdout-buffer finding on scripts/tests/test_pr_review.py:5266 (thread already shows resolved, so answering here for the record rather than via reply --resolve, which only targets unresolved threads): fixed in 7818762. Each subTest iteration in test_every_documented_character_selects_across_the_ascii_boundary now clears the shared stdout buffer (self.out.seek(0); self.out.truncate(0)) before wiring and running its own reply, so its assertIn checks only its own iteration's output rather than one accumulated across all seven. Swept the file for the same setUp-captures-stdout-once-then-loops-subTests shape in every other test class (TestCoverageExitCodes, TestCli, CommentCase, ReplyCase) and found no other instance of the same latent bug. |
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The change is narrowly scoped, covered by new unit tests, and the updated matching behavior is applied symmetrically to both the pattern and candidate text.
Review effort: Lite
Findings: None

Summary
A
--matchstring copied verbatim from a rendered finding fails to select the thread it was copied from when the finding's typographic quotes, dashes, or ellipsis don't survive the copy in ASCII, andNO_MATCHreads identically to the thread being missing or already resolved.matching_threads()now folds both the--matchpattern and each candidate thread body through an ASCII table (_TYPOGRAPHIC_FOLD) before the case-insensitive substring compare, covering the typographic single/double quotes, en/em dash, and ellipsis.NO_MATCHnow states how many unresolved threads exist on the pull request, so a zero and a several no longer read the same, per the issue's secondary suggestion.Closes on promotion: #1299
Two related gaps found during local review are filed separately as out of scope for this fix: #1876 (an ASCII
--and a real em dash still miss each other) and #1877 (a--matchpattern copied from this script's own truncated/whitespace-collapsedunresolved:line can still miss).Test plan
python3 -m unittest scripts.tests.test_pr_review(434 tests, all passing)uvx ruff@latest format --checkanduvx ruff@latest checkclean on both changed filesuvx pyrightshows only the same 2 pre-existing errors present ondevelopbefore this changescripts/local_review.py🤖 Generated with Claude Code