GrandNexus / tools /layer_runtime_test.py
Khaled
Publish GrandNexus 7.1.1 complete snapshot
2bdab99
Raw History Blame Contribute Delete
5.78 kB
"""
Test de conflit EN FONCTIONNEMENT : cœur 29/05 + orchestrateur + couche vivante du 15/05
sur un même NexusCore démarré, pendant quelques secondes.
Mesures : collisions de noms, messages envoyés / livrés / sans destinataire,
errors journalisées par module, statut des modules, fuite de threads.
Usage : python tools/layer_runtime_test.py [secondes]
"""
import collections, importlib, logging, sys, threading, time, pathlib
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent))
LAYER = [ # (module, classe)
("grandnexus.clock.cognitive_clock", "CognitiveClock"),
("grandnexus.sensors.sensor_hub", "SensorHub"),
("grandnexus.actuators.actuator_hub", "ActuatorHub"),
("grandnexus.homeostasis.homeostasis_manager", "HomeostasisManager"),
("grandnexus.planning.executive_planner", "ExecutivePlanner"),
("grandnexus.cognition.perception.filters.attention_filter_v2", "AttentionFilter"),
("grandnexus.memory.working_v2", "WorkingMemory"),
("grandnexus.security.safety_guard", "SafetyGuard"),
("grandnexus.cognition.metacognition.self_model", "SelfModelService"),
("grandnexus.cognition.metacognition.affect_regulator", "AffectRegulator"),
("grandnexus.ops.cost_optimizer", "CostOptimizer"),
("grandnexus.kernel.kernel_bridge", "KernelBridge"),
]
class Collector(logging.Handler):
def __init__(self):
super().__init__(logging.ERROR)
self.errors = collections.Counter(); self.samples = {}
def emit(self, r):
key = r.name
self.errors[key] += 1
self.samples.setdefault(key, r.getMessage()[:140])
def main(seconds=3.0):
threads_before = threading.active_count()
col = Collector(); logging.getLogger().addHandler(col)
from grandnexus.boot import boot
gn = boot(log_level=logging.CRITICAL)
for name in list(logging.root.manager.loggerDict): # certains modules ont leur propre handler
lg = logging.getLogger(name); lg.propagate = True
logging.getLogger().setLevel(logging.ERROR)
core = gn.core
print(f"démarrage du cœur : {sum(s.ok for s in gn.report)}/{len(gn.report)} étapes")
sent, undelivered = collections.Counter(), collections.Counter()
orig_send = core.send_message
def send(source, target, message_type, content, priority=1):
sent[(source, message_type)] += 1
if target not in core.modules:
undelivered[(source, target)] += 1
return orig_send(source, target, message_type, content, priority)
core.send_message = send
# 1) collisions de noms avant tout démarrage
instances, report = {}, []
for mod, cls in LAYER:
try:
C = getattr(importlib.import_module(mod), cls)
name = getattr(C, "MODULE_NAME", cls.lower())
if name in core.modules:
report.append((cls, "CONFLIT", f"le nom '{name}' est déjà pris par "
f"{type(core.modules[name]['instance']).__name__} : non démarré"))
continue
instances[cls] = C(core)
except Exception as e:
report.append((cls, "FAIL création", f"{type(e).__name__}: {e}"))
# 2) démarrage du cœur puis de la couche
t0 = time.time()
try:
core.start()
except Exception as e:
report.append(("NexusCore", "FAIL start", f"{type(e).__name__}: {e}"))
for cls, inst in instances.items():
try:
ok = inst.start()
report.append((cls, "démarré" if ok is not False else "start()=False", ""))
except Exception as e:
report.append((cls, "FAIL start", f"{type(e).__name__}: {e}"))
time.sleep(seconds)
# 3) santé
for cls, inst in instances.items():
hc = getattr(inst, "health_check", None)
if callable(hc):
try:
h = hc(); report.append((cls, "santé", str(h)[:90]))
except Exception as e:
report.append((cls, "FAIL santé", f"{type(e).__name__}: {e}"))
# 4) une question pendant que tout tourne
try:
r = gn.orchestrator.process_input("All men are mortal. Socrates is a man. Is Socrates mortal?")
ans = [o.get("answer") for o in (r["output"] or []) if isinstance(o, dict) and "answer" in o]
report.append(("Orchestrateur", "question en charge", f"answers={ans[:2]} succès={r['success']}"))
except Exception as e:
report.append(("Orchestrateur", "FAIL question", f"{type(e).__name__}: {e}"))
# 5) arrêt
for cls, inst in instances.items():
try: inst.stop()
except Exception as e: report.append((cls, "FAIL stop", str(e)[:80]))
gn.shutdown()
time.sleep(1.0)
elapsed = time.time() - t0
print("\n— Modules de la couche 15/05")
for cls, status, detail in report:
print(f" {cls:22} {status:20} {detail}")
print(f"\n— Messages en {elapsed:.1f}s : {sum(sent.values())} envoyés")
for (src, typ), n in sent.most_common(8):
print(f" {src:22} {typ:22} {n}")
print(f"— Sans destinataire enregistré : {sum(undelivered.values())}")
for (src, tgt), n in undelivered.most_common(8):
print(f" {src:22} -> {tgt:22} {n}")
print(f"— Erreurs journalisées : {sum(col.errors.values())}")
for name, n in col.errors.most_common(10):
print(f" {name:28} {n:5} ex: {col.samples[name]}")
print(f"— Threads : avant={threads_before} après arrêt={threading.active_count()}")
leftover = [t.name for t in threading.enumerate() if t is not threading.main_thread()]
if leftover:
print(" encore vivants :", collections.Counter(n.split('-')[0] for n in leftover).most_common(8))
if __name__ == "__main__":
main(float(sys.argv[1]) if len(sys.argv) > 1 else 3.0)