State drift after P0–P4 completion + 3 post-merge hotfixes (PR #20
--config across subcommands, PR #24 --config in kb ask, PR #25 RRF
fusion_score normalization). README still framed the project as
"spec frozen, code 0 lines"; phase docs and task specs all carried
status: planned. Sweep:
- README.md: top banner now "P0–P4 done (17/31 tasks) + 3 hotfixes
applied"; command table marks each subcommand's owning phase and
current status (kb ask = ✅ via P4-3, kb eval = ⏳ P5);
phase roadmap table grew a Status column (P0–P4 completed, P5
next, P6–P9 pending); component count bumped 30 → 31 to reflect
P3-5 (app-wiring, post-spec); core decisions table notes the
RRF [0,1] normalization invariant; build+실행 section drops the
"P0 미시작" caveat; new pointers to HOTFIXES.md and SMOKE.md.
- docs/SMOKE.md (new): ~80-line recipe for running the full
pipeline against an isolated /tmp/kb-smoke/ workspace via
--config, without polluting ~/.config/kb/ or
~/.local/share/kb/. Covers fixture seeding, sample config.toml
with the post-merge defaults, doctor → ingest → list →
search × 3 modes → inspect → ask sequence, verification
checklist, and known-behaviour notes (fastembed model
download, RAG response time, --config hard-fail on missing
path).
- tasks/phase-{0..4}-*.md: status frontmatter flipped planned →
completed.
- tasks/p0/, tasks/p1/, tasks/p2/, tasks/p3/, tasks/p4/: same
status flip across all 17 component task specs (1+6+2+5+3).
P5–P9 stay planned.
cargo test --workspace: 319 passed; clippy clean (no source
changes in this commit, just docs + frontmatter).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Parse YAML/TOML frontmatter from Markdown bytes into kb_core::Metadata, with auto-derive defaults and unknown-key preservation in metadata.user.
Why now / why this size
Frontmatter is small but contractually load-bearing (Q9 spec). Isolating it from block parsing keeps both halves of kb-parse-md simple and lets us reach 100% test coverage on the rules in design §0 Q9.
Allowed dependencies
kb-core
kb-parse-types (provides shared Warning + WarningKind per design §3.7b)
serde
serde_yaml (or yaml-rust2) for YAML
toml for TOML
time
lingua (lang auto-detect — accept feature-gate if heavy)
thiserror
Forbidden dependencies
kb-store-*, kb-llm*, kb-rag, kb-embed*, kb-search, kb-tui, kb-desktop, kb-source-fs, kb-chunk, kb-normalize, pulldown-cmark (block parser is a sibling task)
Warning / WarningKind come from kb-parse-types (shared with p1-3 blocks parser and downstream kb-normalize). FrontmatterSpan is crate-internal; if any new public type is needed, STOP and update the frozen design doc first.
Behavior contract
All Metadata fields are optional in input. Missing fields populated per design §0 Q9 derive table:
title ← first H1 (from BodyHints.first_h1) → filename without extension if no H1.
lang ← lingua auto-detect on first 4 KB of body → fallback BodyHints.fallback_lang or "und".
created_at / updated_at ← BodyHints.fs_ctime / fs_mtime if missing.