fix(linkcheck): keep the write when the link index cannot be built (#178) #191

Merged
mathias merged 1 commits from fix/linkcheck-keeps-write-178 into main 2026-10-05 21:16:04 +00:00
3 changed files with 81 additions and 1 deletions
@@ -0,0 +1,34 @@
package api_test
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mathiasbq/hyperguild/ingestion/internal/api"
)
// hyperguild#178: an unreadable directory under wiki/ made the link check
// fail and brain_write refuse the note, losing the learning. The note is now
// written with its links as given.
func TestWriteNoteKeepsTheLearningWhenTheLinkCheckCannotIndex(t *testing.T) {
if os.Geteuid() == 0 {
t.Skip("root ignores directory permissions")
}
brain := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(brain, "wiki", "w", "facts"), 0o755))
require.NoError(t, os.WriteFile(filepath.Join(brain, "wiki", "w", "facts", "real.md"), []byte("x"), 0o644))
locked := filepath.Join(brain, "wiki", "other", "locked")
require.NoError(t, os.MkdirAll(locked, 0o755))
require.NoError(t, os.Chmod(locked, 0o000))
t.Cleanup(func() { _ = os.Chmod(locked, 0o755) })
rel, err := api.WriteNote(brain, api.WriteNoteOptions{Wing: "w", Hall: "facts", Filename: "n", Content: "learning [[real]] and [[gone]]"})
require.NoError(t, err)
got, err := os.ReadFile(filepath.Join(brain, filepath.FromSlash(rel)))
require.NoError(t, err)
assert.Contains(t, string(got), "[[gone]]", "links kept as given when the index is partial")
}
+6 -1
View File
@@ -47,7 +47,12 @@ var (
func StripUnresolvedLinks(brainDir, content string) (string, []string, error) { func StripUnresolvedLinks(brainDir, content string) (string, []string, error) {
index, err := entryIndex(brainDir) index, err := entryIndex(brainDir)
if err != nil { if err != nil {
return "", nil, err // A partial index cannot tell an invented link from one into the
// part it could not read, so unwrap nothing, and do not refuse the
// write either: this runs before every brain_write, and a refused
// write is a lost learning (hyperguild#178).
slog.Warn("link check skipped: cannot index the brain", "err", err)
return content, nil, nil
} }
if len(index) == 0 { if len(index) == 0 {
return content, nil, nil return content, nil, nil
@@ -0,0 +1,41 @@
package brain_test
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mathiasbq/hyperguild/ingestion/internal/brain"
)
// hyperguild#178: StripUnresolvedLinks runs before every brain_write and
// brain_update. An unreadable directory under knowledge/ or wiki/ made it
// error, the write was refused and the learning lost. When the link index
// cannot be built, the content is now returned unchanged (no link is
// unwrapped, none is invented) and no error stops the write.
func TestStripUnresolvedLinksKeepsContentWhenTheIndexCannotBeBuilt(t *testing.T) {
if os.Geteuid() == 0 {
t.Skip("root ignores directory permissions")
}
b := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(b, "wiki", "w", "facts"), 0o755))
require.NoError(t, os.WriteFile(filepath.Join(b, "wiki", "w", "facts", "real.md"), []byte("x"), 0o644))
locked := filepath.Join(b, "wiki", "other", "locked")
require.NoError(t, os.MkdirAll(locked, 0o755))
require.NoError(t, os.Chmod(locked, 0o000))
t.Cleanup(func() { _ = os.Chmod(locked, 0o755) })
in := "learning [[real]] and [[gone]]"
out, unlinked, err := brain.StripUnresolvedLinks(b, in)
require.NoError(t, err)
assert.Equal(t, in, out, "content unchanged: no link unwrapped on a partial index")
assert.Empty(t, unlinked)
require.NoError(t, os.Chmod(locked, 0o755))
out, _, err = brain.StripUnresolvedLinks(b, in)
require.NoError(t, err)
assert.NotContains(t, out, "[[gone]]", "positive control: with a readable tree the strip runs")
}