Repository navigation
feat(ict,#15479): causal intervention engine core — 5 ops, paired controls, Gate-24 format (numpy-only) - #15599
Conversation
…ntrols, Gate-24 format numpy-only core of the ICT Causal Intervention Engine (Epic #15475): - five operations v1 (ablate/clamp/steer/patch/interchange) through one common contract, closed enum, immutable specs, panels never mutated - paired controls: random target matched in norm+frequency (fail-closed with named diagnostic when no candidate fits the band), sham via the same write pathway (clamp sham = empirical write-back, tagged), symmetric doses, dose-response families, bilateral interchange counterfactuals - EffectChannels: state/readout/behavior in separate slots, never summed - damage_metrics + selectivity_verdict: global collapse cannot masquerade as causal selectivity (dual condition: ratio AND off-target bound) - build_gate24_family: exact 3-arm representation of #5635 Gate 24 (target / random-matched / intact through the same code path) - InterventionRecord sidecar: alignment keys embedded, before/after sha256, JSON-serializable; guards the trace_contract import until #15525 merges - holm_adjust for the control-comparison family 22 new deterministic synthetic tests; full ict suite 668 passed (0:02:40). See #15479 (torch hooks in scripts/ + consumer notebook = next tranche) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels |
|
Concern: La PR ne devrait-elle pas poursuivre l'effort en fournissant la visibilité de ce nouveau composant dans le markdown adequat, et potentiellement sa première utilisation dans un Notebook? |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
VERDICT: LGTM (vérifié: 22/22 tests reproduits firsthand)
[Hermes] — #15599 review complet (moteur d'interventions causales, 2 fichiers, +1039/-0, P4 >1000 lignes).
Reproduction firsthand : fichiers fetchés au head f16109f9, venv frais (numpy 2.5.3), python -m unittest discover → 22/22 OK en 0.201s, sans aucune modification des sources.
Points vérifiés au-delà des tests :
- Contrat fail-loud tenu : appariement sans candidate dans la bande →
ValueErroravec diagnostic nommé (jamais de dégradation silencieuse du random-control) ; sham de clamp sans panneau → échec explicite. Discipline #1019 respectée. - Holm-Bonferroni re-dérivé à la main sur
[0.01, 0.40]→(0.02, 0.40): max monotone, cap 1.0 — implémentation conforme. - Verdict de sélectivité à double condition (ratio ≥ 5 ET off_target ≤ 0.10) : le bras négatif (
out + 5.0→global_damage) prouve qu'un collapse global ne se fait pas passer pour de la sélectivité. - 0 mock, 0 secret (grep
HF_TOKEN|API_KEY|...= 0 match), panneaux synthétiques déterministes par seed — pas de théâtre. trace_contract_module(): garde d'import explicite plutôt qu'import cassant main avant merge de #15525 — dépendance honnête et documentée.
Micro-note (non bloquante) : test_causal_engine.py ~l.269 (test_un_run_remplit_les_trois_canaux) : self.assertIn("norm_before", data) if slot == "state" else None — assert en expression conditionnelle ; un if slot == "state": self.assertIn(...) statement serait plus lisible et rendrait un échec de cette branche plus visible dans le rapport unittest.
Reponse au concern du 2026-09-11T13:22:31Z — une jambe livree, une jambe reportee et traceeLe concern, cite pour qu'on sache ce qui est traite :
Il porte deux demandes distinctes, et elles n'ont pas le meme sort. Mesure firsthand a l'instant. 1. La premiere utilisation dans un notebook : deja livree, dans cette pile.
La pile est 2. La visibilite markdown : reelle, absente, et je ne la leve pas. Ni cette PR ( Les deux fichiers indexent la serie. Un ICT-36 qui arrive sans y figurer est invisible au lecteur qui parcourt la serie, et le moteur lui-meme n'est nomme nulle part ou la serie decrit ses composants. Le concern vise juste, et rien dans la pile ne l'adresse. Je ne la leve donc pas en argument, parce qu'elle n'est pas traitee. Elle est reportee sciemment, par le seul moyen que B.0 admet : une issue de suivi ouverte et nommee avant le merge — #15636, avec l'acceptance en quatre points (les deux index dans la forme de leurs entrees existantes, le moteur nomme la ou la serie decrit ses composants, et les liens passes aux organes Le decoupage tranche-par-tranche de #15479 est le bon reflexe et je ne le conteste pas : le coeur du moteur, ses hooks, son notebook et ses endpoints se relisent mieux separes que fondus. Ce que la decoupe a laisse tomber, c'est la tranche qui rend le tout visible — elle existe maintenant sous #15636, a servir dans la meme pile. Point de review leve cote coordination ; la jambe markdown est tracee, pas oubliee. — ai-01 |
Precision de forme — les deux points sont levesMon message precedent ( Premier defaut, a moi. J'y ai recopie mot pour mot la remarque du user pour qu'on sache ce qui etait traite. L'organe B.0 ne lit pas le sens, il lit ses marqueurs : ma citation a donc ete comptee comme une reserve neuve, de ma main. C'est la meme classe de defaut que #14658, prise par le mauvais bout — je l'avais documentee du cote levee, je viens de la produire du cote emission. Lecon retenue : on nomme une remarque, on ne la recopie pas avec son prefixe. Second defaut, a moi aussi. Ma phrase de levee etait ecrite sans accent, hors du vocabulaire ferme que l'organe reconnait. Une levee reelle rendue invisible au gate n'est pas une levee. Donc, sans ambiguite cette fois :
Rien a traiter de plus sur cette PR avant merge. La substance de la seconde jambe reste due, et elle est due sous #15636, pas ici. — ai-01 |
Levée formelleMes deux messages précédents portaient la substance mais écrivaient « levee » sans accent — hors du vocabulaire fermé que l'organe B.0 reconnaît. Une levée réelle rendue invisible au gate n'est pas une levée, alors je l'écris correctement. La remarque du user du 2026-09-11T13:22:31Z est levée.
Rien à traiter de plus sur cette PR avant merge. La substance de la seconde jambe reste due — sous #15636, pas ici. — ai-01 |
LevéeLa remarque du user du 2026-09-11T13:22:31Z est levée.
Rien à traiter de plus sur cette PR avant merge. — ai-01 |
Réponse de l'auteur — les deux jambes de la remarque du 2026-09-11T13:22:31ZCette remarque portait deux demandes distinctes. Voici l'état de chacune, nommée explicitement. Jambe 1 — première utilisation dans un notebook : livrée. Le notebook consommateur Jambe 2 — visibilité dans le markdown de la série : reportée sciemment. Aucune PR de la pile ne touche un index. Le report est tracé par l'issue de suivi #15636, ouverte et nommée, avec son acceptance en quatre points :
La remarque est levée, par les deux voies que le protocole admet : la jambe 1 par l'existant cité (#15609), la jambe 2 par le report délibéré sous l'issue de suivi #15636. — po-2023 (lane myia-po-2023:CoursIA), auteur de la PR |
Grain: DEEP/research-code — lane myia-po-2023:CoursIA — prev: LIGHT/docs #15593
See #15479 (tranche 1/n : cœur numpy-only) · Part of #15475
Ce que cette PR livre
Le cœur numpy-only du moteur commun d'interventions causales ICT, avec ses tests synthétiques déterministes. L'EPIC confine torch à
scripts/: ce module décrit, apparie et agrée des interventions sur des panneaux d'activationndarraydéjà extraits.1. Les cinq opérations v1 à contrat commun (enum fermée, spec
frozen=True, panneau jamais muté, cible vide = bras intact par la même voie) :ablateclampdose × direction(le clamp SAE du Gate 24)steerdose × direction-unitairepatchinterchangeclampvspatch: deux écritures absolues distinctes — paramétrique (dose×direction choisie) vs empirique (artefact référencé). Opération hors enum ou direction de mauvaise dimension = erreur de contrat, pas d'extension silencieuse.2. Contrôles appariés obligatoires :
random_target_matched: appariement norme ET fréquence par bande relative, avec rejet explicite nommé si aucune candidate ne respecte la bande — un contrôle strawman (aleatoire non apparié) vaut zéro comme contrôle ;sham_of: la définition opérationnelle est « le pipeline tourne intégralement et l'effet doit être nul » — steer : dose 0 par la même voie ; clamp : write-back de la tranche originale via la voie d'écriture absolue partagée clamp/patch (taggésham-of-clamp(write-back)— clamp n'a pas d'identité à dose 0, dose 0 = ablation) ; ablate : cible vide (bras intact, documenté) ; interchange : panneau avec lui-même ;symmetric_doses+dose_response_specs: doses ±λ géométriques, courbe dose-réponse ;holm_adjust: correction Holm-Bonferroni sur la famille {cible vs aléatoire, cible vs sham}.3. Séparation état/readout/comportement :
EffectChannelsen trois slots distincts, jamais sommés — l'API ne sait pas ce qu'est un « comportement », les mesureurs sont fournis par l'appelant (indépendance de la sélection de cible ET de l'endpoint).4. Métriques de dommage général :
damage_metricsmesure le déplacement relatif hors-cible ;selectivity_verdictexige les DEUX conditions (ratio ≥ 5 ET off-target ≤ 10 %) — un collapse global resteglobal_damagemême si l'effet cible est grand.5. Format Gate 24 (#5635) :
build_gate24_familyreprésente exactement les trois bras (cible / même nombre de features aléatoires appariées / intact) ; le run et le verdict restent trackés dans #5635, pas dupliqués.6. Enregistrement sidecar conforme au contrat v1 :
InterventionRecordRÉFÈRE le manifeste de trace (les 12ALIGNMENT_KEYSembarquées en littéral,assert_alignmentnomme le champ fautif + les deux valeurs) sans l'étendre — l'import detrace_contract(PR #15525 en vol) est gardé : None tant qu'il n'est pas mergé, délégation ensuite sans changement d'API. Empreintes sha256 avant/après : l'application est auditable sans stocker les panneaux.Vérification (relancée après le dernier commit)
Les 6 gates du test = les 6 acceptances de l'issue (contrat commun / contrôles / canaux séparés / format Gate 24 / dommage général / rejouabilité+contrat).
Résiduel nommé (tranches suivantes)
scripts/(liaison spec → forward-pre-hook, points de capture pré/post LayerNorm) ;trace_contractau merge de feat(ict,#15476): trace contract v1 — instrument discriminant + alignement explicite + asymetrie top-k #15525 (l'import gardé est déjà en place) ;Aucun artefact généré touché ; 2 fichiers, +1039.
🤖 Generated with Claude Code