"""Lecture des analyses transversales (`research/lois-2026_insight.md`). Sept analyses, chacune au format :: ## Insight 3 — Le 1er septembre 2026 : « big bang » silencieux … **Dérivé de :** dim08, dim09, dim02, dim12, dim03. **Implications :** … **Confiance : high.** Elles alimentent l'encart « point de veille » du tableau de bord. Elles ne portent aucune source primaire propre — la table de correspondance de la bibliographie le dit — et ne sont donc jamais présentées comme des faits sourcés, mais comme des lectures d'ensemble. """ from __future__ import annotations import re from pipeline.journal import logger from pipeline.modeles import Insight from pipeline.parseurs.markdown import decouper_sections, nettoyer log = logger("parseur.analyses") _TITRE = re.compile(r"^Insight\s+(\d+)\s*[—–-]\s*(.+)$", re.IGNORECASE) _DERIVE = re.compile(r"\*\*Dérivé de\s*:\*\*\s*(.+)", re.IGNORECASE) _IMPLICATIONS = re.compile(r"\*\*Implications\s*:\*\*\s*(.+)", re.IGNORECASE) _CONFIANCE = re.compile(r"\*\*Confiance\s*:\s*([a-zé-]+)", re.IGNORECASE) _DIMENSION = re.compile(r"\b(dim\d{2}|phase\s?5)\b", re.IGNORECASE) def parser(markdown: str) -> list[Insight]: """Extrait les analyses transversales du fichier d'insights.""" analyses: list[Insight] = [] for section in decouper_sections(markdown, niveau_max=2): entete = _TITRE.match(section.titre.strip()) if not entete: continue corps_brut = section.corps implications = None if trouve := _IMPLICATIONS.search(corps_brut): implications = nettoyer(trouve.group(1)) confiance = "medium" if trouve := _CONFIANCE.search(corps_brut): brut = trouve.group(1).lower() confiance = {"high": "high", "élevée": "high", "medium": "medium", "low": "low"}.get( brut, "medium" ) derive_de: list[str] = [] if trouve := _DERIVE.search(corps_brut): derive_de = [ d.lower().replace(" ", "") for d in _DIMENSION.findall(trouve.group(1)) ] corps = _corps_utile(corps_brut) analyses.append( Insight( numero=int(entete.group(1)), titre=nettoyer(entete.group(2)), corps=corps, implications=implications, confiance=confiance, derive_de=derive_de, fichier_origine="research/lois-2026_insight.md", ) ) log.info("analyses transversales lues", analyses=len(analyses)) return analyses def _corps_utile(corps: str) -> str: """Corps de l'analyse, sans les lignes de métadonnées.""" lignes: list[str] = [] for ligne in corps.splitlines(): depouillee = ligne.strip() if not depouillee: continue if _DERIVE.match(depouillee) or _IMPLICATIONS.match(depouillee): continue if _CONFIANCE.match(depouillee): continue lignes.append(nettoyer(depouillee)) return " ".join(lignes).strip()