Native topdata migration summary - Replaced the legacy 2dabuilder runtime path with the native topdata builder. - Native build, validate, compare, and convert flows now cover the canonical topdata pipeline. - compare-topdata is now a native self-check; legacy reference-builder runtime usage was removed. - Parts generation follows the native asset-scan contract and uses sow-assets via project asset resolution. - Generated feat families, class-feat injects, masterfeat/successor expansion, and dataset-derived feat generation were brought to parity and regression-covered. - Remaining mirrored datasets were migrated into native-owned canonical data while preserving lock IDs. - normalize-topdata bridge behavior and migration-era ownership markers were removed. - Documentation was rewritten around the native workflow and active contracts were cleaned up. - Final hardening pass removed stale validator assumptions and cleaned ignored/generated artifacts for PR readiness. Reviewed-on: https://gitea.westgate.pw/ShadowsOverWestgate/sow-tools/pulls/2 Co-authored-by: vickydotbat <vickydotbat@tutamail.com> Co-committed-by: vickydotbat <vickydotbat@tutamail.com>
3.0 KiB
3.0 KiB
Global Feat Injection — Specification
Objective
Ensure the native class feat generation pipeline produces functionally identical output to the legacy system by applying deterministic global feat injections.
Requirements
R1 — Skill-based master feats
For every class skill, inject:
masterfeats:skillfocusmasterfeats:greaterskillfocus
With properties:
{
"GrantedOnLevel": "-1",
"List": "1",
"OnMenu": "0"
}
---
### R2 — Spellcasting master feats
If class core defines:
- `"SpellCaster" = 1`
Then inject:
- `masterfeats:spellfocus`
- `masterfeats:greaterspellfocus`
With properties:
```json
{
"GrantedOnLevel": "-1",
"List": "1",
"OnMenu": "0"
}
R3 — Literacy rule
Inject:
feat:literate
Only if:
feat:illiterateis NOT present
With properties:
{
"GrantedOnLevel": "1",
"List": "3",
"OnMenu": "0"
}
R4 — Default combat/menu feats
Always inject:
feat:offensivefightingfeat:defensivefightingfeat:horsemenu
With properties:
{
"GrantedOnLevel": "1",
"List": "3",
"OnMenu": "1"
}
R5 — Conditional combat feats
Inject:
feat:powerattackfeat:combatexpertise
With properties:
{
"GrantedOnLevel": "-1",
"List": "0",
"OnMenu": "1"
}
R6 — Override precedence
- Overrides MUST be applied after injection.
- Overrides MUST take precedence over injected defaults.
- Injection MUST NOT block or replace explicit override data.
Behavioral Rules
B1 — Output equivalence
- The resulting feat set MUST match legacy output in substance.
- Exact row ordering and numeric IDs are NOT significant.
B2 — Deterministic inclusion
- All injections MUST occur consistently for identical inputs.
- No randomness or order-dependent behavior is allowed.
B3 — Conditional correctness
feat:literateMUST NOT be injected iffeat:illiterateexists.- Spell focus feats MUST ONLY be injected when
"SpellCaster" = 1.
B4 — Integration with pipeline
- Injected feats MUST flow through the same processing stages as authored feats.
- They MUST be subject to:
- overrides
- deduplication
- final emission rules
Acceptance Criteria
An implementation is considered correct if:
-
Parity
- For any given class input, native output produces the same effective feats as legacy.
-
Injection coverage
- All required feats (R1–R5) appear when conditions are met.
-
Exclusion correctness
- No invalid injections occur (e.g., literacy conflict).
-
Override dominance
- Any override affecting injected feats is correctly applied.
-
Stability
- Repeated runs with identical input produce identical output.
Non-Negotiables
- This is parity-critical, not a best-effort feature.
- Native pipeline MUST be capable of fully replacing legacy output.
- There MUST be zero dependency on legacy systems at runtime.
- Any deviation from legacy-equivalent output is a defect.