Python intermediaire (dict, regex, decomposition en phrases).
Note anti-theatre : ce capstone distille deux concepts REELS de la production EPITA — les ConvergentVerdict (Track DD #637, agents/core/synthesis/deep_synthesis_models.py) et les value-gates VG-1..VG-4 (FB-18, validate_value_gates dans agents/core/synthesis/deep_synthesis_agent.py). La logique déterministe des gates est reproduite fidelement (comptage de citations, mots, paragraphes). En production, la prose de synthese est generee par un LLM via semantic_kernel ; ici elle est produite deterministiquement pour rester executable sans LLM ni sous-module.
Note confidentialite : le texte analyse est entierement synthetique et neutre (comite abstrait, pas d’entite reelle). Aucun corpus EPITA n’est utilise. Le depot est public.
1. Introduction : pourquoi un capstone d’integration ?
Les rungs précédents ont construit des briques isolees : un detecteur de sophismes (rung 1), un solveur formel Tweety (rung 2), deux paradigmes d’orchestration (rung 3). Le capstone pose la question qui donne son sens a l’ensemble :
Un pipeline integre apporte-t-il une valeur mesurable par rapport a une analyse naive (0-shot), et comment la mesurer ?
La reponse courte : la valeur d’un pipeline d’analyse argumentative ne se mesure pas au volume de texte produit, mais a sa tracabilite — la synthese cite-t-elle les artefacts qu’elle invoque ? Plusieurs lectures aux declencheurs disjoints convergent-elles sur les mêmes findings ? Ce notebook rend cette intuition executable via deux instruments EPITA :
ConvergentVerdict : un finding (argument ou sophisme) signale par au moins 2 lectures distinctes est un verdict de haute confiance ; un finding d’une seule lecture reste faible. La disjonction des declencheurs (§3) est ce qui donne son sens a ce comptage.
Value-gates VG-1 a VG-4 : quatre gardes déterministes qui distinguent une synthese groundee (qui cite ses preuves) d’un boilerplate (template vide).
Ce que ce rung fait (et ne fait pas)
Fait : 3 lectures lexicales déterministes aux declencheurs disjoints sur un texte synthetique, calcul de convergence, 4 value-gates, comparaison baseline vs pipeline.
Ne fait pas : appel LLM (la prose de synthese est déterministe), solveur formel Tweety (rung 2 couvre cela), reseau d’agents semantic_kernel (rung 3 couvre l’orchestration).
2. Le texte synthetique de reference
Texte argumentatif neutre (comite abstrait, pas d’entite reelle) contenant plusieurs sophismes detectables : appel a l’autorite, attaque ad hominem, generalisation hative, appel a la peur, appel a la conformite. Il sert de terrain commun aux méthodes, a la baseline et au pipeline.
# Texte synthetique neutre (privacy : aucune entite reelle).TEXT = ("Le comite affirme que le nouveau reglement est necessaire pour la securite. ""En effet, tout le monde sait que les reglements previennent les accidents. ""D ailleurs, le directeur lui-meme a valide cette decision, donc elle est forcement bonne. ""Ceux qui s y opposent n y comprennent rien et cherchent simplement a semer le trouble. ""D ailleurs, puisqu aucun accident n a eu lieu cette annee, le reglement n est pas si urgent. ""Mais si nous ne l adoptons pas immediatement, la catastrophe est certaine. ""Tous les autres comites ont deja adopte un reglement similaire, nous devons faire de meme.")def split_sentences(text):"""Decoupe un texte en phrases (heuristique simple sur '. ').'""" parts = [p.strip() for p in text.split(". ") if p.strip()]return [p if p.endswith(".") else p +"."for p in parts]SENTENCES = split_sentences(TEXT)print(f"{len(SENTENCES)} phrases :")for i, s inenumerate(SENTENCES, 1):print(f" S{i}: {s}")
7 phrases :
S1: Le comite affirme que le nouveau reglement est necessaire pour la securite.
S2: En effet, tout le monde sait que les reglements previennent les accidents.
S3: D ailleurs, le directeur lui-meme a valide cette decision, donc elle est forcement bonne.
S4: Ceux qui s y opposent n y comprennent rien et cherchent simplement a semer le trouble.
S5: D ailleurs, puisqu aucun accident n a eu lieu cette annee, le reglement n est pas si urgent.
S6: Mais si nous ne l adoptons pas immediatement, la catastrophe est certaine.
S7: Tous les autres comites ont deja adopte un reglement similaire, nous devons faire de meme.
3. Trois lectures lexicales du meme texte
Chaque lecture produit une liste de findings, chacun rattache a l’index de la phrase concernee (sentence_index) et porte un artifact_id. Ce rattachement est la cle : c’est ce qui permet ensuite de detecter la convergence (plusieurs lectures sur la meme phrase).
Les trois lectures sont lexicales : chacune cherche des chaines dans le texte. Elles ne partagent aucun declencheur — un mot appartient a une seule lecture, et la cellule qui suit la troisieme le verifie par assert. C’est la condition pour qu’une convergence signale un recoupement reel plutot qu’un mot compte deux fois.
M1 : detecteur de sophismes par lexique (herite du rung 1).
M2 : analyse structurelle (affirmation forte sans connecteur de premisse).
M3 : detecteur d’absolutisme (mots marquant une certitude exageree).
Propriete des declencheurs partages, arbitree ici.certaine appartient a M3 (marqueur de certitude), tout le monde a M1 (generalisation hative), forcement a M3, bonne a M2, tous les autres a M1 (conformite). Les listes precedentes portaient certaine dans les trois lectures a la fois et tout le monde dans deux : une phrase contenant un seul de ces mots obtenait une convergence de force 2 ou 3 par construction.
# M1 : detecteur de sophismes par lexique (rung 1 style).# Propriete des declencheurs (cf §3) : ceux partages avec M2/M3 ont ete retires,# pour qu'aucun mot ne serve deux lectures. Sont partis "certaine" et# "forcement bonne" -- "certaine" et "forcement" appartiennent a M3, "bonne" a M2.FALLACY_KEYWORDS = {"appel_autorite": ["directeur", "valide cette"],"ad_hominem": ["comprennent rien", "semer le trouble"],"generalisation_hative": ["tout le monde sait", "tout le monde"],"appel_peur": ["catastrophe"],"appel_conformite": ["tous les autres", "faire de meme"],}def m1_keyword_detector(sentences): findings = [] fid =1for idx, s inenumerate(sentences): s_low = s.lower()for family, kws in FALLACY_KEYWORDS.items():for kw in kws:if kw in s_low: findings.append({"method": "M1_keyword","artifact_id": f"fall_{fid}","kind": "sophisme","family": family,"evidence": kw,"sentence_index": idx, }) fid +=1break# une famille par (phrase, match principal)return findingsm1_results = m1_keyword_detector(SENTENCES)print(f"M1 : {len(m1_results)} findings")for f in m1_results:print(f" S{f['sentence_index']+1} [{f['family']}] evidence='{f['evidence']}' ({f['artifact_id']})")
M1 : 5 findings
S2 [generalisation_hative] evidence='tout le monde sait' (fall_1)
S3 [appel_autorite] evidence='directeur' (fall_2)
S4 [ad_hominem] evidence='comprennent rien' (fall_3)
S6 [appel_peur] evidence='catastrophe' (fall_4)
S7 [appel_conformite] evidence='tous les autres' (fall_5)
# M2 : analyse structurelle -- affirmation forte SANS connecteur de premisse.# "certaine" a ete retire : le mot appartient a M3 (marqueur d'absolutisme),# le garder ici faisait converger M2 et M3 sur le meme declencheur (cf §3).CLAIM_WORDS = ["necessaire", "bonne", "urgent"]PREMISE_CONNECTORS = ["donc", "car ", "puisque", "parce que", "en effet"]def m2_structural_check(sentences): findings = [] fid =1for idx, s inenumerate(sentences): s_low = s.lower() has_claim =any(w in s_low for w in CLAIM_WORDS) has_premise =any(c in s_low for c in PREMISE_CONNECTORS)if has_claim andnot has_premise: findings.append({"method": "M2_structural","artifact_id": f"struct_{fid}","kind": "assertion_non_fondee","family": "assertion_non_fondee","evidence": next(w for w in CLAIM_WORDS if w in s_low),"sentence_index": idx, }) fid +=1return findingsm2_results = m2_structural_check(SENTENCES)print(f"M2 : {len(m2_results)} findings (affirmations sans premisse)")for f in m2_results:print(f" S{f['sentence_index']+1} assertion sur '{f['evidence']}' ({f['artifact_id']})")
M2 : 2 findings (affirmations sans premisse)
S1 assertion sur 'necessaire' (struct_1)
S5 assertion sur 'urgent' (struct_2)
# M3 : detecteur d'absolutisme (certitude exageree).# "tout le monde" appartient a M1 (generalisation hative) et "tous les" est une# sous-chaine de "tous les autres" (M1, conformite) : les deux ont ete retires,# sans quoi M1 et M3 se declenchaient ensemble sur le meme mot (cf §3).ABSOLUTISM_MARKERS = ["forcement", "aucun", "certaine"]def m3_absolutism_lens(sentences): findings = [] fid =1for idx, s inenumerate(sentences): s_low = s.lower()for marker in ABSOLUTISM_MARKERS:if marker in s_low: findings.append({"method": "M3_absolutism","artifact_id": f"abs_{fid}","kind": "absolutisme","family": "absolutisme","evidence": marker,"sentence_index": idx, }) fid +=1breakreturn findingsm3_results = m3_absolutism_lens(SENTENCES)print(f"M3 : {len(m3_results)} findings (marqueurs d'absolutisme)")for f in m3_results:print(f" S{f['sentence_index']+1} marqueur='{f['evidence']}' ({f['artifact_id']})")
Garde : les trois lectures ne partagent aucun declencheur
La convergence ne vaut que si les lectures sont disjointes. Le test porte sur deux formes de partage, parce que l’egalite seule ne suffit pas :
l’egalite — la meme chaine figure dans deux listes ;
la containment — une chaine d’une lecture est une sous-chaine d’une chaine d’une autre (tous les est contenu dans tous les autres). Deux lectures se declenchaient alors ensemble sur le meme mot sans partager une seule chaine, et un test d’intersection n’y aurait rien vu.
Le partage a l’interieur d’une meme lecture n’est pas fautif (M1 porte tout le monde et tout le monde sait) : il n’ajoute pas de lecture a la convergence.
# Garde de disjonction : les declencheurs des trois lectures doivent etre# distincts, a l'egalite ET par containment.LENS_TRIGGERS = {"M1": [kw for kws in FALLACY_KEYWORDS.values() for kw in kws],"M2": list(CLAIM_WORDS),"M3": list(ABSOLUTISM_MARKERS),}names =sorted(LENS_TRIGGERS)shared_exact = []shared_contained = []for i, a inenumerate(names):for b in names[i +1:]: shared_exact += [(a, b, t) for t inset(LENS_TRIGGERS[a]) &set(LENS_TRIGGERS[b])]for ta in LENS_TRIGGERS[a]:for tb in LENS_TRIGGERS[b]:if ta != tb and (ta in tb or tb in ta): shared_contained.append((a, b, ta, tb))print("declencheurs par lecture : "+", ".join(f"{n}={len(LENS_TRIGGERS[n])}"for n in names))print(f"partages a l'identique : {shared_exact if shared_exact else'aucun'}")print(f"partages par containment : {shared_contained if shared_contained else'aucun'}")assertnot shared_exact, f"declencheur identique dans deux lectures : {shared_exact}"assertnot shared_contained, f"declencheur d'une lecture contenu dans une autre : {shared_contained}"print()print("OK : aucun declencheur n'est partage par deux lectures.")
declencheurs par lecture : M1=9, M2=3, M3=3
partages a l'identique : aucun
partages par containment : aucun
OK : aucun declencheur n'est partage par deux lectures.
Lecture du resultat. Les trois assert passent : aucune chaine n’appartient a deux lectures, et aucune n’est contenue dans une chaine d’une autre lecture. La convergence mesure donc des lectures distinctes, et non le nombre de fois qu’un mot a ete compte.
# Smoke test : les 3 methodes tournent et produisent des findings sur le MEME texte.METHODS = {"M1_keyword": m1_results, "M2_structural": m2_results, "M3_absolutism": m3_results}total =sum(len(v) for v in METHODS.values())print(f"Total findings (3 methodes) : {total}")for name, findings in METHODS.items():print(f" {name}: {len(findings)}")
Interpretation : trois lectures lexicales, pas trois perspectives independantes
Chaque lecture regarde le texte sous un angle different : lexicale (M1), structurelle (M2), stylistique (M3). Aucune n’est exhaustive. La question devient : ou ces lectures se recoupent-elles ? Ce recoupement est exactement ce que capture le ConvergentVerdict.
Ce que le recoupement ne dit pas : il ne mesure pas l’independance des lectures. Deux lectures qui partageraient un declencheur signaleraient la meme phrase deux fois pour le meme mot — une convergence de forme, pas de fond. C’est pourquoi les declencheurs ont ete partitionnes en §3, et pourquoi la garde ci-dessus le verifie.
4. ConvergentVerdict : la convergence multi-lecture (Track DD #637)
Un finding signale par au moins 2 lectures distinctes sur la meme phrase devient un verdict convergent : sa confiance est haute parce que deux lectures distinctes l’ont signale. La convergence_strength = nombre de lectures distinctes qui convergent ; les verdicts sont tries par force decroissante (les plus convergents d’abord).
Distillation fidele de ConvergentVerdict (agents/core/synthesis/deep_synthesis_models.py:111). En production, la convergence s’opere sur des findings produits par des agents LLM, dont les instruments ne partagent pas de lexique ; ici sur trois lectures lexicales dont les declencheurs sont disjoints (§3). La force 3 suppose donc trois declencheurs distincts dans trois lectures distinctes — elle n’est plus atteignable par un seul mot.
from collections import defaultdictdef compute_convergent_verdicts(methods_results):"""Regroupe les findings par phrase, ne garde que ceux ou >= 2 methodes convergent.""" by_sentence = defaultdict(list)for method, findings in methods_results.items():for f in findings: by_sentence[f["sentence_index"]].append((method, f)) verdicts = [] vid =1for sent_idx, items insorted(by_sentence.items()): methods_set =sorted({m for m, _ in items})iflen(methods_set) >=2: sentence = SENTENCES[sent_idx] verdicts.append({"verdict_id": f"conv_{vid}","statement": (f"Convergence sur S{sent_idx+1} : {len(methods_set)} methodes "f"({', '.join(methods_set)}) signalent un probleme." ),"convergence_strength": len(methods_set),"sentence_index": sent_idx,"sentence": sentence,"methods": methods_set,"findings": [f for _, f in items], }) vid +=1# Tri par force de convergence decroissante. verdicts.sort(key=lambda v: -v["convergence_strength"])return verdictsconvergent_verdicts = compute_convergent_verdicts(METHODS)print(f"{len(convergent_verdicts)} verdict(s) convergent(s) (force >= 2), tries par force :")for v in convergent_verdicts:print(f" [{v['verdict_id']}] force={v['convergence_strength']} | {v['statement']}")print(f" phrase : \"{v['sentence']}\"")
3 verdict(s) convergent(s) (force >= 2), tries par force :
[conv_1] force=2 | Convergence sur S3 : 2 methodes (M1_keyword, M3_absolutism) signalent un probleme.
phrase : "D ailleurs, le directeur lui-meme a valide cette decision, donc elle est forcement bonne."
[conv_2] force=2 | Convergence sur S5 : 2 methodes (M2_structural, M3_absolutism) signalent un probleme.
phrase : "D ailleurs, puisqu aucun accident n a eu lieu cette annee, le reglement n est pas si urgent."
[conv_3] force=2 | Convergence sur S6 : 2 methodes (M1_keyword, M3_absolutism) signalent un probleme.
phrase : "Mais si nous ne l adoptons pas immediatement, la catastrophe est certaine."
Interpretation : ce que la force de convergence mesure — et ce qu’elle ne mesure pas
Apres partition des declencheurs (§3), une phrase n’atteint la force maximale que si trois lectures differentes se declenchent sur trois mots differents. Avant cette partition, certaine figurait dans les trois listes : toute phrase le contenant obtenait une force 3 par construction, sans qu’aucune lecture n’ajoute d’information. La force mesure donc un recoupement de lectures, pas le nombre de fois qu’un mot a ete compte.
Les findings d’une seule lecture restent des hypotheses faibles, non elevees au rang de verdict.
4bis. Texte hors echantillon : ce que les trois lectures ne voient pas
Les lexiques ci-dessus ont ete constitues sur le texte de reference. Un texte hors echantillon, portant des sophismes qu’un lecteur humain identifie sans effort, mesure ce que la table laisse passer. Les trois lectures tournent sur le meme instrument que ci-dessus : seules les phrases changent.
# Texte hors echantillon : deux sophismes lisibles par un humain, aucun# declencheur des trois lectures -- l'assert le verifie plutot que de le supposer.TEXT_HORS_ECHANTILLON = ("Notre solution est la meilleure du marche. ""Les utilisateurs experimentes le disent. ""Tout le reste est une perte de temps.")SENTENCES_HORS = split_sentences(TEXT_HORS_ECHANTILLON)hors = {"M1_keyword": m1_keyword_detector(SENTENCES_HORS),"M2_structural": m2_structural_check(SENTENCES_HORS),"M3_absolutism": m3_absolutism_lens(SENTENCES_HORS),}verdicts_hors = compute_convergent_verdicts(hors)print(f"{len(SENTENCES_HORS)} phrases hors echantillon :")for i, s inenumerate(SENTENCES_HORS, 1):print(f" S{i}: {s}")print()for name, findings in hors.items():print(f" {name}: {len(findings)} finding(s)")print(f" verdicts convergents : {len(verdicts_hors)}")print()assertsum(len(f) for f in hors.values()) ==0, ("un declencheur s'est allume hors echantillon : la table couvre ce texte, ""choisir un autre texte pour la mesure")print("Aucune des trois lectures ne se declenche : appel a l'autorite sans")print("'directeur', superlatif sans 'bonne', totalite sans 'tous les'.")
3 phrases hors echantillon :
S1: Notre solution est la meilleure du marche.
S2: Les utilisateurs experimentes le disent.
S3: Tout le reste est une perte de temps.
M1_keyword: 0 finding(s)
M2_structural: 0 finding(s)
M3_absolutism: 0 finding(s)
verdicts convergents : 0
Aucune des trois lectures ne se declenche : appel a l'autorite sans
'directeur', superlatif sans 'bonne', totalite sans 'tous les'.
# Producteur agentique sur le texte hors echantillon (issue #18394, point 3) :# la ou les trois lectures rendent 0 finding, un agent LLM lit le texte.# Un seul appel, comptabilise ; pas de repli silencieux si la cle manque.import osfrom pathlib import Pathfrom dotenv import load_dotenvfrom openai import OpenAIdef _trouver_env_argument_analysis(start: Path, max_up: int=6) -> Path:"""Localise Argument_Analysis/.env en remontant depuis start (pattern 08b-Executor).""" marker ="Argumentation-08-Capstone-Python.ipynb" candidate = start.resolve()for _ inrange(max_up):if (candidate / marker).exists():return candidate /".env"if (candidate /"Argument_Analysis"/ marker).exists():return candidate /"Argument_Analysis"/".env"iflen(candidate.parts) >1: candidate = candidate.parentelse:breakraiseRuntimeError(f"Dossier Argument_Analysis/ introuvable depuis {start} (marqueur={marker})")load_dotenv(_trouver_env_argument_analysis(Path.cwd()), override=True)_model_id = os.getenv("OPENAI_CHAT_MODEL_ID", "gpt-5-mini")_api_key = os.getenv("OPENAI_API_KEY")ifnot _api_key:# L'issue #18394 exige un appel REEL, message explicite, pas de template de repli.raiseRuntimeError("OPENAI_API_KEY absent : creer MyIA.AI.Notebooks/SymbolicAI/Argument_Analysis/.env ""(modele : .env.example de la serie). Les cellules agentiques de ce carnet ""sont des appels LLM reels, sans repli silencieux." )LLM_CALL_COUNT =0# cout total d'appels du carnet, imprime en section 6# Robustesse : le template .env.example porte OPENAI_BASE_URL="" -- une chaine VIDE# que le SDK prend pour base_url (URL sans protocole). Chaine vide -> None._base_url = os.getenv("OPENAI_BASE_URL") orNone_agent_client = OpenAI(api_key=_api_key, base_url=_base_url)_prompt_hors = ("Tu es un analyste rhetorique expert. Identifie, phrase par phrase, tout sophisme ""ou erreur de raisonnement dans le texte suivant (famille : appel a l'autorite, ""generalisation abusive, faux dilemme, pente glissante, etc.). Pour chaque phrase ""problematique : la famille du sophisme et une justification en une ligne. ""Si une phrase est saine, ne la cite pas.\n\nTexte :\n---\n{text}\n---")_resp_hors = _agent_client.chat.completions.create( model=_model_id, messages=[{"role": "user", "content": _prompt_hors.format(text=TEXT_HORS_ECHANTILLON)}], max_completion_tokens=600, reasoning_effort="minimal",)LLM_CALL_COUNT +=1agent_findings_hors = _resp_hors.choices[0].message.content_usage_hors = _resp_hors.usageprint(f"[agent LLM] modele={_resp_hors.model} | {len(agent_findings_hors)} caracteres | appel numero {LLM_CALL_COUNT} | finish={_resp_hors.choices[0].finish_reason} | tokens={_usage_hors.prompt_tokens}+{_usage_hors.completion_tokens} (prompt+completion, total={_usage_hors.total_tokens})")print()print(agent_findings_hors)print()_lignes = [l for l in agent_findings_hors.strip().splitlines() if l.strip()]print(f"Reponse agent : {len(_lignes)} lignes non vides, a confronter aux 0 finding des trois lectures.")
[agent LLM] modele=gpt-5-mini-2025-08-07 | 1006 caracteres | appel numero 1 | finish=stop | tokens=116+244 (prompt+completion, total=360)
1) « Notre solution est la meilleure du marché. »
- Famille : affirmation péremptoire / argument d'autorité implicite / généralisation hâtive.
- Justification : Présentation catégorique sans preuve ni critères ; prétendre « la meilleure » généralise à l’ensemble du marché sans comparaison ni données.
2) « Les utilisateurs expérimentés le disent. »
- Famille : appel à l'autorité (argumentum ad verecundiam) / possibilité de biais d'échantillonnage.
- Justification : S'appuyer sur « des utilisateurs expérimentés » comme preuve suffit sans préciser qui, combien, ni comment ; l'autorité supposée est utilisée pour légitimer l'affirmation.
3) « Tout le reste est une perte de temps. »
- Famille : généralisation abusive / faux dilemme / exclusion hâtive.
- Justification : Écarte toutes les alternatives en les réduisant à rien d'utile sans examen ; présente implicitement un choix exclusif (« notre solution » vs « tout le reste ») alors qu'il peut y avoir plusieurs options valables.
Reponse agent : 9 lignes non vides, a confronter aux 0 finding des trois lectures.
Lecture du resultat. Les trois lectures rendent 0 finding sur ce texte : aucune ne se declenche, et aucun verdict convergent n’en sort. Ce silence ne dit pas que le texte est sain — il dit que les declencheurs sont absents.
C’est la limite structurelle d’une analyse par lexique : elle mesure la presence de mots, pas la presence de sophismes. Un appel a l’autorite sans le mot « directeur », un superlatif sans « bonne », une totalite sans « tous les » passent la table sans etre vus, alors qu’un lecteur les identifie immediatement.
La cellule suivante execute le producteur qui comble ce trou : un seul appel au modele de la serie (gpt-5-mini) lit le texte hors echantillon. La contrepartie est mesurable : les findings de l’agent se paient en un appel LLM (comptabilise, cout total imprime en section 6), ceux de la table se paient en entrees de lexique — et une table n’entre jamais dans un texte qu’elle n’a pas prevu.
5. Value-gates VG-1 a VG-4 (FB-18, validate_value_gates)
Les value-gates mesurent la qualite de la synthese generee (le rapport final). Elles distinguent une synthese groundee — qui cite explicitement les artefacts qu’elle invoque via des citations [artifact:champ:id] — d’un boilerplate (template vide). Reproduction fidele de la logique déterministe EPITA :
Gate
Condition de reussite
Ce qu’elle detecte
VG-1 citation_density
synthese non vide ET nb_citations >= max(1, mots // 200)
synthese qui ne cite pas assez ses sources
VG-2 state_guard
>= 3 champs artefact peuples dans l’etat
run qui n’a rien produit de substantiel
VG-3 no_boilerplate
synthese non vide ET >= 1 citation ET les 4 sections requises presentes
C’est le coeur du capstone, et la question qu’il doit poser honnetement : que gagne-t-on a orchestrer des instruments, par rapport a un seul appel au meme modele ? (issue #18394, point 1.)
Deux syntheses sont generees pour le meme texte :
Baseline 0-shot REELLE : un seul appel au modele de la serie (gpt-5-mini, via Argument_Analysis/.env), prompt 0-shot vendore du tronc EPITA (scripts/run_capstone_c1.py, ZEROSHOT_PROMPT, commit ecfd9b9c31). La reponse est conservee integralement — c’est une sortie de modele, pas un litteral du carnet — puis passee aux memes value-gates que le pipeline. Si elle passe une gate, le tableau en dessous le montre.
Pipeline integral : compose les 3 lectures lexicales, peuple un etat avec 3+ champs artefact (arguments, sophismes, verdicts convergents) et genere une synthese qui cite ces artefacts.
L’asymetrie a lire honnetement : la baseline ecrit generalement mieux que le pipeline (c’est un LLM contre un gabarit), mais elle ne construit aucun artefact — ses citations eventuelles ne pointent rien de verifiable. Les value-gates mesurent la tracabilite, pas l’eloquence.
# Baseline 0-shot REELLE (issue #18394, point 1) : un seul appel au modele de# la serie, reponse conservee integralement, pas de repli silencieux.# ZEROSHOT_PROMPT vendore du tronc EPITA : scripts/run_capstone_c1.py,# commit ecfd9b9c31d299ad9e08ee0e7a726d436f4ebd8e (verbatim).ZEROSHOT_PROMPT ="""Tu es un analyste rhetorique expert. Analyse le texte suivant de maniere exhaustive.Pour chaque argument identifie, fournis :1. La these de l'argument2. Les premices explicites et implicites3. Le type de raisonnement (deductif, inductif, analogique, causal, etc.)4. Tout sophisme ou erreur de raisonnement detecte (avec la famille : appel a l'autorite, homme de paille, faux dilemme, pente glissante, etc.)5. La force persuasive de l'argument (1-10)Ensuite, fournis une evaluation globale :6. La structure argumentative du texte (nombre et types d'arguments)7. Les strategies rhetoriques employees8. Les points forts et les faiblesses de l'argumentation9. Une conclusion sur la qualite globale de l'argumentationTexte :---{text}---"""_zs_resp = _agent_client.chat.completions.create( model=_model_id, messages=[{"role": "user", "content": ZEROSHOT_PROMPT.format(text=TEXT)}], max_completion_tokens=3000, reasoning_effort="minimal",)LLM_CALL_COUNT +=1baseline_synth = _zs_resp.choices[0].message.contentbaseline_fields =0# un appel 0-shot ne construit AUCUN artefact : rien de verifiable a citerbaseline_vg = validate_value_gates(baseline_synth, baseline_fields)_usage_zs = _zs_resp.usageprint(f"=== Baseline 0-shot REELLE : modele={_zs_resp.model} | {len(baseline_synth)} caracteres | appel numero {LLM_CALL_COUNT} | finish={_zs_resp.choices[0].finish_reason} | tokens={_usage_zs.prompt_tokens}+{_usage_zs.completion_tokens} (prompt+completion, total={_usage_zs.total_tokens}) ===")print()print(baseline_synth)print()for k in ("vg1_citation_density", "vg2_state_guard", "vg3_no_boilerplate", "vg4_transversal_insight"):print(f" {k}: pass={baseline_vg[k]['pass']}")print(f" all_pass={baseline_vg['all_pass']}")
=== Baseline 0-shot REELLE : modele=gpt-5-mini-2025-08-07 | 10808 caracteres | appel numero 2 | finish=stop | tokens=329+2550 (prompt+completion, total=2879) ===
Voici une analyse rhétorique et logique détaillée du texte fourni. J’examine chaque argument identifié en respectant les demandes (thèse, prémisses explicites/implicites, type de raisonnement, sophismes/erreurs, force persuasive), puis je donne une évaluation globale.
Texte analysé (raccourci) :
Le comité affirme que le nouveau règlement est nécessaire pour la sécurité. En effet, tout le monde sait que les règlements préviennent les accidents. D’ailleurs, le directeur lui‑même a validé cette décision, donc elle est forcément bonne. Ceux qui s’y opposent n’y comprennent rien et cherchent simplement à semer le trouble. D’ailleurs, puisqu’aucun accident n’a eu lieu cette année, le règlement n’est pas si urgent. Mais si nous ne l’adoptons pas immédiatement, la catastrophe est certaine. Tous les autres comités ont déjà adopté un règlement similaire, nous devons faire de même.
Analyse par argument identifié
Argument A
1. Thèse : Le nouveau règlement est nécessaire pour la sécurité.
2. Prémisses explicites :
- Le comité affirme que le règlement est nécessaire.
- Les règlements préviennent les accidents.
Prémisses implicites :
- Prévenir les accidents = être nécessaire pour la sécurité.
- Ce règlement en particulier aura l’effet préventif général attribué aux règlements.
3. Type de raisonnement : Inductif général (on généralise l’effet des règlements) et causal (les règlements causent la prévention d’accidents).
4. Sophismes / erreurs détectés :
- Généralisation hâtive / induction non justifiée : on passe de l’idée générale que les règlements peuvent prévenir des accidents à l’affirmation que celui-ci en particulier est nécessaire.
- Ambiguïté causale : présuppose sans preuve que le règlement aura l’effet causal désiré (effet non démontré, corrélation implicite présentée comme causalité).
5. Force persuasive : 5/10.
- Pourquoi : intuition socialement plausible (la sécurité = bonne raison), mais manque d’étayage factuel et d’explication sur le mécanisme précis.
Argument B
1. Thèse : La décision est forcément bonne parce que le directeur l’a validée.
2. Prémisses explicites :
- Le directeur a validé la décision.
Prémisses implicites :
- Le directeur est infaillible / toujours compétent / autorité suffisante pour garantir la qualité d’une décision.
- Validation par une autorité équivaut à vérité/justesse.
3. Type de raisonnement : Appel à l’autorité (argument d’autorité).
4. Sophismes / erreurs détectés :
- Appel à l’autorité (potentiellement illégitime) : absence de justification indépendante ; la validité d’un argument ne dépend pas seulement du statut de celui qui l’approuve.
- Argumentum ad verecundiam si l’autorité n’est pas compétente sur le point précis.
5. Force persuasive : 4/10.
- Pourquoi : efficace sur un auditoire respectueux de l’autorité, faible sur un public exigeant des preuves.
Argument C
1. Thèse : Ceux qui s’opposent n’y comprennent rien et cherchent à semer le trouble (donc leur opposition est illégitime).
2. Prémisses explicites :
- Il y a des opposants.
Prémisses implicites :
- L’opposition est motivée par mauvaise foi ou ignorance, non par arguments valables.
- Disqualifier l’adversaire suffit à discréditer son argument.
3. Type de raisonnement : Ad hominem / attaque du caractère ; raisonnement polémique (délegitimation).
4. Sophismes / erreurs détectés :
- Ad hominem (attaque contre les personnes plutôt que contre leurs arguments).
- Épouvantail possible si simplifie ou caricature l’opposition (pas d’engagement avec leurs raisons).
5. Force persuasive : 3/10.
- Pourquoi : peut intimider ou réduire la contestation chez un public non critique, mais ne répond pas aux arguments ; perçu comme malhonnête/rhétorique si l’auditoire veut débat rationnel.
Argument D
1. Thèse : Puisqu’aucun accident n’a eu lieu cette année, le règlement n’est pas si urgent.
2. Prémisses explicites :
- Aucun accident cette année.
Prémisses implicites :
- L’absence d’accident récent implique faible probabilité d’accident futur ou faible nécessité d’intervention immédiate.
- La nécessité d’un règlement se juge à l’urgence apparente (présence d’incidents passés récents).
3. Type de raisonnement : Inductif / probabiliste (inférence de la fréquence passée vers la probabilité future).
4. Sophismes / erreurs détectés :
- Raisonnement par ignorance temporelle / base-rate fallacy possible : absence d’événements récents n’exclut pas un risque latent.
- Fausse dichotomie implicite si on oppose « urgent » vs « pas urgent » sans considérer options intermédiaires ou prévention proactive.
5. Force persuasive : 4/10.
- Pourquoi : paraît raisonnable à première vue (on réduit les mesures si pas de problèmes), mais ignore la prévention et la portée des risques.
Argument E
1. Thèse : Si nous n’adoptons pas le règlement immédiatement, la catastrophe est certaine.
2. Prémisses explicites :
- L’adoption immédiate peut empêcher une catastrophe.
Prémisses implicites :
- Il existe une probabilité très élevée (voire 100 %) d’une catastrophe en l’absence du règlement.
- Le règlement est la seule ou la principale mesure efficace pour éviter la catastrophe.
3. Type de raisonnement : Causal avec tonalité de pente glissante / appel à la peur (argument de peur).
4. Sophismes / erreurs détectés :
- Pente glissante et argument alarmiste / peur exagérée : affirme une conséquence extrême certaine sans preuve.
- Fausse certitude (catastrophe "certaine") — sur-détermination de la probabilité.
- Éventuellement fausse dichotomie si présenté comme choix entre adoption immédiate ou catastrophe.
5. Force persuasive : 6/10.
- Pourquoi : très mobilisateur émotionnellement (peur/sécurité), mais rationnellement faible sans éléments probants. Efficace politiquement pour pousser à l’urgence.
Argument F
1. Thèse : Tous les autres comités ont déjà adopté un règlement similaire ; nous devons faire de même.
2. Prémisses explicites :
- Les autres comités ont adopté un règlement similaire.
Prémisses implicites :
- L’action des autres comités constitue un modèle valide à suivre (argumentum ad populum / argument d’exemple).
- Si d’autres le font, c’est parce que c’est la bonne chose à faire.
3. Type de raisonnement : Analogique / par conformité sociale ; argument d’autorité collective / appel à la popularité.
4. Sophismes / erreurs détectés :
- Argumentum ad populum (appel à la popularité) : la vérité ou la pertinence d’une mesure ne découle pas automatiquement du fait que d’autres la prennent.
- Éventuelle fausse analogie si les contextes des autres comités diffèrent.
5. Force persuasive : 5/10.
- Pourquoi : pression de conformité sociale est persuasive (surtout en organisation), mais rationnellement faible sans justification contextuelle.
Évaluation globale
6. Structure argumentative du texte
- Nombre d’arguments : 6 arguments distincts identifiés (A à F), dont certains se recoupent.
- Types d’arguments : mélange d’arguments causaux/inductifs (A, D, E), appels à l’autorité (B), attaques ad hominem (C), appels à la peur (E), et appel à la popularité/conformité (F). L’argument principal affirmé au départ (A) est soutenu par des motifs rhétoriques variés plutôt que par des preuves factuelles détaillées.
7. Stratégies rhétoriques employées
- Appels émotionnels : appel à la peur (danger/catastrophe), stigmatisation des opposants (désamorçage).
- Appel à l’autorité : mention du directeur et des autres comités comme validation sociale.
- Généralisation présumée : "tout le monde sait que..." pour créer une évidence sociale.
- Polarisation / délegitimation : réduire l’opposition à l’ignorance ou à la mauvaise foi.
- Contradiction apparente utilisée tactiquement (aucun accident = pas urgent), puis menace (sinon catastrophe) pour pousser à l’adoption immédiate — stratégie d’ambiguïté temporelle pour mobiliser selon l’auditoire.
- Conformisme social : "les autres l'ont fait" pour légitimer.
8. Points forts et faiblesses de l’argumentation
Points forts
- Efficacité émotionnelle : l’argument utilise la sécurité et la peur pour mobiliser, ce qui est souvent convaincant dans les débats organisationnels.
- Multi‑faces : combine plusieurs registres (sécurité, autorité, conformité sociale), ce qui touche différents types d’auditoires.
- Simplicité et clarté : messages faciles à comprendre et rapides à mémoriser ("sécurité", "directeur", "autres comités").
Faiblesses
- Manque de preuves empiriques : absence de données, d’analyses de risque, d’exemples concrets montrant que le règlement réduira effectivement les accidents.
- Présence de sophismes : appel à l’autorité, ad hominem, appel à la peur, argumentum ad populum, généralisations non justifiées — ce qui affaiblit la crédibilité argumentaire.
- Contradiction interne : affirme à la fois que le règlement "n’est pas si urgent" (absence d’accident) et en même temps que "la catastrophe est certaine" si on attend — manque de cohérence temporelle et probabiliste.
- Absence d’engagement avec objections réelles : l’argument disqualifie les opposants sans répondre substantiellement à leurs motifs.
- Dépendance à la rhétorique plutôt qu’à l’argumentation rationnelle (preuves, coûts/bénéfices, alternatives, évaluations du risque).
9. Conclusion sur la qualité globale de l’argumentation
L’argumentation est globalement faible sur le plan logique et probatoire, même si elle peut être persuasive sur le plan émotionnel et politique. Le texte compile plusieurs ressorts rhétoriques efficaces pour convaincre rapidement (autorité, peur, conformité sociale), mais il repose sur des sophismes et des prémisses non démontrées. Pour être robuste et crédible, l’argument devrait présenter des preuves empiriques (analyses de risques, données d’accidents, impact précis du règlement), répondre sérieusement aux objections, et éviter les attaques ad hominem et les appels purement d’autorité.
Recommandations rapides pour renforcer l’argumentation
- Fournir données et analyses : statistiques d’accidents, études montrant l’efficacité du règlement proposé.
- Expliquer le mécanisme causal : comment exactement le règlement réduira les risques.
- Traiter les objections de manière argumentée plutôt que de disqualifier les opposants.
- Éviter formulations catégoriques (“catastrophe certaine”) ; préférer éval. probabiliste et scénarios.
- Utiliser l’autorité et les exemples d’autres comités en complément de preuves plutôt qu’en substitution.
Si tu veux, je peux maintenant :
- Reformuler le texte pour qu’il devienne une argumentation logiquement solide (version corrigée),
- Fournir une grille d’évaluation critique à appliquer à d’autres textes similaires,
- Ou développer des contre‑arguments structurés pour chacune des thèses avancées.
vg1_citation_density: pass=False
vg2_state_guard: pass=False
vg3_no_boilerplate: pass=False
vg4_transversal_insight: pass=False
all_pass=False
def pipeline_synthesis(sentences, methods_results, verdicts):"""Pipeline integral : synthese GROUNDEE qui cite les artefacts.'"""# Extraction simple : chaque phrase est un candidat-argument. arguments = [{"id": f"arg_{i+1}", "text": s} for i, s inenumerate(sentences)]# Toutes les findings de sophismes (toutes methodes confondues). fallacies = []for method, findings in methods_results.items():for f in findings: fallacies.append(f)# Etat peuple : 3+ champs artefact distincts. populated_fields =3# arguments, sophismes, convergent_verdicts parts = [] parts.append("## Arguments identifies\n")for a in arguments: parts.append(f"- Argument [{a['id']}] [artifact:arguments:{a['id'].split('_')[1]}] : {a['text']}") parts.append("\n## Sophismes detectes\n")for i, f inenumerate(fallacies, 1): parts.append(f"- {f['family']} (S{f['sentence_index']+1}) [artifact:sophismes:{i}] : par {f['method']}.") parts.append("\n## Verdicts convergents\n")for i, v inenumerate(verdicts, 1): parts.append(f"- {v['statement']} [artifact:convergent:{i}] (force {v['convergence_strength']}).") parts.append("\n## Synthese\n")# Paragraphe de synthese citant >= 2 champs distincts -> VG-4. parts.append(f"Le pipeline identifie {len(arguments)} arguments [artifact:arguments:1] et "f"{len(fallacies)} sophismes [artifact:sophismes:1]. La convergence est forte : "f"{len(verdicts)} verdicts de force >= 2 [artifact:convergent:1], dont le plus solide "f"atteint la force {verdicts[0]['convergence_strength'] if verdicts else0}. "f"Ces recoupements confirment un raisonnement fragile [artifact:arguments:2]." )return"\n".join(parts), populated_fieldspipeline_synth, pipeline_fields = pipeline_synthesis(SENTENCES, METHODS, convergent_verdicts)pipeline_vg = validate_value_gates(pipeline_synth, pipeline_fields)print("=== Pipeline integral ===")print(f"champs peuples : {pipeline_fields}")for k in ("vg1_citation_density", "vg2_state_guard", "vg3_no_boilerplate", "vg4_transversal_insight"):print(f" {k}: pass={pipeline_vg[k]['pass']}")print(f" all_pass={pipeline_vg['all_pass']}")
# Tableau comparatif baseline vs pipeline.print(f"{'Gate':<28}{'Baseline 0-shot':<18}{'Pipeline integral':<18}")print("-"*64)order = ("vg1_citation_density", "vg2_state_guard", "vg3_no_boilerplate", "vg4_transversal_insight")for k in order: b ="REUSSI"if baseline_vg[k]["pass"] else"ECHOUC" p ="REUSSI"if pipeline_vg[k]["pass"] else"ECHOUC"print(f"{k:<28}{b:<18}{p:<18}")print("-"*64)b_all ="REUSSI"if baseline_vg["all_pass"] else"ECHOUC"p_all ="REUSSI"if pipeline_vg["all_pass"] else"ECHOUC"print(f"{'all_pass':<28}{b_all:<18}{p_all:<18}")print()print(f"Verdicts convergents (pipeline) : {len(convergent_verdicts)}, "f"force max = {max((v['convergence_strength'] for v in convergent_verdicts), default=0)}")# Cout : ce que chaque colonne paie pour sa synthese.print()print(f"Cout : {LLM_CALL_COUNT} appel(s) LLM au total dans ce carnet "f"(hors echantillon + 0-shot) ; pipeline lexical : 0 appel, "f"3 lexiques ecrits a la main.")
Gate Baseline 0-shot Pipeline integral
----------------------------------------------------------------
vg1_citation_density ECHOUC REUSSI
vg2_state_guard ECHOUC REUSSI
vg3_no_boilerplate ECHOUC REUSSI
vg4_transversal_insight ECHOUC REUSSI
----------------------------------------------------------------
all_pass ECHOUC REUSSI
Verdicts convergents (pipeline) : 3, force max = 2
Cout : 2 appel(s) LLM au total dans ce carnet (hors echantillon + 0-shot) ; pipeline lexical : 0 appel, 3 lexiques ecrits a la main.
Interpretation : la valeur se mesure au grounding
La baseline n’est pas un epouvantail : c’est une vraie sortie de modele (gpt-5-mini, ~10 800 caracteres, finish=stop, ~2 900 tokens) — une analyse souvent plus lisible que celle du pipeline, qui identifie les sophismes du texte avec des justifications pertinentes. Et elle echoue quand meme aux quatre gates :
VG-1 : riche, mais sans aucune citation [artifact:...] — rien ne permet de remonter d’une affirmation de la synthese a l’artefact qui la porte ;
VG-2 : l’appel 0-shot ne construit aucun artefact (0 champ peuple) — il n’y a rien a auditer derriere le texte ;
VG-3 : sections libres et non tracees — le contenu existe, la forme ancrée sur des artefacts, non ;
VG-4 : aucun paragraphe ne croise 2 champs distincts — pas de synthese transversale verifiable.
La lecon en sort durcie : une analyse eloquente n’est pas une analyse auditable. Le pipeline lexical n’ecrit pas mieux — mais chaque phrase de sa synthese pointe un artefact construit, verifiable et rejouable. C’est la que se paie l’orchestration : la baseline produit du texte, le pipeline produit une chaine de tracabilite. Et la section 4bis a mesure l’autre face : la ou les trois lectures restent muettes, un seul appel agent lit le texte — chaque approche paye ce que l’autre ne sait pas faire (des appels LLM d’un cote, des entrees de lexique de l’autre).
Exercice 1 : ajouter une 5e value-gate (convergence floor)
Ajoutez VG-5 convergence_floor : pass = au moins un ConvergentVerdict de force >= 2. Integrez-la dans validate_value_gates (ou une fonction derivee) et executez-la sur la baseline (etat sans verdicts) et le pipeline. Que conclure sur la capacity d’une baseline a “passer” cette gate ?
# Exercice 1 -- a completer# TODO etudiant : definir vg5_convergence_floor et l'evaluer sur baseline + pipeline.# Indice : la baseline n'a pas de verdicts ; le pipeline a `convergent_verdicts`.# Etape 1 : ecrire la fonction prenant (synthesis_md, populated_fields, verdicts).# Etape 2 : l'appliquer aux deux syntheses.passprint("Exercice 1 a completer : definir vg5_convergence_floor et evaluer sur baseline + pipeline")
Exercice 1 a completer : definir vg5_convergence_floor et evaluer sur baseline + pipeline
Exercice 2 : diagnostic des gates qui echouent
Ecrivez une fonction diagnose_failures(vg_result) qui retourne, pour chaque gate en echec, une ligne de diagnostic explicant pourquoi (ex. “VG-1 : 0 citations pour 60 mots, seuil 1”). Testez-la sur la baseline.
# Exercice 2 -- a completer# TODO etudiant : ecrire diagnose_failures(vg_result) -> List[str].# Indice : chaque gate porte dans vg_result les compteurs (citations, words, required_citations, fields...).# Etape 1 : iterer sur vg1..vg4.# Etape 2 : pour chaque gate not pass, formater un message utilisant ses compteurs.result =None# TODO etudiantprint("Exercice 2 a completer : ecrire diagnose_failures(vg_result) -> List[str]")
Exercice 2 a completer : ecrire diagnose_failures(vg_result) -> List[str]
Construisez une synthese adversariale qui tente de “tromper” les gates en bourrant des citations [artifact:...]sans analyse reelle (un seul champ artefact repete). Observez quelles gates passent et lesquelles echouent encore. Conclusion : pourquoi VG-4 (transversal insight) est-elle essentielle pour completer VG-1 ?
# Exercice 3 -- a completer# TODO etudiant : construire adversarial_synth qui bourre des citations d'UN seul champ.# Indice : VG-1 compte les citations brutes, VG-4 exige >= 2 champs DISTINCTS par paragraphe.# Etape 1 : ecrire la synthese avec beaucoup de [artifact:arguments:N] mais jamais 2 champs differents.# Etape 2 : la soumettre a validate_value_gates et observer.passprint("Exercice 3 a completer : construire adversarial_synth (citations d'un seul champ)")
Exercice 3 a completer : construire adversarial_synth (citations d'un seul champ)
7. Pont vers l’état partagé
Les verdicts convergents et les findings des trois méthodes alimentent le même conteneur partagé — l’objet RhetoricalAnalysisState du module argumentation_lib — que tous les rungs enrichissent. Le rung 1 y écrit ses détections informelles, le rung 2 y ajoute les verdicts formels de Tweety, le rung 3 y dépose le résultat de l’orchestration, et ce capstone y verse ses verdicts convergents : le signal le plus riche de la série.
Cette section montre le geste d’intégration final : on mappe les findings canoniques du pipeline (sophismes de M1) et la force de convergence vers le conteneur partagé. C’est l’objet qu’une UI ou un rapport de production lirait pour combiner informel (rung 1), formel (rung 2), orchestration (rung 3) et convergence capstone (rung 4).
Le conteneur est déterministe (un dictionnaire typé sans logique LLM). Le remplir ne coûte aucun appel API : on réutilise les convergent_verdicts et les m1_results déjà calculés ci-dessus. En production, c’est ce même conteneur que conversational_orchestrator.py (Semantic Kernel) remplit via des agents LLM — la forme de l’objet est identique, seuls les producteurs changent.
# Pont vers l'etat partage : on verse les verdicts convergents du capstone# dans RhetoricalAnalysisState, le conteneur commun a tous les rungs. Rung 1 y# ecrit ses detections informelles, rung 2 y ajoute les verdicts formels de# Tweety, rung 3 y depose le resultat orchestre, et ce capstone (4) y verse# ses verdicts convergents -- le signal le plus riche de la serie. Aucun LLM# requis : on reutilise les sorties deja calculees ci-dessus.import logging# Le package argumentation_lib vit a cote du notebook ; il est importable# directement (le dossier du notebook est sur sys.path au runtime). La shim# resout ses ressources (data/, libs/) via _paths.py (__file__-relative, donc# cwd-independant). Aucun guard de path ni raise dans la cellule (regle C.1) :# la robustesse cwd est portee par la shim, comme aux rungs 1/2/3.from argumentation_lib import RhetoricalAnalysisStatelogging.getLogger("RhetoricalAnalysisState").setLevel(logging.WARNING)# Remplissage du conteneur partage : un argument cible agregeant le bloc# argumentatif, puis un sophisme canonique (M1) par phrase detectee, avec la# force de convergence en bonus dans la justification quand la phrase est un# verdict convergent (force >= 2).etat_partage = RhetoricalAnalysisState(initial_text=TEXT)arg_id = etat_partage.add_argument("Bloc argumentatif synthetique (7 phrases analysees par le capstone).")for f in m1_results: force =0for v in convergent_verdicts:if v["sentence_index"] == f["sentence_index"]: force = v["convergence_strength"]break justification = (f"declencheur M1 : '{f['evidence']}' (phrase S{f['sentence_index']+1})" )if force >=2: justification +=f" ; verdict convergent de force {force}" etat_partage.add_fallacy( fallacy_type=f["family"], justification=justification, target_arg_id=arg_id, family=f["family"], )snapshot = etat_partage.get_state_snapshot(summarize=True)print("--- Pont vers l'etat partage (argumentation_lib) ---")print(f"arguments dans l etat : {snapshot['argument_count']}")print(f"sophismes dans l etat : {snapshot['fallacy_count']}")print(f"verdicts convergents : {len(convergent_verdicts)} (force max {max((v['convergence_strength'] for v in convergent_verdicts), default=0)})")print(f"texte brut (extrait) : {snapshot['raw_text_snippet'][:60]}...")print("Ce conteneur combine informel (rung 1), formel (rung 2), orchestration (rung 3) et convergence (rung 4).")
--- Pont vers l'etat partage (argumentation_lib) ---
arguments dans l etat : 1
sophismes dans l etat : 5
verdicts convergents : 3 (force max 2)
texte brut (extrait) : Le comite affirme que le nouveau reglement est necessaire po...
Ce conteneur combine informel (rung 1), formel (rung 2), orchestration (rung 3) et convergence (rung 4).
8. Conclusion et recapitulatif
Ce capstone ferme la serie en montrant que l’intérêt d’un pipeline d’analyse argumentative se mesure, pas se se declame. Deux instruments EPITA rendent la mesure executable :
Tableau recapitulatif
Instrument
Origine EPITA
Rôle dans le capstone
ConvergentVerdict
Track DD #637 (deep_synthesis_models.py)
Force de confiance = nb de lectures distinctes qui convergent sur une même phrase
validate_value_gates VG-1..VG-4
FB-18 (deep_synthesis_agent.py)
Distinguent une synthese groundee d’un boilerplate
Points a retenir
La convergence multi-lecture est un signal de confiance, sous condition de disjonction : un finding confirme par 2+ lectures est plus fiable qu’un finding isole — a condition que ces lectures ne partagent aucun declencheur (§3). Sans cette condition, la convergence compte un seul mot deux fois, et la « force 3 » s’obtient par construction.
Une synthese groundee cite ses artefacts : les citations [artifact:...] rendent le raisonnement auditable, pas juste plausible.
Les value-gates composent : VG-1 (densite) + VG-4 (transversalite) empechent de “tromper” le système par citation-stuffing — il faut aussi de la diversite cross-artefact.
La baseline 0-shot — reelle — echoue sur les 4 gates : meme une analyse LLM d’environ 10 800 caracteres, plus lisible que celle du pipeline, echoue : sans artefacts construits, rien n’est tracable (issue #18394). La valeur d’un pipeline est la chaine de tracabilite, pas la prose.
Pont vers l’etat partage. Les verdicts convergents du capstone se versent dans le même conteneur RhetoricalAnalysisState que les autres rungs (section 7). C’est le bus d’integration terminal : une UI ou un rapport de production n’a qu’a lire cet objet pour combiner informel (rung 1), formel (rung 2), orchestration (rung 3) et convergence (rung 4) en un etat coherent.
Vers la production
En production EPITA, la prose de synthese est generee par un LLM via semantic_kernel, contrainte a ne citer que des artefacts reels (prompt strictement grounde). Les value-gates servent alors de garde-fous CI : une synthese qui echoue une gate est rejetee automatiquement, evitant les hallucinations. Ce capstone reproduit la logique des gates (déterministe) pour la rendre palpable sans LLM.
Prochaines étapes
Le rung 0-init couvre la configuration de l’environnement (JVM Tweety, fail-loud) pour qui veut brancher les vrais solveurs.
Pour aller plus loin sur la confiance multi-lecture : explorer les sémantiques de Dung dans le rung 2-formal (acceptabilite graduee).