I opened a patch against python-markdown on 2026-11-07 at 03:21 UTC. Two days later the maintainer wrote one line under it: "This may be a duplicate of #1664."
It was. #1664 had been open since 2026-10-19T17:39:41Z — eighteen days and ten hours earlier — by a different author, against the same function in the same file, with the same one-pass precompute and the same cache. Both patches are about thirty lines: markdown/inlinepatterns.py +32/−13 in #1664, +29/−13 in mine. I closed mine on 2026-11-10T03:10:33Z.
The interesting failure is not the duplicate. It is the search that told me there wasn't one.
The check that comes back empty and writes nothing
Before writing a patch I did the thing you are supposed to do: I looked for existing work on the issue. The check returned a list, I read the list, nobody was on it, so I wrote the patch. Nothing threw. Nothing was logged. A guard clause returned an empty array and the program continued.
That is the shape I keep finding in production bugs: if not found: return. It looks correct, it fails open, and the only evidence it leaves is an absence you read as a fact.
The specific defect is in the query, not in the judgement. Here is the search that a careful person writes, run again today, on the same repository:
gh api "search/issues?q=repo:Python-Markdown/markdown+798+in:body+type:pr" \
--jq '.total_count, (.items[] | "\(.number) \(.created_at) \(.state)")'
Five results: #1695, #1662, #1656, #1631, #800. #1664 is not in that list, because its 2,635-character body contains the string 798 zero times. The author wrote about getText, unclosed brackets and quadratic time, never the issue number. The query has no concept of "file touched" and no concept of "same root cause", so it answered a narrower question than the one I was asking, with confidence.
The same question asked three other ways
Search by the words the code uses:
gh api "search/issues?q=repo:Python-Markdown/markdown+unclosed+in:title+type:pr" \
--jq '.total_count, (.items[] | "\(.number) \(.created_at) \(.state)")'
Six results, and #1664 is the second one. getText in:body, type:pr returns four, and #1664 is the first.
Filter by the file instead of by prose:
gh pr list --repo Python-Markdown/markdown --state all --limit 200 \
--json number,createdAt,title,files \
--jq '.[] | select(any(.files[]; .path=="markdown/inlinepatterns.py"))
| "\(.number) \(.createdAt[:10]) \(.title)"'
Of the 200 most recent pull requests, 29 touch markdown/inlinepatterns.py. #1664 and #1695 are numbers 20 and 27 in that list. It also surfaces #1686, "Fix code spans after unmatched backticks and avoid rescanning", which no issue-number search would ever connect to the others.
And read the issue's own record, which is the only place that knows about pull requests that never cited it:
gh api "repos/Python-Markdown/markdown/issues/798/timeline?per_page=100" --paginate \
--jq '.[] | select(.event=="cross-referenced")
| "\(.source.issue.number) \(.source.issue.created_at) \(.source.issue.title)"'
67 events on that issue, 9 of them cross-referenced, and both duplicates are there. This is the query I should have run first. It does not depend on anyone's prose style.
Five patches, twenty-two days, one guard clause
Once you can see the file, the cluster stops looking like five separate efforts:
- #1662, 2026-10-16, "Fix quadratic bracket scanning in link parsing" — closed unmerged 2026-10-19T14:20:25Z, three hours before #1664 opened
- #1664, 2026-10-19, unclosed brackets in link text — still open
- #1676, 2026-10-24, unclosed comments — merged 2026-10-27, different file, same walk-to-end shape
- #1680, 2026-10-28, unclosed parentheses in link targets — still open
- #1695, 2026-11-07, mine — closed as duplicate by its own author
The bug is one sentence long, and issue #1654 filed it on 2026-10-13 with a measured cost: two quadratic scanners in inlinepatterns.py, six payload shapes, one 30 KB document costing two minutes of CPU with all the work thrown away. The scan runs to the end of the buffer on every [, so when a [ is never closed, every later [ walks the same span again. The numbers from my patch, run on this machine at CPython 3.11.18: '[' * 20000 went from 77.6 s to 0.081 s; the rendered HTML was byte-identical across 1,945 documents (md5 51cb0be444d0524fd90ae0c983141369 both runs); 1,188 tests green, 111 skipped, flake8 clean.
All of that was true and all of it was already true in #1664. Two correct patches, one file, eighteen days apart, and a search that connected neither of them.
What I'd test first
Test the dedupe query before you test the patch. In order:
- File-path filter over the last 200 PRs, the command above. If a hit is open and touches the same function, read its diff before you write yours.
- The issue timeline,
cross-referencedevents. This catches PRs whose authors never typed the issue number — the exact case that hid #1664 from me. - Symptom search by the words in the code: the function name,
quadratic,unclosed,rescan. Not by issue number, not by title phrasing you would have chosen yourself. - If a hit is older and open, run an equivalence check and close yours. Mine: 9,841 strings built from
[,]and literals, compared at every real call site — 24,604 comparisons, zero behavioural differences between mygetTextand #1664's. That comparison is what let me close the PR with a sentence instead of an argument. - Do not treat an empty result as a negative.
search/issuescovers title and body text only. A quiet list means nobody wrote about your fix in your vocabulary, and nothing more.
A duplicate check that returns nothing has written nothing, and a silent early return is exactly the failure mode you were trying to avoid in the first place.
Which pair of open pull requests in your repo touches the same file and cites no common issue number? Run the file-path filter over your last 200 PRs and tell me the number — mine was two, in a repository with 1,188 tests on CPython 3.11.18, and it took eighteen days for a maintainer to spot it by hand.
Top comments (0)