#!/usr/bin/env python3 """Normaliza el frontmatter de todas las fichas de persona de osint al esquema canonico (projects/osint/CONVENTIONS.md seccion 3b). Preserva valores existentes y campos extra; solo garantiza que todos los campos canonicos esten presentes y en orden, con null/[] por defecto. No toca el body. Idempotente. """ import sys, os, glob sys.path.insert(0, "/home/enmanuel/fn_registry/python/functions") from obsidian import read_obsidian_note, create_obsidian_note OSINT = "/home/enmanuel/Obsidian/osint" CANON = ["tipo", "nombre", "slug", "aliases", "sexo", "fecha_nacimiento", "dni", "telefono", "email", "direccion", "pais", "relaciones", "contexto", "fuente", "tags"] LISTS = {"aliases", "relaciones", "tags"} def main(): n = 0 for fp in sorted(glob.glob(f"{OSINT}/personas/*.md")): base = os.path.basename(fp) if base.startswith("_"): continue f = read_obsidian_note(fp) fm = dict(f["frontmatter"]) slug = os.path.splitext(base)[0] new = {} for k in CANON: if k in fm and fm[k] not in (None, "", []): new[k] = fm[k] else: new[k] = [] if k in LISTS else None # defaults sensatos new["tipo"] = "persona" if not new["nombre"]: new["nombre"] = fm.get("nombre") or slug.replace("-", " ").title() new["slug"] = slug if not new["aliases"]: new["aliases"] = [new["nombre"]] if not new["tags"]: new["tags"] = ["persona", "osint"] if new["fuente"] is None: new["fuente"] = "" # conservar campos extra (horoscopo, etc.) al final for k, v in fm.items(): if k not in new: new[k] = v create_obsidian_note(OSINT, f"personas/{slug}", body=f["body"], frontmatter=new, overwrite=True) n += 1 print(f"fichas de persona normalizadas: {n}") if __name__ == "__main__": main()