fix(creation-screen): the guards did not guard

Review found three tests in test_character_creation_screen.gd could not fail
against the bug they named — including both tests claiming to enforce §7
(Luck is invisible) and the only test covering origin->calling gating. The
five-ability-cards test asserted the script's own range(5) loop bound, not
the scene. The Luck sweep filtered on `Label` and missed both RichTextLabels
(the only nodes rendering authored prose) plus every Button and the
LineEdit. The reroll test's pool assertion already held true before the
reroll ran. The origin-gating test ran only against the deserter origin,
which allows all 7 callings, so shown==allowed was a trivial 7==7.

Rewrote all four to assert against the scene, the rules tables, or a
restrictive injected origin instead of values the code already guaranteed.
Added a node-count guard tying authored cards/chips to Races/Callings/
Skills/Attributes table sizes. Deleted the test-only
_complete_a_valid_draft_for_test() from the shipped Control and replaced it
with a test-file helper that drives the real click handlers, closing the
gap where no test touched _on_race_pressed/_on_calling_pressed/
_on_pool_pressed/_on_bonus_pressed at all. Guarded _ready() against a
degenerate origin (empty/missing allowed_callings) indexing an empty array.

Each fixed guard was deliberately re-broken and confirmed red before being
reverted (see .superpowers/sdd/task-6-report-fix.md, gitignored). 291 tests
green, up from 289.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-13 15:19:10 -05:00
parent 2227d703f6
commit 6589d7c4ed
2 changed files with 123 additions and 26 deletions

View File

@@ -69,7 +69,12 @@ func _ready() -> void:
draft = CreationDraft.fresh()
draft.set_race(Races.IDS[0])
draft.set_calling(_allowed_callings()[0])
var allowed := _allowed_callings()
if not allowed.is_empty():
draft.set_calling(allowed[0])
# A degenerate origin (zero allowed callings, or no build_constraints at all)
# leaves calling_id unset rather than crashing — §13, never an error thrown
# at the player. The CTA simply stays disabled; there is no calling to invent.
_bind()
@@ -285,21 +290,3 @@ func _bind_cta() -> void:
var errors := draft.errors(origin, world)
_enter.disabled = not errors.is_empty()
_error.text = str(errors[0]) if not errors.is_empty() else CTA_HINT
# ---------------------------------------------------------------- test seam
func _complete_a_valid_draft_for_test() -> void:
## Drives the draft to a legal state the way a player would. Test-only, and it
## touches nothing the player's own clicks do not.
draft.name = "Aldric"
draft.set_race("human")
draft.set_calling("sellsword")
for skill in draft.skill_pool():
if draft.can_pick(skill):
draft.toggle_skill(skill)
for skill in Skills.IDS:
if draft.can_take_bonus(skill):
draft.set_bonus_skill(skill)
break
_bind()