A standard frontmatter parser only reads the first block — every affected file's title/tags become invisible to anything but grep. Likely explains several existing brain-gardener audit "malformed: missing title" / "malformed: empty body" findings (e.g. wiki/homelab/decisions/gitea-authentik-sso-plus-mcp-pat-passthrough-2026-07-22.md).
opts.Content can already carry its own ---\ntitle:...\n--- frontmatter block (e.g. from an upstream extraction/promotion step) — this unconditionally prepends a second block instead of parsing and merging into the existing one.
Scope
Parse any existing frontmatter block out of opts.Content before prepending; merge wing/hall/created_at/type/domain/source_type into that single block (existing fields win on conflict, or make precedence an explicit decision) instead of stacking a second block. Then batch-repair the 75 already-affected files (merge their two blocks into one).
Acceptance criteria
New test: writeHallNote given opts.Content that already has frontmatter produces exactly one merged block.
All 75 known-affected files repaired in the same change.
Cross-check with brain-gardener's next audit run for a drop in "malformed: missing title"/"empty body" findings.
## Problem
75 files under `wiki/homelab/**`, `wiki/agentsquad/**`, `wiki/hyperguild/**` etc. have TWO `---...---` frontmatter blocks stacked back to back:
```yaml
---
wing: homelab
hall: failures
created_at: 2026-06-29T19:29:54Z
---
---
title: act_runner host-executor — /tmp & $HOME persist between jobs
tags: [gitea-actions, act_runner, host-executor, ci, idempotency, secret-hygiene, footgun]
---
```
(example: `wiki/homelab/failures/act-runner-host-executor-tmp-persists.md`)
A standard frontmatter parser only reads the first block — every affected file's `title`/`tags` become invisible to anything but grep. Likely explains several existing brain-gardener audit "malformed: missing title" / "malformed: empty body" findings (e.g. `wiki/homelab/decisions/gitea-authentik-sso-plus-mcp-pat-passthrough-2026-07-22.md`).
## Root cause (confirmed)
`ingestion/internal/api/handler.go`, `writeHallNote`:
```go
var fm strings.Builder
fm.WriteString("---\n")
fmt.Fprintf(&fm, "wing: %s\n", brain.Sanitise(opts.Wing))
fmt.Fprintf(&fm, "hall: %s\n", opts.Hall)
fmt.Fprintf(&fm, "created_at: %s\n", time.Now().UTC().Format(time.RFC3339))
...
fm.WriteString("---\n")
if err := os.WriteFile(dest, []byte(fm.String()+opts.Content), 0o644); err != nil {
```
`opts.Content` can already carry its own `---\ntitle:...\n---` frontmatter block (e.g. from an upstream extraction/promotion step) — this unconditionally prepends a second block instead of parsing and merging into the existing one.
## Scope
Parse any existing frontmatter block out of `opts.Content` before prepending; merge `wing`/`hall`/`created_at`/`type`/`domain`/`source_type` into that single block (existing fields win on conflict, or make precedence an explicit decision) instead of stacking a second block. Then batch-repair the 75 already-affected files (merge their two blocks into one).
## Acceptance criteria
- New test: `writeHallNote` given `opts.Content` that already has frontmatter produces exactly one merged block.
- All 75 known-affected files repaired in the same change.
- Cross-check with brain-gardener's next audit run for a drop in "malformed: missing title"/"empty body" findings.
Code fix in hyperguild@1001acf: splitFrontmatter pulls opts.Content's own frontmatter fields out first; wing/hall/created_at are always fresh-injected, type/domain/source_type prefer the note's own existing value over the opts fallback, remaining fields carried through verbatim into one merged block. Regression tests added, full go test ./... green.
Batch-repaired all currently-affected files in mathias/brain (67, not 75 — count moved since filing; some were independently fixed by brain-gardener in the interim, 6 more had appeared from fresh ingests before the code fix landed). Pushed as mathias/brain@b36dfae, rebased cleanly onto brain's live auto-sync main (one conflict, resolved in favor of brain-gardener's already-applied fix for that file). Verified: zero remaining stacked-frontmatter files, all merged blocks parse as valid YAML except a separate pre-existing bug (unquoted colons in titles) — filed as #90, not caused by or related to this fix.
Code fix in hyperguild@1001acf: `splitFrontmatter` pulls `opts.Content`'s own frontmatter fields out first; `wing`/`hall`/`created_at` are always fresh-injected, `type`/`domain`/`source_type` prefer the note's own existing value over the opts fallback, remaining fields carried through verbatim into one merged block. Regression tests added, full `go test ./...` green.
Batch-repaired all currently-affected files in `mathias/brain` (67, not 75 — count moved since filing; some were independently fixed by brain-gardener in the interim, 6 more had appeared from fresh ingests before the code fix landed). Pushed as `mathias/brain@b36dfae`, rebased cleanly onto brain's live auto-sync main (one conflict, resolved in favor of brain-gardener's already-applied fix for that file). Verified: zero remaining stacked-frontmatter files, all merged blocks parse as valid YAML except a separate pre-existing bug (unquoted colons in titles) — filed as #90, not caused by or related to this fix.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
75 files under
wiki/homelab/**,wiki/agentsquad/**,wiki/hyperguild/**etc. have TWO---...---frontmatter blocks stacked back to back:(example:
wiki/homelab/failures/act-runner-host-executor-tmp-persists.md)A standard frontmatter parser only reads the first block — every affected file's
title/tagsbecome invisible to anything but grep. Likely explains several existing brain-gardener audit "malformed: missing title" / "malformed: empty body" findings (e.g.wiki/homelab/decisions/gitea-authentik-sso-plus-mcp-pat-passthrough-2026-07-22.md).Root cause (confirmed)
ingestion/internal/api/handler.go,writeHallNote:opts.Contentcan already carry its own---\ntitle:...\n---frontmatter block (e.g. from an upstream extraction/promotion step) — this unconditionally prepends a second block instead of parsing and merging into the existing one.Scope
Parse any existing frontmatter block out of
opts.Contentbefore prepending; mergewing/hall/created_at/type/domain/source_typeinto that single block (existing fields win on conflict, or make precedence an explicit decision) instead of stacking a second block. Then batch-repair the 75 already-affected files (merge their two blocks into one).Acceptance criteria
writeHallNotegivenopts.Contentthat already has frontmatter produces exactly one merged block.Code fix in hyperguild@1001acf:
splitFrontmatterpullsopts.Content's own frontmatter fields out first;wing/hall/created_atare always fresh-injected,type/domain/source_typeprefer the note's own existing value over the opts fallback, remaining fields carried through verbatim into one merged block. Regression tests added, fullgo test ./...green.Batch-repaired all currently-affected files in
mathias/brain(67, not 75 — count moved since filing; some were independently fixed by brain-gardener in the interim, 6 more had appeared from fresh ingests before the code fix landed). Pushed asmathias/brain@b36dfae, rebased cleanly onto brain's live auto-sync main (one conflict, resolved in favor of brain-gardener's already-applied fix for that file). Verified: zero remaining stacked-frontmatter files, all merged blocks parse as valid YAML except a separate pre-existing bug (unquoted colons in titles) — filed as #90, not caused by or related to this fix.