Trim trailing schwas in multisyllabic rhyme keys

militia (IH-AH) now catches commissioner (IH-AH-ER) — a trailing
reduced syllable falls off the beat. Phrase distinctness is checked by
anchor word so "fire burns" can't pose as a rhyme partner for "fire".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 01:19:02 -04:00
parent 7a1e0e2953
commit 99ff44ca0e
2 changed files with 17 additions and 4 deletions
+10 -4
View File
@@ -173,11 +173,15 @@ def founding_projections(key: str) -> dict[str, str]:
def _multi_key(vowels: list[str]) -> str | None:
"""Key for multisyllabic slant rhymes: a 2+ vowel run where the first
vowel must match exactly and later reduced vowels are merged."""
vowel must match exactly and later reduced vowels are merged. Trailing
schwas are trimmed so militia (IH-AH) still catches commissioner
(IH-AH-ER) — the tail falls off the beat."""
if len(vowels) < 2:
return None
return "m:" + " ".join(
[vowels[0]] + ["x" if v in REDUCED else v for v in vowels[1:]])
parts = [vowels[0]] + ["x" if v in REDUCED else v for v in vowels[1:]]
while len(parts) > 2 and parts[-1] == "x":
parts.pop()
return "m:" + " ".join(parts)
def _grapheme_tail(raw: str) -> str | None:
@@ -449,8 +453,10 @@ def analyze(draft: Draft):
if key:
attach_or_collect(p, key, by_multi, group_by_multi)
# distinctness by anchor word, so the phrase "fire burns" can't pose
# as a different word than the "fire" it starts with
for (sid, key), toks in by_multi.items():
if len(toks) >= 2 and len({t["word"].lower() for t in toks}) >= 2:
if len(toks) >= 2 and len({t["word"].split()[0] for t in toks}) >= 2:
raw_groups.append({"toks": toks, "slant": True, "key": key})
grouped.update(id(t) for t in toks)
+7
View File
@@ -215,3 +215,10 @@ def test_syllables_always_reported():
m = meter_of("the city hums in amber under fading light")
assert m["syl"] == 12
assert m["stress"]
def test_trailing_schwa_trimmed_militia_commissioner():
# commissioner has one extra reduced syllable (IH-AH-ER vs IH-AH)
text = ("Swagger down pat, call my shit Patricia\n"
"Young Money militia, and I am the commissioner")
group_with(text, "patricia", "militia", "commissioner")