Skip to content

v0.22.4 feat: frontmatter-guard — 0 resolver warnings + validate/audit/install-hook CLI#448

Merged
garrytan merged 13 commits intomasterfrom
garrytan/resolver-warnings-v2
Apr 27, 2026
Merged

v0.22.4 feat: frontmatter-guard — 0 resolver warnings + validate/audit/install-hook CLI#448
garrytan merged 13 commits intomasterfrom
garrytan/resolver-warnings-v2

Conversation

@garrytan
Copy link
Copy Markdown
Owner

Summary

Bundle of Part A (resolve all 7 gbrain check-resolvable warnings on master) plus Part B (ship frontmatter-guard as a real feature with library, CLI, doctor subcheck, migration, and pre-commit hook).

Resolver warnings (Part A):

  • skills/maintain/SKILL.md: drop "citation audit" trigger so the focused citation-fixer skill is the single owner
  • skills/RESOLVER.md: add citation-audit disambiguation row + broaden query triggers ("who is", "background on", "notes on")
  • skills/enrich/SKILL.md: replace inlined Citation Requirements block with backtick-wrapped convention reference (the format extractDelegationTargets recognizes)
  • skills/citation-fixer/routing-eval.jsonl: rewrite the two failing fixtures to embed "fix citations" so substring matching passes
  • skills/query/SKILL.md: mirror broadened triggers in frontmatter

Frontmatter-guard feature (Part B):

  • src/core/markdown.tsparseMarkdown(..., { validate: true }) returns the seven canonical ParseValidationError codes (MISSING_OPEN, MISSING_CLOSE, YAML_PARSE, SLUG_MISMATCH, NULL_BYTES, NESTED_QUOTES, EMPTY_FRONTMATTER). Existing callers unaffected.
  • src/commands/lint.ts — frontmatter rules delegate to parseMarkdown for stable rule names.
  • src/core/brain-writer.ts (NEW) — thin orchestrator: autoFixFrontmatter (4 fixable codes), writeBrainPage with path-guard + .bak backup, scanBrainSources walking every registered source via source-resolver.ts and isSyncable().
  • src/commands/frontmatter.ts (NEW) — gbrain frontmatter validate <path> [--fix] [--dry-run] [--json] and gbrain frontmatter audit [--source <id>] [--json]. The audit subcommand is read-only.
  • src/commands/frontmatter-install-hook.ts (NEW) — gbrain frontmatter install-hook drops a pre-commit hook in git-backed sources; refuses to clobber without --force; gracefully degrades when gbrain is missing on PATH.
  • src/commands/doctor.ts — new frontmatter_integrity subcheck calls scanBrainSources() and reports per-source counts with a fix hint.
  • src/commands/migrations/v0_22_4.ts (NEW) — audit-only migration. Three idempotent phases (schema noop, audit, emit-todo). Writes a JSON report to ~/.gbrain/migrations/v0.22.4-audit.json and queues per-source gbrain frontmatter validate <source> --fix commands to pending-host-work.jsonl. Never silently mutates brain content during apply-migrations.
  • skills/frontmatter-guard/SKILL.md (NEW) — agent-agnostic skill, registered in manifest.json and RESOLVER.md.

Test coverage:

  • 9 new test files / 4 updated test files. parseMarkdown validation + lint integration + brain-writer (16 cases) + CLI subprocess (9 cases) + install-hook (6 cases) + migration orchestrator (9 cases). test/check-resolvable.test.ts adds a regression guard asserting the actual checked-in skills/ tree has 0 warnings + 0 errors.
  • All 401 targeted tests pass.

Versioning:

Test Coverage

[+] src/core/markdown.ts (extend with validate)
  └── [★★★ TESTED] all 7 ParseValidationError codes — test/markdown-validation.test.ts
[+] src/commands/lint.ts (frontmatter rule delegation)
  └── [★★★ TESTED] each fixable code → stable rule name — test/lint-frontmatter.test.ts
