# -*- coding: utf-8 -*- """Ядро Коди: рефлексия и недельный отчёт — hermetic. Запуск: ./venv/bin/python tests/test_kodi_core_reflect.py Проверяет: < порога ошибок — рефлексии нет; ≥ 3 расхождений вердикта с меткой человека/чата → задача часу (M, автодоставка, случаи в постановке) + CoreReflection; повтор — только по новым случаям; задачи: ≥ 3 S-задач не влезли в мин → своя рефлексия, разобранные не повторяются; недельный отчёт: не в понедельник — нет, force — текст с метриками, повтор недели — SKIP (идемпотентная доставка). """ import json import os import sys import tempfile sys.path.insert(0, "/root/simbiot-harness") _tmp = tempfile.mkdtemp(prefix="simbiot_core_refl_") os.environ["SIMBIOT_DB"] = os.path.join(_tmp, "harness.db") os.environ["SIMBIOT_CORE_DIR"] = os.path.join(_tmp, "core") os.environ.pop("SIMBIOT_CORE_REFLECT_MIN", None) from harness import es, kodi_core, tg_inbox es.init_db() fails = [] def check(name, cond, extra=""): print(("PASS" if cond else "FAIL"), name, ("| " + str(extra)) if not cond else "") if not cond: fails.append(name) SENT = [] tg_inbox.notify_chat = lambda text: SENT.append(text) or {"ok": True} G = -1004402779881 N = [0] def wrong(verdict_addressed: bool, truth: int, src="feedback"): N[0] += 1 mid = f"m-{N[0]}" es.append_event("inbox", mid, "MessageReceived", {"update_id": N[0], "chat_id": G, "chat_type": "supergroup", "first_name": "Alex", "text": f"реплика {N[0]}"}) es.append_event("inbox", mid, "MessageTriaged" if verdict_addressed else "MessageIgnored", {"addressed": verdict_addressed, "reason": "not_addressed", "rule": "decision", "p": .6}) es.append_event("core", f"lab:{mid}", "CoreLabel" if src == "human" else "CoreFeedback", {"head": "addressing", "msg": mid, "label": truth, "source": src}) def tasks_with(event_type): return [json.loads(e["data"]) for e in es.get_events(0, 10**6) if e["event_type"] == event_type] wrong(True, 0); wrong(False, 1) check("2 ошибки < порога — рефлексии нет", kodi_core.reflect(log=lambda *_: None) == []) wrong(True, 0, "human") made = kodi_core.reflect(log=lambda *_: None) sub = {t["id"]: t for t in tasks_with("TaskSubmitted")} check("3 ошибки → задача рефлексии", len(made) == 1 and "Рефлексия адресации" in sub[made[0]]["title"], made) check("задача — к часу (M) с автодоставкой", sub[made[0]]["size"] == "M" and es.run_projections()["tasks"][made[0]].get("await_delivery")) check("случаи в постановке", "я ответил" in sub[made[0]]["details"] and "было не боту" in sub[made[0]]["details"]) check("повтор без новых случаев — нет", kodi_core.reflect(log=lambda *_: None) == []) # задачи: 3 S-задачи не влезли for i in range(3): tid = f"t-{i}" es.append_event("task", tid, "TaskSubmitted", {"id": tid, "title": f"найди плашку {i}", "size": "S"}) es.append_event("task", tid, "TaskClaimed", {"level": "min"}) es.append_event("task", tid, "TaskClaimed", {"level": "min"}) made2 = kodi_core.reflect(log=lambda *_: None) sub = {t["id"]: t for t in tasks_with("TaskSubmitted")} check("задачи: 3 не влезли → рефлексия задач", len(made2) == 1 and "Рефлексия задач" in sub[made2[0]]["title"], made2) check("задачи: разобранные не повторяются", kodi_core.reflect(log=lambda *_: None) == []) # недельный отчёт from datetime import datetime, timezone if datetime.now(timezone.utc).weekday() != 0: check("не понедельник — отчёта нет", kodi_core.weekly_report() is None and not SENT) txt = kodi_core.weekly_report(force=True) check("отчёт: текст с головами и метриками", txt and "Адресация в группах" in txt and "Задачи" in txt and "рефлексий" in txt and SENT, txt) check("отчёт: повтор недели — SKIP", kodi_core.weekly_report(force=True) is None and len(SENT) == 1) print(f"\n{'OK' if not fails else 'FAILED'}: {len(fails)} fail(s)") sys.exit(1 if fails else 0)