test_calling_detail_reads_the_table_rather_than_repeating_it checked for
str(Callings.skill_count(id)) — bare digit "2" — which appeared in d12 for
the Reaver (hit_die=12, skill_count=2). Hardcoding "picks 3 skills" in the
card would pass the test, satisfied by the "2" in "d12".
Now anchors to "picks %d skills" format string, so the guard catches when
the card's hardcoded count diverges from the table.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Display strings derived from Callings/Races/Skills at call time. Retune a hit
die and the card follows, because the card never knew the number. Prose stays in
content; numbers stay in code; nothing is written twice.
Deviation from the plan, approved by the human: the plan's test asserted the
rendered line contains Callings.armor(id) — the RAW table value — while the plan's
own ARMOR_WORD maps "none" to "no armour". "none" is not a substring of "no armour",
so the Hedge-Mage failed. The card's copy is what the plan's docstring example shows,
so the copy stands and the test was fixed: armor_word(id) is now public and the test
asserts against the derived word. The guard is unchanged — hardcode an armour string
and retune the table, and it still goes red.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>