from math import sqrt
REQUIRED = {"scenario": str, "source_ids": list, "train_hash": str, "test_hash": str,
            "feature_contract": str, "seeds": list, "paired_differences": list,
            "difference_unit": str, "ablation_delta": float}
def analyze(card, ablation_tolerance):
    errors = [name for name, kind in REQUIRED.items()
              if name not in card or type(card[name]) is not kind]
    values = card.get("paired_differences", [])
    if not values or any(type(value) not in (int, float) for value in values):
        errors.append("paired_difference_type")
    if card.get("difference_unit") != "accuracy points" or card.get("train_hash") == card.get("test_hash"):
        errors.append("unit_or_split_hash")
    if not card.get("source_ids") or not card.get("seeds") or any(type(seed) is not int for seed in card.get("seeds", [])):
        errors.append("sources_or_seeds")
    if errors:
        return {"decision": "invalid", "errors": sorted(set(errors)), "interval": None}
    mean = sum(values) / len(values)
    variance = sum((value - mean) ** 2 for value in values) / (len(values) - 1)
    radius = 1.96 * sqrt(variance / len(values))
    interval = (mean - radius, mean + radius)
    decision = "inconclusive" if interval[0] <= 0 <= interval[1] else "directional"
    if abs(card["ablation_delta"]) > ablation_tolerance:
        decision = "ablation-sensitive"
    return {"decision": decision, "errors": [], "interval": interval, "mean": mean}
card = {"scenario": "equal-feature held-out classifier", "source_ids": ["benchmarking-2025"],
        "train_hash": "train:42c1", "test_hash": "test:88af", "feature_contract": "same 12 features",
        "seeds": [11, 19, 23, 31, 47], "paired_differences": [0.02, -0.01, 0.01, 0.00, -0.02],
        "difference_unit": "accuracy points", "ablation_delta": 0.005}
base_result = analyze(card, 0.01)
bad = {key: value for key, value in card.items() if key != "feature_contract"}
bad_result = analyze(bad, 0.01)
shifted = {**card, "paired_differences": [value + 0.04 for value in card["paired_differences"]]}
shifted_result = analyze(shifted, 0.01)
assert base_result["decision"] == "inconclusive" and base_result["interval"][0] < 0 < base_result["interval"][1]
assert bad_result["decision"] == "invalid" and "feature_contract" in bad_result["errors"]
assert shifted_result["decision"] == "directional" and shifted_result["interval"][0] > 0
print(f"PASS: 69 QML card interval={base_result['interval']} invalid={bad_result['errors']} shifted={shifted_result['decision']}")
