- concept: add StringList type with a custom UnmarshalYAML so `links`
accepts both a scalar string (`links: /b`) and a sequence, and tolerates
a malformed shape (e.g. a mapping) as empty instead of failing the whole
bundle load. Missing/empty stays a nil slice.
- validate: validateLinks now also checks frontmatter links via
ExtractFrontmatterLinks, so a frontmatter link to a nonexistent concept is
reported instead of silently dropped.
- graph: skip self-edges (target == concept ID); combine body and
frontmatter links into a fresh slice to avoid append aliasing.
- tests: scalar/sequence/missing/malformed links parsing, deduped and
self-link graph cases, and frontmatter broken-link validation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem
The
okf graphandokf backlinkscommands only parse markdown body links. The frontmatterlinks:field (a YAML list of concept IDs) is completely ignored. An LLM authoring concepts naturally puts links in frontmatter, but the graph shows 0 edges.Fix
Links []stringfield toconcept.FrontmatterstructExtractFrontmatterLinks()in validate packagegraph.Build()andbacklinks.Backlinks()now parse both body and frontmatter links, deduplicated via existing edgeSet