fix(brain): close round-3 review findings on provenance
CI / Lint / Test / Vet (pull_request) Successful in 37s
CI / Mirror to GitHub (pull_request) Skipped

- B1: search.extractProvenance locates the frontmatter with
  frontmatter.Split (fence at column 0), so an indented "---" inside a
  block scalar no longer hides provenance from brain_query.
- B2: brain_edit refuses to edit without a snapshot, and if the stamp
  cannot be verified restores the note and reports failure; a failed
  restore is reported as exactly that, never as "rolled back".
- B3: internal/provenance gets direct tests for the whole-document
  backstop (a stamp that cannot read back is refused), standalone group
  decoding, duplicates, lone CR, tab continuations and unclosable
  fences. Removing verify or the restore now fails the suite.
- Principals YAML would read as non-strings (true, 123, null, ~) are
  quoted instead of refused. An unclosable fence ("---x") is refused
  rather than demoted into the body. writeHallNote creates the hall
  directory only after the note passes, so a refused write leaves
  nothing behind (brain#21).
- MCP brain_ingest (stub LLM) asserted to stamp the caller.

Refs #145 #144

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 23:03:09 +02:00
co-authored by Claude Opus 5.5
parent fcae16569d
commit 7afbd60ea2
8 changed files with 227 additions and 33 deletions
+18 -5
View File
@@ -85,9 +85,15 @@ func Apply(content string, s Stamp) (string, error) {
content = foldFrontmatterCR(content)
block, rest, ok := sharedfm.Split([]byte(content))
var out string
if !ok {
switch {
case !ok && strings.HasPrefix(strings.ReplaceAll(content, "\r\n", "\n"), "---\n"):
// A fence was opened but cannot be closed (e.g. a "---x" line).
// Prepending a second block would demote the original frontmatter
// into the body, so refuse instead (PR #147 review round 3).
return "", fmt.Errorf("%w: unclosed frontmatter fence", ErrUnverifiable)
case !ok:
out = "---\n" + stamp + "---\n" + content
} else {
default:
out = "---\n" + plainGroups(string(block)) + stamp + "---\n" + strings.TrimPrefix(string(rest), "\n")
}
if err := verify(out, s); err != nil {
@@ -203,11 +209,18 @@ func foldFrontmatterCR(content string) string {
return strings.ReplaceAll(s[:4+end], "\r", "\n") + s[4+end:]
}
// scalar renders a bare word as-is and anything else as a JSON string (valid
// YAML double-quoted), so a principal name can never break the line.
// scalar renders a bare word as-is only when YAML reads it back as that same
// string; anything else (true, 123, null, ~, punctuation, newlines) becomes
// a double-quoted string, so a principal name can never break the line or
// change type.
func scalar(v string) string {
if bareScalar.MatchString(v) {
return v
var back any
if yaml.Unmarshal([]byte(v), &back) == nil {
if s, ok := back.(string); ok && s == v {
return v
}
}
}
return fmt.Sprintf("%q", v)
}