hyperguild#79's caller audit (done in a prior session) found the removal
was safe:
- The promote/pending flow (#38/#81, ingestion/internal/api/promote.go)
operates exclusively on brainDir/raw/ -> brainDir/wiki/<wing>/<hall>/. It
never touches brainDir/knowledge/, so removing the knowledge/ write path
does not break it.
- No live caller uses domain/type or the knowledge/ path: checked
hyperguild itself, mathias/skills, mathias/agentsquad, mathias/dispatch,
mathias/cad, mathias/cad-atlas.
- internal/skills/brain (a skill.go + handlers.go pair) defined a third,
even-more-legacy brain_write shape (type/domain/filename, no wing/hall)
for an old "supervisor" MCP server whose cmd/supervisor/main.go no
longer exists. Nothing outside its own test imported it; deleted
entirely as it encodes the exact legacy shape this issue removes.
Changes:
- ingestion/internal/mcp/handlers.go: brain_write's tool schema and
brainWriteArgs drop type/domain; wing+hall are now marked required in
the schema.
- ingestion/internal/api/handler.go: WriteNote has one behaviour — wing+
hall required, routing to wiki/<wing>/<hall>/. writeLegacyNote and the
knowledge/-path branch are deleted. Omitting wing or hall now returns
"wing and hall are required" (400 over HTTP, a tool error over MCP) —
the only sane failure mode left once there is no other valid
destination.
- ingestion/internal/capture/ports.go, internal/brainstore/store.go: drop
Type/Domain from capture.Note and its WriteNoteOptions construction.
pipeline/*.go's unrelated "domain" field (a different, legitimate
concept for brain_ingest_raw) is untouched.
- internal/skills/brain/: deleted (orphaned legacy tool schema, dead
since cmd/supervisor was removed).
Tests: added TestWriteNote_RequiresWingAndHall (api),
TestBrainWriteRequiresWingAndHall +
TestBrainWriteIgnoresLegacyTypeAndDomainParams (mcp) for the new single
behaviour; removed tests that only exercised the deleted legacy path
(TestWrite_IncludesFrontmatterWhenTypeProvided,
TestWriteNote_HallRouteExistingTypeWinsOverOptsType,
TestBrainWriteRejectsTraversal, TestBrainWriteAcceptsDoubleDotInName —
the latter two's filename-sanitisation behaviour is covered independently
by internal/brain/path_test.go's TestNotePath_SanitisesWingAndSlug /
TestSanitise, which is unaffected by this change).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Extracts the #45 write/update/get logic + the wiki upkeep that must
accompany a write (wing _index rebuild, cross-wing auto-tunnel, graph
re-index) into a single concrete brainstore.Store implementing
capture.BrainStore. The MCP brain_write/brain_update/brain_get handlers
are re-pointed at it, so there is one implementation, not two — the DRY
payoff #51 is named for. capture and MCP now share the exact same brain
write path and read-after-write contract.
The Server gains a *brainstore.Store, constructed in NewServer and given
the graph store in WithGraph. Embedding refresh stays out-of-band
(mtime-driven vectorstore.Sync), unchanged. Existing MCP brain_update/
brain_get/brain_write tests pass unmodified — behaviour and the
{id, path, content_hash} response contract are preserved.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>