diff --git a/client/tests/unit/test_content_db.gd b/client/tests/unit/test_content_db.gd index 0c11ea1..dee944a 100644 --- a/client/tests/unit/test_content_db.gd +++ b/client/tests/unit/test_content_db.gd @@ -136,11 +136,26 @@ func test_every_race_and_calling_carries_a_fragment(): # The DM origin panel (M4-b) composes race.fragment + calling.fragment. A # missing one degrades to the blurb at runtime rather than crashing — but it # must never SHIP missing, so the suite is where it fails. + # + # The composition is "{race.fragment} Now you carry a {Calling}'s work — + # {calling.fragment}", so three shape rules make all 28 pairings legal + # sentences: a race fragment opens a sentence (uppercase) and closes it (.); + # a calling fragment continues one after the em dash (lowercase) and closes + # it (.). Guard them here — a future author adding a calling gets a signal, + # not a subtly ungrammatical DM. for id in Races.IDS: assert_true(db.race(id).has("fragment"), "race %s has no fragment" % id) - assert_ne(str(db.race(id).get("fragment", "")).strip_edges(), "", - "race %s has an empty fragment" % id) + var race_fragment := str(db.race(id).get("fragment", "")).strip_edges() + assert_ne(race_fragment, "", "race %s has an empty fragment" % id) + assert_eq(race_fragment.substr(0, 1), race_fragment.substr(0, 1).to_upper(), + "race %s: fragment opens the composition, so it must start uppercase" % id) + assert_true(race_fragment.ends_with("."), + "race %s: fragment must end with '.' — a sentence precedes 'Now you carry…'" % id) for id in Callings.IDS: assert_true(db.calling(id).has("fragment"), "calling %s has no fragment" % id) - assert_ne(str(db.calling(id).get("fragment", "")).strip_edges(), "", - "calling %s has an empty fragment" % id) + var calling_fragment := str(db.calling(id).get("fragment", "")).strip_edges() + assert_ne(calling_fragment, "", "calling %s has an empty fragment" % id) + assert_eq(calling_fragment.substr(0, 1), calling_fragment.substr(0, 1).to_lower(), + "calling %s: fragment follows an em dash, so it must start lowercase" % id) + assert_true(calling_fragment.ends_with("."), + "calling %s: fragment must end with '.' — it closes the composition" % id) diff --git a/content/world/callings/bonesetter.json b/content/world/callings/bonesetter.json index a58459a..c42cf37 100644 --- a/content/world/callings/bonesetter.json +++ b/content/world/callings/bonesetter.json @@ -1 +1 @@ -{ "id": "bonesetter", "name": "Bonesetter", "blurb": "The Warden is distant and does not explain himself. Still — you set the bone, you say the words, and often enough the rot does not take. Often enough.", "fragment": "you set the bone, you say the words over it, and you have stopped claiming to know which one matters." } +{ "id": "bonesetter", "name": "Bonesetter", "blurb": "The Warden is distant and does not explain himself. Still — you set the bone, you say the words, and often enough the rot does not take. Often enough.", "fragment": "you are the one they wake at the third hour, and you have stopped claiming to know whether it is your hands or the Warden that does the saving." } diff --git a/content/world/callings/hedge_mage.json b/content/world/callings/hedge_mage.json index b884056..ad3fde1 100644 --- a/content/world/callings/hedge_mage.json +++ b/content/world/callings/hedge_mage.json @@ -1 +1 @@ -{ "id": "hedge_mage", "name": "Hedge-Mage", "blurb": "No tower took you. What you know, you got from a book you should not have had and a teacher who is not alive to confirm it.", "fragment": "what you know came out of a stolen book, and there is no one left to tell you what you got wrong." } +{ "id": "hedge_mage", "name": "Hedge-Mage", "blurb": "No tower took you. What you know, you got from a book you should not have had and a teacher who is not alive to confirm it.", "fragment": "you taught yourself the rest where nobody would come looking, and the scars are from the parts the book got wrong." } diff --git a/content/world/callings/reaver.json b/content/world/callings/reaver.json index 07c0a10..6a27575 100644 --- a/content/world/callings/reaver.json +++ b/content/world/callings/reaver.json @@ -1 +1 @@ -{ "id": "reaver", "name": "Reaver", "blurb": "They hire you when they want a door opened and do not care about the door. You do not wear plate. You have never needed it.", "fragment": "they point you at a door and pay you not to care what is behind it." } +{ "id": "reaver", "name": "Reaver", "blurb": "They hire you when they want a door opened and do not care about the door. You do not wear plate. You have never needed it.", "fragment": "they send for you when the talking is finished, and they make a point of being somewhere else when you arrive." } diff --git a/content/world/races/beastfolk.json b/content/world/races/beastfolk.json index dde61e4..5f1d6b3 100644 --- a/content/world/races/beastfolk.json +++ b/content/world/races/beastfolk.json @@ -1 +1 @@ -{ "id": "beastfolk", "name": "Beastfolk", "blurb": "Claws you did not ask for and a nose you cannot switch off. Every gate you pass, someone decides what you are before you speak.", "fragment": "You were born with claws the Margreave never learned to ignore, and you have spent your life being looked at a beat too long." } +{ "id": "beastfolk", "name": "Beastfolk", "blurb": "Claws you did not ask for and a nose you cannot switch off. Every gate you pass, someone decides what you are before you speak.", "fragment": "Most towns will take your coin and still want you outside the walls by dark. You stopped taking that personally a long time ago." }