Context
C7 (#23) shipped the soft-warning engine. Its adversarial review confirmed all five
acceptance criteria and approved at confidence 90, but recorded four real defects in the
warning rules themselves. They are adjacent to the ACs rather than inside them, so they
did not block the merge — but each produces a false warning shown to a player, which
is exactly what a soft-warning engine must not do.
-
app/lib/tlc/warnings.rb:69 — BASE_TRAIT_ALLOWANCE = 3 is hardcoded, while
app/platforms/tlc/homebrews/species.rb:34 already stores optional_pool_size
(default 3, author-settable 0..10 via .../species/perform_command.rb:59). A species
authored with a pool of 5 gets a false trait_count warning at 4 selections. The
reviewer verified both files.
-
app/lib/tlc/warnings.rb:117 — the trait allowance omits "+1 per Ancestral Exemplar
take" (docs/players-guide-digest.md:239, the feat at :122). A legal Exemplar
build warns permanently. QA flagged this in an earlier pass too. Note the ticket body
itself said "3, or 4 with Mixed Ancestry", so this is ticket-vs-digest, not
diff-vs-ticket — the rule as specced was incomplete.
-
app/lib/tlc/warnings.rb:197 — abilities reads modified_abilities, which
app/decorators_v2/dnd2024_decorator.rb:81-89 overwrites with beastform scores. A
druid's multiclass_prereq warning appears and disappears with Wild Shape.
-
app/lib/tlc/warnings.rb:41-55 — 10 of 13 MULTICLASS_PREREQS rows survive
mutation. Flipping monk/ranger AND→OR leaves the suite green. The values are
correct against PHB 2024 (verified twice independently) — this is a coverage hole,
not a wrong constant, and it is precisely where a future wrong constant would hide.
Files
app/lib/tlc/warnings.rb
app/platforms/tlc/homebrews/species.rb
spec/lib/tlc/warnings_spec.rb
docs/user-guide/warnings.md
Plan
- Trait allowance from data, not a constant. Read
optional_pool_size off the
character's species where one is set; fall back to BASE_TRAIT_ALLOWANCE when absent.
Keep the Mixed Ancestry +1 that already works.
- Ancestral Exemplar. Add +1 per take. Check the digest for whether "free traits
excluded from count" is a separate rule that also needs encoding — QA raised that
phrasing and it was never resolved.
- Beastform. Read raw abilities rather than
modified_abilities for the multiclass
check, or explicitly skip the check while a beastform is active. Decide which is
correct for the campaign and say why in a comment.
- Pin the prereq table. One table-driven example over all 13 rows closes the hole.
Acceptance Criteria
- Setup: a species authored with
optional_pool_size: 5 → Action: a character of that
species selects 4 traits → Expected: NO trait_count warning. At 6 selections, the
warning fires.
- Setup: a character with Ancestral Exemplar taken twice → Action: select
base allowance + 2 traits → Expected: no warning. One more → warning.
- Setup: a druid whose raw abilities meet a multiclass prerequisite, currently in a
beastform whose scores do not → Action: serialize → Expected: no
multiclass_prereq warning; and the warning does not change when the beastform ends.
- Setup: final diff → Action: flip the AND/OR on any single
MULTICLASS_PREREQS row →
Expected: the suite goes red and names that class. All 13 rows.
Tests + evals
- A spec per acceptance case in
spec/lib/tlc/warnings_spec.rb.
- The prereq pin must be table-driven over all 13 rows, and each row demonstrated red
under its own mutation.
- No eval suite: no LLM surface.
Docs pages touched
docs/user-guide/warnings.md — the trait-count rule as actually implemented.
Out of scope
- The registry, dismissal machinery and serializer shape, all verified working.
Depends on #23
Context
C7 (#23) shipped the soft-warning engine. Its adversarial review confirmed all five
acceptance criteria and approved at confidence 90, but recorded four real defects in the
warning rules themselves. They are adjacent to the ACs rather than inside them, so they
did not block the merge — but each produces a false warning shown to a player, which
is exactly what a soft-warning engine must not do.
app/lib/tlc/warnings.rb:69—BASE_TRAIT_ALLOWANCE = 3is hardcoded, whileapp/platforms/tlc/homebrews/species.rb:34already storesoptional_pool_size(default 3, author-settable 0..10 via
.../species/perform_command.rb:59). A speciesauthored with a pool of 5 gets a false
trait_countwarning at 4 selections. Thereviewer verified both files.
app/lib/tlc/warnings.rb:117— the trait allowance omits "+1 per Ancestral Exemplartake" (
docs/players-guide-digest.md:239, the feat at:122). A legal Exemplarbuild warns permanently. QA flagged this in an earlier pass too. Note the ticket body
itself said "3, or 4 with Mixed Ancestry", so this is ticket-vs-digest, not
diff-vs-ticket — the rule as specced was incomplete.
app/lib/tlc/warnings.rb:197—abilitiesreadsmodified_abilities, whichapp/decorators_v2/dnd2024_decorator.rb:81-89overwrites with beastform scores. Adruid's
multiclass_prereqwarning appears and disappears with Wild Shape.app/lib/tlc/warnings.rb:41-55— 10 of 13MULTICLASS_PREREQSrows survivemutation. Flipping monk/ranger AND→OR leaves the suite green. The values are
correct against PHB 2024 (verified twice independently) — this is a coverage hole,
not a wrong constant, and it is precisely where a future wrong constant would hide.
Files
app/lib/tlc/warnings.rbapp/platforms/tlc/homebrews/species.rbspec/lib/tlc/warnings_spec.rbdocs/user-guide/warnings.mdPlan
optional_pool_sizeoff thecharacter's species where one is set; fall back to
BASE_TRAIT_ALLOWANCEwhen absent.Keep the Mixed Ancestry +1 that already works.
excluded from count" is a separate rule that also needs encoding — QA raised that
phrasing and it was never resolved.
modified_abilitiesfor the multiclasscheck, or explicitly skip the check while a beastform is active. Decide which is
correct for the campaign and say why in a comment.
Acceptance Criteria
optional_pool_size: 5→ Action: a character of thatspecies selects 4 traits → Expected: NO
trait_countwarning. At 6 selections, thewarning fires.
base allowance + 2traits → Expected: no warning. One more → warning.beastform whose scores do not → Action: serialize → Expected: no
multiclass_prereqwarning; and the warning does not change when the beastform ends.MULTICLASS_PREREQSrow →Expected: the suite goes red and names that class. All 13 rows.
Tests + evals
spec/lib/tlc/warnings_spec.rb.under its own mutation.
Docs pages touched
docs/user-guide/warnings.md— the trait-count rule as actually implemented.Out of scope
Depends on #23