diff --git a/worked/civil-law-chile/GRAPH_REPORT.md b/worked/civil-law-chile/GRAPH_REPORT.md
new file mode 100644
index 0000000000..617eb04aa5
--- /dev/null
+++ b/worked/civil-law-chile/GRAPH_REPORT.md
@@ -0,0 +1,98 @@
+# Graph Report - worked-civil-law-chile (2026-09-18)
+
+## Corpus Check
+- 8 files · ~3,010 words
+- Verdict: corpus is large enough that graph structure adds value.
+
+## Summary
+- 72 nodes · 91 edges · 9 communities
+- Extraction: 100% EXTRACTED · 0% INFERRED · 0% AMBIGUOUS
+- Token cost: 0 input · 0 output
+
+## Community Hubs (Navigation)
+- stats_tracker.py
+- LegalGraphBuilder
+- cold_start.py
+- ColdStartInterviewEngine
+- config.py
+- Canon Doctrinal Jurídico Chileno — Open Legal Chile
+- Guía de Audiencia de Conciliación Laboral
+- Guía de Buenas Prácticas Judiciales en Temas Éticos
+- Guía para la Audiencia de Juicio Oral Laboral
+
+## God Nodes (most connected - your core abstractions)
+1. `LegalGraphBuilder` - 8 edges
+2. `safe_urlopen()` - 6 edges
+3. `ColdStartInterviewEngine` - 5 edges
+4. `get_pypi_download_stats()` - 5 edges
+5. `get_github_community_stats()` - 5 edges
+6. `get_suite_adoption_metrics()` - 5 edges
+7. `Canon Doctrinal Jurídico Chileno — Open Legal Chile` - 5 edges
+8. `build_quick_graph()` - 4 edges
+9. `Guía de Audiencia de Conciliación Laboral` - 4 edges
+10. `Guía de Buenas Prácticas Judiciales en Temas Éticos` - 4 edges
+
+## Surprising Connections (you probably didn't know these)
+- `get_github_community_stats()` --calls--> `safe_urlopen()` [EXTRACTED]
+ raw/code/stats_tracker.py → raw/code/config.py
+- `get_pypi_download_stats()` --calls--> `safe_urlopen()` [EXTRACTED]
+ raw/code/stats_tracker.py → raw/code/config.py
+- `send_anonymous_telemetry_ping()` --calls--> `safe_urlopen()` [EXTRACTED]
+ raw/code/stats_tracker.py → raw/code/config.py
+
+## Import Cycles
+- None detected.
+
+## Communities (9 total, 0 thin omitted)
+
+### Community 0 - "stats_tracker.py"
+Cohesion: 0.20
+Nodes (14): Ejecuta una petición HTTP/HTTPS segura validando que el esquema no sea file://…, safe_urlopen(), get_github_community_stats(), get_pypi_download_stats(), get_suite_adoption_metrics(), Any, Open Legal Chile — Rastreador de Estadísticas de Adopción y Telemetría Ética…, Envía un ping anónimo no invasivo para cuantificar instalaciones activas.… (+6 more)
+
+### Community 1 - "LegalGraphBuilder"
+Cohesion: 0.27
+Nodes (6): build_quick_graph(), LegalGraphBuilder, Any, Construye un grafo relacional de forma tolerante a nombres de campos y tipos., Sanitiza identificadores para compatibilidad estricta con la sintaxis de…, Genera diagrama Mermaid compatible con Markdown, GitHub y Antigravity.
+
+### Community 2 - "cold_start.py"
+Cohesion: 0.22
+Nodes (7): json, pathlib, Open Legal Chile — Entrevista de Arranque (Cold-Start Interview) Permite a…, Open Legal Chile — Generador de Grafos de Vínculos y Redes Corporativas…, re, sys, typing
+
+### Community 3 - "ColdStartInterviewEngine"
+Cohesion: 0.36
+Nodes (5): ColdStartInterviewEngine, Any, Motor interactivo para calibrar el perfil de práctica del estudio., Ejecuta la entrevista interactiva por terminal., Guarda el perfil de práctica en practice_profile.json y actualiza directrices.
+
+### Community 4 - "config.py"
+Cohesion: 0.29
+Nodes (6): os, check_configuration(), load_env_file(), Open Legal Chile — Gestor Centralizado de Configuración y Claves de API Carga…, Carga pares clave=valor desde un archivo .env si existe., Verifica el estado del sistema, conectores abiertos y motores de IA.
+
+### Community 5 - "Canon Doctrinal Jurídico Chileno — Open Legal Chile"
+Cohesion: 0.33
+Nodes (5): 🏛️ 1. Obras y Tratados Canónicos Digitalizados por Capítulos, ⚖️ 2. Cumplimiento Estricto de Propiedad Intelectual (Ley N° 17.336), ⚡ 3. Estándar de Optimización de Tokens, 🔍 4. Uso del Motor FTS5 y Herramientas MCP, Canon Doctrinal Jurídico Chileno — Open Legal Chile
+
+### Community 6 - "Guía de Audiencia de Conciliación Laboral"
+Cohesion: 0.40
+Nodes (4): Consulta y Descarga del Documento Original, Guía de Audiencia de Conciliación Laboral, Materia: Laboral | Fecha: 2025-02-15, Resumen Ejecutivo de Práctica Judicial
+
+### Community 7 - "Guía de Buenas Prácticas Judiciales en Temas Éticos"
+Cohesion: 0.40
+Nodes (4): Consulta y Descarga del Documento Original, Guía de Buenas Prácticas Judiciales en Temas Éticos, Materia: Ética Judicial | Fecha: 2026-07-10, Resumen Ejecutivo de Práctica Judicial
+
+### Community 8 - "Guía para la Audiencia de Juicio Oral Laboral"
+Cohesion: 0.40
+Nodes (4): Consulta y Descarga del Documento Original, Guía para la Audiencia de Juicio Oral Laboral, Materia: Laboral | Fecha: 2025-02-15, Resumen Ejecutivo de Práctica Judicial
+
+## Knowledge Gaps
+- **13 isolated node(s):** `🏛️ 1. Obras y Tratados Canónicos Digitalizados por Capítulos`, `⚖️ 2. Cumplimiento Estricto de Propiedad Intelectual (Ley N° 17.336)`, `⚡ 3. Estándar de Optimización de Tokens`, `🔍 4. Uso del Motor FTS5 y Herramientas MCP`, `Materia: Laboral | Fecha: 2025-02-15` (+8 more)
+ These have ≤1 connection - possible missing edges or undocumented components. (Counts symbols only; 39 node(s) total have ≤1 connection when file, concept and rationale nodes are included.)
+
+## Suggested Questions
+_Questions this graph is uniquely positioned to answer:_
+
+- **Why does `LegalGraphBuilder` connect `LegalGraphBuilder` to `cold_start.py`?**
+ _High betweenness centrality (0.137) - this node is a cross-community bridge._
+- **Why does `ColdStartInterviewEngine` connect `ColdStartInterviewEngine` to `cold_start.py`?**
+ _High betweenness centrality (0.124) - this node is a cross-community bridge._
+- **Why does `build_quick_graph()` connect `LegalGraphBuilder` to `cold_start.py`?**
+ _High betweenness centrality (0.036) - this node is a cross-community bridge._
+- **What connects `🏛️ 1. Obras y Tratados Canónicos Digitalizados por Capítulos`, `⚖️ 2. Cumplimiento Estricto de Propiedad Intelectual (Ley N° 17.336)`, `⚡ 3. Estándar de Optimización de Tokens` to the rest of the system?**
+ _13 weakly-connected nodes found - possible documentation gaps or missing edges._
\ No newline at end of file
diff --git a/worked/civil-law-chile/graph.json b/worked/civil-law-chile/graph.json
new file mode 100644
index 0000000000..9d92f18d34
--- /dev/null
+++ b/worked/civil-law-chile/graph.json
@@ -0,0 +1,1907 @@
+{
+ "directed": false,
+ "multigraph": false,
+ "graph": {},
+ "nodes": [
+ {
+ "id": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "label": "LegalGraphBuilder",
+ "_callable": true,
+ "_callable_class": true,
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": "legalgraphbuilder",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L12"
+ },
+ {
+ "id": "raw_code_cold_start_coldstartinterviewengine",
+ "label": "ColdStartInterviewEngine",
+ "_callable": true,
+ "_callable_class": true,
+ "_origin": "ast",
+ "community": 3,
+ "community_name": "ColdStartInterviewEngine",
+ "file_type": "code",
+ "norm_label": "coldstartinterviewengine",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L49"
+ },
+ {
+ "id": "raw_code_config_safe_urlopen",
+ "label": "safe_urlopen()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "code",
+ "norm_label": "safe_urlopen()",
+ "source_file": "raw/code/config.py",
+ "source_location": "L88"
+ },
+ {
+ "id": "raw_code_stats_tracker_get_github_community_stats",
+ "label": "get_github_community_stats()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "code",
+ "norm_label": "get_github_community_stats()",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L63"
+ },
+ {
+ "id": "raw_code_stats_tracker_get_pypi_download_stats",
+ "label": "get_pypi_download_stats()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "code",
+ "norm_label": "get_pypi_download_stats()",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L21"
+ },
+ {
+ "id": "raw_code_stats_tracker_get_suite_adoption_metrics",
+ "label": "get_suite_adoption_metrics()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "code",
+ "norm_label": "get_suite_adoption_metrics()",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L97"
+ },
+ {
+ "id": "raw_code_stats_tracker_send_anonymous_telemetry_ping",
+ "label": "send_anonymous_telemetry_ping()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "code",
+ "norm_label": "send_anonymous_telemetry_ping()",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L134"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_build_quick_graph",
+ "label": "build_quick_graph()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": "build_quick_graph()",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L118"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_legalgraphbuilder_add_edge",
+ "label": ".add_edge()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": ".add_edge()",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L55"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_legalgraphbuilder_add_node",
+ "label": ".add_node()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": ".add_node()",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L43"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_legalgraphbuilder_init",
+ "label": ".__init__()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": ".__init__()",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L25"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_legalgraphbuilder_sanitize_id",
+ "label": "._sanitize_id()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": "._sanitize_id()",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L29"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_legalgraphbuilder_to_dict",
+ "label": ".to_dict()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": ".to_dict()",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L108"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_legalgraphbuilder_to_mermaid",
+ "label": ".to_mermaid()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": ".to_mermaid()",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L65"
+ },
+ {
+ "id": "raw_code_cold_start_coldstartinterviewengine_load_profile",
+ "label": ".load_profile()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 3,
+ "community_name": "ColdStartInterviewEngine",
+ "file_type": "code",
+ "norm_label": ".load_profile()",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L126"
+ },
+ {
+ "id": "raw_code_cold_start_coldstartinterviewengine_run_interactive",
+ "label": ".run_interactive()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 3,
+ "community_name": "ColdStartInterviewEngine",
+ "file_type": "code",
+ "norm_label": ".run_interactive()",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L53"
+ },
+ {
+ "id": "raw_code_cold_start_coldstartinterviewengine_save_profile",
+ "label": ".save_profile()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 3,
+ "community_name": "ColdStartInterviewEngine",
+ "file_type": "code",
+ "norm_label": ".save_profile()",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L82"
+ },
+ {
+ "id": "raw_code_config_check_configuration",
+ "label": "check_configuration()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 4,
+ "community_name": "config.py",
+ "file_type": "code",
+ "norm_label": "check_configuration()",
+ "source_file": "raw/code/config.py",
+ "source_location": "L51"
+ },
+ {
+ "id": "raw_code_config_load_env_file",
+ "label": "load_env_file()",
+ "_callable": true,
+ "_origin": "ast",
+ "community": 4,
+ "community_name": "config.py",
+ "file_type": "code",
+ "norm_label": "load_env_file()",
+ "source_file": "raw/code/config.py",
+ "source_location": "L11"
+ },
+ {
+ "id": "raw_code_stats_tracker",
+ "label": "stats_tracker.py",
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "code",
+ "norm_label": "stats_tracker.py",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_code_stats_tracker_py_any",
+ "label": "Any",
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "code",
+ "norm_label": "any",
+ "source_file": "",
+ "source_location": ""
+ },
+ {
+ "id": "raw_code_config_rationale_89",
+ "label": "Ejecuta una petici\u00f3n HTTP/HTTPS segura validando que el esquema no sea file://\u2026",
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "rationale",
+ "norm_label": "ejecuta una peticion http/https segura validando que el esquema no sea file://...",
+ "source_file": "raw/code/config.py",
+ "source_location": "L89"
+ },
+ {
+ "id": "raw_code_stats_tracker_rationale_1",
+ "label": "Open Legal Chile \u2014 Rastreador de Estad\u00edsticas de Adopci\u00f3n y Telemetr\u00eda \u00c9tica\u2026",
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "rationale",
+ "norm_label": "open legal chile \u2014 rastreador de estadisticas de adopcion y telemetria etica...",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_code_stats_tracker_rationale_135",
+ "label": "Env\u00eda un ping an\u00f3nimo no invasivo para cuantificar instalaciones activas.\u2026",
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "rationale",
+ "norm_label": "envia un ping anonimo no invasivo para cuantificar instalaciones activas....",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L135"
+ },
+ {
+ "id": "raw_code_stats_tracker_rationale_22",
+ "label": "Consulta la API p\u00fablica de PyPI Stats (pypistats.org) para obtener el total de\u2026",
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "rationale",
+ "norm_label": "consulta la api publica de pypi stats (pypistats.org) para obtener el total de...",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L22"
+ },
+ {
+ "id": "raw_code_stats_tracker_rationale_64",
+ "label": "Consulta la API p\u00fablica de GitHub para obtener estrellas, forks y actividad\u2026",
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "rationale",
+ "norm_label": "consulta la api publica de github para obtener estrellas, forks y actividad...",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L64"
+ },
+ {
+ "id": "raw_code_stats_tracker_rationale_98",
+ "label": "Consolida las m\u00e9tricas de adopci\u00f3n globales de Open Legal Chile Suite: PyPI,\u2026",
+ "_origin": "ast",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "file_type": "rationale",
+ "norm_label": "consolida las metricas de adopcion globales de open legal chile suite: pypi,...",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L98"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_py_any",
+ "label": "Any",
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "code",
+ "norm_label": "any",
+ "source_file": "",
+ "source_location": ""
+ },
+ {
+ "id": "raw_code_grafo_vinculos_rationale_123",
+ "label": "Construye un grafo relacional de forma tolerante a nombres de campos y tipos.",
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "rationale",
+ "norm_label": "construye un grafo relacional de forma tolerante a nombres de campos y tipos.",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L123"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_rationale_30",
+ "label": "Sanitiza identificadores para compatibilidad estricta con la sintaxis de\u2026",
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "rationale",
+ "norm_label": "sanitiza identificadores para compatibilidad estricta con la sintaxis de...",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L30"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_rationale_66",
+ "label": "Genera diagrama Mermaid compatible con Markdown, GitHub y Antigravity.",
+ "_origin": "ast",
+ "community": 1,
+ "community_name": "LegalGraphBuilder",
+ "file_type": "rationale",
+ "norm_label": "genera diagrama mermaid compatible con markdown, github y antigravity.",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L66"
+ },
+ {
+ "id": "raw_code_cold_start",
+ "label": "cold_start.py",
+ "_origin": "ast",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "file_type": "code",
+ "norm_label": "cold_start.py",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_code_grafo_vinculos",
+ "label": "grafo_vinculos.py",
+ "_origin": "ast",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "file_type": "code",
+ "norm_label": "grafo_vinculos.py",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_code_cold_start_rationale_1",
+ "label": "Open Legal Chile \u2014 Entrevista de Arranque (Cold-Start Interview) Permite a\u2026",
+ "_origin": "ast",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "file_type": "rationale",
+ "norm_label": "open legal chile \u2014 entrevista de arranque (cold-start interview) permite a...",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_code_grafo_vinculos_rationale_1",
+ "label": "Open Legal Chile \u2014 Generador de Grafos de V\u00ednculos y Redes Corporativas\u2026",
+ "_origin": "ast",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "file_type": "rationale",
+ "norm_label": "open legal chile \u2014 generador de grafos de vinculos y redes corporativas...",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_code_cold_start_py_any",
+ "label": "Any",
+ "_origin": "ast",
+ "community": 3,
+ "community_name": "ColdStartInterviewEngine",
+ "file_type": "code",
+ "norm_label": "any",
+ "source_file": "",
+ "source_location": ""
+ },
+ {
+ "id": "raw_code_cold_start_rationale_50",
+ "label": "Motor interactivo para calibrar el perfil de pr\u00e1ctica del estudio.",
+ "_origin": "ast",
+ "community": 3,
+ "community_name": "ColdStartInterviewEngine",
+ "file_type": "rationale",
+ "norm_label": "motor interactivo para calibrar el perfil de practica del estudio.",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L50"
+ },
+ {
+ "id": "raw_code_cold_start_rationale_54",
+ "label": "Ejecuta la entrevista interactiva por terminal.",
+ "_origin": "ast",
+ "community": 3,
+ "community_name": "ColdStartInterviewEngine",
+ "file_type": "rationale",
+ "norm_label": "ejecuta la entrevista interactiva por terminal.",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L54"
+ },
+ {
+ "id": "raw_code_cold_start_rationale_83",
+ "label": "Guarda el perfil de pr\u00e1ctica en practice_profile.json y actualiza directrices.",
+ "_origin": "ast",
+ "community": 3,
+ "community_name": "ColdStartInterviewEngine",
+ "file_type": "rationale",
+ "norm_label": "guarda el perfil de practica en practice_profile.json y actualiza directrices.",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L83"
+ },
+ {
+ "id": "raw_code_config",
+ "label": "config.py",
+ "_origin": "ast",
+ "community": 4,
+ "community_name": "config.py",
+ "file_type": "code",
+ "norm_label": "config.py",
+ "source_file": "raw/code/config.py",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_code_config_rationale_1",
+ "label": "Open Legal Chile \u2014 Gestor Centralizado de Configuraci\u00f3n y Claves de API Carga\u2026",
+ "_origin": "ast",
+ "community": 4,
+ "community_name": "config.py",
+ "file_type": "rationale",
+ "norm_label": "open legal chile \u2014 gestor centralizado de configuracion y claves de api carga...",
+ "source_file": "raw/code/config.py",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_code_config_rationale_12",
+ "label": "Carga pares clave=valor desde un archivo .env si existe.",
+ "_origin": "ast",
+ "community": 4,
+ "community_name": "config.py",
+ "file_type": "rationale",
+ "norm_label": "carga pares clave=valor desde un archivo .env si existe.",
+ "source_file": "raw/code/config.py",
+ "source_location": "L12"
+ },
+ {
+ "id": "raw_code_config_rationale_52",
+ "label": "Verifica el estado del sistema, conectores abiertos y motores de IA.",
+ "_origin": "ast",
+ "community": 4,
+ "community_name": "config.py",
+ "file_type": "rationale",
+ "norm_label": "verifica el estado del sistema, conectores abiertos y motores de ia.",
+ "source_file": "raw/code/config.py",
+ "source_location": "L52"
+ },
+ {
+ "id": "raw_doctrine_readme",
+ "label": "README.md",
+ "_origin": "ast",
+ "community": 5,
+ "community_name": "Canon Doctrinal Jur\u00eddico Chileno \u2014 Open Legal Chile",
+ "file_type": "document",
+ "node_kind": "page",
+ "norm_label": "readme.md",
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_doctrine_readme_1_obras_y_tratados_can\u00f3nicos_digitalizados_por_cap\u00edtulos",
+ "label": "\ud83c\udfdb\ufe0f 1. Obras y Tratados Can\u00f3nicos Digitalizados por Cap\u00edtulos",
+ "_origin": "ast",
+ "community": 5,
+ "community_name": "Canon Doctrinal Jur\u00eddico Chileno \u2014 Open Legal Chile",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "\ud83c\udfdb\ufe0f 1. obras y tratados canonicos digitalizados por capitulos",
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L7"
+ },
+ {
+ "id": "raw_doctrine_readme_2_cumplimiento_estricto_de_propiedad_intelectual_ley_n_17_336",
+ "label": "\u2696\ufe0f 2. Cumplimiento Estricto de Propiedad Intelectual (Ley N\u00b0 17.336)",
+ "_origin": "ast",
+ "community": 5,
+ "community_name": "Canon Doctrinal Jur\u00eddico Chileno \u2014 Open Legal Chile",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "\u2696\ufe0f 2. cumplimiento estricto de propiedad intelectual (ley n\u00b0 17.336)",
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L24"
+ },
+ {
+ "id": "raw_doctrine_readme_3_est\u00e1ndar_de_optimizaci\u00f3n_de_tokens",
+ "label": "\u26a1 3. Est\u00e1ndar de Optimizaci\u00f3n de Tokens",
+ "_origin": "ast",
+ "community": 5,
+ "community_name": "Canon Doctrinal Jur\u00eddico Chileno \u2014 Open Legal Chile",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "\u26a1 3. estandar de optimizacion de tokens",
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L38"
+ },
+ {
+ "id": "raw_doctrine_readme_4_uso_del_motor_fts5_y_herramientas_mcp",
+ "label": "\ud83d\udd0d 4. Uso del Motor FTS5 y Herramientas MCP",
+ "_origin": "ast",
+ "community": 5,
+ "community_name": "Canon Doctrinal Jur\u00eddico Chileno \u2014 Open Legal Chile",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "\ud83d\udd0d 4. uso del motor fts5 y herramientas mcp",
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L51"
+ },
+ {
+ "id": "raw_doctrine_readme_canon_doctrinal_jur\u00eddico_chileno_open_legal_chile",
+ "label": "Canon Doctrinal Jur\u00eddico Chileno \u2014 Open Legal Chile",
+ "_origin": "ast",
+ "community": 5,
+ "community_name": "Canon Doctrinal Jur\u00eddico Chileno \u2014 Open Legal Chile",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "canon doctrinal juridico chileno \u2014 open legal chile",
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_doctrine_aj_conciliacion_laboral",
+ "label": "aj_conciliacion_laboral.md",
+ "_origin": "ast",
+ "community": 6,
+ "community_name": "Gu\u00eda de Audiencia de Conciliaci\u00f3n Laboral",
+ "file_type": "document",
+ "frontmatter": {
+ "id": "aj_conciliacion_laboral",
+ "titulo": "Gu\u00eda de Audiencia de Conciliaci\u00f3n Laboral",
+ "autor": "Academia Judicial de Chile",
+ "materia": "Laboral",
+ "fecha": "2025-02-15",
+ "fuente": "https://guias.academiajudicial.cl/guias/juzgados_laborales/Guia_Audiencia_Conciliacion_Laboral_v2.1.pdf"
+ },
+ "node_kind": "page",
+ "norm_label": "aj_conciliacion_laboral.md",
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_doctrine_aj_conciliacion_laboral_consulta_y_descarga_del_documento_original",
+ "label": "Consulta y Descarga del Documento Original",
+ "_origin": "ast",
+ "community": 6,
+ "community_name": "Gu\u00eda de Audiencia de Conciliaci\u00f3n Laboral",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "consulta y descarga del documento original",
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L20"
+ },
+ {
+ "id": "raw_doctrine_aj_conciliacion_laboral_gu\u00eda_de_audiencia_de_conciliaci\u00f3n_laboral",
+ "label": "Gu\u00eda de Audiencia de Conciliaci\u00f3n Laboral",
+ "_origin": "ast",
+ "community": 6,
+ "community_name": "Gu\u00eda de Audiencia de Conciliaci\u00f3n Laboral",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "guia de audiencia de conciliacion laboral",
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L10"
+ },
+ {
+ "id": "raw_doctrine_aj_conciliacion_laboral_materia_laboral_fecha_2025_02_15",
+ "label": "Materia: Laboral | Fecha: 2025-02-15",
+ "_origin": "ast",
+ "community": 6,
+ "community_name": "Gu\u00eda de Audiencia de Conciliaci\u00f3n Laboral",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "materia: laboral | fecha: 2025-02-15",
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L14"
+ },
+ {
+ "id": "raw_doctrine_aj_conciliacion_laboral_resumen_ejecutivo_de_pr\u00e1ctica_judicial",
+ "label": "Resumen Ejecutivo de Pr\u00e1ctica Judicial",
+ "_origin": "ast",
+ "community": 6,
+ "community_name": "Gu\u00eda de Audiencia de Conciliaci\u00f3n Laboral",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "resumen ejecutivo de practica judicial",
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L16"
+ },
+ {
+ "id": "raw_doctrine_aj_etica_judicial",
+ "label": "aj_etica_judicial.md",
+ "_origin": "ast",
+ "community": 7,
+ "community_name": "Gu\u00eda de Buenas Pr\u00e1cticas Judiciales en Temas \u00c9ticos",
+ "file_type": "document",
+ "frontmatter": {
+ "id": "aj_etica_judicial",
+ "titulo": "Gu\u00eda de Buenas Pr\u00e1cticas Judiciales en Temas \u00c9ticos",
+ "autor": "Academia Judicial de Chile",
+ "materia": "\u00c9tica Judicial",
+ "fecha": "2026-07-10",
+ "fuente": "https://guias.academiajudicial.cl/guias/guia_etica/Guia_Etica_10jul_2026.pdf"
+ },
+ "node_kind": "page",
+ "norm_label": "aj_etica_judicial.md",
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_doctrine_aj_etica_judicial_consulta_y_descarga_del_documento_original",
+ "label": "Consulta y Descarga del Documento Original",
+ "_origin": "ast",
+ "community": 7,
+ "community_name": "Gu\u00eda de Buenas Pr\u00e1cticas Judiciales en Temas \u00c9ticos",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "consulta y descarga del documento original",
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L20"
+ },
+ {
+ "id": "raw_doctrine_aj_etica_judicial_gu\u00eda_de_buenas_pr\u00e1cticas_judiciales_en_temas_\u00e9ticos",
+ "label": "Gu\u00eda de Buenas Pr\u00e1cticas Judiciales en Temas \u00c9ticos",
+ "_origin": "ast",
+ "community": 7,
+ "community_name": "Gu\u00eda de Buenas Pr\u00e1cticas Judiciales en Temas \u00c9ticos",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "guia de buenas practicas judiciales en temas eticos",
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L10"
+ },
+ {
+ "id": "raw_doctrine_aj_etica_judicial_materia_\u00e9tica_judicial_fecha_2026_07_10",
+ "label": "Materia: \u00c9tica Judicial | Fecha: 2026-07-10",
+ "_origin": "ast",
+ "community": 7,
+ "community_name": "Gu\u00eda de Buenas Pr\u00e1cticas Judiciales en Temas \u00c9ticos",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "materia: etica judicial | fecha: 2026-07-10",
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L14"
+ },
+ {
+ "id": "raw_doctrine_aj_etica_judicial_resumen_ejecutivo_de_pr\u00e1ctica_judicial",
+ "label": "Resumen Ejecutivo de Pr\u00e1ctica Judicial",
+ "_origin": "ast",
+ "community": 7,
+ "community_name": "Gu\u00eda de Buenas Pr\u00e1cticas Judiciales en Temas \u00c9ticos",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "resumen ejecutivo de practica judicial",
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L16"
+ },
+ {
+ "id": "raw_doctrine_aj_juicio_oral_laboral",
+ "label": "aj_juicio_oral_laboral.md",
+ "_origin": "ast",
+ "community": 8,
+ "community_name": "Gu\u00eda para la Audiencia de Juicio Oral Laboral",
+ "file_type": "document",
+ "frontmatter": {
+ "id": "aj_juicio_oral_laboral",
+ "titulo": "Gu\u00eda para la Audiencia de Juicio Oral Laboral",
+ "autor": "Academia Judicial de Chile",
+ "materia": "Laboral",
+ "fecha": "2025-02-15",
+ "fuente": "https://guias.academiajudicial.cl/guias/juzgados_laborales/Guia_Audiencia_Juicio_Oral_Laboral.pdf"
+ },
+ "node_kind": "page",
+ "norm_label": "aj_juicio_oral_laboral.md",
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L1"
+ },
+ {
+ "id": "raw_doctrine_aj_juicio_oral_laboral_consulta_y_descarga_del_documento_original",
+ "label": "Consulta y Descarga del Documento Original",
+ "_origin": "ast",
+ "community": 8,
+ "community_name": "Gu\u00eda para la Audiencia de Juicio Oral Laboral",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "consulta y descarga del documento original",
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L20"
+ },
+ {
+ "id": "raw_doctrine_aj_juicio_oral_laboral_gu\u00eda_para_la_audiencia_de_juicio_oral_laboral",
+ "label": "Gu\u00eda para la Audiencia de Juicio Oral Laboral",
+ "_origin": "ast",
+ "community": 8,
+ "community_name": "Gu\u00eda para la Audiencia de Juicio Oral Laboral",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "guia para la audiencia de juicio oral laboral",
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L10"
+ },
+ {
+ "id": "raw_doctrine_aj_juicio_oral_laboral_materia_laboral_fecha_2025_02_15",
+ "label": "Materia: Laboral | Fecha: 2025-02-15",
+ "_origin": "ast",
+ "community": 8,
+ "community_name": "Gu\u00eda para la Audiencia de Juicio Oral Laboral",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "materia: laboral | fecha: 2025-02-15",
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L14"
+ },
+ {
+ "id": "raw_doctrine_aj_juicio_oral_laboral_resumen_ejecutivo_de_pr\u00e1ctica_judicial",
+ "label": "Resumen Ejecutivo de Pr\u00e1ctica Judicial",
+ "_origin": "ast",
+ "community": 8,
+ "community_name": "Gu\u00eda para la Audiencia de Juicio Oral Laboral",
+ "file_type": "document",
+ "node_kind": "heading",
+ "norm_label": "resumen ejecutivo de practica judicial",
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L16"
+ },
+ {
+ "id": "urllib_error",
+ "label": "urllib_error",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "external": true,
+ "file_type": "concept",
+ "norm_label": "urllib_error",
+ "source_file": "",
+ "type": "external"
+ },
+ {
+ "id": "urllib_request",
+ "label": "urllib_request",
+ "community": 0,
+ "community_name": "stats_tracker.py",
+ "external": true,
+ "file_type": "concept",
+ "norm_label": "urllib_request",
+ "source_file": "",
+ "type": "external"
+ },
+ {
+ "id": "json",
+ "label": "json",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "external": true,
+ "file_type": "concept",
+ "norm_label": "json",
+ "source_file": "",
+ "type": "external"
+ },
+ {
+ "id": "pathlib",
+ "label": "pathlib",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "external": true,
+ "file_type": "concept",
+ "norm_label": "pathlib",
+ "source_file": "",
+ "type": "external"
+ },
+ {
+ "id": "re",
+ "label": "re",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "external": true,
+ "file_type": "concept",
+ "norm_label": "re",
+ "source_file": "",
+ "type": "external"
+ },
+ {
+ "id": "sys",
+ "label": "sys",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "external": true,
+ "file_type": "concept",
+ "norm_label": "sys",
+ "source_file": "",
+ "type": "external"
+ },
+ {
+ "id": "typing",
+ "label": "typing",
+ "community": 2,
+ "community_name": "cold_start.py",
+ "external": true,
+ "file_type": "concept",
+ "norm_label": "typing",
+ "source_file": "",
+ "type": "external"
+ },
+ {
+ "id": "os",
+ "label": "os",
+ "community": 4,
+ "community_name": "config.py",
+ "external": true,
+ "file_type": "concept",
+ "norm_label": "os",
+ "source_file": "",
+ "type": "external"
+ }
+ ],
+ "links": [
+ {
+ "source": "raw_code_cold_start_coldstartinterviewengine_run_interactive",
+ "target": "raw_code_cold_start_coldstartinterviewengine_save_profile",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L79",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_build_quick_graph",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L124",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder_add_edge",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_sanitize_id",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L56",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder_add_node",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_sanitize_id",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L44",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder_to_dict",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_to_mermaid",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L114",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_get_github_community_stats",
+ "target": "raw_code_config_safe_urlopen",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L85",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_get_pypi_download_stats",
+ "target": "raw_code_config_safe_urlopen",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L42",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_get_suite_adoption_metrics",
+ "target": "raw_code_stats_tracker_get_pypi_download_stats",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L102",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_get_suite_adoption_metrics",
+ "target": "raw_code_stats_tracker_get_github_community_stats",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L103",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_send_anonymous_telemetry_ping",
+ "target": "raw_code_config_safe_urlopen",
+ "relation": "calls",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "call",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L150",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_coldstartinterviewengine_load_profile",
+ "target": "raw_code_cold_start_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L126",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_coldstartinterviewengine_run_interactive",
+ "target": "raw_code_cold_start_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L53",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_coldstartinterviewengine_save_profile",
+ "target": "raw_code_cold_start_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L82",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_build_quick_graph",
+ "target": "raw_code_grafo_vinculos_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L118",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder_add_node",
+ "target": "raw_code_grafo_vinculos_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L43",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder_to_dict",
+ "target": "raw_code_grafo_vinculos_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L108",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_get_github_community_stats",
+ "target": "raw_code_stats_tracker_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L63",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_get_pypi_download_stats",
+ "target": "raw_code_stats_tracker_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L21",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_get_suite_adoption_metrics",
+ "target": "raw_code_stats_tracker_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "generic_arg",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L97",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start",
+ "target": "json",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L10",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start",
+ "target": "os",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L8",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start",
+ "target": "sys",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L9",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config",
+ "target": "os",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/config.py",
+ "source_location": "L7",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos",
+ "target": "re",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L8",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "urllib_request",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L10",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "urllib_error",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L11",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "raw_code_config_safe_urlopen",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L14",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "os",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L7",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "sys",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L8",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "json",
+ "relation": "imports",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L9",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start",
+ "target": "pathlib",
+ "relation": "imports_from",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L11",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start",
+ "target": "typing",
+ "relation": "imports_from",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L12",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config",
+ "target": "typing",
+ "relation": "imports_from",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/config.py",
+ "source_location": "L8",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos",
+ "target": "typing",
+ "relation": "imports_from",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L9",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "typing",
+ "relation": "imports_from",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L12",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "raw_code_config",
+ "relation": "imports_from",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "import",
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L14",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder_add_edge",
+ "target": "raw_code_grafo_vinculos_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "parameter_type",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L55",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder_sanitize_id",
+ "target": "raw_code_grafo_vinculos_py_any",
+ "relation": "references",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "context": "parameter_type",
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L29",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start",
+ "target": "raw_code_cold_start_coldstartinterviewengine",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L49",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config",
+ "target": "raw_code_config_load_env_file",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/config.py",
+ "source_location": "L11",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config",
+ "target": "raw_code_config_check_configuration",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/config.py",
+ "source_location": "L51",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config",
+ "target": "raw_code_config_safe_urlopen",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/config.py",
+ "source_location": "L88",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos",
+ "target": "raw_code_grafo_vinculos_build_quick_graph",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L118",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L12",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "raw_code_stats_tracker_send_anonymous_telemetry_ping",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L134",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "raw_code_stats_tracker_get_pypi_download_stats",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L21",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "raw_code_stats_tracker_get_github_community_stats",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L63",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker",
+ "target": "raw_code_stats_tracker_get_suite_adoption_metrics",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L97",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_conciliacion_laboral",
+ "target": "raw_doctrine_aj_conciliacion_laboral_gu\u00eda_de_audiencia_de_conciliaci\u00f3n_laboral",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L10",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_conciliacion_laboral_gu\u00eda_de_audiencia_de_conciliaci\u00f3n_laboral",
+ "target": "raw_doctrine_aj_conciliacion_laboral_materia_laboral_fecha_2025_02_15",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L14",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_conciliacion_laboral_gu\u00eda_de_audiencia_de_conciliaci\u00f3n_laboral",
+ "target": "raw_doctrine_aj_conciliacion_laboral_resumen_ejecutivo_de_pr\u00e1ctica_judicial",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L16",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_conciliacion_laboral_gu\u00eda_de_audiencia_de_conciliaci\u00f3n_laboral",
+ "target": "raw_doctrine_aj_conciliacion_laboral_consulta_y_descarga_del_documento_original",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_conciliacion_laboral.md",
+ "source_location": "L20",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_etica_judicial",
+ "target": "raw_doctrine_aj_etica_judicial_gu\u00eda_de_buenas_pr\u00e1cticas_judiciales_en_temas_\u00e9ticos",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L10",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_etica_judicial_gu\u00eda_de_buenas_pr\u00e1cticas_judiciales_en_temas_\u00e9ticos",
+ "target": "raw_doctrine_aj_etica_judicial_materia_\u00e9tica_judicial_fecha_2026_07_10",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L14",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_etica_judicial_gu\u00eda_de_buenas_pr\u00e1cticas_judiciales_en_temas_\u00e9ticos",
+ "target": "raw_doctrine_aj_etica_judicial_resumen_ejecutivo_de_pr\u00e1ctica_judicial",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L16",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_etica_judicial_gu\u00eda_de_buenas_pr\u00e1cticas_judiciales_en_temas_\u00e9ticos",
+ "target": "raw_doctrine_aj_etica_judicial_consulta_y_descarga_del_documento_original",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_etica_judicial.md",
+ "source_location": "L20",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_juicio_oral_laboral",
+ "target": "raw_doctrine_aj_juicio_oral_laboral_gu\u00eda_para_la_audiencia_de_juicio_oral_laboral",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L10",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_juicio_oral_laboral_gu\u00eda_para_la_audiencia_de_juicio_oral_laboral",
+ "target": "raw_doctrine_aj_juicio_oral_laboral_materia_laboral_fecha_2025_02_15",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L14",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_juicio_oral_laboral_gu\u00eda_para_la_audiencia_de_juicio_oral_laboral",
+ "target": "raw_doctrine_aj_juicio_oral_laboral_resumen_ejecutivo_de_pr\u00e1ctica_judicial",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L16",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_aj_juicio_oral_laboral_gu\u00eda_para_la_audiencia_de_juicio_oral_laboral",
+ "target": "raw_doctrine_aj_juicio_oral_laboral_consulta_y_descarga_del_documento_original",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/aj_juicio_oral_laboral.md",
+ "source_location": "L20",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_readme",
+ "target": "raw_doctrine_readme_canon_doctrinal_jur\u00eddico_chileno_open_legal_chile",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L1",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_readme_canon_doctrinal_jur\u00eddico_chileno_open_legal_chile",
+ "target": "raw_doctrine_readme_2_cumplimiento_estricto_de_propiedad_intelectual_ley_n_17_336",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L24",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_readme_canon_doctrinal_jur\u00eddico_chileno_open_legal_chile",
+ "target": "raw_doctrine_readme_3_est\u00e1ndar_de_optimizaci\u00f3n_de_tokens",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L38",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_readme_canon_doctrinal_jur\u00eddico_chileno_open_legal_chile",
+ "target": "raw_doctrine_readme_4_uso_del_motor_fts5_y_herramientas_mcp",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L51",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_doctrine_readme_canon_doctrinal_jur\u00eddico_chileno_open_legal_chile",
+ "target": "raw_doctrine_readme_1_obras_y_tratados_can\u00f3nicos_digitalizados_por_cap\u00edtulos",
+ "relation": "contains",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/doctrine/README.md",
+ "source_location": "L7",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_coldstartinterviewengine",
+ "target": "raw_code_cold_start_coldstartinterviewengine_load_profile",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L126",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_coldstartinterviewengine",
+ "target": "raw_code_cold_start_coldstartinterviewengine_run_interactive",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L53",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_coldstartinterviewengine",
+ "target": "raw_code_cold_start_coldstartinterviewengine_save_profile",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L82",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_to_dict",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L108",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_init",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L25",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_sanitize_id",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L29",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_add_node",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L43",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_add_edge",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L55",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_legalgraphbuilder",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_to_mermaid",
+ "relation": "method",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L65",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_rationale_1",
+ "target": "raw_code_cold_start",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L1",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_rationale_50",
+ "target": "raw_code_cold_start_coldstartinterviewengine",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L50",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_rationale_54",
+ "target": "raw_code_cold_start_coldstartinterviewengine_run_interactive",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L54",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_cold_start_rationale_83",
+ "target": "raw_code_cold_start_coldstartinterviewengine_save_profile",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/cold_start.py",
+ "source_location": "L83",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config_rationale_1",
+ "target": "raw_code_config",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/config.py",
+ "source_location": "L1",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config_rationale_12",
+ "target": "raw_code_config_load_env_file",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/config.py",
+ "source_location": "L12",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config_rationale_52",
+ "target": "raw_code_config_check_configuration",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/config.py",
+ "source_location": "L52",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_config_rationale_89",
+ "target": "raw_code_config_safe_urlopen",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/config.py",
+ "source_location": "L89",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_rationale_1",
+ "target": "raw_code_grafo_vinculos",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L1",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_rationale_123",
+ "target": "raw_code_grafo_vinculos_build_quick_graph",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L123",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_rationale_30",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_sanitize_id",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L30",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_grafo_vinculos_rationale_66",
+ "target": "raw_code_grafo_vinculos_legalgraphbuilder_to_mermaid",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/grafo_vinculos.py",
+ "source_location": "L66",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_rationale_1",
+ "target": "raw_code_stats_tracker",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L1",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_rationale_135",
+ "target": "raw_code_stats_tracker_send_anonymous_telemetry_ping",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L135",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_rationale_22",
+ "target": "raw_code_stats_tracker_get_pypi_download_stats",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L22",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_rationale_64",
+ "target": "raw_code_stats_tracker_get_github_community_stats",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L64",
+ "weight": 1.0
+ },
+ {
+ "source": "raw_code_stats_tracker_rationale_98",
+ "target": "raw_code_stats_tracker_get_suite_adoption_metrics",
+ "relation": "rationale_for",
+ "_origin": "ast",
+ "confidence": "EXTRACTED",
+ "confidence_score": 1.0,
+ "source_file": "raw/code/stats_tracker.py",
+ "source_location": "L98",
+ "weight": 1.0
+ }
+ ],
+ "hyperedges": []
+}
\ No newline at end of file
diff --git a/worked/civil-law-chile/raw/code/cold_start.py b/worked/civil-law-chile/raw/code/cold_start.py
new file mode 100644
index 0000000000..d41765d5ec
--- /dev/null
+++ b/worked/civil-law-chile/raw/code/cold_start.py
@@ -0,0 +1,131 @@
+"""
+Open Legal Chile — Entrevista de Arranque (Cold-Start Interview)
+Permite a cualquier abogado o estudio jurídico configurar su perfil de práctica,
+tono de litigación y preferencias dogmáticas para que los modelos de IA
+redacten con la identidad y el estilo propio del despacho.
+"""
+
+import os
+import sys
+import json
+from pathlib import Path
+from typing import Dict, Any, Optional, List
+
+PROFILE_FILE = "practice_profile.json"
+
+DEFAULT_QUESTIONS: List[Dict[str, Any]] = [
+ {
+ "id": "firm_name",
+ "pregunta": "¿Cuál es el nombre de su estudio jurídico o su nombre como abogado/a?",
+ "default": "Abogado Independiente"
+ },
+ {
+ "id": "jurisdiction",
+ "pregunta": "¿En qué jurisdicción y tribunales litiga principalmente? (Ej. Santiago - Civil y Laboral, Concepción, etc.)",
+ "default": "Santiago — Tribunales Civiles, Laborales y Cortes de Apelaciones"
+ },
+ {
+ "id": "tone",
+ "pregunta": "¿Cuál es su tono preferido de redacción en escritos y demandas? (1: Formal tradicional, 2: Combativo y riguroso, 3: Conciliador)",
+ "opciones": {
+ "1": "Formal tradicional (estilo judicial sobrio con fórmulas sacramentales)",
+ "2": "Combativo y riguroso (énfasis en tipicidad, causalidad y jurisprudencia dura)",
+ "3": "Conciliador y propositivo (enfoque en resolución rápida de controversias)"
+ },
+ "default": "1"
+ },
+ {
+ "id": "doctrina_preference",
+ "pregunta": "En responsabilidad civil extracontractual, ¿qué criterio doctrinario prefiere citar? (1: Barros Bourie, 2: Alessandri Rodríguez, 3: Ambos)",
+ "opciones": {
+ "1": "Enrique Barros Bourie (Tratado contemporáneo y estándares de conducta)",
+ "2": "Arturo Alessandri Rodríguez (Doctrina clásica)",
+ "3": "Ambos en complementación armónica"
+ },
+ "default": "1"
+ }
+]
+
+class ColdStartInterviewEngine:
+ """Motor interactivo para calibrar el perfil de práctica del estudio."""
+
+ @staticmethod
+ def run_interactive(base_dir: str = ".") -> Dict[str, Any]:
+ """
+ Ejecuta la entrevista interactiva por terminal.
+ """
+ print("\n" + "="*70)
+ print("🏛️ OPEN LEGAL CHILE — ENTREVISTA DE ARRANQUE (COLD-START INTERVIEW)")
+ print("Personalice en 60 segundos el tono, jurisdicción y dogmática de sus agentes.")
+ print("="*70 + "\n")
+
+ respuestas = {}
+ for q in DEFAULT_QUESTIONS:
+ print(f"👉 {q['pregunta']}")
+ if "opciones" in q:
+ for k, v in q["opciones"].items():
+ print(f" [{k}] {v}")
+ val = input(f"Respuesta (Enter para '{q['default']}'): ").strip()
+ if not val:
+ val = q["default"]
+
+ # Si es opción numérica, resolver
+ if "opciones" in q and val in q["opciones"]:
+ respuestas[q["id"]] = q["opciones"][val]
+ else:
+ respuestas[q["id"]] = val
+ print()
+
+ return ColdStartInterviewEngine.save_profile(respuestas, base_dir=base_dir)
+
+ @staticmethod
+ def save_profile(respuestas: Dict[str, Any], base_dir: str = ".") -> Dict[str, Any]:
+ """
+ Guarda el perfil de práctica en practice_profile.json y actualiza directrices.
+ """
+ out_path = os.path.join(base_dir, PROFILE_FILE)
+ with open(out_path, "w", encoding="utf-8") as f:
+ json.dump(respuestas, f, indent=2, ensure_ascii=False)
+
+ # Actualizar sección en CLAUDE.md si existe
+ claude_md = os.path.join(base_dir, "CLAUDE.md")
+ if os.path.exists(claude_md):
+ try:
+ with open(claude_md, "r", encoding="utf-8") as f:
+ content = f.read()
+
+ profile_snippet = (
+ f"\n\n\n"
+ f"## 🏛️ Perfil de Práctica del Despacho ({respuestas.get('firm_name')})\n"
+ f"- **Jurisdicción:** {respuestas.get('jurisdiction')}\n"
+ f"- **Tono procesal:** {respuestas.get('tone')}\n"
+ f"- **Criterio doctrinal civil:** {respuestas.get('doctrina_preference')}\n"
+ f"\n"
+ )
+
+ if "" in content:
+ start = content.find("")
+ end = content.find("") + len("")
+ content = content[:start] + profile_snippet.strip() + content[end:]
+ else:
+ content += profile_snippet
+
+ with open(claude_md, "w", encoding="utf-8") as f:
+ f.write(content)
+ except Exception as e:
+ sys.stderr.write(f"No se pudo actualizar CLAUDE.md: {e}\n")
+
+ print("="*70)
+ print("✅ PERFIL DE PRÁCTICA REGISTRADO EXITOSAMENTE")
+ print(f"Archivo generado: {out_path}")
+ print("Los agentes redactarán automáticamente con la identidad de su firma.")
+ print("="*70 + "\n")
+ return respuestas
+
+ @staticmethod
+ def load_profile(base_dir: str = ".") -> Optional[Dict[str, Any]]:
+ out_path = os.path.join(base_dir, PROFILE_FILE)
+ if os.path.exists(out_path):
+ with open(out_path, "r", encoding="utf-8") as f:
+ return json.load(f)
+ return None
diff --git a/worked/civil-law-chile/raw/code/config.py b/worked/civil-law-chile/raw/code/config.py
new file mode 100644
index 0000000000..9c7e357508
--- /dev/null
+++ b/worked/civil-law-chile/raw/code/config.py
@@ -0,0 +1,110 @@
+"""
+Open Legal Chile — Gestor Centralizado de Configuración y Claves de API
+Carga automáticamente las variables de entorno desde el archivo .env local
+o desde las variables del sistema operativo sin dependencias externas.
+"""
+
+import os
+from typing import Optional
+
+
+def load_env_file(filepath: Optional[str] = None) -> None:
+ """Carga pares clave=valor desde un archivo .env si existe."""
+ if filepath is None:
+ filepath = os.path.join(os.path.dirname(__file__), ".env")
+
+ if not os.path.exists(filepath):
+ return
+
+ try:
+ with open(filepath, "r", encoding="utf-8") as f:
+ for line in f:
+ line = line.strip()
+ if not line or line.startswith("#") or "=" not in line:
+ continue
+ key, val = line.split("=", 1)
+ key = key.strip()
+ val = val.strip().strip("'\"")
+ if key and key not in os.environ:
+ os.environ[key] = val
+ except Exception as e:
+ print(f"[Aviso] No se pudo leer el archivo .env: {e}")
+
+
+# Cargar variables de entorno al importar el módulo
+load_env_file()
+
+# Configuraciones y credenciales del Estado
+BCN_API_KEY: str = os.getenv("BCN_API_KEY", "")
+CNE_EMAIL: str = os.getenv("CNE_EMAIL", "")
+CNE_PASSWORD: str = os.getenv("CNE_PASSWORD", "")
+PORT: int = int(os.getenv("PORT", "8000"))
+
+# Proveedores de Inteligencia Artificial (BYOK - Bring Your Own Key)
+ANTHROPIC_API_KEY: str = os.getenv("ANTHROPIC_API_KEY", "")
+GEMINI_API_KEY: str = os.getenv("GEMINI_API_KEY", "")
+DEEPSEEK_API_KEY: str = os.getenv("DEEPSEEK_API_KEY", "")
+OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "")
+OLLAMA_HOST: str = os.getenv("OLLAMA_HOST", "http://localhost:11434")
+
+# Verificación de credenciales y estado soberano
+def check_configuration() -> dict:
+ """Verifica el estado del sistema, conectores abiertos y motores de IA."""
+ ollama_active = False
+ try:
+ import socket
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.settimeout(0.3)
+ res = sock.connect_ex(("localhost", 11434))
+ sock.close()
+ ollama_active = (res == 0)
+ except Exception:
+ ollama_active = False
+
+ return {
+ "OPEN_SOURCE_SOBERANO": True,
+ "OLLAMA_ACTIVE": ollama_active,
+ "CONNECTORS_OPEN": {
+ "bcn": True,
+ "cgr": True,
+ "dt": True,
+ "pjud": True,
+ "cmf": True,
+ "sii": True,
+ "sma": True,
+ "tdlc": True,
+ "panel_expertos": True,
+ "cne": True
+ },
+ "OPTIONAL_COMMERCIAL_PROVIDERS": {
+ "anthropic": bool(ANTHROPIC_API_KEY and not ANTHROPIC_API_KEY.startswith("tu_")),
+ "gemini": bool(GEMINI_API_KEY and not GEMINI_API_KEY.startswith("tu_")),
+ "deepseek": bool(DEEPSEEK_API_KEY and not DEEPSEEK_API_KEY.startswith("tu_")),
+ "openai": bool(OPENAI_API_KEY and not OPENAI_API_KEY.startswith("tu_")),
+ }
+ }
+
+
+def safe_urlopen(req, timeout: float = 30.0):
+ """Ejecuta una petición HTTP/HTTPS segura validando que el esquema no sea file:// ni arbitrario."""
+ import urllib.request
+ url = req.full_url if hasattr(req, "full_url") else str(req)
+ if not (url.startswith("http://") or url.startswith("https://")):
+ raise ValueError(f"Esquema de URL no permitido por políticas de seguridad: {url}")
+ # nosemgrep: python.lang.security.audit.dynamic-urllib-use-detected.dynamic-urllib-use-detected
+ return urllib.request.urlopen(req, timeout=timeout) # nosec B310
+
+
+if __name__ == "__main__":
+ status = check_configuration()
+ print("\n================================================================================")
+ print(" ⚖️ OPEN LEGAL CHILE — ESTADO DEL SISTEMA (100% OPEN SOURCE & SOBERANO) ⚖️")
+ print("================================================================================")
+ print(" • Motor Jurídico Soberano: ✅ OPERATIVO (100% Local, Cero API Keys, $0)")
+ print(f" • Motor Ollama (Modelos Libres): {'🟢 Activo (localhost:11434)' if status['OLLAMA_ACTIVE'] else '⚪ Inactivo (Opcional para modelos de pesos libres)'}")
+ print(" • 10 Conectores del Estado: ✅ 100% OPERATIVOS Y PÚBLICOS (BCN, CGR, DT, PJUD, etc.)")
+ print("\n🔌 Proveedores Comerciales Propietarios (Opcionales de Terceros — No Requeridos):")
+ for prov, configured in status["OPTIONAL_COMMERCIAL_PROVIDERS"].items():
+ print(f" - {prov.capitalize()}: {'✅ Configurado' if configured else '⚪ No configurado (opcional)'}")
+ print("--------------------------------------------------------------------------------\n")
+
diff --git a/worked/civil-law-chile/raw/code/grafo_vinculos.py b/worked/civil-law-chile/raw/code/grafo_vinculos.py
new file mode 100644
index 0000000000..60e2e1de1b
--- /dev/null
+++ b/worked/civil-law-chile/raw/code/grafo_vinculos.py
@@ -0,0 +1,158 @@
+"""
+Open Legal Chile — Generador de Grafos de Vínculos y Redes Corporativas
+Construye redes relacionales entre personas de interés, autoridades, sociedades,
+bienes raíces, resoluciones sancionatorias y causas judiciales.
+Exporta en código Mermaid (renderizable en Markdown/Chats) y JSON relacional.
+"""
+
+import re
+from typing import List, Dict, Any, Optional, Union
+
+
+class LegalGraphBuilder:
+ # Paleta de colores institucionales para categorías forenses
+ CATEGORY_STYLES = {
+ "sociedad": "fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,color:#0d47a1",
+ "empresa": "fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,color:#0d47a1",
+ "persona": "fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:#1b5e20",
+ "autoridad": "fill:#fff8e1,stroke:#f57f17,stroke-width:2px,color:#e65100",
+ "organismo": "fill:#ede7f6,stroke:#512da8,stroke-width:2px,color:#311b92",
+ "causa": "fill:#ffebee,stroke:#c62828,stroke-width:2px,color:#b71c1c",
+ "sancion": "fill:#fbe9e7,stroke:#d84315,stroke-width:2px,color:#bf360c",
+ "inmueble": "fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#4a148c"
+ }
+
+ def __init__(self):
+ self.nodes = {}
+ self.edges = []
+
+ def _sanitize_id(self, raw_id: Any) -> str:
+ """Sanitiza identificadores para compatibilidad estricta con la sintaxis de Mermaid."""
+ if raw_id is None:
+ raw_id = "node"
+ s = str(raw_id).strip()
+ # Reemplazar caracteres no alfanuméricos por guión bajo
+ clean = re.sub(r'[^a-zA-Z0-9_]', '_', s).strip('_')
+ if not clean:
+ clean = "nodo"
+ # Mermaid falla si el identificador comienza con dígito
+ if clean[0].isdigit():
+ clean = f"id_{clean}"
+ return clean
+
+ def add_node(self, node_id: Any, label: str, category: str = "sociedad", metadata: Optional[Dict[str, Any]] = None) -> str:
+ clean_id = self._sanitize_id(node_id)
+ lbl = str(label if label is not None else clean_id).strip()
+ cat = str(category or "sociedad").lower().strip()
+ self.nodes[clean_id] = {
+ "id": clean_id,
+ "label": lbl,
+ "category": cat,
+ "metadata": metadata or {}
+ }
+ return clean_id
+
+ def add_edge(self, source_id: Any, target_id: Any, relation: str = ""):
+ src = self._sanitize_id(source_id)
+ tgt = self._sanitize_id(target_id)
+ rel = str(relation or "").strip()
+ self.edges.append({
+ "source": src,
+ "target": tgt,
+ "relation": rel
+ })
+
+ def to_mermaid(self, title: str = "Red de Vínculos") -> str:
+ """Genera diagrama Mermaid compatible con Markdown, GitHub y Antigravity."""
+ lines = [
+ "```mermaid",
+ "---",
+ f"title: {title}",
+ "---",
+ "graph TD",
+ " %% Estilos por Categoría",
+ " classDef sociedad fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,color:#0d47a1;",
+ " classDef persona fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:#1b5e20;",
+ " classDef autoridad fill:#fff8e1,stroke:#f57f17,stroke-width:2px,color:#e65100;",
+ " classDef organismo fill:#ede7f6,stroke:#512da8,stroke-width:2px,color:#311b92;",
+ " classDef causa fill:#ffebee,stroke:#c62828,stroke-width:2px,color:#b71c1c;",
+ " classDef sancion fill:#fbe9e7,stroke:#d84315,stroke-width:2px,color:#bf360c;",
+ " classDef inmueble fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#4a148c;",
+ ""
+ ]
+
+ # Declaración de nodos
+ for nid, data in self.nodes.items():
+ lbl = data["label"].replace('"', "'").replace("\n", "
")
+ lines.append(f' {nid}["{lbl}"]')
+
+ # Aplicar clases a los nodos
+ for nid, data in self.nodes.items():
+ cat = data.get("category", "sociedad")
+ if cat in self.CATEGORY_STYLES:
+ lines.append(f" class {nid} {cat};")
+
+ lines.append("")
+
+ # Declaración de aristas
+ for e in self.edges:
+ rel = e["relation"].replace('"', "'").replace("\n", " ")
+ if rel:
+ lines.append(f' {e["source"]} -->|"{rel}"| {e["target"]}')
+ else:
+ lines.append(f' {e["source"]} --> {e["target"]}')
+
+ lines.append("```")
+ return "\n".join(lines)
+
+ def to_dict(self) -> Dict[str, Any]:
+ return {
+ "total_nodes": len(self.nodes),
+ "total_edges": len(self.edges),
+ "nodes": list(self.nodes.values()),
+ "edges": self.edges,
+ "mermaid": self.to_mermaid()
+ }
+
+
+def build_quick_graph(
+ nodes_list: Optional[List[Dict[str, Any]]] = None,
+ edges_list: Optional[List[Dict[str, Any]]] = None,
+ title: str = "Red de Vínculos"
+) -> Dict[str, Any]:
+ """Construye un grafo relacional de forma tolerante a nombres de campos y tipos."""
+ builder = LegalGraphBuilder()
+
+ if isinstance(nodes_list, list):
+ for n in nodes_list:
+ if not isinstance(n, dict):
+ continue
+ nid = n.get("id") or n.get("rut") or n.get("nombre") or n.get("label")
+ if not nid:
+ continue
+ label = n.get("label") or n.get("nombre") or str(nid)
+ cat = n.get("category") or n.get("tipo") or "sociedad"
+ builder.add_node(nid, label, cat, metadata=n.get("metadata"))
+
+ if isinstance(edges_list, list):
+ for e in edges_list:
+ if not isinstance(e, dict):
+ continue
+ src = e.get("source") or e.get("origen") or e.get("desde")
+ tgt = e.get("target") or e.get("destino") or e.get("hacia")
+ if not src or not tgt:
+ continue
+ rel = e.get("relation") or e.get("relacion") or e.get("vinculo") or ""
+ builder.add_edge(src, tgt, rel)
+
+ return builder.to_dict()
+
+
+if __name__ == "__main__":
+ builder = LegalGraphBuilder()
+ builder.add_node("ula", "Universidad de Los Lagos", "organismo")
+ builder.add_node("kimun", "Corporación Kimün", "sociedad")
+ builder.add_node(12345, "Representante Legal", "persona")
+ builder.add_edge("ula", "kimun", "Traspaso de Acciones por $130M")
+ builder.add_edge(12345, "kimun", "Administrador")
+ print(builder.to_mermaid())
diff --git a/worked/civil-law-chile/raw/code/stats_tracker.py b/worked/civil-law-chile/raw/code/stats_tracker.py
new file mode 100644
index 0000000000..bafe88d487
--- /dev/null
+++ b/worked/civil-law-chile/raw/code/stats_tracker.py
@@ -0,0 +1,153 @@
+"""
+Open Legal Chile — Rastreador de Estadísticas de Adopción y Telemetría Ética
+Permite consultar métricas públicas de descargas (PyPI), actividad comunitaria (GitHub)
+y registrar pings anónimos de telemetría respetando el secreto profesional (Zero-Data Leak).
+"""
+
+import os
+import sys
+import json
+import urllib.request
+import urllib.error
+from typing import Dict, Any, Optional
+
+from config import safe_urlopen
+
+PYPI_PACKAGE_NAME = "openlegal-chile"
+GITHUB_REPO = "elpabloultron/open-legal-chile"
+TELEMETRY_ENV_VAR = "OPENLEGAL_TELEMETRY"
+
+
+def get_pypi_download_stats(package_name: str = PYPI_PACKAGE_NAME, timeout: float = 3.0) -> Dict[str, Any]:
+ """
+ Consulta la API pública de PyPI Stats (pypistats.org) para obtener el total de descargas e instalaciones.
+ """
+ url_recent = f"https://pypistats.org/api/packages/{package_name}/recent"
+ url_overall = f"https://pypistats.org/api/packages/{package_name}/overall"
+
+ stats = {
+ "paquete": package_name,
+ "descargas_ultimo_dia": 0,
+ "descargas_ultima_semana": 0,
+ "descargas_ultimo_mes": 0,
+ "descargas_totales_estimadas": 0,
+ "fuente": "pypistats.org",
+ "estado": "disponible"
+ }
+
+ headers = {"User-Agent": f"OpenLegalChile-Suite-Stats/{package_name}"}
+
+ try:
+ req_rec = urllib.request.Request(url_recent, headers=headers)
+ with safe_urlopen(req_rec, timeout=timeout) as resp:
+ data = json.loads(resp.read().decode("utf-8"))
+ data_recent = data.get("data", {})
+ stats["descargas_ultimo_dia"] = data_recent.get("last_day", 0)
+ stats["descargas_ultima_semana"] = data_recent.get("last_week", 0)
+ stats["descargas_ultimo_mes"] = data_recent.get("last_month", 0)
+ except Exception:
+ stats["estado"] = "offline_o_recien_publicado"
+
+ try:
+ req_over = urllib.request.Request(url_overall, headers=headers)
+ with safe_urlopen(req_over, timeout=timeout) as resp:
+ data = json.loads(resp.read().decode("utf-8"))
+ total = sum(item.get("downloads", 0) for item in data.get("data", []))
+ stats["descargas_totales_estimadas"] = max(total, stats["descargas_ultimo_mes"])
+ except Exception:
+ pass
+
+ return stats
+
+
+def get_github_community_stats(repo: str = GITHUB_REPO, timeout: float = 3.0) -> Dict[str, Any]:
+ """
+ Consulta la API pública de GitHub para obtener estrellas, forks y actividad comunitaria.
+ """
+ url = f"https://api.github.com/repos/{repo}"
+ stats = {
+ "repositorio": repo,
+ "estrellas": 0,
+ "forks": 0,
+ "observadores": 0,
+ "issues_abiertos": 0,
+ "url": f"https://github.com/{repo}",
+ "estado": "disponible"
+ }
+
+ headers = {
+ "User-Agent": "OpenLegalChile-Suite",
+ "Accept": "application/vnd.github.v3+json"
+ }
+
+ try:
+ req = urllib.request.Request(url, headers=headers)
+ with safe_urlopen(req, timeout=timeout) as resp:
+ data = json.loads(resp.read().decode("utf-8"))
+ stats["estrellas"] = data.get("stargazers_count", 0)
+ stats["forks"] = data.get("forks_count", 0)
+ stats["observadores"] = data.get("watchers_count", 0)
+ stats["issues_abiertos"] = data.get("open_issues_count", 0)
+ except Exception:
+ stats["estado"] = "offline_o_rate_limit"
+
+ return stats
+
+
+def get_suite_adoption_metrics() -> Dict[str, Any]:
+ """
+ Consolida las métricas de adopción globales de Open Legal Chile Suite:
+ PyPI, GitHub, y capacidades locales instaladas.
+ """
+ pypi = get_pypi_download_stats()
+ gh = get_github_community_stats()
+
+ # Inspeccionar métricas doctrinales locales si existen
+ total_instituciones = 0
+ try:
+ import sqlite3
+ db_path = os.path.join(os.path.dirname(__file__), "doctrina.db")
+ if os.path.exists(db_path):
+ conn = sqlite3.connect(db_path)
+ cur = conn.cursor()
+ cur.execute("SELECT COUNT(*) FROM doctrina_instituciones;")
+ total_instituciones = cur.fetchone()[0]
+ conn.close()
+ except Exception:
+ total_instituciones = 138
+
+ return {
+ "suite": "Open Legal Chile",
+ "version_actual": "1.3.0",
+ "metricas_pypi": pypi,
+ "metricas_github": gh,
+ "capacidades_locales": {
+ "herramientas_mcp_oficiales": 54,
+ "conectores_estado": 10,
+ "instituciones_doctrinales_indexadas": total_instituciones,
+ "documentos_biblioteca_markdown": 58,
+ "filosofia": "100% Open Source (Apache-2.0) | Zero-Data Leak | $0 Costo"
+ }
+ }
+
+
+def send_anonymous_telemetry_ping(client: str = "cli", action: str = "session_start") -> bool:
+ """
+ Envía un ping anónimo no invasivo para cuantificar instalaciones activas.
+ ESTRICTO PRINCIPIO ZERO-DATA LEAK:
+ - NO envía consultas legales, causas, nombres ni RUTs.
+ - Respeta la variable de entorno OPENLEGAL_TELEMETRY=false.
+ """
+ # Si el usuario deshabilitó la telemetría, salir de inmediato sin realizar llamadas
+ if os.environ.get(TELEMETRY_ENV_VAR, "true").strip().lower() in ("0", "false", "off", "no"):
+ return False
+
+ try:
+ # Endpoint de conteo público anónimo (usando hit de badge / telemetría ligera)
+ url = f"https://api.github.com/repos/{GITHUB_REPO}"
+ req = urllib.request.Request(url, headers={"User-Agent": f"OpenLegalChilePing/{client}-{action}"})
+ # Timeout agresivo para no retrasar en lo más mínimo al usuario
+ with safe_urlopen(req, timeout=1.0) as resp:
+ return resp.status == 200
+ except Exception:
+ return False
diff --git a/worked/civil-law-chile/raw/doctrine/README.md b/worked/civil-law-chile/raw/doctrine/README.md
new file mode 100644
index 0000000000..31fae20b24
--- /dev/null
+++ b/worked/civil-law-chile/raw/doctrine/README.md
@@ -0,0 +1,64 @@
+# Canon Doctrinal Jurídico Chileno — Open Legal Chile
+
+Repositorio canónico de dogmática jurídica de la República de Chile estructurado en **Markdown de Alta Densidad (Token-Optimized)** para agentes de inteligencia artificial y profesionales del derecho.
+
+---
+
+## 🏛️ 1. Obras y Tratados Canónicos Digitalizados por Capítulos
+
+El corpus abarca las obras más citadas por la **Corte Suprema**, el **Tribunal Constitucional**, la **Contraloría General de la República** y la **Dirección del Trabajo**:
+
+| Área | Tratadista | Obra Canónica | Capítulos Digitalizados | Ubicación |
+| :--- | :--- | :--- | :--- | :--- |
+| **Civil (Obligaciones)** | René Ramos Pazos | *De las Obligaciones* | 4 Capítulos (Estructura, Efectos, Acciones auxiliares, Extinción y prelación) | [`civil/ramos_pazos_obligaciones/`](civil/ramos_pazos_obligaciones/) |
+| **Civil (Responsabilidad)** | Enrique Barros Bourie | *Tratado de Responsabilidad Extracontractual* | 4 Capítulos (Modelos, Antijuridicidad y culpa, Presunciones Arts. 2320/2329, Daño e imputación) | [`civil/barros_bourie_responsabilidad/`](civil/barros_bourie_responsabilidad/) |
+| **Civil (Bienes)** | Daniel Peñailillo Arévalo | *Los Bienes y Derechos Reales* | 4 Capítulos (Bienes, Dominio y tradición CBR, Posesión inscrita, Reivindicatoria y precario) | [`civil/penailillo_bienes/`](civil/penailillo_bienes/) |
+| **Procesal** | Mario Mosquera y Cristián Maturana | *Los Recursos Procesales* | 3 Capítulos (Impugnación y reposición, Apelación, Casación forma/fondo y queja) | [`procesal/maturana_mosquera_recursos/`](procesal/maturana_mosquera_recursos/) |
+| **Administrativo** | Jorge Bermúdez Soto | *Derecho Administrativo General* | 3 Capítulos (Bases y probidad, Acto Ley 19.880 e invalidez, Falta de servicio y sancionador) | [`administrativo/bermudez_derecho_administrativo/`](administrativo/bermudez_derecho_administrativo/) |
+| **Laboral** | Sergio Gamonal Contreras | *Derecho del Trabajo y Tutela Laboral* | 3 Capítulos (Principios protectores, Contrato y despido Art. 161 CT, Tutela y Ley Karin) | [`laboral/gamonal_derecho_del_trabajo/`](laboral/gamonal_derecho_del_trabajo/) |
+| **Penal** | Enrique Cury Urzúa | *Derecho Penal: Parte General* | 3 Capítulos (Legalidad y conducta, Antijuridicidad y justificación, Culpabilidad y autoría) | [`penal/cury_parte_general/`](penal/cury_parte_general/) |
+| **Constitucional** | José Luis Cea Egaña | *Derecho Constitucional Chileno* | 3 Capítulos (Bases e institucionalidad, Derechos y orden económico, Recurso de protección y TC) | [`constitucional/cea_derecho_constitucional/`](constitucional/cea_derecho_constitucional/) |
+
+---
+
+## ⚖️ 2. Cumplimiento Estricto de Propiedad Intelectual (Ley N° 17.336)
+
+Para conciliar la publicidad del código abierto en GitHub con el régimen de propiedad intelectual chileno e internacional:
+
+1. **Derecho de Cita y Análisis Doctrinal (Art. 71B Ley N° 17.336):**
+ "Es lícita la inclusión en una obra de fragmentos breves de otras obras ajenas, con fines de crítica, ilustración, enseñanza o investigación, indicando su fuente y el nombre del autor."
+ Todas las fichas en `.md` atribuyen de forma rigurosa la autoría, el tratado y el año, sintetizando y extrayendo los conceptos dogmáticos sustanciales sin reproducir maquetas editoriales comerciales.
+2. **Minería de Textos y Datos para Investigación Tecnológica e IA (Art. 71C Ley N° 17.336):**
+ Se autoriza el procesamiento automatizado y vectorización de contenidos para investigación sin perjuicio injustificado a la explotación normal de la obra.
+3. **Aislamiento de Archivos Crudos (`doctrina_raw/`):**
+ Cualquier PDF escaneado completo de consulta personal o privada permanece confinado en `doctrina_raw/`, el cual se encuentra expresamente excluido de control de versiones en el archivo [`.gitignore`](../.gitignore) para no ser publicado en repositorios públicos.
+
+---
+
+## ⚡ 3. Estándar de Optimización de Tokens
+
+Los capítulos siguen una arquitectura diseñada para consumir **menos del 12% de los tokens** que demandaría un escaneo tradicional:
+* **Cero Ruido:** Sin encabezados de página repetitivos, números de fojas descontextualizados ni avisos legales editoriales.
+* **Estructura Atómica:** Secciones claramente delimitadas mediante `## 🏛️ `.
+* **Metadatos Vinculantes:**
+ * `**Definición Canónica:**` Síntesis exacta del concepto dogmático.
+ * `**Requisitos Copulativos:**` Listados numerados de procedencia jurídica.
+ * `**Concordancias Legales:**` Enlaces oficiales normalizados `[BCN - Código ..., Art. X]`.
+ * `**Criterio Jurisprudencial Rector:**` Citas de casaciones y unificaciones de doctrina de la Corte Suprema (`[CS - Rol N° ...]`) y del Tribunal Constitucional (`[STC - Rol N° ...]`).
+
+---
+
+## 🔍 4. Uso del Motor FTS5 y Herramientas MCP
+
+El motor [`doctrina_connector.py`](../doctrina_connector.py) indexa automáticamente todos los capítulos en una base SQLite virtual FTS5 (`doctrina.db`):
+
+* **Búsqueda desde CLI:**
+ ```bash
+ python doctrina_connector.py search "presuncion culpa 2329"
+ python doctrina_connector.py institucion "Recurso de Protección"
+ python doctrina_connector.py list
+ ```
+* **Herramientas MCP:**
+ * `doctrina_search`: Búsqueda con relevancia BM25 y filtrado por área.
+ * `doctrina_get_institucion`: Recuperación de ficha completa.
+ * `doctrina_list_obras`: Listado de tratados y estadísticas de tokens.
diff --git a/worked/civil-law-chile/raw/doctrine/aj_conciliacion_laboral.md b/worked/civil-law-chile/raw/doctrine/aj_conciliacion_laboral.md
new file mode 100644
index 0000000000..e1aba3220b
--- /dev/null
+++ b/worked/civil-law-chile/raw/doctrine/aj_conciliacion_laboral.md
@@ -0,0 +1,23 @@
+---
+id: aj_conciliacion_laboral
+titulo: "Guía de Audiencia de Conciliación Laboral"
+autor: "Academia Judicial de Chile"
+materia: "Laboral"
+fecha: "2025-02-15"
+fuente: "https://guias.academiajudicial.cl/guias/juzgados_laborales/Guia_Audiencia_Conciliacion_Laboral_v2.1.pdf"
+---
+
+# Guía de Audiencia de Conciliación Laboral
+
+**Publicación Oficial de la Academia Judicial de Chile**
+
+### Materia: Laboral | Fecha: 2025-02-15
+
+## Resumen Ejecutivo de Práctica Judicial
+
+Técnicas de negociación judicial, propuesta de bases de arreglo y resguardo de derechos laborales irrenunciables (Art. 5 inc. 2 CT).
+
+## Consulta y Descarga del Documento Original
+
+El documento íntegro en formato PDF oficial se encuentra disponible en:
+[Guía de Audiencia de Conciliación Laboral](https://guias.academiajudicial.cl/guias/juzgados_laborales/Guia_Audiencia_Conciliacion_Laboral_v2.1.pdf)
diff --git a/worked/civil-law-chile/raw/doctrine/aj_etica_judicial.md b/worked/civil-law-chile/raw/doctrine/aj_etica_judicial.md
new file mode 100644
index 0000000000..61fc9f4240
--- /dev/null
+++ b/worked/civil-law-chile/raw/doctrine/aj_etica_judicial.md
@@ -0,0 +1,23 @@
+---
+id: aj_etica_judicial
+titulo: "Guía de Buenas Prácticas Judiciales en Temas Éticos"
+autor: "Academia Judicial de Chile"
+materia: "Ética Judicial"
+fecha: "2026-07-10"
+fuente: "https://guias.academiajudicial.cl/guias/guia_etica/Guia_Etica_10jul_2026.pdf"
+---
+
+# Guía de Buenas Prácticas Judiciales en Temas Éticos
+
+**Publicación Oficial de la Academia Judicial de Chile**
+
+### Materia: Ética Judicial | Fecha: 2026-07-10
+
+## Resumen Ejecutivo de Práctica Judicial
+
+Principios de independencia, imparcialidad, integridad, diligencia debida, secreto profesional y deber de abstención y recusación en el ejercicio jurisdiccional.
+
+## Consulta y Descarga del Documento Original
+
+El documento íntegro en formato PDF oficial se encuentra disponible en:
+[Guía de Buenas Prácticas Judiciales en Temas Éticos](https://guias.academiajudicial.cl/guias/guia_etica/Guia_Etica_10jul_2026.pdf)
diff --git a/worked/civil-law-chile/raw/doctrine/aj_juicio_oral_laboral.md b/worked/civil-law-chile/raw/doctrine/aj_juicio_oral_laboral.md
new file mode 100644
index 0000000000..b62d9df4af
--- /dev/null
+++ b/worked/civil-law-chile/raw/doctrine/aj_juicio_oral_laboral.md
@@ -0,0 +1,23 @@
+---
+id: aj_juicio_oral_laboral
+titulo: "Guía para la Audiencia de Juicio Oral Laboral"
+autor: "Academia Judicial de Chile"
+materia: "Laboral"
+fecha: "2025-02-15"
+fuente: "https://guias.academiajudicial.cl/guias/juzgados_laborales/Guia_Audiencia_Juicio_Oral_Laboral.pdf"
+---
+
+# Guía para la Audiencia de Juicio Oral Laboral
+
+**Publicación Oficial de la Academia Judicial de Chile**
+
+### Materia: Laboral | Fecha: 2025-02-15
+
+## Resumen Ejecutivo de Práctica Judicial
+
+Rendición de prueba bajo sana crítica (Art. 456 CT), absolución de posiciones de representantes legales, interrogatorio de testigos y sentencia oral o diferida (Art. 457 CT).
+
+## Consulta y Descarga del Documento Original
+
+El documento íntegro en formato PDF oficial se encuentra disponible en:
+[Guía para la Audiencia de Juicio Oral Laboral](https://guias.academiajudicial.cl/guias/juzgados_laborales/Guia_Audiencia_Juicio_Oral_Laboral.pdf)
diff --git a/worked/civil-law-chile/review.md b/worked/civil-law-chile/review.md
new file mode 100644
index 0000000000..f1b1c3c152
--- /dev/null
+++ b/worked/civil-law-chile/review.md
@@ -0,0 +1,182 @@
+# Graphify Evaluation — Chilean Civil-Law Corpus (2026-09-18)
+
+**Evaluator:** Hermes Agent (live execution, AST-only path — no LLM, no API key)
+**Corpus:** 4 Python modules + 4 Markdown legal documents (a doctrine index and three Chilean
+Academia Judicial training guides), 8 files · ~3,010 words · 52 KB
+**Pipeline:** detect → extract (AST + Markdown structure) → build → cluster → query
+**Version:** graphify 0.9.63, `graphify update .` only
+
+This is a **legal** corpus, not a typical codebase: roughly half of it is prose doctrine in
+Spanish, with the accents, legal citations and emoji-prefixed headings that come with the genre.
+It is also a mixed-language corpus (English query terms against Spanish documents), which turned
+out to be one of the more interesting things to test.
+
+---
+
+## 1. Corpus Detection
+
+```
+8 files · ~3,010 words
+Verdict: corpus is large enough that graph structure adds value.
+```
+
+**Finding (skeptical):** ~3,010 words is comfortably inside any modern context window, so this
+verdict reads generous. The sibling example in this folder, `worked/mixed-corpus`, covers ~4,020
+words and reports the opposite — that the corpus fits in a single context window. Both cannot be
+right, so the size threshold is worth a second look: a corpus this small is exactly where a graph
+has to justify itself on *structure*, not on volume.
+
+---
+
+## 2. Extraction
+
+```
+graph: 72 nodes · 91 edges · 9 communities
+extraction: 100% EXTRACTED · 0% INFERRED · 0% AMBIGUOUS
+token cost: 0 input · 0 output
+```
+
+Nodes by `file_type`:
+
+| file_type | nodes | where they come from |
+|---|---|---|
+| `code` | 26 | Python modules (AST) |
+| `document` | 21 | Markdown guides and the doctrine index |
+| `rationale` | 17 | docstrings/comments and Markdown prose blocks |
+| `concept` | 8 | inferred concepts with no source file (11 nodes have no `source_file` at all) |
+
+Edges by relation: `contains` 27 · `rationale_for` 17 · `references` 11 · `imports` 11 ·
+`calls` 10 · `method` 9 · `imports_from` 6 — all `_origin: ast`, all `EXTRACTED`.
+
+**What surprised me, positively:** the Markdown documents **do** contribute real nodes on this
+path, with no LLM involved. The token cost of 0 confirms it: the document nodes are built from the
+Markdown *structure* (document → section headings → sub-sections), which is enough for navigation
+and for the community detection to place each guide in its own cluster.
+
+Per-file node counts:
+
+```
+13 raw/code/grafo_vinculos.py
+11 (no source_file — externals/concepts)
+10 raw/code/stats_tracker.py
+ 9 raw/code/cold_start.py
+ 8 raw/code/config.py
+ 6 raw/doctrine/README.md
+ 5 raw/doctrine/aj_conciliacion_laboral.md
+ 5 raw/doctrine/aj_etica_judicial.md
+ 5 raw/doctrine/aj_juicio_oral_laboral.md
+```
+
+**What was NOT extracted — and this is the honest headline for legal corpora:** the *substance* of
+the doctrine. The graph knows that "Guía para la Audiencia de Juicio Oral Laboral" exists and which
+sections it has; it does not know what the guide says. Without the LLM path
+(`/graphify --update` in an assistant, which `graphify update .` itself points to), a legal corpus
+is navigable but not answerable.
+
+---
+
+## 3. Communities
+
+| # | Nodes | Label |
+|---|---|---|
+| 0 | 15 | `stats_tracker.py` |
+| 1 | 12 | `LegalGraphBuilder` |
+| 2 | 9 | `cold_start.py` |
+| 3 | 8 | `ColdStartInterviewEngine` |
+| 4 | 7 | `config.py` |
+| 5 | 6 | `Canon Doctrinal Jurídico Chileno — Open Legal Chile` |
+| 6 | 5 | `Guía de Audiencia de Conciliación Laboral` |
+| 7 | 5 | `Guía de Buenas Prácticas Judiciales en Temas Éticos` |
+| 8 | 5 | `Guía para la Audiencia de Juicio Oral Laboral` |
+
+Four communities for four code modules and three for three guides: at this size the partition is
+essentially "one cluster per file", which is correct but not informative. The two labels that name
+a *class* rather than a file (`LegalGraphBuilder`, `ColdStartInterviewEngine`) are the more useful
+of the nine.
+
+No import cycles detected.
+
+---
+
+## 4. God Nodes
+
+```
+ 1. LegalGraphBuilder 8 edges
+ 2. safe_urlopen() 6
+ 3. ColdStartInterviewEngine 5
+ 4. get_pypi_download_stats() 5
+ 5. get_github_community_stats() 5
+ 6. get_suite_adoption_metrics() 5
+ 7. Canon Doctrinal Jurídico Chileno — Open Legal Chile 5
+ 8. build_quick_graph() 4
+ 9. Guía de Audiencia de Conciliación Laboral 4
+10. Guía de Buenas Prácticas Judiciales en Temas Éticos 4
+```
+
+Three of the ten "core abstractions" are **legal documents**, not code. That is the right answer
+for this corpus and it is genuinely useful: it tells a newcomer that the doctrine guides are
+first-class structure, and it fell out of the structural parse without any model.
+
+---
+
+## 5. Queries (offline, BFS depth 2)
+
+| Query | Start node(s) | Nodes | Verdict |
+|---|---|---|---|
+| `how does the telemetry count adoptions` | `send_anonymous_telemetry_ping()` | 16 | ✅ precise — the right function, from a paraphrase in another language |
+| `legal graph builder` | `LegalGraphBuilder` | 16 | ✅ precise |
+| `token savings` | `⚡ 3. Estándar de Optimización de Tokens` | 6 | ✅ excellent — an **English** query landed on a **Spanish** heading |
+| `plazo para contestar la demanda en el juicio oral laboral` | the right guide + its neighbours | 10 | ⚠️ reaches the correct document, not the rule |
+| `requisitos de la conciliación laboral` | `aj_conciliacion_laboral.md` | 5 | ⚠️ same: document-level answer |
+| `¿qué dice el artículo 446 sobre la audiencia?` | two guides | 10 | ⚠️ same, and no article-level node exists to hit |
+
+The cross-language label matching is the standout: Spanish headings with accents and emoji were
+reachable from English queries, including one that starts with an emoji. For a Chilean legal
+corpus (where every real query will be in Spanish but the agent's working language may not be),
+this matters.
+
+The last three rows are the limit, and it is the correct limit for a 0-token path — but a lawyer
+reading this graph would not know it. "Which document" is not "what the rule says".
+
+---
+
+## 6. What it got right
+
+- **The code graph is precise.** `send_anonymous_telemetry_ping() → safe_urlopen()` and the other
+ call edges are exactly the real call sites, with `source_location` line numbers.
+- **Markdown structure is enough for navigation, at zero cost.** 21 document nodes and 3 legal
+ guides among the god nodes, without a single token spent.
+- **Cross-language retrieval works**, including accented Spanish labels from English queries.
+- **Community labels** are good enough to navigate by, and two of them named the actual classes.
+- **Nothing was mislabelled as inferred.** 91/91 edges `EXTRACTED`, which for a corpus that is half
+ prose is a deliberate and honest choice.
+
+## 7. What it got wrong or missed
+
+1. **Substance is out of reach on the AST-only path.** The corpus check counts the prose, but the
+ extraction leaves it at heading level. Anyone running `graphify update .` on a legal corpus and
+ reading the summary ("100% EXTRACTED") could reasonably overestimate what is in the graph. The
+ tip about `/graphify --update` is printed, but it is one line among several.
+2. **The corpus-size verdict contradicts a sibling example** (3,010 words "adds value" vs 4,020
+ words "fits in one window").
+3. **Heading labels are taken verbatim, emoji included** (`⚡ 3. Estándar de Optimización de
+ Tokens`, `🏛️ 1. Obras y Tratados Canónicos Digitalizados por Capítulos`). For documents-heavy
+ corpora, stripping decorative prefixes would make the node labels usable as navigation.
+4. **Node ids keep accents and the full heading text**
+ (`raw_doctrine_readme_1_obras_y_tratados_canónicos_digitalizados_por_capítulos`). It works, but
+ ids are long and non-ASCII, which is worth knowing before using them as keys elsewhere.
+5. **"Surprising Connections" surfaced nothing surprising here** — all three were the same
+ `stats_tracker.py → config.py` call through `safe_urlopen()`. On a small corpus that is probably
+ expected; on a legal one it means the feature needs more files before it earns its name.
+
+---
+
+## 8. Where this corpus comes from
+
+The files are a slice of [Open Legal Chile](https://github.com/elpabloultron/open-legal-chile)
+(Apache-2.0): a legal-tech suite that builds its own node-link graph over 58 Chilean doctrine
+works and merges it with Graphify's code graph through a single idempotent call. The nine graph
+questions that matter for the merge — schema keys, id conventions, whether edges survive a
+round-trip — were answered by this run, which is why the evaluation is written down here instead of
+being kept privately. The slice is trimmed to keep the example small; the full corpus is 58
+documents.