"""Extensions optionnelles d'UNIQUE (ADR-002). Tout est éteint par défaut. Le noyau M.O.U.H. ne dépend jamais de ce paquet : il l'atteint par deux crochets entourés de try/except (mouh/service.py pour le menu des générateurs, jobs/train_unique.py pour les phases et noyaux d'entraînement). Depuis la v4.1 (mode local, ADR-004), aucune brique n'appelle de service en ligne ni ne télécharge de paquet. Interrupteurs de l'interface : UNIQUE_EXT_TREE=1 (recherche arborescente), UNIQUE_EXT_LOOKUP, UNIQUE_EXT_MEMORY=1. Interrupteurs de l'entraînement : UNIQUE_PHASES=dpo:200,kto:200 et UNIQUE_EXT_JOB_LIGER=1. Mise à jour par un zip : UNIQUE_EXT_INSTALL=, retour arrière UNIQUE_EXT_ROLLBACK=1. """ from __future__ import annotations import os API_VERSION = 1 # contrat entre le job d'entraînement et ce paquet : le job refuse une autre valeur __version__ = "4.15.0" def enabled(name: str) -> bool: """Interrupteur côté Space : UNIQUE_EXT_=1.""" return os.environ.get(f"UNIQUE_EXT_{name.upper()}", "0").strip() == "1" def job_enabled(name: str) -> bool: """Interrupteur côté jobs : UNIQUE_EXT_JOB_=1 (transmis au job par le pilote automatique).""" return os.environ.get(f"UNIQUE_EXT_JOB_{name.upper()}", "0").strip() == "1" def int_env(name: str, default: int) -> int: try: return int(os.environ.get(name, "").strip() or default) except ValueError: return default