mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
synthesize-concepts.ts's design comment says extract_atoms stamps a `concepts:` frontmatter field on each atom and :92 consumes ONLY that field — but the extractor never wrote it, so the atoms → concepts pipeline was dead end-to-end: every cycle reported "synthesize_concepts: skipped — no atoms with concept refs" no matter how many atoms accumulated (696 page-derived atoms / 0 with concepts on our production brain before an external backfill). Fix, all on the extractor side (no synthesize change needed): - EXTRACT_PROMPT asks for `concepts` (1-3 kebab-case TOPIC labels) with an explicit reuse-over-coinage instruction — labels must cluster, since synthesize_concepts only materializes groups of >=2. - parseAtomsResponse validates labels (kebab regex, max 3, drop invalid; empty -> undefined). - The putPage frontmatter write stamps `concepts` alongside lesson / source_quote. Tests: 4 parse cases + an end-to-end regression that goes extractor -> real frontmatter -> synthesize_concepts' OWN DB query path -> concept page. The existing tests fed synthesize via the `_atoms` seam, which is exactly how this gap survived. Validated in production ahead of this PR by stamping the same shape externally: the next synthesize_concepts run wrote 33 concept pages (T2=7/T3=26) from 60 stamped atoms, zero failures. Co-authored-by: 陈源泉 <chenyuanquan@chenyuanquandeMac-mini.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>