Every brain write accepted [[targets]] that resolve to nothing — skill names, repo names, agent-local memory-file slugs — and each one became a permanent [high] broken-link finding. The brain-audit digest grew 19 -> 63 high findings between 2026-08-26 and 2026-09-16; 53 of the 63 were exactly this, and none are fixable by brain-gardener's BrokenLinkFixer, which only repoints edit-distance-1 renames. There is no target to repoint to. StripUnresolvedLinks resolves each link against knowledge/ + wiki/ using brain-gardener's own resolver semantics (bare slug or wing/hall/slug path form, code spans excluded) and unwraps the misses to plain text, reporting them as Ref.Unlinked / the MCP `unlinked` field. Unwrap rather than reject: a refused write on claudewatcher's unattended ingest path is a lost learning, and the author's words are worth keeping even when the link is not. An empty corpus is a no-op, so a misconfigured brainDir cannot strip every link in a note. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
128 lines
4.1 KiB
Go
128 lines
4.1 KiB
Go
package brainstore_test
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/mathiasbq/hyperguild/ingestion/internal/brainstore"
|
|
"github.com/mathiasbq/hyperguild/ingestion/internal/capture"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestStoreWriteReturnsHandle(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := brainstore.New(dir)
|
|
|
|
ref, err := s.Write(context.Background(), capture.Note{
|
|
Content: "# X\n\nbody\n", Filename: "x", Wing: "a", Hall: "facts",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "wiki/a/facts/x.md", ref.Path)
|
|
assert.Equal(t, ref.Path, ref.ID)
|
|
assert.NotEmpty(t, ref.ContentHash)
|
|
assert.False(t, ref.Superseded)
|
|
|
|
_, err = os.Stat(filepath.Join(dir, "wiki/a/facts/x.md"))
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestStoreUpdateSupersedes(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := brainstore.New(dir)
|
|
_, err := s.Write(context.Background(), capture.Note{
|
|
Content: "old\n", Filename: "n", Wing: "a", Hall: "facts",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
ref, err := s.Update(context.Background(), "n", capture.Note{
|
|
Content: "new\n", Wing: "a", Hall: "facts", Reason: "changed",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.True(t, ref.Superseded)
|
|
assert.Equal(t, "wiki/a/facts/n.md", ref.Path)
|
|
|
|
got, _ := os.ReadFile(filepath.Join(dir, "wiki/a/facts/n.md"))
|
|
assert.Contains(t, string(got), "new")
|
|
assert.Contains(t, string(got), "supersede_reason: changed")
|
|
}
|
|
|
|
func TestStoreUpdateByFullPath(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := brainstore.New(dir)
|
|
_, err := s.Write(context.Background(), capture.Note{Content: "old\n", Filename: "n", Wing: "a", Hall: "facts"})
|
|
require.NoError(t, err)
|
|
|
|
ref, err := s.Update(context.Background(), "wiki/a/facts/n.md", capture.Note{Content: "fresh\n"})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "wiki/a/facts/n.md", ref.Path)
|
|
}
|
|
|
|
func TestStoreUpdateMissingErrors(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := brainstore.New(dir)
|
|
_, err := s.Update(context.Background(), "ghost", capture.Note{Content: "x\n", Wing: "a", Hall: "facts"})
|
|
require.Error(t, err)
|
|
_, statErr := os.Stat(filepath.Join(dir, "wiki/a/facts/ghost.md"))
|
|
assert.True(t, os.IsNotExist(statErr), "update must not create")
|
|
}
|
|
|
|
func TestStoreGetRoundTripsHash(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := brainstore.New(dir)
|
|
ref, err := s.Write(context.Background(), capture.Note{
|
|
Content: "# Body\n\ntext\n", Filename: "n", Wing: "a", Hall: "facts",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
note, err := s.Get(context.Background(), ref.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, ref.ContentHash, note.ContentHash, "write→get hash round-trips")
|
|
assert.Equal(t, "a", note.Frontmatter["wing"])
|
|
assert.Contains(t, note.Body, "# Body")
|
|
}
|
|
|
|
func TestStoreWriteUnwrapsUnresolvedWikilinks(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := brainstore.New(dir)
|
|
_, err := s.Write(context.Background(), capture.Note{
|
|
Content: "# Target\n\nbody\n", Filename: "target", Wing: "a", Hall: "facts",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
ref, err := s.Write(context.Background(), capture.Note{
|
|
Content: "See [[target]] and [[secret-hygiene]].\n",
|
|
Filename: "src", Wing: "a", Hall: "facts",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []string{"secret-hygiene"}, ref.Unlinked)
|
|
|
|
got, err := os.ReadFile(filepath.Join(dir, "wiki/a/facts/src.md"))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, string(got), "[[target]]")
|
|
assert.Contains(t, string(got), "and secret-hygiene.")
|
|
assert.NotContains(t, string(got), "[[secret-hygiene]]")
|
|
}
|
|
|
|
func TestStoreUpdateUnwrapsUnresolvedWikilinks(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := brainstore.New(dir)
|
|
_, err := s.Write(context.Background(), capture.Note{
|
|
Content: "old\n", Filename: "n", Wing: "a", Hall: "facts",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
ref, err := s.Update(context.Background(), "n", capture.Note{
|
|
Content: "Related: [[cad-babysit]].\n", Wing: "a", Hall: "facts", Reason: "r",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []string{"cad-babysit"}, ref.Unlinked)
|
|
|
|
got, err := os.ReadFile(filepath.Join(dir, "wiki/a/facts/n.md"))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, string(got), "Related: cad-babysit.")
|
|
assert.NotContains(t, string(got), "[[cad-babysit]]")
|
|
}
|