Phase 3 : sources, citations et seed complet — 368 sources, 0 texte orphelin

Parseurs :
- blocs_claim : les quatre dialectes des rapports de dimension. Le cahier des
  charges en postulait un seul ; sans les quatre, dim05 à dim12 étaient perdus,
  soit les dimensions associations, entreprises, migration et calendrier.
- notes_bas_page : 258 notes, dont 104 sans URL. Les identifiants JORFTEXT
  donnent lieu à une URL canonique reconstruite (schéma fixe, rien d'inventé) ;
  les autres restent sans lien plutôt que d'être devinées.
- bibliographie : 481 références, toutes liées. Indexées par numéro de loi,
  par affaire DC et par cote de document parlementaire — cette dernière étant
  la seule identité d'un texte déposé et non examiné.
- chapitres : rattachement phrase par phrase, résumés repris tels quels.

Résolution des citations : 100 % des 332 marqueurs du rapport, 93 % avec un
lien vérifiable. Il a fallu six conventions de numérotation, une par famille de
dimension (marqueur de fin, en-tête de claim, section, rang, note, section.rang).

Trois pièges corrigés, tous couverts par des tests :
- « décision n° 2026-903 DC » lu comme une loi, ce qui volait à la loi 2026-403
  les phrases — et donc les sources — qui parlaient d'elle
- retrait des marqueurs laissant « … dans les DROM . » ; corrigé à la source
  sans toucher aux espaces avant « ; » et « » » qu'exige le français
- « programmation militaire 2024-2030 » lu comme la loi n° 2024-2030

make seed : 52 textes, 368 sources, 83 événements, 12 affaires CC, 7 analyses.
Zéro texte sans source URL (critère §8.2). Les 2 textes sans résumé et les 17
pertinences déduites sont marqués « à vérifier » avec leur motif.

99 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Cyber Mawonaj
2026-07-25 19:43:03 -04:00
co-authored by Claude Opus 5
parent c36b8dc631
commit c28243cf87
12 changed files with 2108 additions and 3 deletions
+23 -2
View File
@@ -228,6 +228,11 @@ class ResultatSeed:
textes: list[Texte] = field(default_factory=list)
avertissements: list[str] = field(default_factory=list)
# Marqueurs de citation portés par la ligne d'annexe de chaque texte.
# Les lignes éclatées transmettent les leurs aux deux textes issus d'elles :
# sans cela, l'accord « plateforme centrale » MACF n'hériterait d'aucune
# source, alors que sa ligne d'origine en cite trois.
marqueurs: dict[str, list[str]] = field(default_factory=dict)
def __len__(self) -> int:
return len(self.textes)
@@ -249,7 +254,9 @@ def parser(markdown: str) -> ResultatSeed:
else:
for ligne in tableau_a.lignes:
try:
resultat.textes.append(_lire_loi_promulguee(ligne))
texte = _lire_loi_promulguee(ligne)
resultat.textes.append(texte)
resultat.marqueurs[texte.id] = _marqueurs_de_ligne(ligne)
except Exception as erreur: # noqa: BLE001 — on continue le lot
resultat.avertissements.append(f"Tableau A, ligne {ligne!r} : {erreur}")
@@ -258,7 +265,11 @@ def parser(markdown: str) -> ResultatSeed:
else:
for ligne in tableau_b.lignes:
try:
resultat.textes.extend(_lire_texte_en_cours(ligne))
issus = _lire_texte_en_cours(ligne)
marqueurs = _marqueurs_de_ligne(ligne)
resultat.textes.extend(issus)
for texte in issus:
resultat.marqueurs[texte.id] = list(marqueurs)
except Exception as erreur: # noqa: BLE001
resultat.avertissements.append(f"Tableau B, ligne {ligne!r} : {erreur}")
@@ -272,6 +283,16 @@ def parser(markdown: str) -> ResultatSeed:
return resultat
def _marqueurs_de_ligne(ligne: dict[str, str]) -> list[str]:
"""Marqueurs de citation portés par une ligne, toutes colonnes confondues."""
marqueurs: list[str] = []
for cellule in ligne.values():
for marqueur in extraire_marqueurs(cellule):
if marqueur.brut not in marqueurs:
marqueurs.append(marqueur.brut)
return marqueurs
def _trouver(tableaux: list[Tableau], premiere_colonne: str) -> Tableau | None:
for tableau in tableaux:
if tableau.entetes and tableau.entetes[0] == premiere_colonne: