Proyecto independiente No afiliado, patrocinado ni avalado por la Watch Tower Bible and Tract Society o Jehovah's Witnesses.
jw-agent-toolkit
EN

Specs y planes

Fase 82 — jw-legal: casos legales TJ vs Estado, hermenéutica jurídica multi-país y BrainDomain

Fecha: 2026-06-17 Estado: Diseño en revisión Owner: Elias Tier: 3 (investigación + alineamiento profundo) Capa: A — agéntica + nuevo dominio jurídico sobre jw-brain Depende de: F39 NLI runtime, F43 tracing, F49 second-brain (clave: BrainDomain plugin SDK F41), F54 NLLB-200 (opt-in para traducción), F65 meta-orchestrator, F67 doctrinal-reasoner (clave: ReasoningTree extendido), F77 principios YAML, F80.5 probe evaluator (opt-in Tier 4) Documento padre: nuevo overview F81–F82 Predecesor conceptual: F67 doctrinal_reasoner extendió ReAct + NLI a doctrina; F82 extiende el mismo árbol a hermenéutica jurídica

Motivación

Los Testigos de Jehová tienen una historia jurídica documentada de más de un siglo litigando casos contra Estados en materia de libertad religiosa, objeción de conciencia al servicio militar, libertad de prensa, derecho de reunión y predicación pública. Casos emblemáticos cubren ya:

  • EE.UU.: Cantwell v. Connecticut (1940), Minersville School District v. Gobitis (1940), West Virginia State Board of Education v. Barnette (1943), Watchtower v. Stratton (2002) — pilares del Primer y Decimocuarto enmiendas.
  • Europa (ECHR): Religionsgemeinschaft der Zeugen Jehovas v. Austria (40825/98, 2008), Krupko and Others v. Russia (26587/07, 2014), Jehovah’s Witnesses of Moscow v. Russia (302/02, 2010), Bayatyan v. Armenia (23459/03, 2011) — objeción de conciencia consagrada en el art. 9 CEDH.
  • Prohibiciones gubernamentales: Rusia (2017 Supreme Court ruling declarando organización extremista), Corea del Norte (prohibición total), Eritrea, China (criminalización), Singapur (1972/1996), Tayikistán (2007).
  • América Latina: México (sentencia SCJN sobre objeción de conciencia escolar), Argentina (cesación de prohibición 1976), casos en Cortes Supremas regionales sobre transfusiones y custodia.

