"""守卫测试：防止旧逐题（per-question）路径在 unit 化迁移后复活或残留。

Task 3-10 已将三池切分、分批整锁、pair-level 聚合、gate 块基线缓存等契约
从"逐题 qid"迁移到"QuestionUnit 整锁"。本测试对迁移后的源码做静态锚点扫描，
锁住四个不可回退的语义标志：一旦有人误引入旧逐题分桶 / 逐题 gate 缓存 / 逐题
累加 / 未走 unit 化的代码，断言即刻失败。

覆盖模块：batching（分批）、pools（三池切分）、inference（pair 聚合）、
app.harness.validate（gate 块核心残留点）。
"""

import inspect
import re

from app.harness import batching, inference, pools


def test_no_parallel_perquestion_split_helpers():
    """契约迁 unit 后，不得残留会拆 pair 的旧逐题分批 / 切分 / gate 块路径。"""
    from app.harness import validate as hvalidate  # gate 块真实路径

    src = (
        inspect.getsource(batching)
        + inspect.getsource(pools)
        + inspect.getsource(hvalidate)
        + inspect.getsource(inference)  # 覆盖 T6 pair-level 聚合路径
    )
    # 旧逐题分桶残留：正确率不应按 qid 直接取
    assert "correctness.get(qid)" not in src, "batching 仍有逐题分桶残留"

    # gate 块残留探测：validate.py 是逐题 gate 核心残留点。
    # 逐个 baseline_cache.get(...) 调用点都必须按 unit_id 键控、不得回退到裸 qid/question_id，
    # 否则视为逐题残留复活。跨行实参用容纳换行的懒惰匹配抓全整个调用文本。
    baseline_get_calls = re.findall(r"baseline_cache\.get\((?:[^()]|\n)*?\)", src)
    # 兜底：正则必须真抓到 validate.py 的调用，否则 for 空转又成 tautology
    assert baseline_get_calls, "守卫失效：未抓到任何 baseline_cache.get 调用"
    for call in baseline_get_calls:
        assert "unit_id" in call, f"baseline_cache.get 未按 unit_id 键控（逐题残留）: {call}"
        assert "qid" not in call and "question_id" not in call, (
            f"baseline_cache.get 回退逐题 qid: {call}"
        )

    # 逐题累加残留：n_used 不应按逐题 chunk 长度累加（应按 unit）
    assert "n_used += len(chunk)" not in src, "validate n_used 仍逐题累加（应按 unit）"
    # 正向 unit 化探测：pools/batching/validate/inference 已走 unit 契约
    assert src.count("build_units") >= 1, "pools/batching/validate/inference 未走 unit 化聚合"
