fix(brainfs,api): PutRegular/AppendRegular; brain_write creates through the brain root (#188)

brain_write created a new note with os.MkdirAll + os.WriteFile by path,
so a symlinked wing or hall directory redirected the note elsewhere in
the brain or outside it.

New brainfs primitives for creating writes:
- PutRegular: create or replace. Missing parents are created one
  component at a time through the root and every existing component
  must be a real directory; an existing file is replaced only via
  WriteRegular's checks; a new one is created with O_EXCL and confirmed
  (Lstat + SameFile) before writing.
- AppendRegular: create-or-append with the same parent rule, writing
  only after confirming the path is the regular file it opened.
- RealParent: the clean-path + real-directory check, for writers that do
  their own atomic rename.

writeHallNote now uses PutRegular.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 22:35:19 +02:00
co-authored by Claude Opus 5.5
parent ddd4bdc2ac
commit 41b7105b31
4 changed files with 239 additions and 5 deletions
+14 -5
View File
@@ -12,6 +12,7 @@ import (
"time"
"github.com/mathiasbq/hyperguild/ingestion/internal/brain"
"github.com/mathiasbq/hyperguild/ingestion/internal/brainfs"
"github.com/mathiasbq/hyperguild/ingestion/internal/claim"
"github.com/mathiasbq/hyperguild/ingestion/internal/pipeline"
"github.com/mathiasbq/hyperguild/ingestion/internal/search"
@@ -227,14 +228,22 @@ func writeHallNote(brainDir string, opts WriteNoteOptions) (string, error) {
// The directory is created only once the note is known to be writable:
// a refused write leaves nothing behind, not even an empty hall dir
// (brain#21; provenance refusal joins the envelope refusal here).
if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {
return "", fmt.Errorf("create hall dir: %w", err)
// Created through the brain root, never through a symlinked wing or
// hall directory (hyperguild#188).
rel, err := filepath.Rel(brainDir, dest)
if err != nil {
return "", fmt.Errorf("note path: %w", err)
}
if err := os.WriteFile(dest, []byte(final), 0o644); err != nil {
rel = filepath.ToSlash(rel)
bfs, err := brainfs.Open(brainDir)
if err != nil {
return "", fmt.Errorf("open brain: %w", err)
}
defer func() { _ = bfs.Close() }()
if err := bfs.PutRegular(rel, []byte(final)); err != nil {
return "", fmt.Errorf("write: %w", err)
}
rel, _ := filepath.Rel(brainDir, dest)
return filepath.ToSlash(rel), nil
return rel, nil
}
// scalarValues flattens frontmatter fields to key -> scalar value for