|
|
|
@@ -102,16 +102,29 @@ func TestDetectTunnels_ExactTitleMatch(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
func TestDetectTunnels_FuzzyMatch(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
seedNote(t, dir, "wiki/x/facts/routing.md",
|
|
|
|
|
"---\ntitle: Routing\n---\nbody.\n")
|
|
|
|
|
seedNote(t, dir, "wiki/x/facts/routing-table.md",
|
|
|
|
|
"---\ntitle: 'Routing Table'\n---\nbody.\n")
|
|
|
|
|
|
|
|
|
|
// Substring of title appears in content, but not as a whole word.
|
|
|
|
|
candidates, err := brain.DetectTunnels(dir, "rerouting handles failover")
|
|
|
|
|
candidates, err := brain.DetectTunnels(dir, "the routing tables were rebuilt")
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, candidates, 1)
|
|
|
|
|
assert.False(t, candidates[0].Exact, "substring-only match should be fuzzy")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A one-word title whose only appearance is lowercase inside another word is
|
|
|
|
|
// not even a candidate: it would fill the review file with English rather than
|
|
|
|
|
// with references.
|
|
|
|
|
func TestDetectTunnels_SingleWordSubstringIsNotACandidate(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
seedNote(t, dir, "wiki/x/facts/routing.md",
|
|
|
|
|
"---\ntitle: Routing\n---\nbody.\n")
|
|
|
|
|
|
|
|
|
|
candidates, err := brain.DetectTunnels(dir, "rerouting handles failover")
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Empty(t, candidates)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDetectTunnels_NoFrontmatterFallsBackToSlug(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
seedNote(t, dir, "wiki/x/facts/widget-flags.md", "# widget flags\n\nbody.\n")
|
|
|
|
@@ -126,20 +139,21 @@ func TestDetectTunnels_NoFrontmatterFallsBackToSlug(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
func TestAutoTunnel_FuzzyGoesToCandidatesFile(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
// Existing note in a different wing whose title is "Routing".
|
|
|
|
|
seedNote(t, dir, "wiki/other/facts/routing.md",
|
|
|
|
|
"---\nwing: other\nhall: facts\ntitle: Routing\n---\nbody.\n")
|
|
|
|
|
// Source note in another wing whose body mentions "rerouting" (substring match only).
|
|
|
|
|
// Existing note in a different wing whose title is "Routing Table".
|
|
|
|
|
seedNote(t, dir, "wiki/other/facts/routing-table.md",
|
|
|
|
|
"---\nwing: other\nhall: facts\ntitle: 'Routing Table'\n---\nbody.\n")
|
|
|
|
|
// Source note in another wing whose body mentions "routing tables"
|
|
|
|
|
// (substring match only — the title is not there as a whole word).
|
|
|
|
|
seedNote(t, dir, "wiki/jepa-fx/facts/new.md",
|
|
|
|
|
"---\nwing: jepa-fx\nhall: facts\n---\nrerouting traffic\n")
|
|
|
|
|
"---\nwing: jepa-fx\nhall: facts\n---\nrouting tables rebuilt\n")
|
|
|
|
|
|
|
|
|
|
require.NoError(t, brain.AutoTunnel(dir,
|
|
|
|
|
"wiki/jepa-fx/facts/new.md", "rerouting traffic"))
|
|
|
|
|
"wiki/jepa-fx/facts/new.md", "routing tables rebuilt"))
|
|
|
|
|
|
|
|
|
|
// Source must not get auto-linked (fuzzy).
|
|
|
|
|
got, err := os.ReadFile(filepath.Join(dir, "wiki/jepa-fx/facts/new.md"))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.NotContains(t, string(got), "[[other/facts/routing]]")
|
|
|
|
|
assert.NotContains(t, string(got), "[[other/facts/routing-table]]")
|
|
|
|
|
|
|
|
|
|
// Candidates file must list the pair.
|
|
|
|
|
matches, err := filepath.Glob(filepath.Join(dir, "raw", "tunnel-candidates-*.md"))
|
|
|
|
@@ -148,7 +162,7 @@ func TestAutoTunnel_FuzzyGoesToCandidatesFile(t *testing.T) {
|
|
|
|
|
body, err := os.ReadFile(matches[0])
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Contains(t, string(body), "wiki/jepa-fx/facts/new.md")
|
|
|
|
|
assert.Contains(t, string(body), "wiki/other/facts/routing.md")
|
|
|
|
|
assert.Contains(t, string(body), "wiki/other/facts/routing-table.md")
|
|
|
|
|
assert.Contains(t, string(body), "Routing")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -175,3 +189,35 @@ func TestWriteTunnel_AppendsToExistingSeeAlso(t *testing.T) {
|
|
|
|
|
assert.Contains(t, s, "[[a/facts/old]]")
|
|
|
|
|
assert.Contains(t, s, "[[b/facts/y]]")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A one-word title matched case-insensitively links every entry that happens
|
|
|
|
|
// to use that word. Live cost before this rule: 185 entries auto-linked to
|
|
|
|
|
// wiki/telos/decisions/wrong.md (title "WRONG") and 136 to .../status.md,
|
|
|
|
|
// making the two most-linked nodes in the graph pure artifacts.
|
|
|
|
|
func TestDetectTunnels_SingleWordTitleNeedsAnExactCaseMatch(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
seedNote(t, dir, "wiki/telos/decisions/wrong.md",
|
|
|
|
|
"---\nwing: telos\nhall: decisions\ntitle: WRONG\n---\n# WRONG\n\nRetired beliefs.\n")
|
|
|
|
|
|
|
|
|
|
got, err := brain.DetectTunnels(dir, "The obvious fix was to reject the write. Wrong here.")
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
for _, c := range got {
|
|
|
|
|
assert.False(t, c.Exact, "a lowercase prose word must not auto-link a one-word title: %+v", c)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got, err = brain.DetectTunnels(dir, "The beliefs listed under WRONG were retired.")
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, got, 1)
|
|
|
|
|
assert.True(t, got[0].Exact, "the title's own casing appearing in prose is a real reference")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDetectTunnels_MultiWordTitleStaysCaseInsensitive(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
seedNote(t, dir, "wiki/homelab/facts/risk-tier.md",
|
|
|
|
|
"---\nwing: homelab\nhall: facts\ntitle: 'Risk Tier Middleware'\n---\nbody\n")
|
|
|
|
|
|
|
|
|
|
got, err := brain.DetectTunnels(dir, "We rebuilt the risk tier middleware last week.")
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, got, 1)
|
|
|
|
|
assert.True(t, got[0].Exact)
|
|
|
|
|
}
|
|
|
|
|