Prerequisite reachability filters

**Scope Audited**
- Module wiki visibility config and docs.
- Toolkit wiki expression engine and visibility tests.
- Feat prerequisite rendering/reference behavior.

**Changes Made**
- Added `hidden_ref(Field, "dataset")` and `all_hidden_refs(..., "dataset")` helpers in [wiki_tables.go](/home/vicky/Projects/nwnee-shadowsoverwestgate/toolkit/internal/topdata/wiki_tables.go:914).
- Added feat visibility exclusions in [visibility.yaml](/home/vicky/Projects/nwnee-shadowsoverwestgate/module/topdata/wiki/visibility.yaml:44) for:
  - `PREREQFEAT1`
  - `PREREQFEAT2`
  - `REQSKILL`
  - `REQSKILL2`
  - `OrReqFeat0..OrReqFeat4`
- Documented the helpers in [README.md](/home/vicky/Projects/nwnee-shadowsoverwestgate/module/topdata/wiki/README.md:53).
- Added coverage in [wiki_native_test.go](/home/vicky/Projects/nwnee-shadowsoverwestgate/toolkit/internal/topdata/wiki_native_test.go:646).

**Configuration/Schema Impact**
- No schema file change. `visibility.yaml` can now use the two new expression helpers.

**Compatibility Impact**
- Existing visibility expressions are unchanged.
- Missing or `****` prerequisite fields are ignored.
- Present references that resolve to hidden or missing wiki rows are treated as unreachable.

**Tests/Validation**
- Confirmed the new test failed before implementation on unknown helper.
- Ran `go test ./internal/topdata -run TestWikiVisibility`.
- Ran `go test ./internal/topdata`.
- Rebuilt toolkit with `./build-tool.sh`.
- Ran module wiki build with local toolkit:
  `SOW_TOOLS_DEV_BINARY=../toolkit/tools/sow-toolkit ./build-wiki.sh`
  Result: `wiki pages: 771`.
This commit is contained in:
2026-05-21 16:04:18 +02:00
parent f57a3c6ff2
commit 23ef63ca7b
2 changed files with 134 additions and 0 deletions
+50
View File
@@ -911,11 +911,61 @@ func (p *wikiExprParser) callHelper(name string, args []any) (any, error) {
}
}
return false, nil
case "hidden_ref":
if len(args) != 2 {
return nil, fmt.Errorf("hidden_ref expects 2 arguments")
}
hidden, err := p.hiddenWikiReference(args[0], stringifyWikiTableValue(args[1]))
if err != nil {
return nil, err
}
return hidden, nil
case "all_hidden_refs":
if len(args) < 2 {
return nil, fmt.Errorf("all_hidden_refs expects at least 2 arguments")
}
targetDataset := stringifyWikiTableValue(args[len(args)-1])
checked := false
for _, value := range args[:len(args)-1] {
if !presentWikiValue(value) {
continue
}
checked = true
hidden, err := p.hiddenWikiReference(value, targetDataset)
if err != nil {
return nil, err
}
if !hidden {
return false, nil
}
}
return checked, nil
default:
return nil, fmt.Errorf("unknown helper %q", name)
}
}
func (p *wikiExprParser) hiddenWikiReference(value any, targetDataset string) (bool, error) {
targetDataset = strings.TrimSpace(targetDataset)
if !isWikiVisibilityDataset(targetDataset) {
return false, fmt.Errorf("unknown reference dataset %q", targetDataset)
}
if !presentWikiValue(value) {
return false, nil
}
if p.ctx == nil {
return false, nil
}
key := resolveReferenceKey(value, p.ctx.wikiIDMapForDataset(targetDataset))
if key == "" {
return true, nil
}
if !strings.HasPrefix(key, targetDataset+":") {
return true, nil
}
return !p.ctx.canReferenceWikiKey(key), nil
}
func presentWikiValue(value any) bool {
if isNullLike(value) {
return false