#!/usr/bin/env python3 import json from pathlib import Path ROOT = Path(__file__).resolve().parent.parent ENRICHER = ROOT / 'oracle_enricher' KB_FILE = ENRICHER / 'out' / 'oracle_kb.json' DOSSIERS_DIR = ENRICHER / 'out' / 'dossiers' LEXICON_FILE = ENRICHER / 'data' / 'lexicon.json' OUT_FILE = ROOT / 'assets' / 'data' / 'oracle_kb.json' SEEDS = {'огонь', 'вода', 'волк', 'ключ', 'над', 'я', 'зеркало', 'путь', 'смерть', 'лишь'} def main(): lexicon = json.loads(LEXICON_FILE.read_text(encoding='utf-8')) kb = json.loads(KB_FILE.read_text(encoding='utf-8')) if KB_FILE.exists() else {} # Pre-map dossiers by word dossiers = {} for p in DOSSIERS_DIR.glob('*.json'): try: d = json.loads(p.read_text(encoding='utf-8')) w = d.get('word') if w: dossiers[w] = d except Exception: pass out_data = {} real_canon_count = 0 for row in lexicon: w = row['word'] w_id = row['id'] w_emoji = row.get('emoji', '') dossier = dossiers.get(w, {}) canon = kb.get(w) or dossier.get('canon') or {} is_seed = w in SEEDS is_llm_canon = canon.get('via') in ('grok_cli', 'user_edit') is_user_edited = bool(canon.get('user_edited')) has_canon = is_seed or is_llm_canon or is_user_edited or (bool(canon.get('core')) and bool(canon.get('oracle'))) if has_canon: real_canon_count += 1 core = canon.get('core') or '' oracle = canon.get('oracle') or '' layers = canon.get('layers') or [] shadow = canon.get('shadow') or '' asks = canon.get('asks') or '' step = canon.get('step') or '' binds = canon.get('binds') or [] grammar = canon.get('grammar') or { 'operator': dossier.get('operator') or 'substance', 'valence': dossier.get('valence') or 'liminal', 'modifies': '' } else: core = '' oracle = '' layers = [] shadow = (dossier.get('shadow_aspects') and ', '.join(dossier['shadow_aspects'])) or '' asks = '' step = '' binds = [] grammar = { 'operator': dossier.get('operator') or 'substance', 'valence': dossier.get('valence') or 'liminal', 'modifies': '' } entry = { 'id': w_id, 'word': w, 'emoji': w_emoji, 'pos': row.get('pos') or dossier.get('pos') or canon.get('pos') or '', 'category': row.get('category') or dossier.get('category') or canon.get('category') or '', 'family': dossier.get('family') or canon.get('family') or '', 'operator': dossier.get('operator') or (canon.get('grammar') or {}).get('operator') or 'substance', 'valence': dossier.get('valence') or (canon.get('grammar') or {}).get('valence') or 'liminal', 'jurisdictions': dossier.get('jurisdictions') or canon.get('jurisdictions') or ['I'], 'lookup': dossier.get('lookup') or canon.get('lookup') or 'C', 'sources': dossier.get('sources') or [], 'has_canon': has_canon, 'user_edited': is_user_edited, 'core': core, 'oracle': oracle, 'layers': layers, 'shadow': shadow, 'asks': asks, 'step': step, 'binds': binds, 'grammar': grammar, } # Keyed both by word name AND by string id out_data[w] = entry out_data[str(w_id)] = entry OUT_FILE.parent.mkdir(parents=True, exist_ok=True) OUT_FILE.write_text(json.dumps(out_data, ensure_ascii=False, indent=2), encoding='utf-8') print(f'Synchronized {len(lexicon)} words (total keys: {len(out_data)}) into {OUT_FILE} (real canons: {real_canon_count})') if __name__ == '__main__': main()