Available Feats Support

This commit is contained in:
2026-05-22 01:29:07 +02:00
parent afd40f0682
commit e6fdcdec87
4 changed files with 333 additions and 11 deletions
@@ -0,0 +1,200 @@
# Class Progression Feat Projections Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Make class progression feat grouping configurable from wiki YAML so the module template can render granted feats and level-gated available feats separately.
**Architecture:** Extend the `class_progression` data provider config with named class-feat projection fields. The toolkit evaluates each configured projection against class feat rows and groups resolved feat links onto progression rows by level, while the module wiki config declares the project-specific `List` rules and the class template owns output wording.
**Tech Stack:** Go `sow-toolkit`, native topdata wiki YAML, HTML wiki templates, Go tests.
---
## File Map
- `internal/topdata/wiki_data_providers.go`: parse and validate data-provider projection configuration and pass it into class progression row assembly.
- `internal/topdata/wiki_tables.go`: share class progression row assembly with configured class feat projections and keep default compatibility behavior.
- `internal/topdata/wiki_native_test.go`: regression coverage for provider projection parsing, filtering, grouping, ordering, invalid config, and rendered template fields.
- `../module/topdata/wiki/data.yaml`: declare module-owned `GrantedFeats` and `AvailableFeats` projections for class progression.
- `../module/topdata/wiki/templates/pages/classes.html`: render bonus feats inline and use projected available feats in the Notes cell.
- `../module/topdata/wiki/README.md`: document configurable data-provider projections for template authors.
### Task 1: Add Configured Class Feat Projection Tests
**Files:**
- Modify: `internal/topdata/wiki_native_test.go`
- [ ] **Step 1: Write failing provider projection tests**
Add tests that build `wikiDataProviderDefinition` from YAML such as:
```yaml
providers:
ClassProgression:
source: class_progression
levels: 1-4
class_feats:
fields:
GrantedFeats:
when: "{{GrantedOnLevel > 0 && List == 3}}"
AvailableFeats:
when: "{{GrantedOnLevel > 0 && List != 3}}"
```
Assert the parsed provider can render a progression row where `GrantedFeats`
contains `List == 3` feat links, `AvailableFeats` contains positive-level
non-`3` feat links, matched link order follows fixture source row order, and
`BonusFeat` is still present.
- [ ] **Step 2: Add failing invalid configuration coverage**
Add a test that loads a provider field with an empty projection name or empty
`when` expression and expects an error containing `data.yaml`, the provider
name, and the projection field context.
- [ ] **Step 3: Run focused tests to verify RED**
Run:
```bash
go test ./internal/topdata -run 'TestWiki.*ClassProgression.*Projection|TestWikiData.*Provider.*Projection' -count=1
```
Expected: FAIL because `wikiDataProviderDefinition` does not yet accept
`class_feats.fields` and progression rows do not expose `AvailableFeats`.
### Task 2: Implement Generic Provider Projections
**Files:**
- Modify: `internal/topdata/wiki_data_providers.go`
- Modify: `internal/topdata/wiki_tables.go`
- Test: `internal/topdata/wiki_native_test.go`
- [ ] **Step 1: Extend provider config types and validation**
Add typed YAML support for:
```go
type wikiDataProviderClassFeatConfig struct {
Fields map[string]wikiDataProviderProjectionField `json:"fields" yaml:"fields"`
}
type wikiDataProviderProjectionField struct {
When string `json:"when" yaml:"when"`
}
```
Validate each configured projection field name and `when` expression before
provider execution.
- [ ] **Step 2: Carry projections into progression row assembly**
Change the provider path so `ClassProgression` passes provider-owned class feat
projection fields into progression row assembly. Preserve table-based
`class_progression` callers by giving them the current default `GrantedFeats`
behavior.
- [ ] **Step 3: Evaluate and group projections**
In progression row assembly, resolve class feat links once per matching row,
evaluate configured `when` expressions against class feat rows, and append
matched links to the configured progression field for each positive
`GrantedOnLevel` value in source row order.
- [ ] **Step 4: Run focused tests to verify GREEN**
Run:
```bash
go test ./internal/topdata -run 'TestWiki.*ClassProgression.*Projection|TestWikiData.*Provider.*Projection' -count=1
```
Expected: PASS.
### Task 3: Configure Module Wiki Output
**Files:**
- Modify: `../module/topdata/wiki/data.yaml`
- Modify: `../module/topdata/wiki/templates/pages/classes.html`
- Modify: `../module/topdata/wiki/README.md`
- [ ] **Step 1: Declare module projections**
Update `ClassProgression` in `../module/topdata/wiki/data.yaml` so module YAML
owns `GrantedFeats` and `AvailableFeats` selection:
```yaml
ClassProgression:
source: class_progression
levels: 1-12
class_feats:
fields:
GrantedFeats:
when: "{{GrantedOnLevel > 0 && List == 3}}"
AvailableFeats:
when: "{{GrantedOnLevel > 0 && List != 3}}"
```
- [ ] **Step 2: Render projected fields in the class template**
Keep bonus feats in the Feats cell with a conditional comma. Render
`AvailableFeats` in the Notes cell with module-owned “becomes available”
wording using supported template loop/filter syntax.
- [ ] **Step 3: Document the projection surface**
Add a concise `data.yaml` note to the wiki README explaining that data-provider
projection fields can expose configured per-level class feat lists to page
templates and that wording stays in templates.
### Task 4: Verify The Cross-Repo Wiki Path
**Files:**
- Verify: `internal/topdata/...`
- Verify: `../module/topdata/wiki/...`
- [ ] **Step 1: Run toolkit regression tests**
Run:
```bash
go test ./internal/topdata -count=1
```
Expected: PASS.
- [ ] **Step 2: Build the local toolkit**
Run:
```bash
./build-tool.sh
```
Expected: exit `0` and refresh `tools/sow-toolkit` when source changes require
it.
- [ ] **Step 3: Build module wiki with the local toolkit**
Run from `../module`:
```bash
SOW_TOOLS_DEV_BINARY=../toolkit/tools/sow-toolkit ./build-wiki.sh --force
```
Expected: exit `0` and regenerate class wiki pages under `.cache/wiki/pages/`.
- [ ] **Step 4: Inspect fighter output**
Check generated fighter progression output for inline bonus feat text in Feats
cells and `becomes available` notes for level-gated selectable feat links.
- [ ] **Step 5: Run diff checks**
Run:
```bash
git diff --check
```
in both toolkit and module repos.