Weak endings rhyme at line ends

Feminine rhymes anchor on the unstressed final syllable: infancy
joins see/be/me (Lateralus). End-slant pass tries the bare final
vowel as a fallback key, with claiming.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 03:26:09 -04:00
parent c94cb9f42e
commit a8c076163d
2 changed files with 37 additions and 4 deletions
+27 -4
View File
@@ -333,6 +333,16 @@ def multi_keys(word: str) -> tuple[str, ...]:
return tuple(dict.fromkeys(out))
def weak_end_key(word: str) -> str | None:
"""The bare final vowel, stress be damned — at line ends poets rhyme
the weak syllable (infancy / see, eternity / be)."""
ph = phones_for(word)
if not ph:
return None
vowels = _all_vowels(ph)
return ("v:" + vowels[-1]) if vowels else None
def slant_key(word: str) -> str | None:
phones = phones_for(word)
if phones:
@@ -611,10 +621,23 @@ def analyze(draft: Draft):
by_slant = defaultdict(list)
for t in tokens:
if t["is_end"] and id(t) not in grouped:
key = slant_key(t["word"])
if key:
attach_or_collect(t, key, by_slant, group_by_slant)
for (sid, key), toks in by_slant.items():
keys = [slant_key(t["word"])]
wk = weak_end_key(t["word"])
if wk and wk not in keys:
keys.append(wk) # feminine endings: infancy rhymes see
for key in filter(None, keys):
gi = group_by_slant.get((t["sid"], key))
if gi is not None:
raw_groups[gi]["toks"].append(t)
t["slant"] = True
grouped.add(id(t))
break
else:
for key in filter(None, keys):
by_slant[(t["sid"], key)].append(t)
for (sid, key), toks in sorted(by_slant.items(),
key=lambda kv: (-len(kv[1]), kv[0][1])):
toks = [t for t in toks if id(t) not in grouped]
if len(toks) >= 2 and len({t["word"].lower() for t in toks}) >= 2:
raw_groups.append({"toks": toks, "slant": True, "key": key})
grouped.update(id(t) for t in toks)
+10
View File
@@ -420,3 +420,13 @@ def test_analyze_rejects_oversized_drafts():
from fastapi import HTTPException
with _pytest.raises(HTTPException):
analyze(Draft(text="a" * 200_000))
def test_weak_ending_rhymes_at_line_end():
# Lateralus: stress sits on IN-fancy, but the weak final syllable
# carries the rhyme at the line end
text = ("All I see\n"
"In my infancy\n"
"Red and yellow then came to be\n"
"Reaching out to me")
group_with(text, "see", "infancy", "be", "me")