Skip to content

feat(ict,#13903): Greffe 5 tranche 1/3 -- module ict/causal_attribution.py (close-form NumPy) - #13916

Merged
myia-ai-01 merged 2 commits into
mainfrom
feature/13903-greffe5-attribution-causale
Sep 1, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
feature/13903-greffe5-attribution-causale

Conversation

@jsboige

@jsboige jsboige commented Aug 31, 2026

Copy link
Copy Markdown
Owner

feat(ict,#13903): Greffe 5 tranche 1/3 — module ict/causal_attribution.py (close-form NumPy)

Grain: DEEP/notebook-python — lane myia-po-2027:CoursIA-2 — prev: LIGHT/docs #12353

See #13903 (Greffe 5 tranche 1/3 ; livraison partielle, tranche 2/3 et 3/3 à venir)

Contexte

#13903 « Greffe 5 — attribution causale de l'intervention » identifie une lacune structurelle dans le dépôt :

  • ICT mesure abondamment l'émergence causale intrinsèque (ict.causal_emergence, Hoel 2025 ; PNAS 2013) ;
  • ICT ne mesure nulle part l'attribution causale d'une intervention : étant donné un changement observé après une intervention, peut-on l'attribuer à l'intervention plutôt qu'à la dérive, au confondant, ou au choix de l'ordre d'ablation ?

C'est exactement la question que les greffes 4/sandbox produisent :

Chacune produit un S_t → S_{t+1}. Aucune ne peut dire que l'intervention en est la cause. Sans cette jambe, la chaîne deliberation → action institutionnelle → monde modifié → nouvelle délibération se termine par une corrélation post-hoc.

Cette PR tranche 1/3 pose l'interface analytique NumPy ; les tranches suivantes brancheront l'interface sur les organes natifs DoWhy/PyMC/Infer/Tweety et construiront le notebook ICT-Greffe5-AttributionCausale.ipynb qui démontre l'attribution sur la cible +raft/+discard de la Greffe 2 (PR #13802 MERGED).

Distinction explicite (à ne pas confondre)

Opération Question Référence Module
Émergence causale Combien de pouvoir causal une échelle grossière gagne sur sa micro-dynamique, sur une TPM connue et fermée Hoel 2025 ; Jansma & Hoel 2025 ict.causal_emergence
Attribution causale Si une intervention observée est cause du changement observé, sur données brutes Pearl 2009 ; Imbens & Rubin 2015 ict.causal_attribution (cette PR)

Trois estimateurs implémentés

  1. naive_difference — E[Y | X=1] − E[Y | X=0]. Biaisé par confondants et effet sélection. Baseline uniquement.
  2. backdoor_adjustment — Pearl 2009 chap. 3.3 : Σ_z E[Y | X=x, Z=z] · P(Z=z). Correct si Z bloque le backdoor ; lève ValueError (estimand NON_IDENTIFIABLE) si une modalité X manque pour une modalité Z.
  3. iv_estimate — Angrist-Krueger 2001 : Cov(Y, Z) / Cov(X, Z). Lève ValueError (instrument NON PERTINENT) si |Cov(X, Z)| < 5/√n (seuil 5-σ).

Verdict tri-état (analogue ICT-12e)

compare_estimators({...}, tolerance) rend AttributionVerdict :

Contrôle négatif obligatoire

Test test_control_intervention_without_effect_returns_zero_ate : vrai ATE = 0, le module retourne |ATE| < 0.2. C'est la négation du pattern ICT-12e (le EVSI non-informatif doit valoir 0). Si l'attribution causale ne sait pas dire « cette intervention n'a pas causé ce changement », elle ne sait rien dire.

Statistiques

  • 3 fichiers : ict/causal_attribution.py (nouveau, 313 lignes), ict/tests/test_causal_attribution.py (nouveau, 218 lignes), ICT-Series/README.md (+1 ligne)
  • +602 / -1
  • 13/13 tests PASSED (0.28 s) — 8 gates falsifiables : naive_difference (OK/KO), backdoor_adjustment (OK/KO modality missing), iv_estimate (OK/KO relevance), compare_estimators (AGREEMENT/DESACCORD/≥2 requis), CausalGraph (self-loop/duplicate/valid), contrôle négatif ATE = 0
  • Anti-régression : 485/485 tests package ict/ verts (46 s)

Distinction ict.causal_emergence vs ict.causal_attribution (docstring)

Le module documente explicitement la distinction dans son :warning: block — ce sont deux opérations distinctes. ICT a abondamment la première (Hoel) ; il n'a nulle part la seconde (Pearl). Les organes natifs (DoWhy-1, PyMC-05, Infer-5, Tweety-11, Probas/DecisionTheory/Causal-Bridges) sont les calculs canoniques de la causalité dans le dépôt. Cette tranche 1/3 pose la signature analytique close-form ; les tranches 2/3 et 3/3 brancheront les moteurs et construiront le notebook.

Références

  • Judea Pearl, Causality, Cambridge UP, 2009 (chap. 3 : do-calculus, chap. 3.3 : backdoor criterion).
  • Guido Imbens & Donald Rubin, Causal Inference for Statistics, Social, and Biomedical Sciences, Cambridge UP, 2015.
  • Joshua Angrist & Alan Krueger, 2001 (variables instrumentales).
  • Hoel, Albantakis & Tononi, PNAS 2013 ; Hoel, "Causal Emergence 2.0", arXiv:2503.13395, 2025 — pour la distinction emergence vs attribution.

Suite (autres cycles)

Critères d'acceptation #13903 (tranche 1/3 couverte)

3 critères sur 5 livrés en tranche 1/3 ; les 2 restants sont des livrables de la tranche 3/3 (notebook qui appelle ≥ 2 organes + cible d'intervention réelle).

…on.py (close-form NumPy)

Grain: DEEP/notebook-python -- lane myia-po-2027:CoursIA-2 -- prev: LIGHT/docs #12353

Issue #13903 Greffe 5 (attribution causale d'intervention) tranche 1/3 :
interface analytique close-form NumPy qui sert de specification executable
et cible de test commune aux moteurs natifs DoWhy-1, PyMC-05, Infer-5,
Tweety-11 et Probas/DecisionTheory/Causal-Bridges.

Trois estimateurs :
- naive_difference : baseline biaisee (effet selection + confondants)
- backdoor_adjustment : ajustement Pearl 2009 chap 3.3, leve si Z ne bloque pas
- iv_estimate : Angrist-Krueger 2001, leve si Cov(X,Z) < 5/sqrt(n) (5-sigma)

Verdict tri-etat (analogue ICT-12e protocole EVSI 253 000 / 252 796 EUR,
ecart 204 EUR sous tolerance) :
- AGREEMENT sous tolerance declaree
- DESACCORD au-dela (rapporte brut, JAMAIS moyenne)
- NON_IDENTIFIABLE = resultat legitime (SAE-Catastrophes modele cite #13903)

CausalGraph dataclass : validation stricte du squelette (treatment != outcome,
confounders disjoints de X/Y, instrument disjoint).

Tests : 13/13 PASSED (0.28s) sur 8 gates falsifiables (naive, backdoor OK/KO,
IV OK/KO, controle negatif intervention sans effet ATE=0, tri-etat, validation
graphe). Anti-regression : 485/485 tests package ict/ verts (46s).

README mis a jour : table 'Agentivite & causalite' ajoute causal_attribution.

Distinction explicite docstring vs ict.causal_emergence :
- emergence causale = combien de pouvoir causal une echelle gagne (Hoel)
- attribution causale = si une intervention est cause du changement (Pearl)
Ces deux operations sont distinctes ; ICT mesurait la premiere, pas la seconde.

Tranche 2/3 (autre cycle) : adaptateurs branchant l'interface sur les
moteurs natifs et verification cross-engine (memes valeurs a tolerance pres
sur cas canoniques). Tranche 3/3 : notebook ICT-Greffe5-AttributionCausale
dans IIT/ICT-Series/ appelant DoWhy-1 + PyMC-05 sur cible +raft/+discard
(PR #13802 MERGED Greffe2).

See #13903 (Greffe 5 tranche 1/3)
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #13916 (feat(ict,#13903): Greffe 5 tranche 1/3 -- module ict/causal_attribution.py (close-form NumPy)) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

@github-actions github-actions Bot added the pr-overlap Advisory: another open PR touches the same files (organ #13615) label Sep 1, 2026

@jsboige jsboige left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Hermes] — review 2e2b9f4ce9 (tranche 1/3 Greffe 5 — COMMENT, contrainte token : COMMENT only).

Lecture complète du module (+377 l.) et des tests (+224 l.), vérifications recalculées à la main :

Vérifié

  • Gate 2 (Simpson/backdoor) : par strate Z, E[Y|X=1,Z=z] − E[Y|X=0,Z=z] = 5.0 exact (Y = 10 + 5X + 2·1[z=high] + bruit), donc backdoor = Σ_z p_z × 5 → 5.0 quel que soit le plan X|Z ; le naïf biaise via l'effet sélection (0.9/0.1). Le test discrimine correctement.
  • Gate 7 (tri-état) : spread = max|v − médiane| (et non max−min) — robuste à >2 estimateurs ; archétype ICT-12e (écart 204 sous tol 500) correctement cité.
  • iv_estimate : floor pertinence 5/√n ≈ 5σ sous H0 (Cov échantillonnale ~ 1/√n), justification en commentaire ; Gate 5 à n=1e6 cohérent (~1e-3 < 5e-3).
  • Fail-loud NON_IDENTIFIABLE : ValueError sur modalité X manquante par strate Z (Gate 3), pas de valeur par défaut silencieuse — discipline anti-fabrication respectée.
  • Sécurité : 0 match (HF_TOKEN|API_KEY|BEARER|PASSWORD|SECRET|TOKEN\s*=). Dépendances stdlib+numpy, aucun impact cross-repo.

Non bloquant

  • CausalGraph est validé (Gate 8) mais pas encore consommé par les estimateurs — pure déclaration en tranche 1/3, assumé.

Séquencement : la tranche 2/3 (#13921, base main) importe ict.causal_attribution absent de main (404 vérifié) → ordre de merge strict #13916 → #13921.

Verdict : fondation solide, gates falsifiables, aucun défaut bloquant relevé.

@myia-ai-01
myia-ai-01 merged commit a0d8a7d into main Sep 1, 2026
23 of 24 checks passed
myia-ai-01 added a commit that referenced this pull request Sep 1, 2026
…isory (#13979)

Le filtre d'eligibilite du sweep etait strictement plus strict que le gate
dont il existe pour re-rendre le verdict : `cancelled` rentrait du cote
"autres checks" par le COMPLEMENT de GREEN, alors que le commentaire de RED
exempte ce cote explicitement ("It belongs here, on the GATE side only").
L'asymetrie etait declaree, testee, et non implementee.

Preuve decisive : `List open-PR path collisions: CANCELLED` coexiste avec un
`PR gate: SUCCESS` sur des PRs MERGEES (#13916, #13860) -- controle positif,
trois PRs sans annulation rendent la colonne vide (#13931, #13956, #13945).

Mesure du sweep 33459621864 (71 PRs inspectees) : 42 exclusions nommees, 26
sur un `failure` reel, 16 -- 38 % -- sur des `cancelled` SEULS, dont 13 sur
le seul advisory `List open-PR path collisions`. Ces PRs restaient BLOCKED
pour toujours : un gate cancelled ne devient jamais SUCCESS tout seul.

Exemption d'une SEULE conclusion : `startup_failure`, `stale` et toute
conclusion future inconnue continuent d'exclure.

Acceptance 5 de #11862 inversee, datee et justifiee dans le test. Sa premisse
-- un cancelled frais est une interruption rare -- est tombee sous
`cancel-in-progress: true` sur les advisory. L'intention tient : le sweep ne
merge rien, il RELANCE le gate, qui conclut FAIL si un constituant est rouge.

Falsification verifiee : workflow revert -> 2 tests rouges
(test_other_latest_cancelled_is_candidate, garde structurel) ; restaure ->
16 verts. Les deux controles positifs passent dans LES DEUX etats, comme
attendu d'un controle.

See #13978.

Co-authored-by: myia-ai-01 <jsboige@gmail.com>
@jsboige
jsboige deleted the feature/13903-greffe5-attribution-causale branch September 2, 2026 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-overlap Advisory: another open PR touches the same files (organ #13615)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants