5.6 KiB
5.6 KiB
feat Generated Families Contract
Status Snapshot
Current state as of 2026-05-13:
- Implemented for the current native
featpipeline. - Native tests cover generated-family expansion, family-owned shared defaults, masterfeat-backed inheritance, and lock/TLK identity preservation.
- The one explicitly deferred item in this contract is still current:
feat.2daremains native-built but excluded fromcompare-topdatareference-catalog coverage throughcompare_reference: false.
Canonical authored paths:
topdata/data/feat/base.jsontopdata/data/feat/lock.jsontopdata/data/feat/generated/skill_focus.jsontopdata/data/feat/generated/greater_skill_focus.jsontopdata/data/feat/generated/weapon_focus.jsontopdata/data/feat/generated/weapon_specialization.jsontopdata/data/feat/generated/greater_weapon_focus.jsontopdata/data/feat/generated/greater_weapon_specialization.jsontopdata/data/feat/generated/improved_critical.jsontopdata/data/feat/generated/overwhelming_critical.jsontopdata/data/feat/modules/activecombat/core.jsontopdata/data/feat/modules/activecombat/specialattacks.jsontopdata/data/feat/modules/class/core.jsontopdata/data/feat/modules/combat/core.jsontopdata/data/feat/modules/defensive/core.jsontopdata/data/feat/modules/magical/core.jsontopdata/data/feat/modules/other/core.jsontopdata/data/feat/modules/proficiency/core.jsontopdata/data/feat/modules/racial/core.jsontopdata/data/feat/modules/removedandhidden/core.jsontopdata/data/feat/modules/skillfeat/affinity.jsontopdata/data/feat/modules/skillfeat/focus.jsontopdata/data/feat/modules/skillfeat/greaterfocus.jsontopdata/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:
{
"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:
{
"family": "weapon_focus",
"family_key": "weaponfocus",
"template": "masterfeats:weaponfocus",
"name_prefix": "Weapon Focus",
"label_prefix": "FEAT_WEAPON_FOCUS",
"constant_prefix": "FEAT_WEAPON_FOCUS",
"legacy_family_keys": ["epic_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
familyis 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, andauto_prereq_fields default_fieldsis a family-wide shared layer; it applies to existing and newly generated child rows before per-child overrides are mergedapply_after_modules: truemakes 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 ofmasterfeatsoverrideslegacy_family_keysdeclares old generated-family prefixes whose existing row IDs should be inherited by the current family; this is how renamed families such asgreater_skill_focusretaining vanillaepic_skill_focusrows preserve hardcoded engine behavior without hardcoding the rename in toolkit logic- family-expansion files must declare
template,family_key, andchild_source.dataset child_source.columnis used when expansion is gated by a non-null source fieldchild_source.predicate: "accessible"currently meansHideFromLevelUp != 1- skill focus families intentionally do not set
allow_existing_only, so any new accessible skill automatically receives matching focus rows - compact
overridesare keyed by source dataset key:skills:*for skill familiesbaseitems:*for weapon families
- generated rows carry
meta.familyso 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.2dapipeline and share inheritance, override, TLK, and family-metadata behavior
Current rollout policy:
feat.2dastill builds nativelyfeat.2dais still excluded fromcompare-topdataoutput-catalog self-check coverage viacompare_reference: false- manual and irregular feat families remain authored directly in modules rather than compact generated-family files