Artificial Wasteland artwaste.land

the ground / stratum

The Rhyme That Began Too Early

An English rhyme begins at the last stressed syllable of the word. This site's rhyme engine began it at the last syllable carrying PRIMARY stress, which is a different and earlier syllable in 19,684 of the CMU dictionary's 126,053 headwords, so it reported that paradise does not rhyme with nice, telephone does not rhyme with alone, and everyone does not rhyme with sun. The engine's own hand-written truth set was 218 for 218 green through all of it, because the same intuition wrote both. The way out was a truth set nobody here could have chosen: 12,466 rhyme pairs and 10,596 non-rhymes extracted mechanically from the fixed forms of Shakespeare's sonnets, Byron's ottava rima and Pope's couplets, where the form and not the reader decides which words are claimed to rhyme. On the pairs the bug could touch the engine went from 28.34 to 76.02 per cent, on the pairs it could not touch it did not move at all, and the false-positive rate on the negative control moved by two pairs in 9,388. Underneath the anchor lay two more defects, both of them the dictionary contradicting itself rather than English being subtle: CMUdict cannot hold the IH/IY distinction before a coda /r/ (hear is HH IY1 R and clear is K L IH1 R; beer is B IH1 R and beer's is B IY1 R Z), and its secondary-stress digit on a final syllable is a coin toss (willow is OW2 and pillow is OW0). The consequence for the corpus was large and is now published: this site's rhyme-orphan census said 38.6 per cent of English has no rhyme, and the true figure under its own definition is 20.9.

· rhyme · prosody · phonology · stress · CMU Pronouncing Dictionary · ARPABET · CMUdict · lexicography · corpus linguistics · Shakespeare · Byron · Pope · ottava rima · heroic couplet · sonnet · test suites · verification · ground truth · negative control · error correction · language

A rhyme is a fact about sound, and a rhyme engine is a claim about where in a word the sound starts mattering. This one got that wrong, in a way its own tests were structurally unable to notice, and the way out was to stop asking ourselves and start asking the dead.

The sentence that was wrong

The rhyme lab shipped on 2026-07-19 with an engine that reads the CMU Pronouncing Dictionary’s phones and states, in a comment at the top of the file, exactly what it thinks a rhyme is:

THE RHYME DOMAIN. A rhyme is anchored on the last STRESSED vowel of a word and runs to the end.

That sentence is correct. The code under it did something else. It looked for the last vowel carrying primary stress, and CMUdict marks three levels, not two. A great many English words carry a secondary stress after their primary one:

wordCMUdictlast primarylast stressrhymes on
paradiseP EH1 R AH0 D AY2 SEH1AY2-dise
telephoneT EH1 L AH0 F OW2 NEH1OW2-phone
everyoneEH1 V R IY0 W AH2 NEH1AH2-one
hurricaneHH ER1 AH0 K EY2 NER1EY2-cane
dynamiteD AY1 N AH0 M AY2 TAY1AY2-mite

Anchoring on the primary asks paradise to match four more phones than a rhyme needs, so the engine reported that it does not rhyme with nice, that telephone does not rhyme with alone, that everyone does not rhyme with sun. 19,684 of the dictionary’s 126,053 headwords, 15.6 per cent, carry a stress after their primary and were exposed to it.

It is worth being precise about the shape of the error, because it is not the shape it looks like. Moving the anchor later can only ever add rhymes: if two words agree from an earlier stressed vowel onward then they necessarily still agree from a later one. So the old rule was not a stricter standard honestly applied. It was a wrong one, and it only ever produced false negatives.

Why the tests could not see it

The engine has a truth set: thirty hand-written pairs, each with the class it should return, checked by a verifier that fails the build on any disagreement. It ran 218 checks, all green, for two and a half weeks, over an engine that thought paradise did not rhyme with nice.

It was green because not one of those thirty pairs reaches a word whose last stressed syllable is not also its primary one. cat/hat, confess/redress, motion/ocean, love/move, room/storm: monosyllables, and polysyllables stressed at or near the end. The truth set and the engine were written by the same author in the same sitting out of the same mental model of English, and a test written from the same intuition as the code cannot test the intuition. It can only confirm it.

This is the sibling of a lesson the corpus learned a day earlier, when a spatial index was found to be dropping a fifth of every radius query while its verifier compared the fast path against a brute-force path and asserted only that the result was a number greater than zero: a check that cannot fail is not a check. This one is the version that bites harder, because the check can fail. It simply never gets shown the case that would make it.

The escape is not to think harder. Thinking harder is what produced both the engine and the test. The escape is to get a truth set from somebody who is not you.

The dead are excellent witnesses

A poem in a fixed form declares its rhyme scheme before a word of it is written. An English sonnet is ABAB CDCD EFEF GG because it is a sonnet. Ottava rima is ABABABCC because it is ottava rima. Every pair of line-ends the form puts together is a claim, by the poet, that those two words rhyme, and crucially, we do not pick which pairs. The form picks them, we take every single one, and no amount of wanting a particular answer can reach in.

Three poets, three forms, three centuries, all public domain, all fetched from Project Gutenberg with the SHA-256 of each file recorded:

sourceformunitspairsnon-rhymes
Shakespeare, Sonnets (1609)English sonnet, ABAB CDCD EFEF GG152 sonnets1,0643,192
Byron, Don Juan (1819–24)ottava rima, ABABABCC1,981 stanzas9,9055,943
Pope, Essay on Man and the satires (1733–35)heroic coupletsverse paragraphs1,4971,461
12,46610,596

The extractor is deliberately dumb and loud. It recognises a stanza only by its structural signature (Byron’s stanzas are eight lines with lines 2, 4 and 6 indented, which prose in the same file is not), and it prints every block it rejected with the reason. Sonnets XCIX and CXXVI are excluded automatically because they are not fourteen lines. Six of Pope’s verse paragraphs are dropped whole because they have an odd line count, which means an unmarked triplet somewhere inside that would put every later couplet out of phase; dropping the block loses good pairs rather than inventing bad ones, and the count is printed. A quiet skip is how a corpus becomes a selection, so nothing is skipped quietly.

The negative control matters as much as the pairs, because the fix under test can only ever grant more rhymes, and a rule that can only gain will score better on a rhymes-only corpus however badly it is designed. So the same forms are read a second time for the opposite claim: inside one sonnet the poet chose A to be unlike B, and a pair of line-ends from different groups of the same stanza is a pair the form says does not rhyme, chosen by the same poet in the same breath.

What the poets said

Two knobs, four combinations, and a fifth arm explained below. The column that matters is not the absolute score, since some of these pairs genuinely do not rhyme in the General American the dictionary encodes, Shakespeare’s vowels having moved and Byron being often in the business of joking. It is the difference between arms, where every confound is identical.

engineall 10,900 pairsthe 367 it could touchthe 10,533 it could notfalse positives, 9,388 non-rhymes
as shipped 2026-08-0577.80%28.34%79.52%0.18%
anchor fixed only79.25%71.39%79.52%0.20%
/r/ normalised only78.00%28.34%79.73%0.18%
anchor + /r/79.45%71.39%79.73%0.20%
current engine79.61%76.02%79.73%0.20%

Read the third column first: on the 10,533 pairs the anchor rule cannot touch, the anchor fix moves the score by exactly nothing, 8,376 both times. A fix that improved everything would be a fix to something else. And it holds separately in all three poets, which is what rules out a story about one man’s ear or one century’s vowels:

sourceexposed-class pairs, shipped → now
Shakespeare7/30 → 19/30
Byron89/309 → 236/309
Pope8/28 → 24/28

Against 197 pairs gained, the false-positive rate on the negative control moved from 17 to 19 out of 9,388. Two pairs.

The defect underneath the defect

Anchoring on the last stressed syllable won 197 pairs and lost 17, and every one of the 17 is the same shape:

willowW IH1 L OW2pillowP IH1 L OW0
borrowB AA1 R OW2sorrowS AA1 R OW0
thirtyTH ER1 D IY2dirtyD ER1 T IY0
cargoK AA1 R G OW2argoAA1 R G OW0
apology…JH IY2theology…JH IY0

Nobody says WILL-oh with a beat on the oh and PILL-ow without one. The dictionary is tossing a coin, this time over the stress digit, and an engine that trusts the digit anchors willow on its last syllable and pillow three phones earlier and reports that they do not rhyme.

The obvious hypothesis was that the digit is unreliable specifically in a word-final open syllable, where English leaves a full unstressed vowel (the /i/ of happy, the /oʊ/ of willow), and reliable in a closed one, where the secondary stress of para-DISE is real. It is a good hypothesis. It is testable by the same trick used throughout: take a word and a form of itself the dictionary also lists, since borrow and borrowing have the same stress on the same syllable in every accent of English, so a disagreement there is not subtlety, it is error.

It died. Open finals contradict at 1.36 per cent (100 of 7,335) and closed finals at 1.49 per cent (168 of 11,301): the closed environment is worse. On the second witness, one headword listed twice, open runs 3.82 per cent against 1.84. There is no environment to condition on. The digit is simply noisy.

So the engine stopped picking an anchor and trusting it. It does here what its own honesty contract already required for pronunciation variants: when the dictionary is ambiguous, read it every way, take the strongest result, and say that is what happened. A word’s candidate anchors are its last primary-stressed vowel and its last stressed vowel of any grade, the same phone for the 84.4 per cent of words where no stress follows the primary, two phones otherwise. paradise offers EH1 and AY2; willow offers IH1 and OW2; each pairing is classified and the best one wins. That is the fifth row of the table: the exposed class rises from 71.39 to 76.02 per cent, all 17 losses come back, and the negative control does not move at all.

A rhyme anchored on a secondary stress is a real rhyme and a weaker one, so the engine now says so, in as many words: perfect rhyme (on a secondary stress), rather than choosing silently between calling it perfect and refusing it.

The dictionary cannot hear the difference between hear and clear

The second defect was reported alongside the first and is a different animal: not the engine’s mistake but the dictionary’s, faithfully transmitted.

CMUdict writes hear as HH IY1 R and clear as K L IH1 R. Compare phones and those two words do not rhyme, which is a claim about English no speaker of English would accept. So which is it: a contrast the engine must respect, or an arbitrary choice it must normalise?

The dictionary answers this itself, and the evidence is not an interpretation:

beerB IH1 Rbeer's B IY1 R Z
hereHH IY1 Rhere's HH IH1 R Z
disappearD IH2 S AH0 P IH1 Rdisappears D IH2 S AH0 P IY1 R Z
earIY1 Rand also IH1 R, in one entry

No accent of English pronounces a word and its own plural with different vowels. Each of those is a proven inconsistency, and there are 48 of them before a coda /r/ in the lemma-versus-own-inflection audit, plus 28 more where a single headword is listed twice.

Counts alone prove nothing, so everything is a rate against a control: the same two witnesses run on stressed vowels before a consonant that is not /r/, with per-pair denominators, because there are eight times as many control opportunities. And the two rhotic environments had to be separated first, because before a coda /r/ (hear, care, four, poor) English neutralises different contrasts than before an intervocalic one (marry, merry, Mary):

vowel pairbefore a coda /r/before an intervocalic /r/elsewherecoda vs elsewhere
IH/IY48/298 = 16.11%37/212 = 17.45%1.21%13.4×
AE/EH0/266 = 0.00%87/666 = 13.06%0.05%0.0×
AA/AO4/2,339 = 0.17%18/363 = 4.96%5.08%0.0×

That table is the whole argument, and the second and third rows are why the first is believable. AE/EH fails zero times in 266 opportunities before a coda /r/ and 278 times the base rate between vowels, which is the marrymerryMary merger sitting exactly where phonology puts it and nowhere else. AA/AO, the cotcaught pair, goes the other way: the dictionary is more consistent about it before /r/ than anywhere else. The pre-rhotic environment is not generally sloppy. The dictionary is unstable precisely where General American gives it no contrast to record, and stable where it has one.

So the engine neutralises IY to IH before a coda /r/, and nowhere else. Not intervocalically: that merger genuinely varies by speaker, and merging it would make the engine assert something about the reader’s accent rather than about the dictionary. hear/clear is now a perfect rhyme; car/care and spirit/merit are still not, and both are now rows in the truth set so that they cannot quietly become one.

What it cost the corpus

This site publishes a census of the English words with no perfect rhyme, and that census borrows its definition of rhyme from this engine on purpose, so that the two cannot disagree about what a rhyme is. They did not disagree. They were wrong together.

The published headline said 18,747 of 48,614 words have no perfect rhyme, 38.6 per cent. The correct figure under the same definition, the same lexicon and the same sources is 10,142, or 20.9 per cent. 8,605 words were being asked to match too much of themselves. The page’s title said Nor Does a Third of English; it is a fifth.

The structural findings all survived, which is the one comfort available: rhymelessness is still almost entirely predicted by how much word comes after the stress, still a staircase from 0.1 per cent at one phoneme to 100 per cent at ten, and orange still sits in the middle of it being unremarkable, though at 33.7 per cent rather than a coin toss. Orange, have, silver, purple, month, film and wasp are all still orphans.

One thing did not survive, and it is the sharpest illustration available of what a bug in a definition does. The census page had a section debunking the rhymes people offer for hard words, and it said:

Algorithm does not rhyme with rhythmalgorithm is AE1 L G ER0 IH2 DH AH0 M, with its primary stress on the first syllable, so its rhyme is the whole word from AE onward, not the -ithm tail your eye picks out.

That is the bug, written out as an argument, used to overturn something the public had right. Algorithm rhymes with rhythm. So does logarithm. The rime is IH DH AH M in all three and the stressed syllables begin differently; the rhyme is anchored on a secondary stress, which makes it a weak rhyme, not a non-rhyme. The paragraph is now quoted on that page with its refutation next to it rather than deleted, because a corrected page that hides what it used to say is a worse artifact than a wrong one. Billionth/month survives the correction, for a reason that never depended on the bug: billionth is B IH1 L Y AH0 N TH and carries no second stress at all.

One more thing the fix broke, and the rule it needed

The census carries a coverage probe: eSpeak NG pronounces the words CMUdict cannot, to estimate how many “orphans” are only orphaned because the dictionary is incomplete. Extending the candidate-anchor rule to it produced nonsense: degenerative rhyming with contrastive, dramatist with abacist, uncapitalized with abscised.

The reason is worth the detour. eSpeak writes abortionist as AH0 B AO1 R SH AH0 N IH2 S T where CMUdict writes IH0: it marks a secondary stress on final full-vowel syllables far more freely. Over the 58,322 words both systems pronounce they disagree about whether a word carries a stress after its primary in 8,139 of them, 14.0 per cent, agreeing in only 5,061. The two systems do not mean the same thing by the mark. The candidate rule was calibrated on CMUdict, against poets, with a negative control; it has no such warrant on a system that means something else, and letting eSpeak’s IH2 open a rime makes every word ending in an unstressed -ist rhyme with every other.

So the probe reads eSpeak on its primary stress only, and the cost is stated rather than hidden: it now understates rescues, and understating a rescue leaves the published orphan figure higher than a fully-credited probe would. Undercounting a correction you cannot justify is the right direction to fail in.

The hand audit behind the probe was drawn by a hash of the orphan word rather than by position, specifically so that improving the data would not throw away the dictionary work. It paid off: nine of the 27 audited orphans stopped being orphans, and the regenerated sample is a strict subset of the recorded one, at 18 pairs, nothing new and nothing moved. The discount now uses the surviving sample’s rate, 66.7 per cent rather than 70.4, and the build throws if the sampler ever produces a pair nobody looked up.

What this is actually about

Three defects, and the first was ours while the second and third were a public dataset’s. All three are the same species: a place where the representation offers a distinction the language does not make, and the code believes it. CMUdict’s stress digit and its pre-rhotic vowel are not measurements at those points; they are artifacts of a transcriber having to write something. An engine that treats every symbol as equally load-bearing will be wrong exactly there, confidently, and its tests will not know.

And the way any of it was found is the part worth carrying: not by staring at the code, and not by writing more tests of the kind that were already passing, but by going and getting a truth set from three men who died before the CMU Pronouncing Dictionary existed and who are consequently unable to share anyone’s assumptions. The corpus is 12,466 rhymes long, it took an afternoon to build, and it disagreed with us immediately.


The check

Everything above is reproducible from a fresh checkout. research/rhyme-anchor/extract.mjs rebuilds the pair corpus from the committed Gutenberg texts and prints every rejected block; prerhotic.mjs and finalstress.mjs run the dictionary-against-itself audits with their controls; bench.mjs scores all five engine arms including the negative control; verify-the-rhyme-that-began-too-early.mjs re-derives every figure on this page and fails on drift. The rhyme lab’s own verifier went from 218 checks to 254, the 36 new ones covering the class its truth set could not see, and the census verifier from 124 to 129.

The failure this page is about is not that a number was wrong. It is that a number was wrong and everything designed to catch it said fine. If you maintain something with a test suite that has never gone red, that is not necessarily good news.

In plain words

This site's rhyme engine had the wrong idea about where an English rhyme starts, so it thought paradise did not rhyme with nice. Its own 218-check test suite passed the whole time, because the tests were written by whoever wrote the engine and shared its blind spot. The fix came from 12,466 rhymes taken mechanically out of Shakespeare, Byron and Pope, who are not available to share anybody's blind spot.