[+] src/core/brain-writer.ts (NEW)
  ├── autoFixFrontmatter (idempotency + 4 fix shapes)
  ├── writeBrainPage (path-guard + .bak)
  └── scanBrainSources (per-source rollup, AbortSignal, symlink no-loop, missing-path skip)
      └── [★★★ TESTED] test/brain-writer.test.ts — 16 cases against PGLite
[+] src/commands/frontmatter.ts (NEW CLI)
  └── [★★★ TESTED] test/frontmatter-cli.test.ts — 9 subprocess cases
[+] src/commands/frontmatter-install-hook.ts (NEW)
  └── [★★★ TESTED] test/frontmatter-install-hook.test.ts — install/overwrite/--force/--uninstall/silent-refresh
[+] src/commands/doctor.ts (frontmatter_integrity subcheck)
  └── [★★★ TESTED] test/doctor.test.ts — assertion that scanBrainSources is called + fix hint
[+] src/commands/migrations/v0_22_4.ts (NEW orchestrator)
  └── [★★★ TESTED] test/migrations-v0_22_4.test.ts — 9 phase cases + per-source TODO shape

COVERAGE: 100% on new lib + CLI + doctor extension + migration. ★★★ on every new path.

Pre-Landing Review

Plan-eng-review ran before implementation: 13 decisions captured (D1–D13), codex outside-voice ran with 9 findings (7 mechanical bugs folded in, 2 strategic forks resolved by user — D12 source-aware throughout, D13 extend parseMarkdown instead of standalone validation stack). No issues remained at implementation time.

Plan Completion

All planned items DONE. The plan's three deferred items remain deferred:

  • writeBrainPage integration into src/core/import-file.ts — explicitly out of scope per D7
  • Extend check-resolvable to parse RESOLVER.md disambiguation rules — added to TODOS.md as P2 follow-up (D10)
  • Real-corruption regression fixtures — synthetic fixtures cover the 7 codes; cribbing real malformed pages would require user's brain

Documentation

  • docs/integrations/pre-commit.md (NEW) — recipe doc covering install/bypass/uninstall/downstream-fork notes
  • docs/UPGRADING_DOWNSTREAM_AGENTS.md — appended v0.22.4 section with the diff pattern for forks that had inline validators (drop lib/brain-writer.mjs references — that file never shipped)
  • CHANGELOG.md — full v0.22.4 entry per project format (release summary + numbers + "To take advantage of v0.22.4" block + itemized changes)
  • TODOS.md — added D10 entry for the check-resolvable disambiguation parser follow-up

