feat(pipeline): per-wing sources, shared concepts/entities, one slug one page (#208)

With Config.Wing a source goes to wiki/<wing>/sources/ (wing/hall frontmatter);
concepts and entities stay in the shared wiki/concepts and wiki/entities, so an
entity cited from two wings is ONE page with both sources (the per-wing facts/
layout duplicated it). A source slug already used anywhere but its own wing's
sources/ is refused (slug is the graph identity). wiki.FindSlug added.
Mutation-checked: collision guard, shared inventory, per-wing source path.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 20:08:30 +02:00
co-authored by Claude Sonnet 5.5
parent 8342de5c49
commit ce5a5268e7
6 changed files with 205 additions and 137 deletions
+7
View File
@@ -52,6 +52,13 @@ func Run(ctx context.Context, cfg Config, brainDir, content, source string, dryR
var inventory map[wiki.PageType][]wiki.Entry
var err error
if cfg.Wing != "" {
// A source slug is a page's graph identity: refuse to take over a slug
// that lives anywhere but this wing's own sources/.
if existing, found, ferr := wiki.FindSlug(brainDir, wiki.Slug(source)); ferr != nil {
return Result{}, fmt.Errorf("check source slug: %w", ferr)
} else if own := "wiki/" + cfg.Wing + "/sources/" + wiki.Slug(source) + ".md"; found && existing != own {
return Result{}, fmt.Errorf("source slug %q is already used by %s", wiki.Slug(source), existing)
}
inventory, err = wiki.LoadWingInventory(brainDir, cfg.Wing)
} else {
inventory, err = wiki.LoadInventory(brainDir)