Commit Graph
3 Commits
Author SHA1 Message Date
mathiasandClaude Opus 5.5 9eb3d2456d fix(tunnel): brain_tunnel cannot write outside the wiki or through symlinks
CI / Lint / Test / Vet (pull_request) Successful in 52s
CI / Mirror to GitHub (pull_request) Skipped
brain_tunnel passes caller-supplied source and target paths to
WriteTunnel, which checked only the first segments ("wiki/<wing>/...")
and joined them onto the brain dir. "wiki/b/x/../../../../tmp/f.md"
resolved outside the brain, and appendSeeAlso read and rewrote that file
(verified by execution): any MCP token holder could append to any
existing file the pod user can write, inside the brain (raw/, sessions/,
classification.yaml) or outside it.

- checkNotePath: only a clean, local wiki/.../<slug>.md path, with no
  ".", ".." or empty segments.
- Both notes are read and rewritten through brainfs. New
  brainfs.WriteRegular: never creates; Lstat through the root, open with
  O_NOFOLLOW|O_NONBLOCK, and require the opened handle to be the same
  regular file (os.SameFile). os.Root.OpenFile follows an in-root final
  symlink even with O_NOFOLLOW (verified on go1.27), so the flag alone
  does not refuse it.
- The source is no longer rewritten when the target is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 22:23:45 +02:00
mathiasandClaude Opus 5 6e69698343 fix(brain): a one-word tunnel title must match the prose case-exactly
CI / Mirror to GitHub (push) Successful in 4s
CI / Lint / Test / Vet (push) Successful in 31s
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>
2026-09-17 00:08:40 +02:00
mathias ddd07ae7eb feat(brain): cross-wing tunnels — bidirectional wikilinks + auto-detect
CI / Lint / Test / Vet (push) Successful in 11s
CI / Mirror to GitHub (push) Successful in 3s
Adds the `brain_tunnel` MCP tool and auto-tunnel behaviour for
`brain_write`, so concepts that appear in multiple wings become
navigable from any of them.

New surface in package brain:
- WriteTunnel(brainDir, src, tgt) — appends a `## See also` bidirectional
  wikilink between two notes in different wings. Idempotent (link not
  duplicated on re-call) and reuses an existing See also section.
- DetectTunnels(brainDir, content) — walks brain/wiki/, returns
  TunnelCandidates for notes whose title appears in content. Tags
  whole-word case-insensitive hits as Exact=true and substring-only hits
  as Exact=false.
- AutoTunnel(brainDir, src, content) — wraps DetectTunnels: writes
  cross-wing exact matches, stages fuzzy matches into
  brain/raw/tunnel-candidates-<YYYY-MM-DD>.md for human review.

MCP wiring:
- `brain_tunnel` tool: explicit manual link (source, target).
- `brain_write` with wing+hall now triggers AutoTunnel on the new
  content. Failures are logged and never abort the primary write.

readTitleAndCreated also humanises the slug fallback (hyphens → spaces)
so titleless notes participate in content matching.

Closes hyperguild#16.

Tests: idempotency, same-wing rejection, missing-note rejection,
See-also reuse, exact/fuzzy detection, slug fallback, MCP tool happy
path, auto-tunnel hook (cross-wing exact → linked; same-wing → skipped;
fuzzy → candidates file).
2026-05-18 21:32:49 +02:00