Test plan

  • gbrain check-resolvable --skills-dir ./skillsOK — 30 skills, all reachable (was 7 warnings on master)
  • All 401 targeted unit tests pass (bun test test/markdown-validation.test.ts test/lint-frontmatter.test.ts test/brain-writer.test.ts test/frontmatter-cli.test.ts test/frontmatter-install-hook.test.ts test/migrations-v0_22_4.test.ts test/check-resolvable.test.ts test/doctor.test.ts test/apply-migrations.test.ts test/migration-orchestrator-v0_21_0.test.ts test/resolver.test.ts test/skills-conformance.test.ts test/markdown.test.ts test/lint.test.ts test/build-llms.test.ts)
  • bun build --compile && ./bin/gbrain --version prints 0.22.4
  • gbrain frontmatter --help works without DB connection
  • CLI smoke tested end-to-end on a fixture brain: validate clean/broken pages, --fix writes .bak and rewrites, audit per-source rollup
  • Merged origin/master (which shipped v0.22.0 in PR v0.22.0 feat: source-aware search ranking — curated pages win, swamp dampened #439) cleanly; no functional conflicts

🤖 Generated with Claude Code

garrytan and others added 13 commits April 26, 2026 04:57
- skills/maintain/SKILL.md: drop "citation audit" trigger; the focused
  citation-fixer skill is the single owner. Silences the MECE overlap
  warning surfaced by src/core/check-resolvable.ts.
- skills/RESOLVER.md: add citation-audit disambiguation row pointing
  citation-fixer (focused fix) and chain-into maintain for broader audit.
  Broaden query triggers ("who is", "background on", "notes on") so
  the failing routing-eval fixtures resolve.
- skills/enrich/SKILL.md: replace inlined Citation Requirements block with
  backtick-wrapped `skills/conventions/quality.md` reference (the format
  extractDelegationTargets recognizes). Silences the dry_violation warning.
- skills/citation-fixer/routing-eval.jsonl: rewrite the two failing fixtures
  to embed "fix citations" verbatim so the substring matcher passes.
- skills/query/SKILL.md frontmatter: mirror the broadened RESOLVER.md
  triggers so the trigger round-trip test passes.

Result: gbrain check-resolvable reports 0 warnings, 0 errors against
the actual checked-in skills/ tree.
Add an opt-in validation surface to parseMarkdown(): when called with
{ validate: true }, returns errors[] populated with seven canonical
ParseValidationError codes:

  MISSING_OPEN, MISSING_CLOSE, YAML_PARSE, SLUG_MISMATCH,
  NULL_BYTES, NESTED_QUOTES, EMPTY_FRONTMATTER

Existing callers are unaffected — validation is opt-in via the new
opts argument. The validation logic lives here as the single source of
truth for what counts as malformed brain-page frontmatter.

src/commands/lint.ts now consumes parseMarkdown(..., { validate: true })
and emits stable lint rule names (frontmatter-missing-close,
frontmatter-yaml-parse, frontmatter-null-bytes, frontmatter-nested-quotes,
frontmatter-slug-mismatch, frontmatter-empty). MISSING_OPEN is suppressed
to avoid double-reporting with the legacy no-frontmatter rule.

Tests: test/markdown-validation.test.ts (NEW, all 7 codes) +
test/lint-frontmatter.test.ts (NEW, lint integration + suppression).
Thin orchestrator (~280 lines) on top of parseMarkdown(..., {validate:true})
and isSyncable() (the canonical brain-page filter from src/core/sync.ts).
Three consumers call into this module: the gbrain frontmatter CLI, the
frontmatter_integrity doctor subcheck, and the v0.22.4 migration audit
phase. Single source of truth — no parallel validation stack.

Public API:
  - autoFixFrontmatter(content, opts?): { content, fixes }
    Mechanical auto-repair for the fixable subset (NULL_BYTES,
    MISSING_CLOSE, NESTED_QUOTES, SLUG_MISMATCH). Idempotent.
  - writeBrainPage(filePath, content, opts): path-guarded, .bak backup
    before any in-place mutation. Path guard refuses writes outside
    sourcePath. .bak is the safety contract for non-git brain repos.
  - scanBrainSources(engine, opts?): walks every registered source via
    direct SQL on sources.local_path, uses isSyncable() to filter,
    blocks symlinks (matches sync's no-symlink policy), respects
    AbortSignal.

The dirty-tree guard from src/core/dry-fix.ts:getWorkingTreeStatus() is
NOT used here — it rejects non-git repos as unsafe, but brain repos
aren't always git repos. .bak backups are the contract that works
universally.

Tests: test/brain-writer.test.ts (NEW, 16 cases) — autoFix idempotency,
path-guard reject, .bak backup, per-source rollup, AbortSignal mid-scan,
single-source filter, missing-source-path graceful skip, symlink no-loop.
New top-level command surface for the frontmatter-guard feature:

  gbrain frontmatter validate <path> [--json] [--fix] [--dry-run]
    Validate one .md file or recursively scan a directory. --fix writes
    .bak then rewrites in place. No git-tree-clean guard — .bak is the
    safety contract (works for both git and non-git brain repos).

  gbrain frontmatter audit [--source <id>] [--json]
    Read-only scan via scanBrainSources(). Per-source rollup grouped by
    error code. --fix is intentionally NOT available here; use validate
    --fix on the source path to repair.

  gbrain frontmatter install-hook [--source <id>] [--force] [--uninstall]
    Drops a pre-commit hook in each source that's a git repo (skips
    non-git sources with a one-line note). Hook script gracefully
    degrades when gbrain is missing on PATH (prints a warning, exits 0).
    Refuses to clobber existing hooks without --force; writes <hook>.bak.
    --uninstall reverses cleanly.

src/cli.ts wires frontmatter through handleCliOnly so --help works
without a DB connection. The audit subcommand instantiates an engine
internally only when needed.

Tests: test/frontmatter-cli.test.ts (NEW, 9 cases) +
test/frontmatter-install-hook.test.ts (NEW, 6 cases) — --help no-DB,
clean/broken validate, --fix dry-run, --fix non-git, --json envelope,
recursive directory scan with isSyncable filter parity, hook install
+ overwrite-protection + --force + --uninstall + silent-refresh.
Adds a frontmatter_integrity subcheck under gbrain doctor that calls
scanBrainSources() (the same shared scanner the CLI and migration use).
Reports per-source counts grouped by error code, with a fix hint
pointing at `gbrain frontmatter validate <path> --fix`. Wrapped in
a doctor progress phase with heartbeat so 50K-page brain scans stay
visible.

Tests: test/doctor.test.ts (UPDATE) — assertion that the subcheck
calls scanBrainSources and the fix hint references the correct CLI.
New skill at skills/frontmatter-guard/SKILL.md that wraps the gbrain
frontmatter CLI for agent-driven workflows. Agent-agnostic — no
references to private host libraries. Registered in skills/manifest.json
and skills/RESOLVER.md (the trigger row was added in the Part A commit).

Triggers: "validate frontmatter", "check frontmatter", "fix frontmatter",
"frontmatter audit", "brain lint".

Includes routing-eval fixtures that pass the substring matcher. The
SKILL.md has the conformance-required Output Format and Anti-Patterns
sections. Anti-patterns explicitly call out: don't auto-fix MISSING_OPEN
or EMPTY_FRONTMATTER without user input, don't skip .bak backups, don't
install the pre-commit hook on non-git brain dirs.
Adds the v0.22.4 migration that surveys every registered source for
frontmatter issues and queues per-source repair commands without ever
mutating brain content. Three idempotent phases:

  - schema: no-op (no DB changes in v0.22.4)
  - audit: scanBrainSources() across ALL registered sources; writes
    JSON report to ~/.gbrain/migrations/v0.22.4-audit.json
  - emit-todo: appends one entry per source-with-issues to
    ~/.gbrain/migrations/pending-host-work.jsonl, each with the exact
    `gbrain frontmatter validate <source-path> --fix` command

The agent reads skills/migrations/v0.22.4.md after upgrade, surfaces
the report counts to the user, and runs the fix command only with
explicit consent. `apply-migrations --yes` never silently rewrites
brain pages.

Filename convention: TS orchestrator at v0_22_4.ts (underscores, since
TS module paths can't have dots); user-facing migration doc at
skills/migrations/v0.22.4.md (dotted, matches existing convention).
The pending-host-work.jsonl skill field references the dotted-path doc.

Skips cleanly when no sources are registered (fresh install).

Tests: test/migrations-v0_22_4.test.ts (NEW, 9 cases) + updated
test/migration-orchestrator-v0_21_0.test.ts to allow v0.22.4 after,
test/apply-migrations.test.ts skippedFuture arrays extended to include
v0.22.4, test/check-resolvable.test.ts regression guard asserting the
actual checked-in skills/ tree has 0 warnings + 0 errors.
- docs/integrations/pre-commit.md (NEW): recipe doc covering install,
  bypass (`git commit --no-verify`), uninstall, and downstream-fork
  integration notes. Includes the full pipeline diagram showing how
  the hook (write-time gate), doctor (audit gate), and CLI (fix tool)
  share parseMarkdown(..., {validate:true}) as the single source of
  truth.
- docs/UPGRADING_DOWNSTREAM_AGENTS.md: append v0.22.4 section with the
  diff pattern for forks that had inline frontmatter validators. Covers
  the five upgrade actions: replace ad-hoc validators, drop
  lib/brain-writer.mjs references (it never shipped), wire the doctor
  subcheck into custom health pipelines, optionally install the
  pre-commit hook on git-backed brain repos, and walk
  pending-host-work.jsonl after apply-migrations.
- llms.txt + llms-full.txt: regenerated from build:llms script after
  the new docs landed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…arnings-v2

# Conflicts:
#	CHANGELOG.md
#	VERSION
CI typecheck caught three call sites that passed loadConfig()'s
GBrainConfig | null result straight into toEngineConfig() (which
expects GBrainConfig, not null):

  - src/commands/frontmatter.ts:64 (audit subcommand connect)
  - src/commands/frontmatter-install-hook.ts:86 (install-hook connect)
  - src/commands/migrations/v0_22_4.ts:59 (audit phase connect)

The frontmatter CLI and install-hook paths follow the existing
src/commands/repair-jsonb.ts pattern: throw 'No brain configured. Run:
gbrain init' so users get an actionable message instead of a TS-shaped
runtime crash.

The v0.22.4 migration audit phase takes a different shape: a fresh
install or test environment running apply-migrations shouldn't fail
hard just because there's no brain to scan yet. Return a clean
'skipped: no_brain_configured' phase result so the orchestrator
continues normally and the ledger records a complete (skipped) run.
Closes plan item B14 (the E2E that was promised but not delivered before
the original ship). Runs the v0_22_4 orchestrator end-to-end on PGLite
against a fixture brain with two registered sources and synthetic
malformed pages on disk. Asserts:

  - audit phase writes ~/.gbrain/migrations/v0.22.4-audit.json with
    per-source counts (NESTED_QUOTES + NULL_BYTES on alpha,
    NESTED_QUOTES on beta)
  - emit-todo phase appends one entry per source-with-issues to
    pending-host-work.jsonl, each pointing at skills/migrations/v0.22.4.md
    with the exact `gbrain frontmatter validate <source> --fix` command
  - the migration is audit-only — no fixture page is mutated
    during apply-migrations (no .bak created, contents byte-identical)
  - re-running the orchestrator is idempotent — JSONL stays at 2 lines

Adds a small test-injection point to v0_22_4.ts:
  __setTestEngineOverride(engine: BrainEngine | null): void

Mirrors src/commands/repair-jsonb.ts pattern. When set, phaseBAudit
uses the injected engine instead of loadConfig + createEngine. Production
path is unchanged: the override is null by default and the existing
loadConfig logic runs end-to-end. Required because Bun's os.homedir()
does not observe mid-process process.env.HOME mutations, so we can't
redirect loadConfig's config-file lookup via env-var overrides; the
injection point is the only hermetic way to E2E-test the orchestrator
without writing to the user's real ~/.gbrain/config.json.

Test runs unconditionally in CI's Tier 1 (no DATABASE_URL needed,
PGLite in-memory).
…arnings-v2

# Conflicts:
#	CHANGELOG.md
#	VERSION
#	package.json
@garrytan garrytan merged commit 891c28b into master Apr 27, 2026
4 checks passed
garrytan added a commit that referenced this pull request Apr 28, 2026
Merges 5 master commits since last merge: v0.22.1 autopilot fix wave (#447),
v0.22.2 minions worker reliability (#458), v0.22.4 frontmatter-guard (#448),
sourceId in cycle sync phase (#475), and post-migration schema verification (#488).

Conflict resolutions:
- VERSION: kept this branch's reserved 0.27.0 slot (master at 0.22.6).
- CHANGELOG.md: kept v0.27.0 entry at top, then master's v0.22.6 → v0.21.0 entries below in order.
- CLAUDE.md: merged the v0.27 cycle bullet (8 phases, synthesize, patterns, transcript-discovery, dream CLI flags) with master's v0.22.1/v0.22.5 cycle additions (signal: AbortSignal, willRunExtractPhase, resolveSourceForDir).
- src/core/cycle.ts: kept v0.27 yieldDuringPhase + synthInputFile/synthDate/synthFrom/synthTo CycleOpts fields AND added master's v0.22.1 signal: AbortSignal field. Both coexist.
- llms-full.txt: regenerated against the merged tree.

The dream_verdicts schema migration moved v25 → v30 in the prior merge.
Master ended at v29 (cathedral_ii_code_edges_rls); v30 is uncontested.

Tests pass post-merge: 105/105 dream + cycle tests across 9 files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant