# `feat` Generated Families Contract Canonical authored paths: - `topdata/data/feat/base.json` - `topdata/data/feat/lock.json` - `topdata/data/feat/generated/skill_focus.json` - `topdata/data/feat/generated/greater_skill_focus.json` - `topdata/data/feat/generated/weapon_focus.json` - `topdata/data/feat/generated/weapon_specialization.json` - `topdata/data/feat/generated/greater_weapon_focus.json` - `topdata/data/feat/generated/greater_weapon_specialization.json` - `topdata/data/feat/generated/improved_critical.json` - `topdata/data/feat/generated/overwhelming_critical.json` - `topdata/data/feat/modules/activecombat/core.json` - `topdata/data/feat/modules/activecombat/specialattacks.json` - `topdata/data/feat/modules/class/core.json` - `topdata/data/feat/modules/combat/core.json` - `topdata/data/feat/modules/defensive/core.json` - `topdata/data/feat/modules/magical/core.json` - `topdata/data/feat/modules/other/core.json` - `topdata/data/feat/modules/proficiency/core.json` - `topdata/data/feat/modules/racial/core.json` - `topdata/data/feat/modules/removedandhidden/core.json` - `topdata/data/feat/modules/skillfeat/affinity.json` - `topdata/data/feat/modules/skillfeat/focus.json` - `topdata/data/feat/modules/skillfeat/greaterfocus.json` - `topdata/data/feat/modules/skillfeat/other.json` `skill_affinity` is no longer authored as a generated feat file. It is synthesized from canonical `racialtypes` race grants. Compact family-expansion shape: ```json { "family": "skill_focus", "family_key": "skillfocus", "template": "masterfeats:skillfocus", "name_prefix": "Skill Focus", "label_prefix": "FEAT_SKILL_FOCUS", "constant_prefix": "FEAT_SKILL_FOCUS", "default_fields": { "DESCRIPTION": { "tlk": { "key": "masterfeats:skillfocus.description", "text": "..." } }, "CRValue": "0.5", "ReqSkillMinRanks": "1", "TOOLSCATEGORIES": "6" }, "apply_after_modules": true, "child_ref_field": "REQSKILL", "child_source": { "dataset": "skills", "predicate": "accessible" }, "overrides": { "skills:craft_alchemy": { "ICON": "ife_foc_alchm" } } } ``` Weapon family shape: ```json { "family": "weapon_focus", "family_key": "weaponfocus", "template": "masterfeats:weaponfocus", "name_prefix": "Weapon Focus", "label_prefix": "FEAT_WEAPON_FOCUS", "constant_prefix": "FEAT_WEAPON_FOCUS", "default_fields": { "DESCRIPTION": { "tlk": { "key": "masterfeats:weaponfocus.description", "text": "..." } }, "MINATTACKBONUS": "1", "TOOLSCATEGORIES": "1" }, "apply_after_modules": true, "identity_source": "child_source_value", "child_source": { "dataset": "baseitems", "column": "WeaponFocusFeat" }, "overrides": { "baseitems:heavymace": { "ICON": "ife_wepfoc_Lma" } } } ``` Rules: - any generated feat file with family-expansion fields is treated as an authored family-expansion definition - `family` is descriptive only; the builder does not hardcode family names - family behavior is driven by authored fields such as `template_fields`, `default_fields`, `apply_after_modules`, `identity_source`, `child_ref_field`, and `auto_prereq_fields` - `default_fields` is a family-wide shared layer; it applies to existing and newly generated child rows before per-child overrides are merged - `apply_after_modules: true` makes the generated family the final authoritative shared layer for legacy explicitly authored child rows, so shared baselines can live in the generated family file instead of `masterfeats` overrides - family-expansion files must declare `template`, `family_key`, and `child_source.dataset` - `child_source.column` is used when expansion is gated by a non-null source field - `child_source.predicate: "accessible"` currently means `HideFromLevelUp != 1` - skill focus families intentionally do not set `allow_existing_only`, so any new accessible skill automatically receives matching focus rows - compact `overrides` are keyed by source dataset key: - `skills:*` for skill families - `baseitems:*` for weapon families - generated rows carry `meta.family` so the underscore family rule is preserved even before wiki generation exists - emitted feat keys must prefer existing canonical lock/TLK identities over newly derived child spellings - manual and irregular feat content continues to live under `feat/modules/` - generated families and module-authored feats are merged into the same final `feat.2da` pipeline and share inheritance, override, TLK, and family-metadata behavior Current rollout policy: - `feat.2da` still builds natively - `feat.2da` is still excluded from `compare-topdata` output-catalog self-check coverage via `compare_reference: false` - manual and irregular feat families remain authored directly in modules rather than compact generated-family files