fix(brain): a one-word tunnel title must match the prose case-exactly
AutoTunnel matched note titles case-insensitively, so a one-word title linked
every entry that happened to use that word. Measured on the live corpus: 185
entries carry an auto-written See-also link to wiki/telos/decisions/wrong.md
(title "WRONG") and 136 to .../status.md — the two most-linked nodes in the
whole graph, and both of them artifacts of the English language rather than
references. telos's projects/problems/strategies/goals/beliefs entries account
for another ~60 between them.
That pollution is not cosmetic: inbound-link count is what the duplicate
Fixer picks survivors by, what orphan detection reads, and what brain_graph
shows.
One-word titles now need the title's own casing in the prose ("WRONG", "BERT",
"NLP" — an entity name in a sentence still links). Multi-word titles keep the
case-insensitive match: "risk tier middleware" is a real mention however it is
capitalised, and a three-word collision is not an accident.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -54,11 +54,24 @@ func DetectTunnels(brainDir, content string) ([]TunnelCandidate, error) {
|
||||
return nil
|
||||
}
|
||||
title, _ := readTitleAndCreated(path, strings.TrimSuffix(d.Name(), ".md"))
|
||||
needle := strings.ToLower(strings.TrimSpace(title))
|
||||
if needle == "" {
|
||||
title = strings.TrimSpace(title)
|
||||
if title == "" {
|
||||
return nil
|
||||
}
|
||||
idx := strings.Index(lowerContent, needle)
|
||||
|
||||
// A one-word title has to match the prose case-exactly. Matched
|
||||
// case-insensitively, it links every entry that happens to use the
|
||||
// word: "WRONG" (wiki/telos/decisions/wrong.md) collected 185 inbound
|
||||
// See-also links and "Status" 136, making the two most-linked nodes in
|
||||
// the graph artifacts of the English language rather than references.
|
||||
// Multi-word titles keep the case-insensitive match — "risk tier
|
||||
// middleware" in prose is a real mention however it is capitalised,
|
||||
// and a three-word collision is not an accident.
|
||||
haystack, needle := lowerContent, strings.ToLower(title)
|
||||
if isSingleWord(title) {
|
||||
haystack, needle = content, title
|
||||
}
|
||||
idx := strings.Index(haystack, needle)
|
||||
if idx == -1 {
|
||||
return nil
|
||||
}
|
||||
@@ -69,7 +82,7 @@ func DetectTunnels(brainDir, content string) ([]TunnelCandidate, error) {
|
||||
out = append(out, TunnelCandidate{
|
||||
TargetPath: filepath.ToSlash(rel),
|
||||
MatchedTerm: title,
|
||||
Exact: isWholeWord(lowerContent, idx, len(needle)),
|
||||
Exact: isWholeWord(haystack, idx, len(needle)),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
@@ -79,6 +92,11 @@ func DetectTunnels(brainDir, content string) ([]TunnelCandidate, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// isSingleWord reports whether title is one whitespace-free token.
|
||||
func isSingleWord(title string) bool {
|
||||
return !strings.ContainsAny(title, " \t")
|
||||
}
|
||||
|
||||
// isWholeWord reports whether the substring at [idx, idx+n) in s is
|
||||
// bounded by non-alphanumeric characters (or string edges).
|
||||
func isWholeWord(s string, idx, n int) bool {
|
||||
|
||||
Reference in New Issue
Block a user