sea affinity prose: reinsert the (rank icon) parenthetical + pluralize the NC verb (they/yo leave, he/she/it leaves) — TDD

Two user follow-ups to the personalized affinity prose: (1) the corner-rank + suit-icon abbrev rides the card name again (e.g. 'the Queen of Pentacles (Q <i class=fa-crown></i>)'), mirroring SIG_READY — majors render just the numeral, e.g. '(I)'. (2) The NC clause conjugates the subject verb: they + yo are treated as PLURAL -> 'they leave' / 'yo leave behind'; the singular he/she/it keep the 3rd-person 'leaves'.

TDD: per-role-clauses test updated to 'they leave'; new yo-pluralizes + he-keeps-leaves cases; a with-abbrev PC case asserting the full rank+icon parenthetical. 51 drama+epic ITs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-06-08 22:23:19 -04:00
parent b0d153ebc1
commit a6db8c628f
2 changed files with 52 additions and 15 deletions

View File

@@ -167,17 +167,29 @@ class GameEvent(models.Model):
# into the gamer's Role-correlated Celtic position, woven into a
# role-specific clause. The actor's @handle is prepended by the
# template; pronouns resolve via the actor (subj/poss). "The " is
# stripped so a levity/gravity qualifier butts the proper name.
# stripped so a levity/gravity qualifier butts the proper name; the
# corner-rank + suit-icon abbrev rides the card name (mirrors SIG_READY).
card = d.get("card_name", "a card").replace("The ", "", 1)
corner_rank = d.get("corner_rank", "")
suit_icon = d.get("suit_icon", "")
if corner_rank:
icon_html = f' <i class="fa-solid {suit_icon}"></i>' if suit_icon else ""
abbrev = f" ({corner_rank}{icon_html})"
else:
abbrev = ""
card_ref = f"the {card}{abbrev}"
subj, _, poss = _actor_pronouns(self.actor)
# they + yo are PLURAL → the plural verb "leave" (not "leaves"); the
# singular he/she/it keep the 3rd-person "leaves" (user-spec).
leaves = "leave" if subj in ("they", "yo") else "leaves"
clause = {
"PC": f"the {card} crowns all {poss} loftiest illusions",
"NC": f"the {card} traces all the narratives {subj} leaves behind",
"EC": f"the {card} always looms before {poss} calling",
"SC": f"the {card} covers all {poss} righteous conduct",
"AC": f"the {card} always crosses {poss} sinister connections",
"BC": f"the {card} lays all {poss} foundational work",
}.get(d.get("role", ""), f"the {card} marks {poss} affinity")
"PC": f"{card_ref} crowns all {poss} loftiest illusions",
"NC": f"{card_ref} traces all the narratives {subj} {leaves} behind",
"EC": f"{card_ref} always looms before {poss} calling",
"SC": f"{card_ref} covers all {poss} righteous conduct",
"AC": f"{card_ref} always crosses {poss} sinister connections",
"BC": f"{card_ref} lays all {poss} foundational work",
}.get(d.get("role", ""), f"{card_ref} marks {poss} affinity")
return f"draws {poss} Sea of cards, where {clause}."
if self.verb == self.SEA_RELINQUISHED:
card_name = d.get("card_name", "a card").replace("The ", "", 1)

View File

@@ -181,21 +181,24 @@ class GameEventModelTest(TestCase):
)
# ── to_prose — SEA_DRAWN / SEA_RELINQUISHED ──────────────────────────
def test_sea_drawn_prose_pc_crown_clause(self):
def test_sea_drawn_prose_pc_crown_clause_with_abbrev(self):
event = record(self.room, GameEvent.SEA_DRAWN, actor=self.user,
role="PC", slot_number=1, card_name="The Magician")
# Default pronouns = pluralism → "their"; "The " stripped before "the".
role="PC", slot_number=1, card_name="Queen of Pentacles",
corner_rank="Q", suit_icon="fa-crown")
# Default pronouns → "their"; the corner-rank + suit-icon abbrev rides the
# card name (rendered |safe in the scroll).
self.assertEqual(
event.to_prose(),
"draws their Sea of cards, where the Magician crowns all "
"their loftiest illusions.")
'draws their Sea of cards, where the Queen of Pentacles '
'(Q <i class="fa-solid fa-crown"></i>) crowns all their '
'loftiest illusions.')
def test_sea_drawn_prose_per_role_clauses(self):
# Each Role gets its own clause (user-spec 2026-06-09). Default pronouns:
# subj "they", poss "their".
# subj "they" (plural → "leave"), poss "their". No abbrev (no corner_rank).
cases = {
"PC": "the Maid crowns all their loftiest illusions",
"NC": "the Maid traces all the narratives they leaves behind",
"NC": "the Maid traces all the narratives they leave behind",
"EC": "the Maid always looms before their calling",
"SC": "the Maid covers all their righteous conduct",
"AC": "the Maid always crosses their sinister connections",
@@ -208,6 +211,28 @@ class GameEventModelTest(TestCase):
event.to_prose(),
f"draws their Sea of cards, where {clause}.", f"role={role}")
def test_sea_drawn_nc_clause_pluralizes_yo(self):
# yo is treated as PLURAL → "yo leave behind", not "leaves".
self.user.pronouns = "bawlmorese"
self.user.save(update_fields=["pronouns"])
event = record(self.room, GameEvent.SEA_DRAWN, actor=self.user,
role="NC", card_name="Maid")
self.assertEqual(
event.to_prose(),
"draws yos Sea of cards, where the Maid traces all the "
"narratives yo leave behind.")
def test_sea_drawn_nc_clause_keeps_leaves_for_singular(self):
# A singular subject (he) keeps the 3rd-person "leaves".
self.user.pronouns = "misogyny"
self.user.save(update_fields=["pronouns"])
event = record(self.room, GameEvent.SEA_DRAWN, actor=self.user,
role="NC", card_name="Maid")
self.assertEqual(
event.to_prose(),
"draws his Sea of cards, where the Maid traces all the "
"narratives he leaves behind.")
def test_sea_drawn_prose_uses_actor_pronouns(self):
self.user.pronouns = "bawlmorese"
self.user.save(update_fields=["pronouns"])