208 lines
4.2 KiB
Markdown
208 lines
4.2 KiB
Markdown
# Global Feat Injection — Specification
|
||
|
||
## Status Snapshot
|
||
|
||
Current state as of 2026-05-13:
|
||
|
||
- This document is partially stale relative to the implementation in
|
||
`internal/topdata/native.go`.
|
||
- Current code injects:
|
||
- always-on menu feats: `feat:specialattacks`, `feat:throw`,
|
||
`feat:grapple`, `feat:offensivefighting`, `feat:defensivefighting`,
|
||
`feat:horsemenu`
|
||
- conditional combat feats: `feat:powerattack`, `feat:combatexpertise`
|
||
- class-skill shorthand rows for `masterfeats:skillfocus` at level `-1` and
|
||
`masterfeats:greaterskillfocus` at level `12`
|
||
- This contract should be treated as a parity note, not as an exact
|
||
implementation transcript, until it is fully rewritten around the current
|
||
behavior.
|
||
|
||
## 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:skillfocus`
|
||
- `masterfeats:greaterskillfocus`
|
||
|
||
With properties:
|
||
|
||
````json
|
||
{
|
||
"GrantedOnLevel": "-1",
|
||
"List": "1",
|
||
"OnMenu": "0"
|
||
}
|
||
|
||
For the current implementation, `masterfeats:greaterskillfocus` is injected with
|
||
`GrantedOnLevel = 12`, not `-1`.
|
||
|
||
---
|
||
|
||
### R2 — Spellcasting master feats
|
||
|
||
If class core defines:
|
||
|
||
- `"SpellCaster" = 1`
|
||
|
||
Then inject:
|
||
|
||
- `masterfeats:spellfocus`
|
||
- `masterfeats:greaterspellfocus`
|
||
|
||
Historical note:
|
||
|
||
- This rule is not currently implemented as an automatic global injection in
|
||
`native.go`.
|
||
- Spell-focus expansion is supported when the class feat data explicitly
|
||
references `masterfeats:spellfocus`.
|
||
|
||
If automatic spellcaster-driven injection is still required, it remains
|
||
outstanding work.
|
||
|
||
With properties:
|
||
|
||
```json
|
||
{
|
||
"GrantedOnLevel": "-1",
|
||
"List": "1",
|
||
"OnMenu": "0"
|
||
}
|
||
````
|
||
|
||
---
|
||
|
||
### R3 — Literacy rule
|
||
|
||
Inject:
|
||
|
||
- `feat:literate`
|
||
|
||
**Only if**:
|
||
|
||
- `feat:illiterate` is NOT present
|
||
|
||
With properties:
|
||
|
||
```json
|
||
{
|
||
"GrantedOnLevel": "1",
|
||
"List": "3",
|
||
"OnMenu": "0"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### R4 — Default combat/menu feats
|
||
|
||
Always inject:
|
||
|
||
- `feat:specialattacks`
|
||
- `feat:throw`
|
||
- `feat:grapple`
|
||
- `feat:offensivefighting`
|
||
- `feat:defensivefighting`
|
||
- `feat:horsemenu`
|
||
|
||
With properties:
|
||
|
||
```json
|
||
{
|
||
"GrantedOnLevel": "1",
|
||
"List": "3",
|
||
"OnMenu": "1"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### R5 — Conditional combat feats
|
||
|
||
Inject:
|
||
|
||
- `feat:powerattack`
|
||
- `feat:combatexpertise`
|
||
|
||
With properties:
|
||
|
||
```json
|
||
{
|
||
"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:literate` MUST NOT be injected if `feat:illiterate` exists.
|
||
- 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:
|
||
|
||
1. **Parity**
|
||
- For any given class input, native output produces the same effective feats as legacy.
|
||
|
||
2. **Injection coverage**
|
||
- All required feats (R1–R5) appear when conditions are met.
|
||
|
||
3. **Exclusion correctness**
|
||
- No invalid injections occur (e.g., literacy conflict).
|
||
|
||
4. **Override dominance**
|
||
- Any override affecting injected feats is correctly applied.
|
||
|
||
5. **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**.
|