6.6 KiB
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-ownedGrantedFeatsandAvailableFeatsprojections 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:
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:
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:
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:
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:
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:
go test ./internal/topdata -count=1
Expected: PASS.
- Step 2: Build the local toolkit
Run:
./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:
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:
git diff --check
in both toolkit and module repos.