Skip to content

feat: graph and backlinks parse frontmatter links field#10

Merged
akeemjenkins merged 2 commits into
mainfrom
feat/graph-frontmatter-links
Jul 8, 2026
Merged

feat: graph and backlinks parse frontmatter links field#10
akeemjenkins merged 2 commits into
mainfrom
feat/graph-frontmatter-links

Conversation

@akeemjenkins

Copy link
Copy Markdown
Contributor

Problem

The okf graph and okf backlinks commands only parse markdown body links. The frontmatter links: 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

  • Add Links []string field to concept.Frontmatter struct
  • Add ExtractFrontmatterLinks() in validate package
  • graph.Build() and backlinks.Backlinks() now parse both body and frontmatter links, deduplicated via existing edgeSet

@akeemjenkins

Copy link
Copy Markdown
Contributor Author

Review — reviewed against current main (d641562), test-merged locally

Verified: merges cleanly (including alongside main's graph.go lint fix); go build / go vet / go test ./... pass, and golangci-lint is clean (0 issues) on the merged result.

Nicely factored. ExtractFrontmatterLinks returns the same Link struct, so frontmatter targets flow through the identical resolveLink path as inline links (relative/absolute/.md handling stays consistent for free), and dedup between body and frontmatter links is correct in both graph (edgeSet) and backlinks (seen + break), with tests proving the overlap collapses.

⚠️ Important — a single-string links value crashes the whole bundle load

Links []string (concept.go:25) only accepts a YAML list of strings. Verified empirically:

links: /b             -> cannot unmarshal !!str into []string
links: [/b, /c]       -> ok
links: [{target: /b}] -> cannot unmarshal !!map into string

Because bundle.Load propagates the parse error, one concept writing the very natural links: /b fails the entire bundle, not just that file. Suggest a custom UnmarshalYAML that accepts scalar-or-sequence (or, at minimum, don't let a malformed links take down the whole load, and document the expected shape).

⚠️ Important — the validator ignores frontmatter links

validateLinks still only scans c.Body, so a frontmatter link pointing at a nonexistent concept is silently dropped by the graph and never reported by okf validate. This PR is what creates the divergence (graph/backlinks now consume frontmatter links; validate doesn't), so it's the right place to also iterate ExtractFrontmatterLinks(c.Frontmatter.Links) in validation.

Nits

  • Self-links: a concept listing itself yields an a -> a graph self-edge (backlinks guards this via c.ID == conceptID; graph does not).
  • append(bodyLinks, fmLinks...) aliases the returned slice — harmless today, but worth copying to avoid a future footgun.
  • Coverage gaps: duplicate frontmatter links, an FM link to a nonexistent concept, self-links, and the malformed-shape cases above.

Recommendation: approve after making links parsing robust (at least not fataling the whole bundle). The validator-consistency fix is strongly encouraged in this same PR since it's the source of the inconsistency.

🤖 Automated review via Claude Code, verified locally against current main.

- 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>
@akeemjenkins akeemjenkins merged commit 807064a into main Jul 8, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant