Skip to content

refactor(bridges,#14051): cabler quasi_experimental sur l'organe canonique causal_organs - #14150

Merged
myia-ai-01 merged 1 commit into
mainfrom
feature/14051-bridges-dedupe
Sep 2, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
feature/14051-bridges-dedupe

Conversation

@jsboige

@jsboige jsboige commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Grain: MED/research-code — lane myia-po-2027:CoursIA-2 — prev: MED/notebook-python #14133

See #14051 (partiel — acceptances 3 et 4, organe Quasi-Experimental uniquement).

Le defaut

ict/bridges/quasi_experimental.py portait des copies locales des organes du
notebook Quasi-Experimental.ipynb (_panel_did_two_by_two, _iv_2sls_scalaire,
make_panel_did, iv_replay). La « verification cross-moteur » du pont comparait
donc ict.causal_attribution a une reproduction de l'organe, pas a l'organe.

Consequence mesurable : une derive de l'estimateur du notebook aurait laisse le pont
vert. C'est precisement le defaut que l'acceptance 3 de #14051 nomme, et que le
__init__.py niait en toutes lettres (« Les adaptateurs ici ne reimplementent rien »).

Ce que fait la PR

  1. causal_organs.py (+61, module canonique deja sur main via feat(probas,#14051): tranche 1/2 — extraire causal_organs.py (DiD + IV) #14076) recoit
    panel_did_two_by_two, extrait de la cellule 5 du notebook — pas de la copie
    du pont. Le docstring cite la forme .query() de la cellule verbatim et explique
    pourquoi le notebook garde deliberement sa forme deroulee (pedagogie).

  2. quasi_experimental.py (343 -> 255 lignes) importe desormais les quatre
    organes depuis causal_organs. La queue adapt_* est byte-identique a main
    a l'exception de l'unique site d'appel renomme (verifiable par diff).

  3. _iv_2sls_scalaire est supprime, pas canonise. Mesure a l'appui : 0 site
    d'appel dans tout le depot
    , et le notebook ne definit aucune fonction 2SLS
    scalaire (les cellules 36 et 40 font la forme matricielle inline). Le canoniser
    aurait cree une troisieme copie d'un organe que personne n'appelle.

  4. __init__.py : la phrase globale fausse est remplacee par un constat
    par adaptateur — quasi_experimental = cablage canonique (verrouille par le
    test ci-dessous) ; pymc_enumerate = copies declarees, encore (enumerate_scm
    cellule 5 et p_y_given_m_x cellule 20 sont byte-identiques a leurs cellules ;
    leur cablage suit le merge de feat(probas,#14051): pymc_causal_organs.py -- seconde moitie de l'acceptance 1 (2 organes, 8 gates, falsifiabilite prouvee) #14133).

  5. test_bridges_canonical_wiring.py (nouveau) — acceptance 4, gates W1 a W7 :

    • W1-W3 : getattr(qe, nom) is getattr(co, nom) — identite d'objet, pas egalite
      de valeur. from X import f lie une reference a l'import : monkeypatcher
      X.f ensuite ne se propage pas, donc l'identite est le seul invariant honnete.
    • W4 : __module__ == "causal_organs". W5 : plus aucun def d'organe dans la
      source du pont. W6 : l'organe canonique egale une transcription litterale de
      l'arithmetique de la cellule 5 (abs=1e-12). W7 : adapt_panel_did_to_backdoor
      egale le pipeline recalcule entierement via causal_organs, pour pretrend 0.0 et 0.5.

Preuves

Mesure Resultat
ict/tests/ (suite ICT complete) 511 passed (baseline avant rewiring : 7 passed sur le sous-ensemble pont, inchange apres)
Causal-Bridges/tests/ 16 passed
Sites d'appel de _iv_2sls_scalaire 0 dans tout le depot (mesure avant suppression, cf. anti-regression)
Queue adapt_* vs main identique sauf 1 ligne (le site d'appel renomme)
Catalogue aucun churn (byte-identique a main)

Falsifiabilite des gates, prouvee par mutation : re-coller une copie locale de
make_panel_did dans le pont fait rougir exactement W1, W4 et W5 pour cet organe,
et laisse les autres verts. W7 reste correctement vert sur une copie byte-identique
— c'est la division du travail voulue entre gates structurels (l'organe vient-il du
module canonique ?) et gate de sortie (le resultat est-il le bon ?). Le fichier a ete
restaure byte-exact apres la mutation (diff vide).

Hors scope, et pourquoi

L'acceptance 2 (PyMC-05) et la moitie pymc_enumerate de l'acceptance 3 dependent de
#14133, qui n'est pas encore sur main : le module canonique qu'elles doivent
importer n'existe pas encore la-bas. Empiler une PR dependante aurait cree une chaine
de blocage plutot qu'un livrable. Ce perimetre est celui declare dans l'amendement de
claim sur l'issue (paths: Probas/PyMC/**, Probas/DecisionTheory/Causal-Bridges/**, IIT/ICT-Series/ict/bridges/**).

Note de tag (pour re-qualification ai-01)

La composante dominante en lignes est du dedupe/rewire, ce qui plaiderait pour
refactor (classe META). J'ai retenu research-code parce que le livrable substantiel
est l'organe canonique ajoute a causal_organs.py et le fait que la verification
cross-moteur porte desormais sur l'organe reel. Si ai-01 juge refactor plus juste,
cette PR ne tient alors pas le plancher G-VAR-1 de ce cycle
— je le signale plutot que
de laisser le tag trancher silencieusement en faveur du gate.

…nique

Le pont ict/bridges portait des copies locales des organes du notebook
Quasi-Experimental : sa "verification cross-moteur" comparait donc
ict.causal_attribution a une reproduction de l'organe, pas a l'organe.
Une derive du notebook aurait laisse le pont vert.

- causal_organs.py : + panel_did_two_by_two, extrait de la cellule 5 du
  notebook (pas de la copie du pont).
- quasi_experimental.py : 343 -> 255 lignes, importe les 4 organes depuis
  causal_organs ; queue adapt_* byte-identique sauf le site d'appel renomme.
- _iv_2sls_scalaire supprime (0 site d'appel dans le depot ; le notebook ne
  definit aucune 2SLS scalaire) plutot que canonise en 3e copie.
- __init__.py : la phrase globale fausse devient un constat par adaptateur
  (pymc_enumerate reste des copies declarees, cablage gate par #14133).
- test_bridges_canonical_wiring.py : gates W1-W7 (identite d'objet, __module__,
  absence de def, egalite a la cellule 5, pipeline recalcule).

511 passed (ict/tests/), 16 passed (Causal-Bridges/tests/).
Mutation : re-coller une copie locale fait rougir W1/W4/W5, W7 reste vert.

See #14051

@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 #14150 sur head 7d2c639 (non couvert ; la review ce2798a était sur #14148, autre PR).

Issue-First Method Match (#14051) : méthode conforme. Acceptances 3 (perte des copies + __init__ cesse d'affirmer le faux) et 4 (test anti-dérive) implémentées ; portée partielle déclarée (pymc_enumerate reste copies déclarées, câblage gated par #14133). Pas de divergence source/mandat.

Claims vérifiés firsthand :

  • « 0 site d'appel _iv_2sls_scalaire » : code-search repo-wide = 1 hit (sa propre définition sur main). Confirmé — la suppression plutôt que la canonisation évite une 3e copie, cohérent avec l'issue.
  • parents[4] : ict/bridges → bridges → ict → ICT-Series → IIT → MyIA.AI.Notebooks. Arithmétique exacte.
  • Gates W1-W7 lus en détail : identité d'objet (is), __module__, scan source def, ré-derivation littérale cellule 5 (.query(), abs=1e-12), égalité pipeline complet sur pretrend 0.0/0.5. La note monkeypatch-vs-identité est techniquement correcte (from X import f lie une référence). La division du travail gates structurels vs W7 (sortie) est énoncée honnêtement — le claim de mutation (W1/W4/W5 rougissent, W7 reste vert sur copie byte-identique) est cohérent avec ce design.

Security scan : 0 match (HF_TOKEN|API_KEY|BEARER|PASSWORD|SECRET|TOKEN\s*=).

Non-blocking : le bootstrap sys.path.insert(0) dans quasi_experimental.py est un effet de bord global d'import (risque de collision de nom si Causal-Bridges bouge ou qu'un homonyme apparaît) ; le test documente qu'il s'appuie dessus. Acceptable pour un module posé à côté de son notebook, les W-gates verrouillent l'état présent.

Claims 511/16 passed non ré-exécutés ici (env ICT complet requis) — verdict fondé sur le design des gates + vérifications ci-dessus. Structure saine. (contrainte token : COMMENT only)

@myia-ai-01
myia-ai-01 merged commit 8b87f57 into main Sep 2, 2026
15 checks passed
@jsboige
jsboige deleted the feature/14051-bridges-dedupe branch September 2, 2026 13:12
jsboige added a commit that referenced this pull request Sep 2, 2026
…e pymc_causal_organs (#14273)

Symetrique de #14150 (mergee), qui a cable quasi_experimental sur
causal_organs. Ferme l'autre moitie du trou de falsifiabilite que le
docstring de ict/bridges/__init__.py declarait lui-meme : le pont detenait
des reproductions byte-identiques des cellules 5 et 20 de
PyMC-05-Causal-Inference.ipynb, si bien que sa verification cross-engine
comparait ict.causal_attribution a une REPRODUCTION de l'organe et non a
l'organe -- une derive d'estimateur dans PyMC-05 l'aurait laissee verte.

La cible importable (pymc_causal_organs.py) est arrivee sur main avec le
merge de #14133 ; la condition que le docstring nommait est donc levee.

Equivalence mesuree avant substitution, pas supposee :
- 16 assignations de CPT x 4 noeuds, 836 cas enumerate_scm, ecart max 0.00e+00
- 17 grandeurs comparees a origin/main (front_door_estimate,
  adapt_enumerate_scm_to_backdoor aux graines 0/42/7) : toutes a 0.000e+00

FRONT_DOOR_SCM survit comme alias du meme objet -- c'est le nom que
consomme ict/tests/test_bridges.py.

Gates W8-W12 (symetriques de W1-W5), verifies par mutation :
- une copie de fonction reintroduite rougit 3 gates (identite, __module__,
  source)
- une copie de la table de CPT, a valeurs identiques, ne rougit QUE W10 --
  ni __module__ ni un scan de `def` ne peuvent la voir. C'est la raison
  d'etre de ce gate, et elle est mesuree.

Le scan de source de W12 est ancre sur une definition (regex `^\s*def <nom>\(`)
et non sur un substring : un `in` naif rougissait sur le closure
`p_y_given_m_x_native`, qui APPELLE l'organe canonique. Le gate porte un
controle positif pour que le motif se valide par ses faux negatifs. Le
closure est renomme `_p_y_front` -- `_native` etait devenu un contresens.

539 tests ICT verts, 8 tests de l'organe verts, organe non modifie.

See #14051

Co-authored-by: myia-po-2027 <po-2027@coursia.lan>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants