ICT-15l — Indépendance au générateur de nouveauté : le relief b1 survit-il au contrôle de dimension ?
Issue : #13308Epic (Observatoire des formes relationnelles) : #13303Substrat Axelrod régénéré : #12673Discriminant nerf/b1 : ICT-15j
Cadrage
Sur le substrat Axelrod régénéré (#12673), le discriminant topologique d’ICT-15j mesure du relief : b1_max_persistence = 0,3989 pour une population agent-based en sélection-mutation (graine 20260720), contre 0,0000 pour la baseline dégénérée replicateur. La lecture tentante — « la nouveauté stratégique produit du relief là où le bruit n’en produit pas » — est exactement la frontière que l’énoncé général ne peut pas franchir sans un contrôle : le mécanisme qui injecte la nouveauté peut n’être que le relief qu’on a mis dans le générateur en le construisant (#13308).
Ce notebook exécute le protocole pré-enregistré de l’issue :
deux générateurs de nouveauté structurellement distincts (resemencement uniforme sur catalogue fermé vs dérive comportementale par mutation de bits d’un génome — vocabulaire ouvert) ;
un contrôle négatif de dimension : le simplexe est doublé d’étiquettes sans aucun comportement nouveau (chaque stratégie dupliquée sous deux noms) — s’il produit aussi du relief, le discriminant ne mesure pas la nouveauté mais la dimension/le turnover ;
appariement : même substrat IPD, même bruit, même taille de population, même longueur de trajectoire, même taux de mutation, graines identiques entre régimes ;
verdict en toutes lettres, pré-enregistré avant la mesure.
Règle de verdict pré-enregistrée
Avec relief(r) = moyenne sur les 3 graines de b1_max_persistence, seuil τ = 0,05 (constante TAU dans le code, tolerance du verdict ICT-15j) :
condition
verdict
relief(R1) > τetrelief(R2) > τetrelief(R3) ≤ τ
ROBUSTE_AU_GENERATEUR
exactement un de relief(R1), relief(R2)> τ (avec R0 ≤ τ)
ARTEFACT_DE_GENERATEUR
relief(R3) > τ
CONFONDU_AVEC_LA_DIMENSION
aucun des cas ci-dessus
INCONCLUSIVE
La règle est appliquée programmatiquement dans la cellule §6 — le verdict imprimé est calculé, jamais écrit à la main.
Discipline
Pas de promotion en « loi ICT » quel que soit le verdict : la promotion est un acte séparé qui demande l’observatoire externe (#13303). La mesure reste descriptive : « nombre de classes H^1 persistantes dans le nerf simplicial sur les sections locales des proxys ». On ne nomme pas l’objet.
Statut épistémique — Sans verdict à ce jour : aucune ligne de la matrice de dissociations ne concerne ce notebook ; son statut épistémique sera porté par la matrice le cas échéant.
# Imports + recette observable, REPLIQUE EXACTE d'ICT-15j (cellules f22b81e8/ff929034)import sys, timefrom pathlib import PathICT_ROOT = Path('.').resolve()sys.path.insert(0, str(ICT_ROOT))import numpy as npimport matplotlibmatplotlib.use('Agg')import matplotlib.pyplot as pltfrom ict import spectral as SPfrom ict import sensitivity as SEfrom ict import strategic_morphodynamics as SMfrom ict.nerve_discriminant import nerve_b1C, D =1, 0def spec_gap_wrap(states, n_symbols):returnfloat(SP.spectral_summary(states, n_symbols)['spectral_gap'])def sens_mean_wrap(states, n_symbols):returnfloat(SE.sensitivity_distribution(states, n_symbols, lambda x: x)['mean'])def sens_max_wrap(states, n_symbols):returnfloat(SE.sensitivity_distribution(states, n_symbols, lambda x: x)['max'])PROXIES_FN = {'spectral_gap': spec_gap_wrap,'sensitivity_mean': sens_mean_wrap,'sensitivity_max': sens_max_wrap,}def windowed_proxy_signature(states, n_symbols, n_windows=30):"""30 fenetres glissantes x 3 proxys -- meme recette qu'ICT-15j.""" L =len(states) sections = {name: [] for name in PROXIES_FN}for w inrange(n_windows): start = (w * L) // n_windows end =max(start +2, ((w +1) * L) // n_windows) chunk = states[start:end]iflen(chunk) <2: chunk = states[start:start +4] if start +4<= L else states[start:]for name, fn in PROXIES_FN.items():try: sections[name].append(fn(chunk, n_symbols))exceptException: sections[name].append(float('nan')) cleaned = {}for name, vals in sections.items(): arr = np.array(vals, dtype=float) valid = arr[np.isfinite(arr)] cleaned[name] = (valid.tolist() iflen(valid) >0else [0.0] * n_windows)for name in cleaned:whilelen(cleaned[name]) < n_windows: cleaned[name].append(0.0)return cleaneddef coop_to_b1(coop, name, n_symbols=8):"""Serie de cooperation -> 8 symboles (quantiles) -> sections -> b1_max_persistence. Chaque regime passe par CETTE fonction et aucune autre : l'observable est identique entre regimes, seul le generateur change. """ q = np.quantile(coop, np.linspace(0, 1, n_symbols +1)[1:-1]) states = np.digitize(coop, q).tolist() sections = windowed_proxy_signature(states, n_symbols, n_windows=30) r = nerve_b1(sections, name, epsilon_quantile=0.55)return r.b1_max_persistence, len(set(states))print("recette observable chargee (replique ICT-15j).")
Ce que chaque générateur fait au vocabulaire : - R1 tire les mutants uniformément dans un catalogue fixe — un type absent peut réapparaître, mais aucun comportement nouveau n’existe ; - R2 mute localement le code d’un comportement existant (1 bit du génome) — les mutants sont des variantes de voisins, et la plupart n’existaient pas dans la population initiale ; - R3 double les étiquettes sans toucher aux comportements — la dimension du simplexe monte de 6 à 12, la distribution de mutation sur les comportements est inchangée.
Appariement (montré, pas affirmé — imprimé par la cellule suivante) : même substrat IPD canonique, même bruit d’exécution noise = 0.02, pop = 60, n_generations = 400, n_rounds = 30, mutation_rate = 0.05, graines [20260720, 42, 7]identiques entre régimes. R0 est le régime déterministe (champ moyen) : l’appariement porte sur ses parties stochastiques (construction de la matrice de gains, estimation de la coopération sous bruit).
# Constantes appariees -- IDENTIQUES pour les 4 regimesSEEDS = [20260720, 42, 7]POP, GENS, ROUNDS, NOISE, MU =60, 400, 30, 0.02, 0.05TAU =0.05# seuil de verdict (tolerance ICT-15j), pre-enregistre en tete de notebookprint("=== Protocole d'appariement (commun aux 4 regimes) ===")print(f" substrat : IPD canonique (payoff_pair de ict.strategic_morphodynamics)")print(f" bruit d'execution : noise = {NOISE}")print(f" population : {POP} agents (R0 : champ moyen, pas d'agents)")print(f" generations/pas : {GENS}")print(f" rounds par match : {ROUNDS}")print(f" taux de mutation : {MU}")print(f" graines : {SEEDS} (identiques entre regimes)")print(f" observable : coop -> 8 symboles (quantiles) -> 30 fenetres x 3 proxys -> b1")print(f" seuil de verdict : tau = {TAU}")
=== Protocole d'appariement (commun aux 4 regimes) ===
substrat : IPD canonique (payoff_pair de ict.strategic_morphodynamics)
bruit d'execution : noise = 0.02
population : 60 agents (R0 : champ moyen, pas d'agents)
generations/pas : 400
rounds par match : 30
taux de mutation : 0.05
graines : [20260720, 42, 7] (identiques entre regimes)
observable : coop -> 8 symboles (quantiles) -> 30 fenetres x 3 proxys -> b1
seuil de verdict : tau = 0.05
Dynamique de champ moyen x(t+1) = (1-mu) * x(t) * f(t)/<f>(t) + mu/n sur la matrice de gains du substrat. La trajectoire converge vers l’équilibre mutation-sélection et s’y fige : c’est le régime « mutation uniforme » de la table de #13308, attendu à relief nul. Le taux de coopération est mesuré comme dans les régimes agent-based : par une matrice empirique de coopération C_ij (paires jouées sous le même bruit), puis coop(t) = x(t)^T C x(t).
def regime_r0(seed):"""Replicateur-mutation deterministe. Coop mesuree via matrice C empirique (meme bruit que les regimes agent-based) : coop(t) = x(t)^T C x(t).""" rng = np.random.default_rng(seed) st = SM.make_strategies(rng) A = SM.payoff_matrix(st, n_rounds=200, n_reps=3, rng=rng) x0 = np.full(A.shape[0], 1.0/ A.shape[0]) traj = SM.replicator_mutation_trajectory(A, x0, n_steps=GENS, mutation_rate=MU) names =list(st.keys()) n =len(names) Cm = np.zeros((n, n)) reps =20for i inrange(n):for j inrange(n): c =0.0for _ inrange(reps): own_i, own_j = [], []for _ inrange(ROUNDS): a =int(st[names[i]](np.array(own_i), np.array(own_j))) b =int(st[names[j]](np.array(own_j), np.array(own_i)))if NOISE >0:if rng.random() < NOISE: a =1- aif rng.random() < NOISE: b =1- b own_i.append(a); own_j.append(b) c += (a == C) + (b == C) Cm[i, j] = c / (2* reps * ROUNDS) coop = np.einsum('ti,ij,tj->t', traj, Cm, traj)return coopr0_b1 = {}print("R0 -- replicateur-mutation deterministe (vocabulaire ferme, mu/n)")for seed in SEEDS: coop = regime_r0(seed) b1v, nsym = coop_to_b1(coop, f'r0_{seed}') r0_b1[seed] = b1vprint(f" seed {seed:>9d} : b1_max_persistence = {b1v:.4f} (n_symboles={nsym})")
3. R1 — générateur A : resemencement uniforme agent-based (la référence #12673)
Wright-Fisher à population finie : chaque génération, appariement aléatoire, matchs IPD bruités, reproduction proportionnelle au gain, et mutation = resemencement uniforme dans le catalogue fermé des 6 stratégies. C’est le régime qui a régénéré le substrat Axelrod d’ICT-15j — la référence dont le relief (0,3989 sur la graine 20260720) est l’objet du doute.
Structurellement distinct de R1 : chaque agent porte un génome memory-1 de 5 bits — [coup initial, réaction à (D,D), réaction à (D,C), réaction à (C,D), réaction à (C,C)] — et la mutation inverse un bit du génome d’un enfant. Le mutant n’est pas tiré d’un catalogue : c’est un voisin à un bit de son parent. L’espace des comportements est ouvert (32 génomes), la population initiale n’en porte que 5 (les classiques memory-1 : ALLC, ALLD, TFT, GRIM approximé, PAVLOV) — les mutations créent donc des comportements qui n’existaient pas, et on compte ces nouveautés au fil de la trajectoire.
R1 (générateur A)
R2 (générateur B)
source du mutant
tirage uniforme dans un catalogue fermé
perturbation locale du code d’un incumbent
comportements accessibles
les 6 du catalogue
les 32 génomes (vocabulaire ouvert)
effet sur le vocabulaire
composition seulement
croissance effective (comptée ci-dessous)
# Genomes memory-1 : [init, r(D,D), r(D,C), r(C,D), r(C,C)]GEN_ALLC = [1, 1, 1, 1, 1]GEN_ALLD = [0, 0, 0, 0, 0]GEN_TFT = [1, 0, 1, 0, 1] # joue le dernier coup de l'adversaireGEN_GRIM = [1, 0, 0, 0, 1] # approx memory-1 : C seulement apres (C,C)GEN_PAV = [1, 1, 0, 0, 1] # win-stay lose-shiftGENOMES0 = [GEN_ALLC, GEN_ALLD, GEN_TFT, GEN_GRIM, GEN_PAV]def genome_play(g, own, opp):iflen(own) ==0:return g[0]return g[1+ ((int(own[-1]) <<1) |int(opp[-1]))]def regime_r2(seed):"""Generateur B : derive comportementale. Retourne (coop, n_comportements_nouveaux).""" rng = np.random.default_rng(seed) initial_set = {tuple(g) for g in GENOMES0} pop_g = [list(GENOMES0[rng.integers(0, len(GENOMES0))]) for _ inrange(POP)] seen = {tuple(g) for g in pop_g} coop = np.zeros(GENS +1)def generation(): perm = rng.permutation(POP) payoffs = np.zeros(POP) n_coop =0 n_plays =0for k inrange(0, POP, 2): i, j =int(perm[k]), int(perm[k +1]) gi, gj = pop_g[i], pop_g[j] own_i, own_j = [], [] g_i = g_j =0.0for _ inrange(ROUNDS): a = genome_play(gi, own_i, own_j) b = genome_play(gj, own_j, own_i)if NOISE >0:if rng.random() < NOISE: a =1- aif rng.random() < NOISE: b =1- b pa, pb = SM.payoff_pair(a, b) g_i += pa; g_j += pb own_i.append(a); own_j.append(b) n_coop += (a == C) + (b == C) n_plays +=2 payoffs[i] = g_i / ROUNDS payoffs[j] = g_j / ROUNDSreturn n_coop /max(n_plays, 1), payoffsfor g inrange(GENS +1): coop[g], payoffs = generation()if g == GENS:break w = np.clip(payoffs, 1e-6, None) parents = rng.choice(POP, size=POP, p=w / w.sum()) children = [list(pop_g[p]) for p in parents] mutators = rng.random(POP) < MUfor m in np.nonzero(mutators)[0]: bit =int(rng.integers(0, 5)) children[m][bit] =1- children[m][bit] seen.add(tuple(children[m])) pop_g = childrenreturn coop, len(seen - initial_set)r2_b1, r2_novel = {}, {}print("R2 -- generateur B : derive comportementale (genomes 5 bits, vocabulaire ouvert)")for seed in SEEDS: coop, novel = regime_r2(seed) b1v, nsym = coop_to_b1(coop, f'r2_{seed}') r2_b1[seed] = b1v r2_novel[seed] = novelprint(f" seed {seed:>9d} : b1_max_persistence = {b1v:.4f} "f"(comportements nouveaux hors catalogue initial : {novel})")
5. R3 — contrôle négatif : la dimension sans la nouveauté
Le simplexe est doublé : chaque stratégie existe sous deux étiquettes (#a, #b), les comportements sont strictement les mêmes, la distribution de mutation sur les comportements est inchangée. La dimension passe de 6 à 12 sans qu’aucune nouveauté soit injectée. Ordre des étiquettes par blocs (tous les #a, puis tous les #b) : l’ordre interleaved serait un no-op bit-exact — la cellule le démontre avant de mesurer.
Le piège de l’ordre interleaved. Dupliquer en alternant s0#a, s0#b, s1#a, s1#b, ... fait correspondre l’étiquette i au comportement i//2. Pour le générateur numpy, integers(0, 12) // 2 == integers(0, 6)bit à bit sur tout le flux (vérifié sur 200 000 tirages ci-dessous) : la trajectoire R3-interleaved est alors exactement celle de R1 — le « contrôle » mesurerait la référence elle-même. C’est une preuve de symétrie du mécanisme, pas un contrôle : l’ordre par blocs casse cette correspondance et donne au contrôle sa propre trajectoire, distributionnellement identique à R1 sur les comportements.
# Demonstration du no-op interleaved : integers(0, 2n)//2 == integers(0, n), bit a bit_r6 = np.random.default_rng(20260720).integers(0, 6, 200_000)_r12 = np.random.default_rng(20260720).integers(0, 12, 200_000)print(f"integers(0,12)//2 == integers(0,6) sur 200 000 tirages : "f"{bool((_r12 //2== _r6).all())}")def regime_r3_interleaved(seed):"""Duplication interleaved : NO-OP bit-exact de R1 (demonstration, pas un controle).""" rng = np.random.default_rng(seed) base = SM.make_strategies(rng) dup = {}for k, v in base.items(): dup[f'{k}#a'] = v dup[f'{k}#b'] = v evo = SM.evolve_population(dup, pop_size=POP, n_generations=GENS, n_rounds=ROUNDS, noise=NOISE, mutation_rate=MU, rng=rng)return evo.cooperation_ratec1_ref = regime_r1(SEEDS[0])c3_int = regime_r3_interleaved(SEEDS[0])print(f"R3-interleaved reproduit R1 bit a bit (seed {SEEDS[0]}) : "f"{bool(np.array_equal(c1_ref, c3_int))}")def regime_r3(seed):"""Controle negatif : etiquettes dupliquees PAR BLOCS -- dimension 12, memes 6 comportements, meme distribution de mutation sur les comportements.""" rng = np.random.default_rng(seed) base = SM.make_strategies(rng) dup = {f'{k}#a': v for k, v in base.items()} dup.update({f'{k}#b': v for k, v in base.items()}) evo = SM.evolve_population(dup, pop_size=POP, n_generations=GENS, n_rounds=ROUNDS, noise=NOISE, mutation_rate=MU, rng=rng)return evo.cooperation_rater3_b1 = {}print("R3 -- controle dimension-sans-nouveaute (etiquettes dupliquees par blocs)")for seed in SEEDS: coop = regime_r3(seed) b1v, nsym = coop_to_b1(coop, f'r3_{seed}') r3_b1[seed] = b1vprint(f" seed {seed:>9d} : b1_max_persistence = {b1v:.4f} (n_symboles={nsym})")
integers(0,12)//2 == integers(0,6) sur 200 000 tirages : True
R3-interleaved reproduit R1 bit a bit (seed 20260720) : True
R3 -- controle dimension-sans-nouveaute (etiquettes dupliquees par blocs)
seed 20260720 : b1_max_persistence = 0.3531 (n_symboles=8)
seed 42 : b1_max_persistence = 0.2411 (n_symboles=8)
seed 7 : b1_max_persistence = 0.4624 (n_symboles=8)
6. Résultats et verdict
Les trois graines par régime, la moyenne, et le verdict calculé par la règle pré-enregistrée en tête de notebook — jamais écrit à la main.
regimes = {'R0 replicateur-mutation (deterministe)': r0_b1,'R1 generateur A (resemencement uniforme)': r1_b1,'R2 generateur B (derive genomique)': r2_b1,'R3 controle dimension-sans-nouveaute': r3_b1,}print(f"{'regime':42s} | "+" | ".join(f"seed {s}"for s in SEEDS) +" | moyenne | ecart-type")print("-"*100)means = {}for name, d in regimes.items(): v = np.array([d[s] for s in SEEDS]) means[name] = v.mean()print(f"{name:42s} | "+" | ".join(f"{d[s]:>7.4f}"for s in SEEDS) +f" | {v.mean():>7.4f} | {v.std():>9.4f}")m_r0 = means['R0 replicateur-mutation (deterministe)']m_r1 = means['R1 generateur A (resemencement uniforme)']m_r2 = means['R2 generateur B (derive genomique)']m_r3 = means['R3 controle dimension-sans-nouveaute']# Regle pre-enregistree (cellule d'en-tete) -- appliquee programmatiquementif m_r3 > TAU: verdict ='CONFONDU_AVEC_LA_DIMENSION'elif (m_r1 > TAU) and (m_r2 > TAU): verdict ='ROBUSTE_AU_GENERATEUR'elif (m_r1 > TAU) != (m_r2 > TAU): verdict ='ARTEFACT_DE_GENERATEUR'else: verdict ='INCONCLUSIVE'print()print(f"relief(R0) = {m_r0:.4f} | relief(R1) = {m_r1:.4f} | "f"relief(R2) = {m_r2:.4f} | relief(R3) = {m_r3:.4f} | tau = {TAU}")print(f"VERDICT (regle pre-enregistree) = {verdict}")# Barplot in-situ : relief moyen par regimefig, ax = plt.subplots(figsize=(7, 3.6))names_short = ['R0\ndeterministe', 'R1\ngene A', 'R2\ngene B', 'R3\ncontrole dim']vals = [m_r0, m_r1, m_r2, m_r3]colors = ['#888888', '#4477aa', '#4477aa', '#cc3311']bars = ax.bar(names_short, vals, color=colors, edgecolor='black', linewidth=0.6)ax.axhline(TAU, color='black', linestyle='--', linewidth=1, label=f'seuil tau = {TAU}')for b, v inzip(bars, vals): ax.text(b.get_x() + b.get_width() /2, v +0.01, f'{v:.3f}', ha='center', va='bottom', fontsize=9)ax.set_ylabel('b1_max_persistence (moyenne 3 graines)')ax.set_title('Relief du discriminant nerf par regime (graines apparieees)')ax.legend(loc='upper left', fontsize=8)fig.tight_layout()plt.close(fig) # backend Agg (cell. 1) : show() non interactif -> UserWarning superfluprint("Barplot : R1 et R2 (bleu) = generateurs de nouveaute ; R3 (rouge) = controle dimension.")
La réfutation est nette. Le contrôle négatif — dimension doublée, zéro comportement nouveau, distribution de mutation inchangée sur les comportements — produit le même relief que les deux générateurs de nouveauté (R3 ≈ R1 ≈ 0,35 de moyenne, chacun > τ sur les 3 graines). Selon la règle pré-enregistrée de #13308, le discriminant ne mesure donc pas la nouveauté stratégique sur cette recette : l’écart R1 > 0 = R0 attribue le relief au turnover stochastique de population finie (dérive Wright-Fisher + bruit d’exécution), pas à l’apparition de stratégies nouvelles. L’énoncé « la nouveauté produit du relief là où le bruit n’en produit pas » tombe sur cette instance — et c’est exactement ce que le test était conçu pour pouvoir faire.
Les deux générateurs s’accordent entre eux — mais ça ne sauve rien. R1 (catalogue fermé) et R2 (dérive génomique, 26-27 comportements nouveaux par trajectoire) donnent du relief tous les deux. Sans le contrôle, on aurait écrit ROBUSTE_AU_GENERATEUR. Le contrôle révèle que cette robustesse était vraie et vide : le relief ne discriminait pas la nouveauté, il accompagnait la stochasticité agent-based. Un contrôle négatif qui échoue vaut plus qu’une replication qui réussit.
Résolution du discriminant. La démonstration interleaved montre en prime que b1_max_persistence est grossier sur cette recette : deux trajectoires de coopération différentes peuvent partager exactement le même nerf (R1 et R3-interleaved sont float-identiques parce que les proxys fenêtrés coïncident). Toute conclusion fine appuyée sur des écarts de b1 à la 2ᵉ décimale doit être tenue pour fragile.
Ce que ce notebook ne fait pas : il ne réteste pas Qwen ni le banc humour (#13306 suit son propre protocole), et il ne promeut rien — le verdict est un fait d’instance et de recette, la promotion est un acte séparé (#13303).
Exercice 1 (null de permutation). Le verdict dit que le relief accompagne la stochasticité, pas la trajectoire elle-même. Testez : permutez aléatoirement la série de coopération de R1 (structure temporelle détruite, distribution conservée) et mesurez b1_max_persistence sur 5 permutations. Si les valeurs restent dans la plage des régimes agent-based, le discriminant lit-il un contenu de trajectoire ou une statistique de distribution ?
# Exercice 1 -- a completer.# Indice : coop = regime_r1(20260720) ; puis pour k in range(5) :# perm = rng.permutation(len(coop)) ; b1, ns = coop_to_b1(coop[perm], f'perm{k}')# Etape 1 : construire le generateur de permutations (np.random.default_rng distinct).# Etape 2 : mesurer les 5 b1 et les comparer a r1_b1[20260720].# Etape 3 : conclure en une phrase -- le discriminant lit-il la trajectoire ou la distribution ?pass
Exercice 2 (le relief du contrôle suit-il le taux de turnover ?). Si le relief de R3 vient du turnover stochastique, il devrait répondre au taux de mutation. Recalculez R3 (blocs) avec MU = 0.01 puis MU = 0.10 sur la graine 20260720 et comparez les trois b1_max_persistence. Attention à garder l’appariement : ne changez QUE MU.
# Exercice 2 -- a completer.# Indice : copier regime_r3 en parametrant MU (argument mu=...), ne rien changer d'autre.# Etape 1 : mesurer b1 pour mu in [0.01, 0.05, 0.10] sur la graine 20260720.# Etape 2 : le relief croit-il avec le taux de turnover ?pass
Exercice 3 (génomes memory-2 : plus de dimension, plus de nouveauté possible). Le générateur B ouvre 32 comportements (5 bits). Un génome memory-2 — réaction aux deux derniers coups de chaque joueur, 16 états + coup initial = 17 bits, 131 072 comportements — rend l’espace presque infini. Implémentez la lecture du génome memory-2 (la mutation reste un bit par mutant) et mesurez R2-memory-2 sur la graine 20260720. Le verdict change-t-il ? On attend honnêtement : non — le contrôle R3 prédit que la dimension n’est pas le bon axe.
# Exercice 3 -- a completer.# Indice : genome = [init] + 16 bits d'index (own1,opp1,own0,opp0) ; l'index de reaction# est base 4 sur les deux derniers coups. Garder POP, GENS, ROUNDS, NOISE, MU apparies.# Etape 1 : ecrire genome_play_2 (lecture a deux pas d'historique).# Etape 2 : reutiliser la boucle de regime_r2 avec ce genome (population initiale : les# 5 classiques transcrits en memory-2).# Etape 3 : mesurer b1 et comparer a r2_b1[20260720] et a m_r3.pass
Conclusion — un discriminant honnête est un discriminant contrôlé
régime
mécanisme
relief (moy. 3 graines)
lecture
R0
replicateur-mutation déterministe
0,0000
convergence figée, nuage saturé
R1
générateur A (catalogue fermé)
~0,35
relief, mais voir R3
R2
générateur B (dérive génomique)
~0,41
relief, mais voir R3
R3
dimension sans nouveauté
~0,35
le relief est là aussi
Le protocole pré-enregistré de #13308 rend son verdict : CONFONDU_AVEC_LA_DIMENSION. Sur le substrat Axelrod régénéré et la recette observable d’ICT-15j, le relief du discriminant nerf accompagne la stochasticité de population finie, pas l’apparition de comportements nouveaux. La réplication sur deux générateurs structurellement distincts (R1/R2) aurait suggéré une robustesse — le contrôle négatif la vide de son sens : c’est la leçon méthodologique du notebook, la même que #13306 applique au détecteur d’humour. Un instrument qui mesure sa propre construction doit être falsifié par le contrôle le moins glamour du banc — et ici, il l’a été.
Raccord : ICT-15j mesure, ICT-15l audite la mesure. La prochaine étape n’est pas un meilleur générateur de nouveauté mais un observable plus fin (ou une question différente) ; la campagne multi-annotateurs de #12756 et l’observatoire externe #13303 restent le cap.