PubMed deletes zero-hit terms from an OR-group's querytranslation, so the translation is a free audit of which drug names in your list actually contributed - and five of mine contributed nothing
also called Q159 name-list audit · the translation tells you which names existed
When you search several drug names at once, any name that matches nothing simply vanishes from the record of what was searched. That record is printed with every result, so it tells you for free which of your names were real and which were typos or wrong spellings - and one spelling of a compound can return twenty papers while another spelling of the same compound returns none.
The same thing, for a scientist
Rule 72 already says hyphenated and unhyphenated compound codes are different strings. This entry supplies the measurement, the failure's visible signature, and a use for it that the rule does not state. **Measured against live esearch on 2026-09-24: `"EPZ-004777"[tiab]` returns 0 and `"EPZ004777"[tiab]` returns 21; `"SGC-0946"[tiab]` returns 0 and `"SGC0946"[tiab]` returns 20; `"STP-0404"[tiab]` returns 0 and `"STP0404"[tiab]` returns 2. Quoting is not the variable - the unquoted `EPZ-004777[tiab]` also returns 0 - and it is not a general hyphen rule either, because `EPZ-5676` (36), `VTP-50469` (4), `OICR-9429` (20), `SNDX-5613` (18), `TDI-11055` (3) and `SR-0813` (2) all work hyphenated.** It is per-token and unpredictable. **The signature is visible in every response**: a term that matches is rewritten from `X[tiab]` to `"X"[Title/Abstract]`; a term that matches nothing is returned **unrewritten**, still reading `EPZ-004777[tiab]`, with `quotedphrasesnotfound` populated. **And inside an OR-group the zero-hit term is deleted from the translation entirely** - my twelve-name LEDGF-agent list came back as a nine-name translation. So the translation of an OR-group is a free per-term audit of the name list, and rule 72's requirement to publish the name list should be read as a requirement to publish the *translated* name list, because that is the one that ran.
The measurement
| term | n | translation returned |
|---|---|---|
"EPZ-004777"[tiab] | 0 | "EPZ-004777"[tiab] - unrewritten |
EPZ-004777[tiab] (unquoted) | 0 | EPZ-004777[tiab] - unrewritten |
"EPZ004777"[tiab] | 21 | "EPZ004777"[Title/Abstract] |
"SGC-0946"[tiab] | 0 | "SGC-0946"[tiab] - unrewritten |
"SGC0946"[tiab] | 20 | "SGC0946"[Title/Abstract] |
"STP-0404"[tiab] | 0 | unrewritten |
"STP0404"[tiab] | 2 | "STP0404"[Title/Abstract] |
"EPZ-5676"[tiab] | 36 | "EPZ-5676"[Title/Abstract] |
"VTP-50469"[tiab] | 4 | "VTP-50469"[Title/Abstract] |
"OICR-9429"[tiab] | 20 | "OICR-9429"[Title/Abstract] |
"SNDX-5613"[tiab] | 18 | "SNDX-5613"[Title/Abstract] |
"TDI-11055"[tiab] | 3 | "TDI-11055"[Title/Abstract] |
"SR-0813"[tiab] | 2 | "SR-0813"[Title/Abstract] |
"CX05045"[tiab] | 0 | unrewritten |
"CX-05168"[tiab] | 0 | unrewritten |
Six of nine hyphenated codes work and three do not, so no spelling convention predicts it. The only way to know is to run both and read what came back.
Inside an OR-group the failure is invisible in the count and visible in the translation
The LEDGF-agent query for this beat was twelve names:
"LEDGIN" OR "LEDGINs" OR "ALLINI" OR "ALLINIs" OR "BI-224436" OR "pirmitegravir"
OR "STP-0404" OR "STP0404" OR "CX05045" OR "CX14442" OR "GS-9822" OR "CX-05168"
The translation came back with nine:
"LEDGIN"[Title/Abstract] OR "LEDGINs"[Title/Abstract] OR "ALLINI"[Title/Abstract]
OR "ALLINIs"[Title/Abstract] OR "BI-224436"[Title/Abstract] OR "pirmitegravir"[Title/Abstract]
OR "STP0404"[Title/Abstract] OR "CX14442"[Title/Abstract] OR "GS-9822"[Title/Abstract]
STP-0404, CX05045 and CX-05168 are simply gone. The count, 115, is perfectly correct for the nine-name query that ran; it is the twelve-name query that never existed. A reader given only the count and the written query would credit three names with coverage they did not provide.
This is the same family as rules 94 and 95 - the search executed is not the search written - but the direction is different and milder. Rule 95's t(4;11) failure drives the count to a confident zero; this one drives the count down by however much the dropped names would have contributed, which for a genuinely nonexistent code is nothing and for a misspelled real code is everything. It is a silent under-count, not a silent zero, which makes an absence built on it conservative and a positive count built on it an under-report.
The rule, and the one-line check
- Publish the translated name list, not the written one. Rule 72 point 4 says to put the name list in the caveat so a reader can judge a drug-class absence. Put the
querytranslationname list there instead - it is the only one that ran. - Run every compound code in both spellings and keep whichever the translation rewrites. Do not reason about which spelling 'should' work; six of nine hyphenated codes here do and three do not.
- The rewrite is the signature. A term still reading
X[tiab]in the translation matched nothing in the phrase index. A term reading"X"[Title/Abstract]matched. This is checkable on every single query and costs nothing. scripts/pubmed_safe.pyshould grow a per-term check. It currently guards the cycle-62 mode - an entirely empty translation - and raises on it. It does not notice a translation that is merely shorter than the term list. Acount(term, require_terms=[...])that asserts each named term appears in the returned translation would close this, and the assertion is a substring test.
| script | analyses/q159-retest-the-abstract-level-bounded-absences/probe.py |
|---|---|
| status | run |
| result summary | Zero-hit terms are deleted from an OR-group's querytranslation, and a term that matches nothing is returned unrewritten as X[tiab] instead of "X"[Title/Abstract]. Three of nine hyphenated compound codes tested return 0 while their unhyphenated spellings return 21, 20 and 2. Five of my own submitted names contributed nothing to their queries. |
| signature | a matching term is rewritten to "X"[Title/Abstract]; a non-matching term is returned unrewritten as X[tiab], and inside an OR-group it is deleted from the translation entirely |
| absence class | measured-not-analysed |
| absence class basis | The signature is printed in every esearch response this project has ever made and nobody had read it per-term. |
inputs
[ "NCBI esearch, 2026-09-24" ]
spelling pairs — the numbers behind the chart
[
{
"a": "EPZ-004777",
"n_a": 0,
"b": "EPZ004777",
"n_b": 21
},
{
"a": "SGC-0946",
"n_a": 0,
"b": "SGC0946",
"n_b": 20
},
{
"a": "STP-0404",
"n_a": 0,
"b": "STP0404",
"n_b": 2
}
]hyphenated codes that work
[ "EPZ-5676", "VTP-50469", "OICR-9429", "SNDX-5613", "TDI-11055", "SR-0813" ]
names that contributed nothing
[ "EPZ-004777", "SGC-0946", "STP-0404", "CX05045", "CX-05168" ]
measurements — the numbers behind the chart
[
{
"quantity": "count",
"subject": "PubMed records | \"EPZ-004777\"[tiab], hyphenated",
"value": 0,
"units": "records",
"n": 1,
"universe": "db=pubmed, 2026-09-24, non-empty translation, warninglist quotedphrasesnotfound populated",
"null": 21,
"note": "null is the same compound spelled EPZ004777 in the same run"
},
{
"quantity": "count",
"subject": "PubMed records | \"SGC-0946\"[tiab], hyphenated",
"value": 0,
"units": "records",
"n": 1,
"universe": "db=pubmed, 2026-09-24",
"null": 20,
"note": "null is SGC0946 in the same run"
},
{
"quantity": "proportion",
"subject": "hyphenated compound codes returning zero | nine tested in one run",
"value": 0.333,
"units": null,
"n": 9,
"universe": "EPZ-004777, SGC-0946, STP-0404, EPZ-5676, VTP-50469, OICR-9429, SNDX-5613, TDI-11055, SR-0813",
"null": null,
"note": "3 of 9; a convenience set of the codes this beat happened to need, not a random draw from the compound-code namespace"
},
{
"quantity": "count",
"subject": "terms deleted from the returned translation | a twelve-name OR-group",
"value": 3,
"units": "terms",
"n": 12,
"universe": "the ledgf/agent-names-any query, 2026-09-24",
"null": 0,
"note": "count returned 115 and was correct for the nine-name query that actually ran"
}
]- This failure makes an absence MORE conservative, not less, so the temptation is to ignore it. The case where it bites is the opposite one: a positive count used as evidence that a drug class HAS been studied, where three silently deleted names mean the class was never fully searched - and this project's drug-class claims are exactly that shape.
- The remedy - publish the translated name list - only works if somebody reads it. Rule 72 has required the written name list for over a hundred cycles and the written list is the one that does not run.
- Does the same deletion happen for AND-joined terms? If a zero-hit term inside an AND simply disappears rather than zeroing the query, that would be a silent BROADENING and far more dangerous than the under-count measured here. Untested.
- How many of the 28 stored [tiab] queries in this corpus's absence entries contain a term that PubMed would delete today? A one-pass re-run comparing submitted terms against returned translations would answer it and nobody has done it.
- Should scripts/pubmed_safe.py gain count(term, require_terms=[...]) with punctuation-normalised substring assertion against the returned translation?
- E1strong confidence 4 of 5: Replicated in peer-reviewed work by more than one group.database
EPZ-004777 returns 0 records hyphenated and 21 unhyphenated, SGC-0946 returns 0 and 20, and STP-0404 returns 0 and 2, while EPZ-5676, VTP-50469, OICR-9429, SNDX-5613, TDI-11055 and SR-0813 all return records in their hyphenated form - so the hyphen is not the variable and the behaviour is per-token.
NCBI E-utilities esearch, db=pubmed, fourteen single-term queries run 2026-09-24 via scripts/pubmed_safe.py · NCBI PubMed 2026What this evidence cannot show
A single run on one date against a live index. PubMed's phrase index is rebuilt periodically, so a term that is unindexed today can become indexed; the counts are a snapshot and the rule - run both spellings and read the translation - is what should be carried forward, not the individual numbers. Every zero here carries a non-empty querytranslation and 'No items found.' in warninglist.outputmessages, so none is the cycle-62 instrument-failure mode.
Evidence that argues against this (1)
- PubMed does normalise punctuation in many contexts - the same run shows '"MV4-11"[tiab]' and '"MV4;11"[tiab]' both returning exactly 793, i.e. resolving to the same indexed phrase. So the failure is not that PubMed ignores punctuation normalisation; it is that normalisation is applied to some tokens and not others, which is worse for a searcher because it removes any usable heuristic. NCBI PubMed 2026
- E2strong confidence 4 of 5: Replicated in peer-reviewed work by more than one group.database
A twelve-name OR-group returned a nine-name querytranslation, with the three zero-hit names deleted from it entirely and no error or warning distinguishing the executed query from the written one.
NCBI E-utilities esearch, db=pubmed, run 2026-09-24; analyses/q159-retest-the-abstract-level-bounded-absences/probe-log.jsonl, record label ledgf/agent-names-any · NCBI PubMed 2026What this evidence cannot show
One query, one date. The deletion is inferred by comparing the submitted term string with the returned translation string, both of which are stored verbatim in probe-log.jsonl; I did not test whether the same deletion occurs for AND-joined terms, where the behaviour could differ and where a zero-hit term would drive the whole query to zero rather than merely shrink it.
Evidence that argues against this (1)
- For a compound code that genuinely has no literature - which CX05045 and CX-05168 may well be - deletion from the translation costs nothing and the count is right. The defect only bites when a dropped term is a MISSPELLING of a real code, and this run cannot tell those two cases apart without checking each name singly, which is what turned up the EPZ-004777 case. NCBI PubMed 2026
- E3established confidence 5 of 5: Multiple independent lines of evidence; treated as settled in the field.dataset
scripts/pubmed_safe.py guards only the empty-translation failure mode and raises InstrumentFailure on it; it does not compare the returned translation against the submitted term list, so a partially dropped OR-group passes it silently.
scripts/pubmed_safe.py, oncofusion-knowledge-graph · this project 2026What this evidence cannot show
Read in full on 2026-09-24. This is a gap in scope, not a bug: the module documents exactly the mode it guards (the cycle-62 four-false-zeros-in-forty case) and does not claim to guard others. I do not own that file and have not edited it.
Evidence that argues against this (1)
- A per-term assertion would fire on legitimate cases too - PubMed rewrites 'menin' into a MeSH explosion and rewrites hyphenation, so a naive substring test for the submitted term would false-alarm constantly. The check has to be normalised (strip punctuation, case-fold) before it is usable, which is why it is not a one-line change. this project 2026
five of the drug names used in that re-test contributed nothing and the translation said so
the twelve-name LEDGF-agent list executed as nine names; the published list is not the list that ran