Chained feat prereq wiki visibility fix

This commit is contained in:
2026-05-21 16:09:13 +02:00
parent 23ef63ca7b
commit d0e5e42090
2 changed files with 81 additions and 12 deletions
+55
View File
@@ -727,6 +727,61 @@ datasets:
} }
} }
func TestWikiVisibilityIndexUsesBuiltVisibilityForReferenceHelpers(t *testing.T) {
policy, err := parseWikiVisibilityDefinitions([]byte(`
datasets:
feat:
include:
- when: "{{true}}"
exclude:
- when: "{{hidden_ref(PREREQFEAT1, \"feat\")}}"
`), "visibility.yaml")
if err != nil {
t.Fatalf("parse visibility policy: %v", err)
}
ctx := &wikiContext{
visibilityPolicy: &policy,
featRows: map[string]map[string]any{
"feat:zbase": {
"FEAT": "Base Feat",
"DESCRIPTION": "Description",
},
"feat:dependent": {
"FEAT": "Dependent Feat",
"DESCRIPTION": "Description",
"PREREQFEAT1": 1,
},
"feat:chain_dependent": {
"FEAT": "Chain Dependent Feat",
"DESCRIPTION": "Description",
"PREREQFEAT1": 2,
},
"feat:missing_prereq": {
"FEAT": "Missing Prereq Feat",
"DESCRIPTION": "Description",
"PREREQFEAT1": 999,
},
},
featIDToKey: map[int]string{1: "feat:zbase", 2: "feat:dependent"},
}
visible, err := ctx.buildWikiVisibilityIndex(&policy)
if err != nil {
t.Fatalf("build visibility index: %v", err)
}
if !visible["feat:zbase"] {
t.Fatalf("expected base feat to be visible")
}
if !visible["feat:dependent"] {
t.Fatalf("expected feat with visible prerequisite to remain visible")
}
if !visible["feat:chain_dependent"] {
t.Fatalf("expected feat with transitive visible prerequisite to remain visible")
}
if visible["feat:missing_prereq"] {
t.Fatalf("expected feat with missing prerequisite to be hidden")
}
}
func TestWikiVisibilityMetadataOverrideCannotBypassEligibility(t *testing.T) { func TestWikiVisibilityMetadataOverrideCannotBypassEligibility(t *testing.T) {
policy, err := parseWikiVisibilityDefinitions([]byte(` policy, err := parseWikiVisibilityDefinitions([]byte(`
datasets: datasets:
+26 -12
View File
@@ -187,21 +187,35 @@ func (ctx *wikiContext) buildWikiVisibilityIndex(policy *wikiVisibilityDefinitio
} }
} }
referenceSets := ctx.collectWikiVisibilityReferenceSets(policy, visible) referenceSets := ctx.collectWikiVisibilityReferenceSets(policy, visible)
for _, dataset := range []string{"classes", "racialtypes", "skills", "spells", "baseitems", "feat"} { previousVisible := ctx.visibleWikiKeys
definition, ok := policy.Datasets[dataset] ctx.visibleWikiKeys = visible
if !ok { defer func() {
continue ctx.visibleWikiKeys = previousVisible
} }()
rows := ctx.wikiRowsForDataset(dataset) for pass := 0; pass <= len(visible); pass++ {
for _, key := range sortedKeys(rows) { changed := false
include, err := ctx.evaluateWikiVisibility(dataset, key, rows[key], definition, referenceSets) for _, dataset := range []string{"classes", "racialtypes", "skills", "spells", "baseitems", "feat"} {
if err != nil { definition, ok := policy.Datasets[dataset]
return nil, err if !ok {
continue
} }
visible[key] = include rows := ctx.wikiRowsForDataset(dataset)
for _, key := range sortedKeys(rows) {
include, err := ctx.evaluateWikiVisibility(dataset, key, rows[key], definition, referenceSets)
if err != nil {
return nil, err
}
if visible[key] != include {
changed = true
}
visible[key] = include
}
}
if !changed {
return visible, nil
} }
} }
return visible, nil return nil, fmt.Errorf("wiki visibility index did not converge")
} }
func (ctx *wikiContext) evaluateWikiVisibilityWithoutSets(dataset, key string, row map[string]any, definition wikiVisibilityDataset) (bool, error) { func (ctx *wikiContext) evaluateWikiVisibilityWithoutSets(dataset, key string, row map[string]any, definition wikiVisibilityDataset) (bool, error) {