Estos casos están documentados públicamente:

  • jw.org/legal sección oficial con cada caso significativo (https://www.jw.org/en/news/legal/), curado y traducido a múltiples idiomas.
  • ECHR HUDOC base de datos pública con API JSON estructurada (sentencias completas, partes, dispositivo, idioma original).
  • Anuarios de los Testigos de Jehová documentan año a año casos por país (corpus JWPUB ya descifrado por el toolkit, F5.5).
  • HRW, Forum 18, USCIRF reports sobre persecución religiosa por país.

Hoy el toolkit no tiene canal para:

  1. Investigar casos por país, tópico jurídico o jurisprudencia comparada.
  2. Producir cadena de pensamiento auditable sobre interpretación jurídica (hermenéutica de una norma a un caso concreto).
  3. Tracking de evolución legislativa por territorio (e.g. “¿qué pasó en Rusia entre 1997 ley sobre libertad de conciencia y 2017 declaratoria de extremismo?”).
  4. Comparación cross-país de precedentes (e.g. “¿cómo se trata la objeción al servicio militar en Armenia vs Corea del Sur vs Turquía?”).

El patrón ya validado en F67 doctrinal_reasoner (ReAct + NLI por paso) es directamente aplicable a hermenéutica jurídica. La interpretación jurídica clásica se descompone en cuatro tipos de análisis (textual, contextual/sistemático, comparado/histórico, aplicación al caso) — paralelos naturales a los StepKind del reasoner doctrinal.

Esta fase entrega un nuevo paquete jw-legal que plug-in al BrainDomain SDK (F41), reutiliza el reasoner extendiéndolo, y añade fuentes de datos jurídicas. Cero cambios al núcleo del toolkit.

Objetivos

  1. LegalCasesTJBrainDomain como plugin entry-point jw_agent_toolkit.brain_domains con NodeTypeSpec/EdgeTypeSpec para LegalCase, Law, Territory, CourtPrecedent, LegalArgument, PersecutionEvent.
  2. Catálogo Territory ISO 3166-1 alpha-2 + JW Branch regions canónico, multi-país día 1, vive en jw-core (infra compartida).
  3. LegalNewsSource extendiendo jw_core.news.NewsSource para HUDOC (primero), jw.org/legal (después), Anuarios JWPUB (tercero), HRW opt-in.
  4. Agente legal_case_researcher que toma {country?, topic?, year_range?, party?} y devuelve AgentResult con Finding[] por caso relevante.
  5. Extensión de ReasoningTree (F67) con nuevo LegalStepKind ∈ {"textual_analysis","contextual_analysis","comparative_analysis","application"}.
  6. Agente hermeneutics_analyzer que produce el árbol hermenéutico paso a paso con cita verificable y NLI verify por step.
  7. Agente precedent_synthesizer multi-país: orquesta vía MetaOrchestrator (F65) sub-queries por jurisdicción y produce comparación con coverage_confidence por hallazgo.
  8. Principios PF020PF024 YAML versionados en jw-eval/principles/data/ aplicados a los tres agentes legales con fidelity_wrap(on_fail="reject").
  9. Coverage gaps como dato de primera clase: cada LegalCase tiene coverage_confidence ∈ {"high","medium","low","unknown"}; el precedent_synthesizer advierte cuando una conclusión cruza confianzas heterogéneas.
  10. Cadena de pensamiento auditable: tracing F43 emite CustomEvent("hermeneutic_step", payload={...}) por paso; viewer existente la muestra; export Markdown del árbol.
  11. Citas verificables: URLs canónicas a HUDOC, jw.org/legal o JWPUB anchor en toda Citation.
  12. Modo “Generativo con citas” (matriz de guardrails del README, no autónomo): output es investigación + análisis educativo, jamás consejo legal accionable; toda salida sin citación se rechaza.

No-objetivos (boundaries vinculantes)

  • No sustituye asesoría legal profesional. Toda salida lleva disclaimer explícito.
  • No produce escritos legales firmables (demandas, alegatos, recursos). El letter_composer (existente) puede bosquejar estructura argumentativa, no firmar.
  • No cubre casos sensibles individuales (custodia infantil disputada, transfusiones de menores, casos de divorcio JW–no-JW). Decisión del usuario confirmada: scope acotado a “JW vs Estado”.
  • No scrapea bases jurídicas de pago (Westlaw, LexisNexis, vLex, Aranzadi). Solo fuentes públicas con API documentada o con scrape ya validado y legalmente compatible con GPL-3.0 del repo.
  • No infiere derecho consuetudinario sin respaldo primario. Toda afirmación sobre “el tribunal X falla siempre Y” requiere ≥2 casos primarios citados.
  • No persiste PII de litigantes individuales identificables más allá de lo ya publicado por la fuente oficial. Casos donde JW Inc. es parte (Watchtower Bible and Tract Society) son personas jurídicas, no PII.
  • No se conecta con jw-meeting-scheduler (F81). Dominios separados, modelos separados, stores separados.
  • No entra en autonomy mode. Toda predicción/sugerencia jurídica requiere revisión humana explícita.
  • No predice fallos futuros (no es ML predictivo de sentencias). El sintetizador resume qué ha pasado, no qué pasará.
  • No publica externamente conclusiones sin auditoría humana del owner. El módulo es local-first.
  • No ataca religiones rivales ni produce apologética hostil contra Estados. El reformulator del F67 ya neutraliza framing tóxico; F82 hereda ese contrato.
  • No se compromete con paridad de cobertura entre países en v1. Coverage gaps son aceptables y reportados; el target es “lo que está públicamente disponible bien estructurado”, no “todos los países completos”.

Decisión 1: storage backend para casos legales

Opción A — SQLite local cifrado (estilo F81)

Pros: aislamiento, mismo patrón ya usado en field_report.py y F81. Contras: los casos JW vs Estado son registro público; cifrarlos al mismo nivel que PII de congregación rompe el modelo conceptual; queries GraphRAG cross-territory pesados (multi-país día 1 ⇒ joins de territorios + leyes + casos + precedentes).

Opción B — BrainDomain plugin sobre jw-brain (DuckDB embedded o Neo4j opt-in)

Pros:

  • Modelo “canon público compartible” del jw-brain encaja perfectamente: las sentencias publicadas son registro público.
  • Plugin SDK F41 (jw_agent_toolkit.brain_domains entry-point) permite empaquetar como package externo sin tocar el núcleo.
  • GraphRAG queries multi-hop “casos del país X que citan ley Y que se aplica también en país Z” salen baratas.
  • Multi-tenant via JW_BRAIN_HOME ya cableado.
  • Reutiliza QueryRouter (F49) con su estrategia WIKI_FIRST / GRAPH_FIRST / VECTOR_FALLBACK.

Contras: requiere modelar bien el schema desde el inicio; cambios futuros de schema requieren migrations cuidadosas.

Decisión: Opción B — BrainDomain plugin

Justificación: el contrato conceptual de jw-brain (“canon público que beneficia compartirse entre instalaciones”) describe exactamente los casos legales JW vs Estado. Ponerlos en SQLite cifrado privado sería inconsistente con que el output del módulo es educativo/divulgativo. F49 invirtió en la infraestructura de plugins exactamente para casos como este.

Decisión 2: prioridad de fuentes primarias

Opciones evaluadas

FuenteAPI/AccesoCalidad estructuralRecall casos JWIdiomasLicencia
ECHR HUDOCAPI JSON pública, sin gatingEstructurado (partes, dispositivo, ratio)Alto (~50 casos JW directos)en/fr (originales), traducciones a 30+Council of Europe, libre uso académico
jw.org/legalWeb scrape, sin API formalEditorial (no jurisprudencia raw)Muy alto (selección curada por JW)60+ idiomas© Watchtower; uso fair-use para investigación
Anuarios JW (JWPUB)Local offline F5.5Texto narrativoAlto histórico (1920+)variosMismo que jw.org
HRW ReportsRSS + webNarrativo, no jurisprudenciaMedioen (principal), traduccionesCC-BY-NC
Forum 18RSSPeriodismo religioso libertadAlto en jurisdicciones cerradasen (ru/uk en notas)CC-BY
USCIRFPDF reports anualesReporting estatalMedioenUS gov public domain
Westlaw / LexisNexis / vLexPaywallJurisprudencia raw completaMuy altovarios❌ no compatible GPL/scrape
AJWRBWebCrítica de TJ sobre transfusionesBajo en JW vs Estadoen© variable

Decisión: orden de implementación HUDOC → jw.org/legal → Anuarios → (opt-in HRW, Forum 18)

Justificación:

  1. HUDOC primero por API limpia, casos canónicos en libertad religiosa, sin riesgos legales de scrape.
  2. jw.org/legal segundo por cobertura curada, multi-idioma nativa, casos que HUDOC no cubre (EE.UU., LATAM, Asia).
  3. Anuarios tercero para profundidad histórica pre-1990s (HUDOC arranca tarde) y casos de jurisdicciones cerradas documentadas internamente.
  4. HRW / Forum 18 opt-in para corroborar persecución no judicializada en jurisdicciones cerradas (Eritrea, Corea del Norte).
  5. Westlaw / LexisNexis explícitamente excluidos: paywall + ToS prohíbe scrape sistemático; no aporta a un proyecto GPL-3.0 local-first.

Decisión 3: arquitectura del reasoner

Engine paralelo a F67 con su propio loop, su propio modelo.

Pros: independencia total, libertad de diseño. Contras: duplica el ReAct loop, duplica integración NLI, duplica tracing, duplica tests.

Opción B — Extensión de ReasoningTree (F67) con LegalStepKind

Reusa engine.py, executor.py, models.py. Solo añade:

  • LegalStepKind Literal type que el executor.run_react_loop trata igual.
  • tool_dispatcher legal que routea hacia tools jurídicos (HUDOC search, Territory lookup, Law citation, Precedent expand).
  • Campos opcionales en ReasoningStep: law_ref, precedent_cites, territory.

Pros:

  • Cero código duplicado; el NLI verify, el truncate, el tracing son idénticos.
  • Auditoría es uniforme: el viewer existente muestra ambos tipos de árbol.
  • Tests del F67 sirven como base; solo añadimos tests del dispatcher legal.

Contras: acopla la evolución del legal_reasoner a la del doctrinal_reasoner. Si F67 cambia el modelo, F82 lo hereda.

Decisión: Opción B — Extensión

Justificación: el riesgo de acoplamiento es bajo; F67 tiene contratos Pydantic estables. La ganancia de reuso (engine + executor + NLI + tracing + viewer) es enorme. La consistencia conceptual también: doctrina y hermenéutica jurídica son ambas formas de interpretación de textos autoritativos con citación verificable.

Decisión 4: catálogo Territory

Contras: news_monitor, field_report, futuras integraciones que usen territorios duplicarían el catálogo.

Opción B — En jw-core/territories.py paralelo a locale_context.py

Territory catalog vive en jw_core/territories.py (ISO 3166-1 alpha-2 + JW Branch regions). El plugin jw-legal consume.

Contras: ya existe jw_core.data.locale_context.LOCALE_CONTEXTS (16 países poblados con iso_3166, name multilang, languages, dominant_religions, sensitive_topics, cultural_anchors, holidays_to_acknowledge, notes). Duplicar país + idiomas en dos catálogos es deuda técnica desde el día 1.

Opción C — Territory compone LocaleContext por iso_3166 (recomendada)

Territory vive en jw_core/territories.py. Cada entrada referencia el LocaleContext correspondiente por iso_3166 y solo añade los campos legales que LocaleContext no tiene: jw_branch_region, legal_status_summary, ban_history. La búsqueda por iso_3166 devuelve un objeto compuesto con datos de ambos catálogos (locale + legal).

@dataclass(frozen=True)
class Territory:
    iso_3166: str                             # FK a LocaleContext
    jw_branch_region: str
    legal_status_summary: LegalStatus
    ban_history: tuple[str, ...] = ()

def get_territory_full(iso: str) -> dict:
    """Compose Territory + LocaleContext into a single dict."""
    territory = TERRITORIES.get(iso.upper())
    locale = get_locale(iso)
    return {**asdict(locale) if locale else {}, **asdict(territory) if territory else {}}

Pros: cero duplicación; LocaleContext ya tiene los 16 países más importantes; Territory añade solo lo legal; cualquier mejora de LocaleContext (nuevos países, idiomas) beneficia automáticamente al plugin legal. Contras: dos archivos a actualizar cuando se añade un país nuevo (uno para context cultural, otro para legal). Aceptable — son dimensiones ortogonales.

Decisión: Opción C — composición sobre LocaleContext

Justificación: respeta DRY y aprovecha 16 países ya curados. LocaleContext.notes["en"] para RU dice literalmente “JW activity is severely restricted in Russia (designated ‘extremist’)” — esa señal ya existe; el plugin legal añade la dimensión jurídica formal (ban_history con fechas de sentencias).

Decisión 5: coverage confidence como dato de primera clase

Multi-país día 1 fuerza declarar gaps de cobertura honestamente. Modelo:

CoverageConfidence = Literal["high", "medium", "low", "unknown"]

# Reglas de asignación automática al ingestar:
# high     = sentencia primaria leída + verified via second source
# medium   = referenced by JW source curado (jw.org/legal) sin verify primario
# low      = mencionado en HRW/Forum 18/USCIRF (reporting periodístico/diplomático)
# unknown  = entry stub creado por el ingester sin contenido aún

El precedent_synthesizer emite warning cuando una conclusión cruza confianzas heterogéneas (e.g. “Comparando Krupko v. Russia (confidence=high) con caso en Eritrea (confidence=low) — la asimetría de cobertura puede distorsionar la conclusión”).

Arquitectura del sistema

┌──────────────────────────────────────────────────────────────────────┐
│  FUENTES PRIMARIAS                                                    │
├──────────────────────────────────────────────────────────────────────┤
│  ECHR HUDOC API  │  jw.org/legal  │  JWPUB Anuarios  │  HRW (opt-in)  │
└────────┬─────────────────┬───────────────┬────────────────┬───────────┘
         │                 │               │                │
         │  F82.2 LegalNewsSource (extiende jw_core.news.NewsSource)     │
         │                 │               │                │
         ▼                 ▼               ▼                ▼
┌──────────────────────────────────────────────────────────────────────┐
│  jw-brain backend (DuckDB embedded por defecto, Neo4j opt-in)         │
│  BrainDomain plugin "legal-cases-tj" (entry-point F41)                │
│  Schema:                                                              │
│   Nodes:   LegalCase, Law, Territory, CourtPrecedent,                 │
│            LegalArgument, PersecutionEvent                            │
│   Edges:   CITES_LAW, APPLIES_IN_TERRITORY, APPEALS_AGAINST,          │
│            CONTRADICTS, SUPPORTED_BY_PRECEDENT, GROUNDS_ARGUMENT,     │
│            OCCURRED_IN, JUDGED_BY                                      │
│   Provenance: source, fetched_at, coverage_confidence                  │
└────────┬─────────────────────────────────────────────────────────────┘

         ├──────────────────────────────────────────────────────────────┐
         ▼                                                              ▼
┌────────────────────────────┐                  ┌──────────────────────────────┐
│ legal_case_researcher (F82.3)│                │ hermeneutics_analyzer (F82.5) │
│ Input: {country, topic, year}│                │ extiende F67 ReasoningTree    │
│ Output: AgentResult con      │                │ Steps:                        │
│   Finding[] por caso         │                │  textual_analysis             │
│   metadata.coverage_summary  │                │   → contextual_analysis        │
│ @fidelity_wrap(PF020,reject) │                │     → comparative_analysis     │
└────────────┬─────────────────┘                │       → application            │
             │                                  │ NLI verify F39 mode "reject"  │
             │                                  │ @fidelity_wrap(PF021,reject)  │
             │                                  └──────────────┬────────────────┘
             │                                                 │
             └─────────────────┐         ┌─────────────────────┘
                               ▼         ▼
                ┌────────────────────────────────────────────┐
                │ precedent_synthesizer (F82.6)               │
                │ MetaOrchestrator (F65) DAG:                 │
                │  step1: case_researcher por país            │
                │  step2: hermeneutics_analyzer cross-país    │
                │  step3: critique cross-confidence           │
                │ Output: ComparativeAnalysis + warnings      │
                │ @fidelity_wrap(PF022,reject)                │
                └─────────────────────┬──────────────────────┘


                       ┌──────────────────────────────────────┐
                       │ Tier 4 (opt-in) F80.5 ProbeEvaluator │
                       │ Probes legales:                       │
                       │  - legal_case_cites_precedent         │
                       │  - respects_jurisdiction              │
                       │  - hermeneutic_coherence              │
                       └──────────────────────────────────────┘


                       ┌──────────────────────────────────────┐
                       │ Tracing F43 CustomEvent JSONL          │
                       │ Viewer existente muestra árbol         │
                       │ Export Markdown / PDF                   │
                       └──────────────────────────────────────┘


                       CLI / MCP / REST / Tauri viewer

Schemas del BrainDomain

NodeTypeSpec

# packages/jw-legal/src/jw_legal/brain/schema.py

from jw_brain.schema.nodes import NodeTypeSpec
from jw_brain.schema.edges import EdgeTypeSpec

def legal_node_specs() -> list[NodeTypeSpec]:
    return [
        NodeTypeSpec(
            name="LegalCase",
            canonical_id_pattern="case:{country_iso}:{court}:{year}:{case_id}",
            properties={
                "country_iso": str,         # ISO 3166-1 alpha-2
                "court": str,               # e.g. "ECHR", "SCOTUS", "TC-ES"
                "court_level": str,         # "trial", "appeal", "constitutional"
                "year": int,
                "case_name": str,            # e.g. "Krupko and Others v. Russia"
                "case_number": str,          # ECHR app no, US docket, etc.
                "date_decided": str,         # YYYY-MM-DD
                "verdict_summary": str,
                "primary_principle": str,    # freedom_of_religion | conscientious_objection | ...
                "jw_parties_role": str,      # claimant | defendant | intervener
                "coverage_confidence": str,  # high | medium | low | unknown
                "language_original": str,    # ISO 639-1
                "url_canonical": str,         # HUDOC / jw.org / fallback
            },
            wiki_page_template="legal_case.md",
            obsidian_subdir="cases/",
            confidence_threshold=0.95,
        ),
        NodeTypeSpec(
            name="Law",
            canonical_id_pattern="law:{country_iso}:{code}",
            properties={
                "country_iso": str,
                "code": str,                 # e.g. "CE-art-16" (Constitución Española)
                "title": str,
                "topic": str,                # freedom_of_religion | assembly_permit | ...
                "effective_date": str,        # YYYY-MM-DD
                "repealed_date": str | None,
                "url_canonical": str,
            },
            wiki_page_template="law.md",
            obsidian_subdir="laws/",
            confidence_threshold=0.90,
        ),
        NodeTypeSpec(
            name="Territory",
            canonical_id_pattern="territory:{iso_3166_1_alpha2}",
            properties={
                "iso_3166_1_alpha2": str,
                "country_name_en": str,
                "country_name_local": str,
                "jw_branch_region": str,     # e.g. "Africa Central", "Russia (closed)"
                "languages": list[str],
                "legal_status_summary": str, # "free practice" | "restricted" | "banned"
                "ban_history": list[str],    # historial de prohibiciones
            },
            wiki_page_template="territory.md",
            obsidian_subdir="territories/",
        ),
        NodeTypeSpec(
            name="CourtPrecedent",
            canonical_id_pattern="precedent:{country_iso}:{court}:{year}:{principle_id}",
            properties={
                "country_iso": str,
                "court": str,
                "year": int,
                "principle_held": str,
                "ratio_decidendi": str,       # razón decisoria
            },
            obsidian_subdir="precedents/",
        ),
        NodeTypeSpec(
            name="LegalArgument",
            canonical_id_pattern="arg:{lang}:{principle}:{slug}",
            properties={
                "language": str,
                "principle": str,
                "framing": str,               # textual | contextual | comparative | application
                "scriptural_basis": str,      # opcional, refs bíblicas
                "secular_basis": str,         # tratados internacionales, etc.
            },
            obsidian_subdir="arguments/",
        ),
        NodeTypeSpec(
            name="PersecutionEvent",
            canonical_id_pattern="persec:{country_iso}:{year}:{slug}",
            properties={
                "country_iso": str,
                "date": str,
                "event_type": str,           # arrest | ban | property_seizure | violence
                "response": str,              # legal | diplomatic | none
                "source_kind": str,           # hrw | forum18 | uscirf | yearbook
                "victims_count": int | None,
            },
            obsidian_subdir="persecution/",
        ),
    ]

def legal_edge_specs() -> list[EdgeTypeSpec]:
    return [
        EdgeTypeSpec(name="CITES_LAW",
                     sources=("LegalCase",), targets=("Law",),
                     confidence_threshold=0.85),
        EdgeTypeSpec(name="APPLIES_IN_TERRITORY",
                     sources=("Law",), targets=("Territory",),
                     confidence_threshold=0.95),
        EdgeTypeSpec(name="APPEALS_AGAINST",
                     sources=("LegalCase",), targets=("LegalCase",),
                     directional=True),
        EdgeTypeSpec(name="SUPPORTED_BY_PRECEDENT",
                     sources=("LegalCase",), targets=("CourtPrecedent",)),
        EdgeTypeSpec(name="CONTRADICTS",
                     sources=("Law",), targets=("Law",),
                     directional=False, sensitive=True),
        EdgeTypeSpec(name="GROUNDS_ARGUMENT",
                     sources=("LegalArgument",), targets=("Law", "CourtPrecedent")),
        EdgeTypeSpec(name="OCCURRED_IN",
                     sources=("PersecutionEvent",), targets=("Territory",)),
        EdgeTypeSpec(name="JUDGED_BY",
                     sources=("LegalCase",), targets=("Territory",)),
    ]

Plugin entry-point

# packages/jw-legal/pyproject.toml
[project.entry-points."jw_agent_toolkit.brain_domains"]
legal-cases-tj = "jw_legal.brain:LegalCasesTJBrainDomain"
# packages/jw-legal/src/jw_legal/brain/__init__.py
from jw_legal.brain.schema import legal_node_specs, legal_edge_specs

class LegalCasesTJBrainDomain:
    name = "legal-cases-tj"

    @property
    def nodes(self):
        return legal_node_specs()

    @property
    def edges(self):
        return legal_edge_specs()

Catálogo Territory (vive en jw-core, compone LocaleContext existente)

LocaleContext (jw_core/data/locale_context.py) ya tiene 16 países poblados con nombres multilenguaje, idiomas, religiones, anchors culturales, festividades y notes. No duplicamos esos campos. Territory añade solo la dimensión legal y referencia el locale por iso_3166.

# packages/jw-core/src/jw_core/territories.py

from dataclasses import dataclass
from typing import Literal

from jw_core.data.locale_context import LocaleContext, get_locale

LegalStatus = Literal["free", "restricted", "banned", "unknown"]

@dataclass(frozen=True)
class Territory:
    """Legal dimension of a country. Composes LocaleContext for cultural data."""
    iso_3166: str                        # FK a LocaleContext.iso_3166
    jw_branch_region: str                # "España", "Russia (closed since 2017)", "Africa Central"
    legal_status_summary: LegalStatus
    ban_history: tuple[str, ...] = ()    # Cronología "YYYY-MM-DD: descripción"

    @property
    def locale(self) -> LocaleContext | None:
        """Cultural context from locale_context.py (16 países base)."""
        return get_locale(self.iso_3166)


# Hand-curado para los ~30 países con historial legal JW relevante.
# Los nombres + idiomas + religiones vienen de LocaleContext (no se duplican).
TERRITORIES: dict[str, Territory] = {
    "ES": Territory(
        iso_3166="ES",
        jw_branch_region="España",
        legal_status_summary="free",
        ban_history=("1956-1970: not formally recognized as religious entity",),
    ),
    "RU": Territory(
        iso_3166="RU",
        jw_branch_region="Russia (closed since 2017)",
        legal_status_summary="banned",
        ban_history=(
            "2017-04-20: Supreme Court ruling — extremist organization",
            "2017-07-17: appeal denied",
        ),
    ),
    "KP": Territory(
        iso_3166="KP",
        jw_branch_region="(no branch)",
        legal_status_summary="banned",
        ban_history=("Continuous ban; no legal framework for religious activity",),
    ),
    # ... ~30 entradas iniciales en F82.0; resto poblado iterativamente.
    # Para países sin entry: get_territory() → None (no crash).
}


def get_territory(iso: str) -> Territory | None: ...
def get_territory_full(iso: str) -> dict | None:
    """Compose Territory + LocaleContext into a single dict for agents."""
    ...
def territories_by_status(status: LegalStatus) -> list[Territory]: ...
def territories_by_branch(branch: str) -> list[Territory]: ...

Implicación para F82.0: el catálogo arranca con ~30 países con historial legal JW conocido (no necesita ISO 3166-1 completo día 1). pycountry sigue siendo dep útil para validación (pycountry.countries.get(alpha_2=iso)) y para futura expansión, pero no es prerequisito de v1.

Contratos de tipos del reasoner extendido

# packages/jw-legal/src/jw_legal/reasoner_extension.py

from jw_agents.reasoner.models import (
    ReasoningStep, ReasoningTree, Citation, NLIStatus, ReasonerConfig,
)
from pydantic import BaseModel, Field
from typing import Literal

LegalStepKind = Literal[
    "textual_analysis",      # qué dice literalmente la norma
    "contextual_analysis",   # contexto histórico, telos, sistemática
    "comparative_analysis",  # jurisprudencia comparada multi-país
    "application",           # aplicación al caso concreto
]

class LegalReasoningStep(ReasoningStep):
    """Extiende ReasoningStep con metadata jurídica.

    Mantiene compatibilidad: el executor F67 sigue funcionando porque
    los campos extra son opcionales.
    """
    legal_kind: LegalStepKind | None = None
    law_ref: str | None = None             # canonical_id de Law
    precedent_cites: list[str] = []         # canonical_ids de CourtPrecedent
    territory: str | None = None           # ISO 3166-1
    coverage_confidence: str = "unknown"

class HermeneuticalTree(BaseModel):
    """Output del hermeneutics_analyzer."""
    territory: str                         # foco principal (ISO)
    legal_question: str                    # qué se interpreta
    base_tree: ReasoningTree               # estructura F67 con steps legales
    coverage_summary: dict[str, int]       # {"high": 3, "medium": 1, "low": 0, "unknown": 0}
    cross_country_warnings: list[str]      # si extiende a multi-país

class ComparativeAnalysis(BaseModel):
    """Output del precedent_synthesizer."""
    topic: str
    countries: list[str]                   # ISO codes incluidos
    per_country_findings: dict[str, list[str]]  # iso → finding_ids
    cross_country_agreement: list[str]
    cross_country_divergence: list[str]
    coverage_warnings: list[str]
    trace_path: str | None = None

API pública

# packages/jw-legal/src/jw_legal/__init__.py

from jw_legal.brain import LegalCasesTJBrainDomain
from jw_legal.news.hudoc import HUDOCSource
from jw_legal.news.jw_legal_section import JWLegalSectionSource
from jw_legal.news.yearbooks import YearbookSource
from jw_legal.agents.researcher import legal_case_researcher
from jw_legal.agents.hermeneutics import hermeneutics_analyzer
from jw_legal.agents.precedent import precedent_synthesizer
from jw_legal.reasoner_extension import (
    LegalStepKind, LegalReasoningStep,
    HermeneuticalTree, ComparativeAnalysis,
)

CLI

# Investigar casos por país y tópico
jw legal cases --country RU --topic conscientious_objection --since 2010

# Hermenéutica jurídica de una norma a un caso
jw legal hermeneutics \
    --law "law:ES:CE-art-16" \
    --case "case:ES:TC:1985:154" \
    --steps textual,contextual,comparative,application

# Síntesis de precedentes cross-país
jw legal precedents --topic freedom_of_religion --countries RU,AM,KR,TR --since 2000

# Importar HUDOC
jw legal ingest hudoc --query "Jehovah's Witnesses" --since 2000

# Importar jw.org/legal
jw legal ingest jworg-legal --languages en,es,ru

# Importar anuarios (offline)
jw legal ingest yearbooks --path /ruta/a/jwpubs/ --range 1950-2020

# Listar territorios cubiertos
jw legal territories --status banned

# Exportar árbol hermenéutico a Markdown
jw legal hermeneutics --law "..." --case "..." --export reasoning.md

MCP tools

  • legal_search_cases(country?: str, topic?: str, year_from?: int, year_to?: int, party?: str) → list[dict]
  • legal_hermeneutics(law_ref: str, case_ref: str | None, steps: list[str] = None, language: str = "es") → HermeneuticalTree
  • legal_compare_precedents(topic: str, countries: list[str], year_range: tuple[int, int] | None) → ComparativeAnalysis
  • legal_ingest(source: Literal["hudoc","jworg","yearbook","hrw"], **opts) → dict
  • legal_list_territories(status: str | None) → list[dict]

REST endpoints (jw-mcp rest_api.py)

POST /api/v1/legal/cases
  body: { country?, topic?, year_from?, year_to?, party? }
  resp: list[LegalCaseFinding]

POST /api/v1/legal/hermeneutics
  body: { law_ref, case_ref?, steps?, language }
  resp: HermeneuticalTree

POST /api/v1/legal/precedents
  body: { topic, countries, year_range? }
  resp: ComparativeAnalysis

GET  /api/v1/legal/territories
  query: status?
  resp: list[Territory]

Fase F82.0 — Catálogo Territory ISO + JW Branch (1 semana)

Tareas:

  1. Añadir pycountry>=24 a packages/jw-core/pyproject.toml (validación opcional, no peso runtime).
  2. Crear packages/jw-core/src/jw_core/territories.py con Territory dataclass que referencia LocaleContext por iso_3166.
  3. Hand-curar ~30 países con historial legal JW relevante: RU, KP, ES, MX, US, AR, BR, KR, CN, JP, DE, FR, IT, ER, SG, TJ, CU, VN, MM, GR, AM, AZ, TR, GE, MD, BY, KZ, UZ, TM, IR. Para los 16 que ya están en LocaleContext (MX, BR, US, ES, AR, CO, PE, DE, FR, IT, JP, KR, CN, PH, RU + futuros), solo añadir entries Territory con jw_branch_region + legal_status_summary + ban_history. Para los ~14 nuevos (KP Corea del Norte, ER Eritrea, SG Singapur, TJ Tayikistán, CU Cuba, VN Vietnam, MM Myanmar, GR Grecia, AM Armenia, AZ Azerbaiyán, TR Turquía, GE Georgia, MD Moldavia, BY Bielorrusia, etc.), también añadir entry mínima a LocaleContext (al menos name + languages) para que la composición funcione.
  4. Funciones helper get_territory, get_territory_full (compone con LocaleContext), territories_by_status, territories_by_branch.
  5. Validador CI: cada iso_3166 es válido (pycountry.countries.get(alpha_2=iso)) y existe LocaleContext para él (si no, warning en test).
  6. Tests: round-trip, búsqueda por status, búsqueda por branch, composición con LocaleContext.
  7. Documentar fuente de cada ban_history entry con comentario inline (URL + fecha de fetch).

Criterios de éxito:

  • ≥30 territorios poblados con Territory + ban_history verificable.
  • 100% de los Territory.iso_3166 tienen LocaleContext correspondiente (test enforced).
  • 0 duplicación de campos cubiertos por LocaleContext (test que detecta Territory.languages añadido como tuple).
  • Tests verdes en CI sin red.
  • get_territory_full("RU") devuelve dict que combina culture + legal sin colisiones.

Fase F82.1 — BrainDomain plugin (1 semana)

Tareas:

  1. Scaffold packages/jw-legal/ con uvx create-jw-agent jw-legal --type=brain-domain --lang=es (extender F42 si no existe el subtype).
  2. Implementar LegalCasesTJBrainDomain clase con nodes y edges properties.
  3. legal_node_specs() y legal_edge_specs() con los 6 nodos y 8 aristas definidos arriba.
  4. Wiki page templates Jinja2 para LegalCase, Law, Territory, CourtPrecedent en templates/.
  5. Entry-point en pyproject.toml y verificar discovery con jw_brain.domain.registry.discover_domains().
  6. Tests: registro descubierto, NodeRegistry valida canonical_id_pattern, EdgeRegistry valida sources/targets.

Criterios de éxito:

  • jw brain init --domain legal-cases-tj --backend duckdb crea el grafo vacío.
  • jw brain status lista “legal-cases-tj” como dominio activo.
  • 100% de los NodeTypeSpec parsean su canonical_id_pattern correctamente.

Fase F82.2 — Fuente HUDOC + cassettes (2 semanas)

Tareas:

  1. HUDOCSource(NewsSource):
    • fetch(since: datetime, languages: list[str]) → list[NewsItem].
    • Llama HUDOC API: GET https://hudoc.echr.coe.int/eng/app/conversion/docx/?library=ECHR&id={appno}.
    • Filtra por respondent o applicants que contengan “Jehovah’s Witnesses” o variantes.
    • Mapea a LegalCase y aristas (CITES_LAW al CEDH, JUDGED_BY → Territory).
  2. Parser de sentencia HUDOC: extrae case_name, case_number, date_decided, verdict_summary, ratio_decidendi.
  3. Cassettes pytest-recording con respuestas HUDOC para casos canónicos (Krupko, Religionsgemeinschaft, Bayatyan, Moscow Jehovah’s Witnesses).
  4. Tests E2E sin red usando cassettes.
  5. Ingester CLI jw legal ingest hudoc --query "..." --since 2000 que popula el BrainDomain.
  6. coverage_confidence="high" para casos primarios HUDOC (sentencia leída directamente).

Criterios de éxito:

  • ≥50 casos JW directos en HUDOC mapeados a LegalCase nodes.
  • 8 cassettes goldens cubren casos representativos.
  • Tests verdes sin red.
  • Ingester idempotente: re-ingest del mismo caso no duplica nodos.

Tareas:

  1. legal_case_researcher(country?, topic?, year_range?, party?) → AgentResult:
    • Query al BrainDomain via QueryRouter.GRAPH_FIRST.
    • Filtra por country, topic, year, party.
    • Cada caso → Finding con Citation(url=case.url_canonical, source_kind="legal_case").
    • metadata.coverage_summary con histograma de confidence.
  2. @fidelity_wrap(principles=[PF020, PF021], on_fail="reject").
  3. Tracing F43: CustomEvent("case_query", payload={query_terms, results_count}).
  4. Tests: 5 goldens (Russia post-2017, EE.UU. pre-1950, ECHR libertad conciencia, multi-país Asia, sin resultados).

Criterios de éxito:

  • Query “Rusia + conscientious_objection + 2010-2025” devuelve ≥3 casos relevantes.
  • coverage_summary siempre presente.
  • 0 falsos positivos (casos no JW mezclados).

Fase F82.4 — Extensión ReasoningTree con LegalStepKind (3 días)

Tareas:

  1. LegalReasoningStep(ReasoningStep) con campos opcionales legal_kind, law_ref, precedent_cites, territory, coverage_confidence.
  2. LegalToolDispatcher para el executor.run_react_loop:
    • Routea tool_hint="law.lookup" → BrainDomain query.
    • Routea tool_hint="precedent.expand" → traversal de aristas.
    • Routea tool_hint="territory.context" → catálogo Territory.
  3. NLI verify se ejecuta igual; verdict per step se anota.
  4. Tests: 3 árboles legales con dispatcher mockeado.

Criterios de éxito:

  • executor.run_react_loop consume LegalReasoningStep sin cambios al engine.
  • Dispatcher routea correctamente los 3 tool_hints.
  • NLI status reflejado por step.

Fase F82.5 — Agente hermeneutics_analyzer (2 semanas)

Tareas:

  1. hermeneutics_analyzer(law_ref, case_ref=None, steps=("textual","contextual","comparative","application"), language="es") → HermeneuticalTree:
    • Plan: genera secuencia de LegalReasoningSteps en orden DAG (textual ← contextual ← comparative ← application).
    • Ejecuta cada paso vía executor.run_react_loop con LegalToolDispatcher.
    • NLI verify por paso; si falla en mode reject, trunca árbol.
    • Resume coverage_summary agregando confidence de cada step.
  2. Prompts Jinja2 para planner (es/en/pt).
  3. Reformulator opt-in heredado de F67 para neutralizar framing tóxico (“demuestra que la sentencia X es injusta” → “qué argumenta la sentencia X”).
  4. Tests: 10 goldens E2E con cassettes (Krupko + CEDH art. 9, Bayatyan + objeción, Religionsgemeinschaft + reconocimiento legal, etc.).
  5. Export Markdown del árbol.

Criterios de éxito:

  • ≥8 de 10 goldens producen árbol no truncado.
  • 100% de steps con nli_status="entails" tienen Citation poblada.
  • Latencia <8s p95 por árbol completo (sin red, con cassettes).

Fase F82.6 — Agente precedent_synthesizer (1 semana)

Tareas:

  1. precedent_synthesizer(topic, countries, year_range) → ComparativeAnalysis:
    • Usa MetaOrchestrator (F65) con DAG:
      • Step 1: por cada country, legal_case_researcher paralelo.
      • Step 2: por cada hallazgo, hermeneutics_analyzer opcional.
      • Step 3: critique cross-confidence (warning si cruzan confidences).
    • Output: ComparativeAnalysis con agreement/divergence inferidos por NLI entre rationale de cada país.
  2. coverage_warnings siempre presente.
  3. Tests: 3 goldens (objeción de conciencia EU vs Asia, libertad religiosa LATAM vs Europa, prohibiciones gubernamentales Russia vs Corea).

Criterios de éxito:

  • Synthesis no afirma agreement entre países con confidence asimétrica >1 nivel.
  • 100% outputs llevan coverage_warnings no vacío cuando aplique.
  • Reproducible con seed fijo.

Fase F82.7 — Principios PF020PF024 + fidelity_wrap (3 días)

Tareas:

  1. Crear YAMLs en packages/jw-eval/src/jw_eval/principles/data/:
# PF020-no-hallucinated-rulings.yaml
id: PF020-no-hallucinated-rulings
version: 1
severity: hard
applies_to: [legal_case_researcher, hermeneutics_analyzer, precedent_synthesizer]
source: "jw.org/legal editorial standards; ECHR Rules of Court art. 73"
rationale: >
  Toda afirmación sobre el contenido de una sentencia o dispositivo debe
  poder respaldarse en una fuente primaria (HUDOC, jw.org/legal, anuario)
  citada con URL canónica. Prohibido inferir conclusiones jurisprudenciales
  sin Citation poblada.
detect:
  forbidden_phrases:
    - "los tribunales siempre fallan"
    - "las cortes uniformemente"
    - "en todas las jurisdicciones"
  forbidden_regex:
    - "(?i)\\b(es bien sabido|notoriamente)\\b.*\\b(tribunal|corte)\\b"

# PF021-cite-jurisdiction-explicitly.yaml
id: PF021-cite-jurisdiction-explicitly
version: 1
severity: hard
applies_to: [hermeneutics_analyzer, precedent_synthesizer]
source: "lex specialis principle"
rationale: >
  Toda interpretación de una norma debe explicitar el territory (ISO 3166-1)
  y el court level (constitutional / supreme / appeal / trial) bajo el que
  aplica. La hermenéutica jurídica no transfiere automáticamente entre
  jurisdicciones.

# PF022-respect-coverage-confidence.yaml
id: PF022-respect-coverage-confidence
version: 1
severity: hard
applies_to: [precedent_synthesizer]
source: "internal coverage protocol"
rationale: >
  Síntesis cross-país que compara casos con coverage_confidence
  heterogénea (e.g. high vs low) debe emitir coverage_warning explícito.
  Prohibido afirmar agreement/divergence sin que coverage_summary lo permita.

# PF023-no-legal-advice.yaml
id: PF023-no-legal-advice
version: 1
severity: hard
applies_to: [legal_case_researcher, hermeneutics_analyzer, precedent_synthesizer]
source: "ABA Model Rules 1.1, 5.5"
rationale: >
  Los agentes son herramientas de investigación y educación. Prohibido
  emitir consejo legal accionable. Prohibido prescribir cursos de acción
  específicos para casos individuales.
detect:
  forbidden_phrases:
    - "usted debería demandar"
    - "le recomendamos presentar"
    - "el curso de acción es"

# PF024-disclaim-no-professional-advice.yaml
id: PF024-disclaim-no-professional-advice
version: 1
severity: soft
applies_to: [legal_case_researcher, hermeneutics_analyzer, precedent_synthesizer]
source: "internal disclaimer policy"
rationale: >
  Todo output del módulo legal debe incluir un disclaimer explícito de
  que no constituye asesoría legal. El disclaimer es responsabilidad del
  caller cuando expone el output a usuario final.
  1. Cablear fidelity_wrap en los 3 agentes con on_fail="reject" para hard, on_fail="warn" para soft.
  2. Tests: cada principio rechaza al menos 1 input violador y deja pasar inputs no violadores.

Criterios de éxito:

  • 5 principios cargan correctamente via jw_eval.principles.load_principles().
  • fidelity_wrap rechaza outputs violadores en goldens (test E2E).
  • 0 regresiones en tests existentes de jw-eval y jw-agents.

Stack técnico

  • jw-brain BrainDomain SDK (F41) — entry-point jw_agent_toolkit.brain_domains.
  • jw_core.news.NewsSource protocol — extendido por HUDOCSource, JWLegalSectionSource, YearbookSource.
  • jw_agents.reasoner (F67)ReasoningTree, ReasoningStep, executor.run_react_loop, NLI verify.
  • MetaOrchestrator (F65) — DAG planning para precedent_synthesizer.
  • pycountry (pycountry>=24) — ISO 3166-1 alpha-2 catalog.
  • httpx (ya en repo) — HUDOC API async.
  • pytest-recording — cassettes HUDOC.
  • pyyaml — principios.
  • jw-eval.principles — loader.
  • jw_agents.fidelity_wrap — Tier 1 NLI + Tier 2 principles + (opt-in) Tier 4 probes.
  • jw_agents.tracing (F43) — CustomEvent JSONL.
  • jw-core.fidelity.nli — NLI runtime (con NLI provider configurable; default DeBERTa-MNLI).
  • jw-finetune.preference (F77) — futuro: DPO training sobre casuística JW (out of scope F82, abre puerta).
  • jw-interp.runtime.ProbeEvaluator (F80.5) — opt-in Tier 4 con probes legales.

Métricas de éxito globales

MétricaBaselineTarget F82
Territorios catalogados0≥200 ISO + ≥90 con jw_branch_region
LegalCases ingestados de HUDOC0≥50
LegalCases totales en BrainDomain (HUDOC + jw.org + yearbooks)0≥150
Goldens hermenéutica resueltos sin truncarn/a≥8 de 10
Citations pobladas en steps con nli_status=entailsn/a100%
Outputs con coverage_warning cuando aplican/a100%
Outputs con disclaimer (PF024 soft)n/a100%
Latencia precedent_synthesizer p95 multi-paísn/a<5s con cassettes
Tests verdes2 716≥2 850 al final
0 alucinaciones (Findings sin Citation) en goldens00
Reproducibilidad con seedn/a100%

Riesgos y mitigaciones

  1. HUDOC API rate limit / cambio de schema — la API es estable pero no SemVer.

    • Mitigación: cliente con retry exponencial y throttler (patrón F9); cassettes en CI; alert manual si la suite de goldens se rompe.
  2. Multi-país coverage desigual día 1 — Europa Occidental sobre-representada en HUDOC; jurisdicciones cerradas (Eritrea, Corea del Norte) tienen casi cero jurisprudencia accesible.

    • Mitigación: coverage_confidence como dato de primera clase; PF022 evita comparaciones espurias; PersecutionEvent separado de LegalCase para jurisdicciones sin proceso judicial.
  3. NLI no entrenado en lenguaje legaldeberta-mnli y proveedores LLM-NLI están entrenados en SNLI/MultiNLI, no en corpus legal. Falsos positivos esperables.

    • Mitigación: documentar Tier 1 más débil para este módulo; F80.5 ProbeEvaluator opt-in con probes legales como Tier 4 complementario; abrir futura sub-fase F82.8 para fine-tune NLI legal si surge demanda.
  4. Jurisprudencia en idiomas nacionales — sentencias rusas en ruso, coreanas en coreano, etc. (50+ idiomas).

    • Mitigación: F54 NLLB-200 ya disponible en el repo (200 idiomas, is_commercial_safe=False, OK para uso personal/educativo). Activar opt-in cuando el caso tiene language_original != en/es/pt. Documentar el flag claramente.
  5. Cambio de estructura jw.org/legal — el scrape se rompe.

    • Mitigación: scrape solo como secondary source; HUDOC es primary; tests con cassettes; alert manual.
  6. Falsos positivos en filtro “Jehovah’s Witnesses” — HUDOC puede tener referencias colaterales que no son casos JW.

    • Mitigación: filtro de doble pase (campo respondent + campo applicant); cassettes goldens con conocidos true-positive; whitelist de variantes ortográficas.
  7. Casos sensibles individuales colándose — un caso “JW vs Estado” puede contener PII de litigantes individuales.

    • Mitigación: alcance limitado a Watchtower Bible and Tract Society (persona jurídica) y casos donde el JW individual es ya público (mismo nombre en HUDOC + jw.org/legal). Si el caso involucra menores, no se ingresa.
  8. Bias sobrerrepresentación europeo-occidental — HUDOC + jw.org/legal cubren Europa y América del Norte mejor que África subsahariana.

    • Mitigación: PersecutionEvent desde HRW + Forum 18 + USCIRF compensa para jurisdicciones cerradas; coverage_summary del agente lo refleja explícitamente; warning estructural.
  9. Hallucinated rulings por el LLM downstream — el LLM que sintetiza prosa puede inventar dispositivos.

    • Mitigación: fidelity_wrap(PF020, on_fail="reject"); cada step debe tener Citation; tests con goldens que cazan hallucination.
  10. Tracking de derecho consuetudinario — jurisdicciones de common law (UK, EE.UU., Canada, India) tienen capas de precedente difíciles de modelar.

    • Mitigación: CourtPrecedent nodo separado de LegalCase con ratio_decidendi explícito; v1 modela common law a nivel de “sentencia individual”; refactor futuro si surge necesidad.
  11. Modelo de “Law” demasiado simple — leyes tienen versiones, enmiendas, derogaciones.

    • Mitigación: campo effective_date + repealed_date cubre el caso 80%; arista REPEALED_BY futura si demanda.
  12. Carga inicial del catálogo Territory tediosa — 200 países con ban_history hand-curados.

    • Mitigación: arranco con los ~30 países de máximo interés (Rusia, Corea del Norte, Eritrea, Singapur, etc.); resto con legal_status_summary="unknown"; PR-based expansion.
  13. Ingest desactualizado por re-corridas concurrentes del news_monitor.

    • Mitigación: SeenStore (F49) ya cableado para deduplicar; coverage_confidence="unknown" como entry stub.
  14. PF023 “no-legal-advice” demasiado restrictivo — puede rechazar respuestas legítimas de investigación.

    • Mitigación: phrases muy específicas (imperativo personal “usted debería”); tests por phrase para cazar falsos positivos.
  15. F67 cambia los contratos — al extender ReasoningStep heredamos su evolución.

    • Mitigación: contratos F67 son Pydantic estables; cambios mayores activarían bump major del paquete jw-agents; F82 lo manejaría con migration test.

Gaps y dependencias

  • Bloqueador F82.0: pycountry debe ser dep nueva del workspace; añadir a jw-core deps.
  • Bloqueador F82.1: BrainDomain plugin SDK (F41) ya está; sin esto F82 no arranca.
  • Bloqueador F82.5: F67 doctrinal_reasoner ya está; reusable directo.
  • No bloqueador, recomendado: F80.5 ProbeEvaluator runtime ya está; Tier 4 legal queda como F82.9 futura.
  • No bloqueador, recomendado: F54 NLLB-200 ya está; activar opt-in para casos en idiomas no-EN/ES/PT.
  • Futuro (no bloqueador):
    • F82.8 — fine-tune NLI legal-specific sobre casuística HUDOC + jw.org/legal.
    • F82.9 — Probes lineales de principios legales (extiende F80.5).
    • F82.10 — Generación de borradores de escritos vía letter_composer reutilizado.

Próximos pasos inmediatos

  1. Aprobación del spec (este documento) por el owner.
  2. Plan de implementación Fase F82.0 (Territory catalog) vía superpowers:writing-plans skill.
  3. Scaffold packages/jw-legal/ con create-jw-agent (F42).
  4. HUDOC API key: ECHR no requiere key para queries básicas, pero verificar quota de uso.
  5. Hand-curation inicial: usuario aporta lista de 30 países con ban_history priorizados (Rusia, Corea del Norte, Eritrea, Singapur, Tayikistán, Cuba, Vietnam, China, Myanmar, etc.).
  6. Decisión NLI: ¿activar F54 NLLB-200 desde el día 1 para casos no-EN/ES/PT? Implica overhead en testing (más cassettes).

Referencias

  • ECHR HUDOC API — https://hudoc.echr.coe.int
  • ECHR HUDOC API docs — https://www.echr.coe.int/Documents/HUDOC_Manual_ENG.pdf
  • jw.org/legal sección oficial — https://www.jw.org/en/news/legal/
  • pycountry — https://pypi.org/project/pycountry/
  • F49 second-brain spec — docs/superpowers/specs/2026-06-01-fase-49-second-brain-design.md
  • F41 plugin SDK spec — docs/superpowers/specs/2026-05-31-fase-41-plugin-sdk-design.md
  • F67 doctrinal-reasoner spec — docs/superpowers/specs/2026-06-11-fase-67-doctrinal-reasoner-design.md
  • F77 principios YAML — packages/jw-eval/src/jw_eval/principles/
  • F80 interpretability — docs/superpowers/specs/2026-06-12-fase-80-interpretability-tri-model-design.md
  • Religionsgemeinschaft der Zeugen Jehovas v. Austria — ECHR 40825/98, 2008-07-31
  • Krupko and Others v. Russia — ECHR 26587/07, 2014-06-26
  • Jehovah’s Witnesses of Moscow v. Russia — ECHR 302/02, 2010-06-10
  • Bayatyan v. Armenia — ECHR 23459/03, 2011-07-07
  • Cantwell v. Connecticut — 310 U.S. 296, 1940
  • West Virginia State Board of Education v. Barnette — 319 U.S. 624, 1943
  • Watchtower Bible & Tract Society v. Stratton — 536 U.S. 150, 2002
  • USCIRF Annual Reports — https://www.uscirf.gov/annual-reports
  • Forum 18 News Service — https://www.forum18.org/
  • HRW Religion reports — https://www.hrw.org/topic/religion

Editar esta página en docs/superpowers/specs/2026-06-17-fase-82-legal-cases-tj-design.md