Commit Graph
3 Commits
Author SHA1 Message Date
mathiasandClaude Sonnet 5 a75fd95ab8 fix(frontmatter): consolidate 3 independent fence-parsers into one
CI / Lint / Test / Vet (pull_request) Successful in 34s
CI / Mirror to GitHub (pull_request) Skipped
hyperguild#138: internal/mcp/tools_notes.go's frontmatterBlock,
internal/api/frontmatter.go's parseFrontmatter, and
internal/frontmatter/frontmatter.go's split each independently detected a
note's --- fence, converging on the same shape through parallel bug-fixing
across today's #123/#126/#128 sagas. Each carried a subtly different gap:
internal/frontmatter's closing-fence match had no trailing-newline
requirement (a document ending "\n---extra" was treated as validly closed);
internal/mcp needed CRLF/BOM guards bolted on across two separate review
rounds after both silently defeated its own HasPrefix check; internal/api
never gained either fix, so the same encoding-dependent bypass was live
there too, just never triggered by a test.

internal/frontmatter is the leaf package (imports nothing internal), so it
becomes the canonical fence detector: exported Split(doc []byte) (block,
rest []byte, ok bool), BOM-stripped and CRLF-normalized, with the stricter
trailing-newline-required close. internal/api and internal/mcp now call it
instead of re-detecting the fence themselves, keeping only what's genuinely
package-specific (api's ordered fmLine round-trip shape, mcp's map + block-
scalar-fold logic).

Found two real regressions while wiring the callers, caught by each
package's own pre-existing byte-exactness tests going red immediately:
Split's block/rest boundary sits one byte differently than either caller's
prior contract (it keeps the fence-adjacent newline on each side, by design
for Fix's own reconstruction) — both callers now TrimSuffix/TrimPrefix
exactly that one byte to restore their exact prior semantics. Neither
regression would have been visible without those tests already existing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 14:57:34 +02:00
mathias 7ed2a7d3b4 fix(api): frontmatter parser must not misparse indented list items as keys (#135)
CI / Mirror to GitHub (push) Successful in 4s
CI / Lint / Test / Vet (push) Successful in 40s
Co-authored-by: Mathias <mthbqv@gmail.com>
2026-09-23 08:12:06 +00:00
mathiasandClaude Opus 4.8 95a69fc2c1 feat(brain): add UpdateNote/ReadNote supersede primitives + frontmatter editor
Implements the api-layer half of #45. UpdateNote supersedes a note in
place (whole-note body replace, frontmatter re-stamp: updated_at,
supersedes=prior content hash, supersede_reason), preserving created_at,
wing, hall, and any custom fields. Never creates — a missing target is
an error so callers fall back to brain_write. ReadNote is the read-after-
write primitive (frontmatter + body + content_hash). ContentHash is the
sha256 handle that round-trips write/update → get.

Frontmatter is edited via a line-preserving ordered editor rather than a
yaml.v3 round-trip, which would reorder keys and strip comments — the
brain writes flat key:value frontmatter by hand.

Embeddings are not refreshed here: the rewritten file's mtime advances,
which the out-of-band vectorstore.Sync ticker uses to re-embed it — the
same mechanism brain_write relies on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 08:25:00 +02:00