#!/usr/bin/env python3
"""Clean-room verifier for the CAIN-42 Evolution 21 evidence bundle (Governed Open-Ended Intelligence Fabric).

Imports NOTHING from CAIN: Python standard library + `cryptography` only, with its OWN copies of every rule it
re-derives (evidence-class weights and labels, independence grouping, confidence and epistemic quality, the discovery
lifecycle, research authority as charter ∩ role, promotion scope as an intersection, Shannon information gain, the
multi-dimensional regression rule). From the published JSON it re-hashes every file against MANIFEST.json,
recomputes every published digest, verifies every Ed25519 signature and quorum, and checks the invariant, bench,
research-demonstration, self-evolution, mutation, tamper and scale records for consistency. It does not re-run the
fabric, and it does NOT prove that any hypothesis is true.

    python3 verify_e21.py <bundle dir>      -> JSON on stdout; exit 0 only if INTACT
"""
from __future__ import annotations

import base64
import hashlib
import json
import math
import re
import sys
from pathlib import Path

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric import ed25519

D = {k: f"CAIN42/E21-{v}/v1" for k, v in {
    "discovery": "DISCOVERY-STATE", "evidence": "RESEARCH-EVIDENCE", "hypothesis": "HYPOTHESIS",
    "charter": "RESEARCH-CHARTER", "experiment": "EXPERIMENT-DESIGN", "exp_approval": "EXPERIMENT-APPROVAL",
    "causal": "CAUSAL-CLAIM", "counterfactual": "COUNTERFACTUAL", "review": "PEER-REVIEW",
    "adversarial_attempt": "ADVERSARIAL-ATTEMPT", "knowledge": "KNOWLEDGE-CLAIM", "revocation": "KNOWLEDGE-REVOCATION",
    "capability": "CAPABILITY-PROPOSAL", "promotion": "CAPABILITY-PROMOTION", "invention": "INVENTION",
    "info": "INFORMATION-VALUE", "memory": "DISCOVERY-MEMORY", "benchmark": "BENCHMARK",
    "bench_result": "BENCHMARK-RESULT", "regression": "INTELLIGENCE-REGRESSION",
    "disclosure": "GOVERNANCE-WEAKNESS-DISCLOSURE", "exec": "RESEARCH-EXECUTION-DECISION", "adversarial": "ADVERSARIAL",
    "master": "MASTER"}.items()}
D.update({"e19_state": "CAIN42/E19-GOVERNED-STATE/v1", "e19_root_mutation": "CAIN42/E19-GOVERNANCE-MUTATION/v1",
          "e20_exec": "CAIN42/E20-INSTITUTIONAL-EXECUTION-DECISION/v1"})
REQUIRED = ("README.md", "MANIFEST.json", "SCHEMAS.json", "INVARIANTS.json", "ATTACK_MANIFEST.json",
            "TEST_RESULTS.json", "SCALE_RESULTS.json", "DISCOVERY_RESULTS.json", "HYPOTHESIS_RESULTS.json",
            "EXPERIMENT_RESULTS.json", "REPLICATION_RESULTS.json", "KNOWLEDGE_RESULTS.json", "CAUSAL_RESULTS.json",
            "CAPABILITY_RESULTS.json", "SELF_EVOLUTION_RESULTS.json", "PERFORMANCE.json", "SIGNATURES.json",
            "HASHES.json", "CLEAN_ROOM_VERIFIER.json", "PUBLIC_SAFE_EXAMPLES.json", "LIMITATIONS.json",
            "LIMITATIONS.md", "UNKNOWN.json", "UNVERIFIED.json", "PROVENANCE.json", "CAIN42_E21_EVIDENCE_BUNDLE.json",
            "MUTATION_RESULTS.json", "TAMPER_RESULTS.json", "CAIN42_EVOLUTION21_CLAIMS.json", "REPRODUCE.txt",
            "verify_e21.py.txt", "index.html")
FORBIDDEN_MATERIAL = ("-----begin", "private_key", "secret_key", "password")
FORBIDDEN_WORDS = ("discovered agi", "created agi", "guarantees scientific truth", "guarantees autonomous",
                   "guarantees safe self-improvement", "controls every autonomous", "solved alignment",
                   "unhackable", "perfect detection")
CLAIM_STATES = ("IMPLEMENTED", "TESTED", "VERIFIED", "REPRODUCIBLE", "SIMULATED", "UNVERIFIED", "UNKNOWN",
                "NOT_IMPLEMENTED", "NOT_PERFORMED")
REQUIRED_CATEGORIES = (
    "hypothesis_poisoning", "evidence_poisoning", "false_discovery", "fabricated_experiment", "simulation_laundering",
    "replication_fraud", "benchmark_gaming", "dataset_contamination", "model_contamination", "research_agent_collusion",
    "reviewer_collusion", "confirmation_loop", "consensus_amplification", "knowledge_graph_poisoning",
    "memory_poisoning", "causal_inference_manipulation", "counterfactual_leakage", "experiment_authority_escalation",
    "research_budget_abuse", "agent_spawning_abuse", "capability_laundering", "novelty_laundering",
    "self_improvement_escalation", "research_institution_capture", "institutional_knowledge_poisoning",
    "reward_hacking", "information_gain_abuse", "curiosity_abuse", "search_space_explosion", "resource_exhaustion",
    "model_substitution", "dataset_substitution", "experiment_environment_substitution", "time_manipulation",
    "provenance_mutation", "evidence_replay", "knowledge_resurrection", "revoked_claim_reuse",
    "superseded_model_reuse", "stale_benchmark_reuse", "authority_resurrection", "governance_loophole")
REQUIRED_DEMO = ("FORMULATE_HYPOTHESES", "COMPETING_TRACKS", "DESIGN_EXPERIMENTS", "RUN_SIMULATIONS",
                 "PRODUCE_OBSERVATIONS", "IDENTIFY_CONTRADICTIONS", "REJECT_HYPOTHESIS", "REPLICATE_RESULT",
                 "CANDIDATE_CAPABILITY", "QUARANTINE_CAPABILITY", "ADVERSARIAL_TEST", "PROMOTE_AFTER_GOVERNANCE",
                 "BOUNDED_DEMONSTRATION", "PREDICTION_VS_OUTCOME", "UPDATE_KNOWLEDGE", "PRESERVE_FAILED_PATHS",
                 "NO_SELF_AUTHORIZATION")
# ---- independent copies of the E21 rules --------------------------------------------------------------------
METHOD_CLASSES = ("SIMULATION", "SYNTHETIC_EXPERIMENT", "CONTROLLED_EXPERIMENT", "REAL_WORLD_OBSERVATION",
                  "INDEPENDENT_REPLICATION", "THIRD_PARTY_REPRODUCTION")
OBSERVATIONAL = {"CONTROLLED_EXPERIMENT", "REAL_WORLD_OBSERVATION", "INDEPENDENT_REPLICATION",
                 "THIRD_PARTY_REPRODUCTION"}
WEIGHT = {"SIMULATION": 0.1, "SYNTHETIC_EXPERIMENT": 0.2, "CONTROLLED_EXPERIMENT": 0.6,
          "REAL_WORLD_OBSERVATION": 0.5, "INDEPENDENT_REPLICATION": 0.8, "THIRD_PARTY_REPRODUCTION": 1.0}
DATA_KIND = {"SIMULATION": "simulated", "SYNTHETIC_EXPERIMENT": "synthetic"}
TRANSITIONS = {"PROPOSED": {"HYPOTHESIS"}, "HYPOTHESIS": {"INVESTIGATING"},
               "INVESTIGATING": {"SIMULATED", "OBSERVED", "DISPUTED", "REFUTED"},
               "SIMULATED": {"OBSERVED", "INVESTIGATING", "DISPUTED", "REFUTED"},
               "OBSERVED": {"REPLICATING", "DISPUTED", "REFUTED"}, "REPLICATING": {"SUPPORTED", "DISPUTED", "REFUTED"},
               "SUPPORTED": {"DISPUTED", "REFUTED", "SUPERSEDED", "VERIFIED"},
               "DISPUTED": {"INVESTIGATING", "REFUTED", "SUPPORTED", "SUPERSEDED"}, "REFUTED": {"SUPERSEDED"},
               "VERIFIED": {"DISPUTED", "REFUTED", "SUPERSEDED"}, "SUPERSEDED": set()}
ALWAYS_FORBIDDEN = {"modify_governance", "modify_policy", "grant_authority", "exfiltrate", "disable_audit",
                    "real_payment", "actuate"}
GOVERNANCE_SURFACE = {"admit_member", "restructure", "federate", "adjudicate", "delegate", "spawn",
                      "modify_governance", "modify_policy", "grant_authority", "disable_audit", "bypass_boundary",
                      "self_approve", "mint_resource"}
ADVERSARIAL_KINDS = {"confirm", "refute", "alternative", "assumption_attack", "reproduce"}
TRACE_FORBIDDEN = {"chain_of_thought", "private_reasoning", "scratchpad", "hidden_reasoning", "thoughts",
                   "reasoning_trace"}
CAPABILITY_ORDER = ("QUARANTINED", "VALIDATED", "ADVERSARIAL_TESTED", "SECURITY_REVIEWED", "PROMOTED_LIMITED")


def canon(o) -> bytes:
    return json.dumps(o, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode()


def h(o) -> str:
    return hashlib.sha256(canon(o)).hexdigest()


def dig(domain: str, fields: dict) -> str:
    return h({"domain": domain, **fields})


def sig_ok(pub: str, sig: str, domain: str, fields: dict) -> bool:
    try:
        ed25519.Ed25519PublicKey.from_public_bytes(base64.b64decode(pub)).verify(
            base64.b64decode(sig), dig(domain, fields).encode())
        return True
    except (InvalidSignature, ValueError, TypeError):
        return False


def strip(d: dict, *keys: str) -> dict:
    return {k: v for k, v in d.items() if k not in keys}


def signed_ok(obj: dict, domain: str, pub: str = None) -> bool:
    if not obj or "signer" not in obj or "signature_b64" not in obj:
        return False
    if pub is not None and obj["signer"] != pub:
        return False
    return sig_ok(obj["signer"], obj["signature_b64"], domain, strip(obj, "signer", "signature_b64"))


def quorum_ok(approval: dict, subject: str, keys, threshold: int, excluded=()) -> bool:
    if approval["subject"] != subject:
        return False
    valid = {pub for pub, s in approval["signatures"] if pub in keys and pub not in set(excluded)
             and sig_ok(pub, s, D["e19_root_mutation"], {"subject": subject})}
    return len(valid) >= threshold


def forbidden_keys(o) -> set:
    out = set()
    if isinstance(o, dict):
        for k, v in o.items():
            if str(k).lower() in TRACE_FORBIDDEN:
                out.add(k)
            out |= forbidden_keys(v)
    elif isinstance(o, list):
        for v in o:
            out |= forbidden_keys(v)
    return out


def valid_at(ev: dict, revoked: dict, now: float) -> bool:
    b = ev["body"]
    return b["evidence_id"] not in revoked and b["created_at"] <= now < b["expires_at"]


def confidence(evidence: list, agents: dict, revoked: dict, hyp: str, now: float) -> dict:
    """Independent copy: one vote per (controller, environment, dataset, model) group; any contradiction in a group
    wins; the group's weight and class are those of its strongest member."""
    groups = {}
    for ev in evidence:
        b = ev["body"]
        s = b["supports"].get(hyp, 0)
        if not s or not valid_at(ev, revoked, now):
            continue
        key = (agents[b["producer"]]["controller"], b["environment"], b["dataset"], b["model"])
        s = 1 if s > 0 else -1
        w = WEIGHT[b["method_class"]]
        if key not in groups:
            groups[key] = (s, w, b["method_class"])
        else:
            p = groups[key]
            top = max((p[1], p[2]), (w, b["method_class"]))
            groups[key] = (min(p[0], s), top[0], top[1])
    sup = sum(w for s, w, _ in groups.values() if s > 0)
    con = sum(w for s, w, _ in groups.values() if s < 0)
    obs_sup = sum(1 for s, _, c in groups.values() if s > 0 and c in OBSERVATIONAL)
    obs_con = sum(1 for s, _, c in groups.values() if s < 0 and c in OBSERVATIONAL)
    rep = sum(1 for s, _, c in groups.values() if s > 0 and c in ("INDEPENDENT_REPLICATION",
                                                                  "THIRD_PARTY_REPRODUCTION"))
    tp = sum(1 for s, _, c in groups.values() if s > 0 and c == "THIRD_PARTY_REPRODUCTION")
    if not groups:
        q = "UNKNOWN"
    elif obs_con >= 1 and con >= sup:
        q = "REFUTED" if obs_con >= 2 or sup == 0 else "DISPUTED"
    elif obs_con >= 1:
        q = "DISPUTED"
    elif rep >= 1 and obs_sup >= 2 and tp >= 1:
        q = "STRONGLY_SUPPORTED"
    elif rep >= 1 and obs_sup >= 2:
        q = "SUPPORTED"
    elif obs_sup >= 1:
        q = "PRELIMINARY"
    else:
        q = "LOW_CONFIDENCE"
    return {"confidence": round((sup + 0.5) / (sup + con + 1.0), 6), "uncertainty": round(1.0 / (1.0 + sup + con), 6),
            "independent_groups": len(groups), "observational_support": obs_sup,
            "observational_contradiction": obs_con, "independent_replications": rep,
            "third_party_reproductions": tp, "quality": q}


def entropy(p: dict) -> float:
    return -sum(v * math.log2(v) for v in p.values() if v > 0)


def info_gain(prior: dict, lk: dict) -> float:
    z = sum(prior.values())
    prior = {k: v / z for k, v in prior.items()}
    h0, g = entropy(prior), 0.0
    for o, l in lk.items():
        po = sum(prior[x] * l.get(x, 0.0) for x in prior)
        if po > 0:
            g += po * (h0 - entropy({x: prior[x] * l.get(x, 0.0) / po for x in prior}))
    return round(g, 9)


class Checks:
    def __init__(self) -> None:
        self.detail, self.problems = [], []

    def check(self, name: str, ok, info=None) -> None:
        ok = bool(ok)
        self.detail.append({"check": name, "ok": ok, "info": info if isinstance(info, (str, int, float, bool))
                            or info is None else json.loads(json.dumps(info, default=str))})
        if not ok:
            self.problems.append(name)


def main(root: Path) -> int:
    C = Checks()

    def load(n):
        return json.loads((root / n).read_text())

    # ---- files, manifest, hashes, signature ----
    C.check("files.required_present", all((root / n).exists() for n in REQUIRED),
            [n for n in REQUIRED if not (root / n).exists()])
    man = load("MANIFEST.json")
    bad = [n for n, s in man["files"].items() if not (root / n).exists()
           or hashlib.sha256((root / n).read_bytes()).hexdigest() != s]
    C.check("manifest.file_hashes", not bad, bad)
    listed = set(man["files"]) | {"MANIFEST.json"} | set(man.get("unhashed_presentation", []))
    extra = sorted(p.name for p in root.iterdir() if p.is_file() and p.name not in listed and p.name != "verify_e21.py")
    C.check("manifest.covers_all_files", not extra, extra)
    C.check("manifest.presentation_unhashed", man.get("unhashed_presentation") == ["index.html"], "index.html")
    hs = load("HASHES.json")["files"]
    C.check("hashes.match_files", all(hashlib.sha256((root / n).read_bytes()).hexdigest() == s for n, s in hs.items()),
            len(hs))
    sg = load("SIGNATURES.json")
    C.check("signatures.master_binds_hashes", sg["master"]["hashes_digest"] == h(hs), "hashes digest")
    C.check("signatures.master_signature", sig_ok(sg["signer_public_key_b64"], sg["signature_b64"], D["master"],
                                                  sg["master"]), "ed25519")
    C.check("signatures.key_class_honest", sg.get("key_class") == "EPHEMERAL", sg.get("key_class"))
    texts = {p.name: p.read_text().lower() for p in root.iterdir() if p.is_file() and p.suffix in (".json", ".md", ".txt")
             and p.name not in ("verify_e21.py.txt",)}
    C.check("no_forbidden_material", not any(m in t for t in texts.values() for m in FORBIDDEN_MATERIAL), "material")

    ex = load("PUBLIC_SAFE_EXAMPLES.json")
    now = ex["now"]
    agents, evidence, revoked = ex["agents"], ex["evidence"], ex["revoked"]
    rules = ex["rules"]
    # ---- rules published match the verifier's own copies ----
    C.check("rules.method_classes", tuple(rules["method_classes"]) == METHOD_CLASSES, "classes")
    C.check("rules.class_weights", rules["class_weight"] == WEIGHT, "weights")
    C.check("rules.observational", set(rules["observational"]) == OBSERVATIONAL, "observational")
    C.check("rules.transitions", {k: set(v) for k, v in rules["transitions"].items()} == TRANSITIONS, "transitions")
    C.check("rules.lifecycle_artefacts_unique", set(rules["stage_artefact"]) == set(rules["lifecycle"]) and
            len(set(rules["stage_artefact"].values())) == len(rules["lifecycle"]), len(rules["lifecycle"]))
    C.check("rules.laws_present", all(x in rules["laws"] for x in (
        "DISCOVERY IS NOT TRUTH IS NOT AUTHORITY IS NOT EXECUTION", "CURIOSITY IS NOT AUTHORITY",
        "RESEARCH AUTHORITY IS NOT EXECUTION AUTHORITY", "SIMULATION IS NOT REALITY")) and
            len(rules["constitution"]) == 7, len(rules["laws"]))
    C.check("rules.flywheel_open_ended", rules["flywheel"][0] == "UNKNOWN" and rules["flywheel"][-1] == "NEW_UNKNOWN",
            "flywheel")
    C.check("rules.non_evidence_labels", {"COUNTERFACTUAL", "HYPOTHETICAL", "PREDICTED"} <=
            set(rules["non_evidence_labels"]) and not set(rules["non_evidence_labels"]) & set(METHOD_CLASSES), "labels")

    # ---- research program ----
    pg = ex["program"]
    ch = pg["charter"]
    C.check("charter.digest", dig(D["charter"], ch) == pg["charter_digest"], "digest")
    C.check("charter.subject_binds_digest", pg["charter_subject"] == f"research-charter:{pg['charter_digest']}", "subject")
    C.check("charter.quorum", quorum_ok(pg["approval"], pg["charter_subject"], pg["governance_keys"], pg["threshold"]),
            "k-of-n")
    C.check("charter.threshold_at_least_two", pg["threshold"] >= 2, pg["threshold"])
    C.check("charter.authority_none", ch["authority"] == "NONE", "none")
    C.check("charter.actions_known", set(ch["actions"]) <= set(pg["research_actions"]), "actions")
    C.check("charter.budget_within_ceiling", all(v <= ch["max_budget"].get(k, 0) for k, v in ch["budget"].items()),
            "budget")
    roles = dict((a, r) for a, r in ch["roles"])
    ra_ok = all(set(pg["research_authority"][a]) == set(ch["actions"]) & set(pg["research_roles"][roles[a]])
                for a in pg["research_authority"])
    C.check("research_authority.rederived_charter_and_role", ra_ok, "charter ∩ role")
    C.check("research_authority.disjoint_from_institution_powers",
            not set(pg["research_actions"]) & set(pg["institution_powers"]), "disjoint")
    C.check("research_authority.not_in_execution_authority",
            all(not set(v) & set(pg["research_actions"]) for v in pg["execution_authority"].values()), "disjoint")
    C.check("research_authority.coordinator_not_superuser",
            set(pg["research_authority"]["coord"]) != set(pg["research_actions"]), "bounded")
    bud = pg["budget"]
    C.check("budget.used_within_limits", all(bud["used"][k] <= bud["limits"][k] + 1e-9 for k in bud["limits"]), "used")
    C.check("budget.limits_within_ceiling", all(bud["limits"][k] <= pg["ceiling"][k] + 1e-9 for k in bud["limits"]),
            "ceiling")

    # ---- agents, environments ----
    C.check("agents.keys_well_formed", all(len(base64.b64decode(a["pub"])) == 32 for a in agents.values()), len(agents))
    C.check("agents.controllers_present", all(a["controller"] for a in agents.values()), "controllers")
    envs = ex["environments"]
    C.check("environments.digests", all(h({k: e[k] for k in ("name", "kind", "version", "content")}) == e["digest"] == d
                                        for d, e in envs.items()), len(envs))
    C.check("environments.kinds", all(e["kind"] in ("sandbox", "controlled_lab", "field") for e in envs.values()),
            "kinds")

    # ---- evidence ----
    C.check("evidence.present", len(evidence) >= 5, len(evidence))
    C.check("evidence.digests", all(dig(D["evidence"], e["body"]) == e["digest"] for e in evidence), "digests")
    C.check("evidence.producer_signatures", all(signed_ok(e["signed"], D["evidence"], agents[e["body"]["producer"]]["pub"])
                                                and strip(e["signed"], "signer", "signature_b64") == e["body"]
                                                for e in evidence), "ed25519")
    C.check("evidence.classes_valid", all(e["body"]["method_class"] in METHOD_CLASSES for e in evidence), "classes")
    C.check("evidence.labels_match_class", all(e["body"]["data_kind"] == DATA_KIND.get(e["body"]["method_class"],
                                                                                     "observational")
                                               for e in evidence), "labels")
    C.check("evidence.simulations_in_sandboxes", all(envs[e["body"]["environment"]]["kind"] == "sandbox"
                                                     for e in evidence if e["body"]["method_class"] in
                                                     ("SIMULATION", "SYNTHETIC_EXPERIMENT")), "sandbox")
    C.check("evidence.real_observations_outside_sandboxes",
            all(envs[e["body"]["environment"]]["kind"] != "sandbox" for e in evidence
                if e["body"]["method_class"] == "REAL_WORLD_OBSERVATION"), "not sandbox")
    by_id = {e["body"]["evidence_id"]: e for e in evidence}

    def ikey(b):
        return (agents[b["producer"]]["controller"], b["environment"], b["dataset"], b["model"])
    reps = [e["body"] for e in evidence if e["body"]["method_class"] == "INDEPENDENT_REPLICATION"]
    C.check("evidence.replications_target_known", reps and all(r["replicates"] in by_id for r in reps), len(reps))
    C.check("evidence.replications_independent", all(ikey(r) != ikey(by_id[r["replicates"]]["body"]) and
                                                      agents[r["producer"]]["controller"] !=
                                                      agents[by_id[r["replicates"]]["body"]["producer"]]["controller"]
                                                      for r in reps), "independent")
    C.check("evidence.third_party_only_from_registered",
            all((e["body"]["method_class"] == "THIRD_PARTY_REPRODUCTION") == (e["body"]["producer"] in ex["third_party"])
                for e in evidence), "third party")
    C.check("evidence.no_private_reasoning", not any(forbidden_keys(e["body"]) for e in evidence), "no CoT")
    C.check("evidence.validity_windows", all(e["body"]["created_at"] < e["body"]["expires_at"] and
                                             e["body"]["created_at"] <= now for e in evidence), "windows")
    C.check("evidence.provenance_present", all(e["body"]["provenance"] for e in evidence), "provenance")
    C.check("evidence.revocations_reference_evidence", set(revoked) <= set(by_id), sorted(revoked))
    C.check("evidence.ids_unique", len(by_id) == len(evidence), "unique")

    # ---- confidence (re-derived) ----
    conf = ex["confidence"]
    rederived = {hy: confidence(evidence, agents, revoked, hy, now) for hy in conf}
    for field in ("confidence", "uncertainty", "independent_groups", "observational_support",
                  "observational_contradiction", "independent_replications", "third_party_reproductions", "quality"):
        C.check(f"confidence.{field}_rederived", all(conf[hy][field] == rederived[hy][field] for hy in conf),
                {hy: rederived[hy][field] for hy in conf})
    C.check("confidence.no_authority", all(c["authority"] == "NONE" for c in conf.values()), "none")

    # ---- hypotheses ----
    hy = ex["hypotheses"]
    C.check("hypotheses.digests", all(dig(D["hypothesis"], v["body"]) == v["digest"] for v in hy.values()), len(hy))
    C.check("hypotheses.assumptions_visible", all(v["body"]["assumptions"] for v in hy.values()), "assumptions")
    C.check("hypotheses.falsifiable", all(v["body"]["predictions"] for v in hy.values()), "predictions")
    C.check("hypotheses.retired_only_when_refuted", all(
        (r == "refuted" and rederived[k]["quality"] == "REFUTED") or r == "superseded" for k, r in ex["retired"].items()),
        ex["retired"])
    C.check("hypotheses.alternatives_kept", len(hy) >= 3 and set(ex["retired"]) < set(hy), "kept")

    # ---- discovery ----
    ds = ex["discovery"]
    db = ds["body"]
    C.check("discovery.digest", dig(D["discovery"], db) == ds["digest"], "digest")
    hyp = db["hypothesis"]
    live = sorted(k for k, e in by_id.items() if e["body"]["supports"].get(hyp) and valid_at(e, revoked, now))
    C.check("discovery.evidence_rederived", db["evidence"] == live, live)
    C.check("discovery.contradictions_visible", db["contradictions"] == sorted(k for k in live if by_id[k]["body"]
                                                                             ["supports"][hyp] < 0), "contradictions")
    C.check("discovery.observations_rederived", db["observations"] == sorted(
        k for k in live if by_id[k]["body"]["method_class"] in OBSERVATIONAL), "observations")
    C.check("discovery.confidence_rederived", db["confidence"] == rederived[hyp]["confidence"] and
            db["uncertainty"] == rederived[hyp]["uncertainty"], "confidence")
    C.check("discovery.replication_status", db["replication_status"] == ("REPLICATED" if rederived[hyp]
                                                                         ["independent_replications"] else
                                                                         "NOT_REPLICATED"), "replication")
    C.check("discovery.supported_backed_by_evidence", ds["status"] not in ("SUPPORTED", "VERIFIED") or
            rederived[hyp]["quality"] in ("SUPPORTED", "STRONGLY_SUPPORTED"), ds["status"])
    hist = ds["history"]
    C.check("discovery.history_follows_lifecycle", hist and hist[0][0] == "PROPOSED" and all(
        b in TRANSITIONS[a] for a, b, _ in hist) and all(hist[i][1] == hist[i + 1][0] for i in range(len(hist) - 1)),
        [x[1] for x in hist])
    C.check("discovery.no_proposed_to_verified", not any(a == "PROPOSED" and b in ("SUPPORTED", "VERIFIED")
                                                         for a, b, _ in hist), "no shortcut")
    C.check("discovery.authority_none", db["authority"] == "NONE", "none")
    C.check("discovery.fields_complete", all(k in db for k in (
        "discovery_id", "parent_discovery_id", "research_question", "hypothesis", "method", "inputs", "models", "tools",
        "datasets", "environment", "assumptions", "observations", "evidence", "uncertainty", "confidence",
        "replication_status", "contradictions", "provenance")), "fields")
    lin = ds["lineage"]
    recs = lin["records"]
    C.check("lineage.record_digests", [dig(D["e19_state"], r) for r in recs] == lin["digests"], "digests")
    C.check("lineage.parent_links", all(r["parent_state_id"] == (recs[i - 1]["state_id"] if i else "genesis")
                                        for i, r in enumerate(recs)), "links")
    C.check("lineage.sequence_contiguous", [r["sequence_number"] for r in recs] == list(range(len(recs))), "seq")
    C.check("lineage.time_monotone", all(recs[i]["created_at"] <= recs[i + 1]["created_at"]
                                         for i in range(len(recs) - 1)), "time")
    C.check("lineage.epistemic_kind", all(r["kind"] == "epistemic_state" for r in recs), "kind")
    C.check("lineage.policy_bound_to_charter", all(r["policy_digest"] == pg["charter_digest"] for r in recs), "policy")
    C.check("lineage.one_record_per_transition", len(recs) == len(hist) + 1, len(recs))
    C.check("lineage.root", h({"lineage": lin["lineage_id"], "digests": lin["digests"]}) == lin["root"], "root")

    # ---- experiment ----
    xp = ex["experiment"]
    C.check("experiment.design_digest", dig(D["experiment"], xp["design"]) == xp["digest"], "digest")
    C.check("experiment.approval_signature", signed_ok(xp["approval"], D["exp_approval"], xp["authority_pub"]), "ed25519")
    C.check("experiment.approval_binds_design", xp["approval"]["experiment"] == xp["digest"] and
            xp["approval"]["environment"] == xp["design"]["where"], "binds")
    C.check("experiment.approval_not_execution_authority", xp["approval"]["execution_authority"] == "NONE" and
            xp["approval"]["scope"] == "RUN_IN_ENVIRONMENT_ONLY", "scope")
    C.check("experiment.forbids_governance_bypass", ALWAYS_FORBIDDEN <= set(xp["design"]["forbidden"]), "forbidden")
    C.check("experiment.fields_complete", all(xp["design"].get(k) not in ("", None, [], {}) for k in (
        "what_tested", "why", "where", "resources", "authority", "constraints", "possible_outcomes", "forbidden",
        "termination", "variables", "method_class")), "fields")
    run = xp["run"]
    C.check("experiment.forbidden_op_terminated", run["status"] == "TERMINATED" and run["observations"] == {} and
            any(o in ALWAYS_FORBIDDEN for o in run["operations"]), run["reasons"])

    # ---- peer review and adversarial ----
    researchers = {db["author"]} | {e["body"]["producer"] for e in evidence if e["body"]["supports"].get(hyp)}
    rv = ex["reviews"]
    C.check("review.digests", all(dig(D["review"], strip(r, "digest", "authority")) == r["digest"] for r in rv), len(rv))
    C.check("review.reviewers_not_researchers", not {r["reviewer"] for r in rv} & researchers, "independent")
    rc = {agents[x]["controller"] for x in researchers if x in agents}
    C.check("review.reviewer_controllers_independent", not {agents[r["reviewer"]]["controller"] for r in rv} & rc,
            "controllers")
    C.check("review.two_independent_reviewers", len({agents[r["reviewer"]]["controller"] for r in rv}) >= 2, len(rv))
    C.check("review.method_or_evidence_review", {"methodological", "evidence"} & {r["kind"] for r in rv}, "kinds")
    C.check("review.no_open_objection", all(r["verdict"] == "ACCEPT" for r in rv), "no objection")
    adv = ex["adversarial"]
    C.check("adversarial.digests", all(dig(D["adversarial_attempt"], strip(a, "digest")) == a["digest"] for a in adv),
            len(adv))
    C.check("adversarial.all_five_kinds", {a["kind"] for a in adv} == ADVERSARIAL_KINDS, "kinds")
    C.check("adversarial.not_by_author", all(a["by"] != db["author"] for a in adv), db["author"])
    C.check("adversarial.none_broke", all(a["outcome"] != "BROKEN" for a in adv), "held")

    # ---- knowledge ----
    kn = ex["knowledge"]
    C.check("knowledge.claim_digests", all(dig(D["knowledge"], c["body"]) == c["digest"] for c in kn["claims"].values()),
            len(kn["claims"]))
    C.check("knowledge.evidence_from_source", all(set(c["body"]["evidence"]) <= set(live) for c in kn["claims"].values()),
            "source")
    vers = {}
    for x in kn["history"]:
        vers.setdefault(x["claim_id"], []).append(x["version"])
    C.check("knowledge.versions_sequential", all(v == list(range(1, len(v) + 1)) for v in vers.values()), vers)
    C.check("knowledge.history_matches_current", all(any(x["digest"] == c["digest"] for x in kn["history"])
                                                     for c in kn["claims"].values()), "history")

    # ---- capability bridge ----
    cp = ex["capability"]
    pr, pm = cp["proposal"], cp["promotion"]
    C.check("capability.proposal_digest", dig(D["capability"], pr) == cp["digest"], "digest")
    C.check("capability.promotion_signature", signed_ok(pm, D["promotion"], cp["registry_pub"]), "ed25519")
    C.check("capability.promotion_binds_proposal", pm["proposal"] == cp["digest"] and pm["capability_id"] ==
            pr["capability_id"], "binds")
    scope_max = set(pr["requested_scope"]) & set(cp["effective_authority"]) & set(cp["e19_executable"])
    C.check("capability.scope_is_intersection", set(pm["scope"]) == scope_max, sorted(scope_max))
    C.check("capability.no_governance_surface", not set(pr["requested_scope"]) & GOVERNANCE_SURFACE and
            set(cp["governance_surface"]) == GOVERNANCE_SURFACE, "surface")
    C.check("capability.grants_no_authority", pm["grants_authority"] is False and pm["authority"] == "NONE", "none")
    C.check("capability.limited_deployment", pm["targets"] == sorted(pr["targets"]) and pm["operators"] ==
            sorted(pr["operators"]) and pm["targets"] and pm["operators"] and pm["expires_at"] > pm["issued_at"], "limited")
    C.check("capability.rollback_plan", bool(pr["rollback_plan"]) and pm["rollback_plan"] == pr["rollback_plan"], "rb")
    C.check("capability.quorum_excludes_researchers", quorum_ok(cp["approval"], f"promote-capability:{cp['digest']}",
                                                                pg["governance_keys"], pg["threshold"],
                                                                excluded=cp["researcher_pubs"]), "quorum")
    C.check("capability.no_researcher_signed", not {p for p, _ in cp["approval"]["signatures"]} &
            set(cp["researcher_pubs"]), "excluded")
    stages = [s for s, _ in cp["stages"]]
    C.check("capability.stages_in_order", stages == list(CAPABILITY_ORDER), stages)
    C.check("capability.derived_from_supported", ds["status"] in ("SUPPORTED", "VERIFIED") and
            pr["derived_from"] == [db["discovery_id"]], ds["status"])
    C.check("capability.proposer_is_researcher_excluded", pr["proposer"] in cp["researchers"], pr["proposer"])

    # ---- execution ----
    xe = ex["execution"]
    dec, e20 = xe["decision"], xe["e20_decision"]
    C.check("execution.digest", dig(D["exec"], dec) == xe["digest"], "digest")
    C.check("execution.e20_digest", dig(D["e20_exec"], e20) == xe["e20_digest"] == dec["e20_decision_digest"], "e20")
    C.check("execution.authorized_through_e8", dec["decision"] == "AUTHORIZED" and dec["commit"] == "E8" and
            xe["authority"] == "E8" and not dec["reasons"] and e20["commit"] == "E8" and e20["decision"] == "AUTHORIZED",
            "E21->E20->E19->E8")
    C.check("execution.within_promotion", dec["capability"] in pm["scope"] and dec["target"] in pm["targets"] and
            dec["agent"] in pm["operators"] and dec["capability_id"] == pm["capability_id"], "within")
    C.check("execution.same_action_at_e20", e20["member"] == dec["agent"] and e20["capability"] == dec["capability"] and
            e20["target"] == dec["target"] and e20["at"] == dec["at"], "same action")
    C.check("execution.e19_bound", bool(e20["e19_contract_digest"]) and bool(e20["e19_decision_digest"]), "e19")
    rf = ex["refused"]
    C.check("refused.digests", all(dig(D["exec"], v["decision"]) == v["digest"] for v in rf.values()), len(rf))
    C.check("refused.all_denied", all(v["decision"]["decision"] == "DENY" and v["decision"]["reasons"] and
                                      v["decision"]["commit"] == "NONE" for v in rf.values()), "deny")
    C.check("refused.target_escape", "LIMITED_DEPLOYMENT_TARGET_EXCEEDED" in rf["target_escape"]["decision"]["reasons"],
            "target")
    C.check("refused.scope_escalation", "CAPABILITY_SCOPE_EXCEEDED" in rf["scope_escalation"]["decision"]["reasons"],
            "scope")
    C.check("refused.operator_escape", "LIMITED_DEPLOYMENT_OPERATOR_EXCEEDED" in rf["operator_escape"]["decision"]
            ["reasons"], "operator")
    C.check("refused.discovery_is_not_a_basis", rf["discovery_as_basis"]["decision"]["claimed_basis_ignored"] and
            "NO_INSTITUTIONAL_AUTHORITY_FOR_CAPABILITY" in rf["discovery_as_basis"]["decision"]["reasons"], "basis")

    # ---- loophole, cascade ----
    lp = ex["loophole"]
    C.check("loophole.disclosure_signature", signed_ok(lp["disclosure"], D["disclosure"], lp["registry_pub"]), "ed25519")
    C.check("loophole.exploit_not_permitted", lp["disclosure"]["exploit_permitted"] is False and
            lp["disclosure"]["authority"] == "NONE", "disclose only")
    C.check("loophole.exploit_proposal_refused", "GOVERNANCE_WEAKNESS_CAN_ONLY_BE_DISCLOSED" in
            lp["exploit_proposal_refusal"], lp["exploit_proposal_refusal"])
    cs = ex["cascade"]
    C.check("cascade.digest", dig(D["revocation"], strip(cs["report"], "digest", "authority")) == cs["report"]["digest"],
            "digest")
    C.check("cascade.reaches_capability", cs["report"]["claims_invalidated"] and cs["report"]["dependents_invalidated"]
            and cs["report"]["capabilities_suspended"], "cascade")
    C.check("cascade.execution_denied_after", cs["execution_after"]["decision"] == "DENY" and "CAPABILITY_SUSPENDED" in
            cs["execution_after"]["reasons"], "denied")

    # ---- memory ----
    mem = ex["memory"]
    ent = mem["entries"]
    C.check("memory.chain_digests", [dig(D["memory"], e) for e in ent] == mem["chain"], len(ent))
    C.check("memory.chain_links", all(e["prev"] == (mem["chain"][i - 1] if i else "genesis") and e["seq"] == i
                                      for i, e in enumerate(ent)), "links")
    C.check("memory.failures_retained", any(e["kind"] == "failure" for e in ent) and any(
        e["kind"] == "failure" and "modify_policy" in json.dumps(e["payload"]) for e in ent), "failures")
    C.check("memory.refutations_retained", sum(1 for e in ent if e["kind"] == "failure" and "refuted" in
                                               json.dumps(e["payload"])) >= 2, "refutations")
    C.check("memory.no_private_reasoning", not any(forbidden_keys(e["payload"]) for e in ent), "no CoT")
    C.check("memory.no_authority_kinds", not any(e["kind"] in ("policy", "authority", "permission") for e in ent), "kinds")

    # ---- causal, counterfactual, information value, regression ----
    cz = ex["causal"]
    C.check("causal.digest", dig(D["causal"], strip(cz, "digest", "authority", "model_confidence_ignored")) ==
            cz["digest"], "digest")
    C.check("causal.level_matches_relation", (cz["relation"] == "CAUSES") == (cz["level"] in ("OBSERVED_INTERVENTION",
                                                                                               "VERIFIED_CAUSAL")),
            cz["level"])
    C.check("causal.observed_intervention_has_controlled_evidence", cz["level"] != "OBSERVED_INTERVENTION" or any(
        by_id[e]["body"]["method_class"] == "CONTROLLED_EXPERIMENT" and cz["cause"] in by_id[e]["body"]["intervention"]
        for e in cz["evidence"]), "intervention")
    cf = ex["counterfactual"]
    C.check("counterfactual.digest", dig(D["counterfactual"], strip(cf, "digest", "authority")) == cf["digest"], "digest")
    C.check("counterfactual.labels", cf["labels"] == ["HYPOTHETICAL", "SIMULATED", "UNEXECUTED"] and
            cf["executed"] is False and cf["authority"] == "NONE", "labels")
    iv = ex["information_value"]
    gains = {e: info_gain(iv["prior"], lk) for e, lk in iv["experiments"].items()}
    C.check("information_value.rederived", all(abs(r["expected_information_gain_bits"] - gains[r["experiment"]]) < 1e-9
                                               for r in iv["result"]["ranking"]), gains)
    C.check("information_value.ranked", [r["experiment"] for r in iv["result"]["ranking"]] ==
            sorted(gains, key=lambda e: (-gains[e], e)), "order")
    C.check("information_value.digest_and_not_permission", dig(D["info"], strip(iv["result"], "digest", "authority")) ==
            iv["result"]["digest"] and iv["result"]["value_is_permission"] is False, "not permission")
    rg = ex["regression"]
    deltas = {k: round(rg["after"][k] - rg["before"][k], 6) for k in rg["before"]}
    C.check("regression.deltas_rederived", rg["result"]["deltas"] == deltas, deltas)
    C.check("regression.any_dimension_regresses", rg["result"]["regressions"] == sorted(
        k for k, v in deltas.items() if v < -abs(rg["tolerance"])) and rg["result"]["single_score_used"] is False,
        rg["result"]["regressions"])
    C.check("regression.digest", dig(D["regression"], strip(rg["result"], "digest")) ==
            rg["result"]["digest"], "digest")

    # ---- competition, benchmarks, invention ----
    cm = ex["competition"]
    C.check("competition.commitments", all(h({"answer": cm["reveals"][t]["answer"], "salt": cm["salts"][t]}) ==
                                           cm["commits"][t] for t in cm["reveals"]), "commit-reveal")
    C.check("competition.contamination_excluded", not set(cm["report"]["contaminated"]) &
            set(cm["report"]["independent_tracks"]), cm["report"]["contaminated"])
    bm_ = ex["benchmarks"]
    C.check("benchmarks.digests", all(dig(D["benchmark"], strip(b, "digest")) == b["digest"] for b in bm_["benchmarks"]),
            "digests")
    C.check("benchmarks.train_test_disjoint", all(not set(b["train"]) & set(b["test"]) for b in bm_["benchmarks"]),
            "disjoint")
    rr = bm_["result"]
    C.check("benchmarks.result_digest_and_binding", dig(D["bench_result"], strip(rr, "digest", "authority")) ==
            rr["digest"] and rr["benchmark_digest"] in {b["digest"] for b in bm_["benchmarks"]} and
            rr["creates_authority"] is False, "binding")
    C.check("benchmarks.leakage_refused", "BENCHMARK_LEAKAGE_TEST_DATA_IN_TRAINING" in bm_["leakage_refusal"], "leak")
    inv_ = ex["invention"]
    C.check("invention.digests", all(dig(D["invention"], strip(x, "digest")) == x["digest"] for x in inv_), "digests")
    C.check("invention.states", [x["state"] for x in inv_] == ["CANDIDATE", "APPARENTLY_NOVEL",
                                                               "VERIFIED_AGAINST_CORPUS", "NOT_NOVEL"],
            [x["state"] for x in inv_])
    C.check("invention.corpus_scoped", inv_[2]["scope"] == "ONLY_AGAINST_THE_SUPPLIED_CORPUS" and inv_[2]
            ["corpus_version"], "scoped")

    # ---- self-evolution ----
    se = ex["self_evolution"]
    C.check("self_evolution.ok", se["ok"] is True, "ok")
    C.check("self_evolution.authority_not_widened", set(se["decision"]["authority_after"]) <=
            set(se["decision"]["authority_before"]) and set(se["decision"]["authority_after"]) <=
            set(se["strategy_a"]["authority"]), se["decision"]["authority_after"])
    C.check("self_evolution.regression_rolled_back", se["regressing_candidate"]["decision"] == "ROLLED_BACK", "rollback")
    C.check("self_evolution.escalation_refused", "RESEARCH_OPTIMIZATION_IS_NOT_AUTHORITY_ESCALATION" in
            se["escalation_attempt"]["reasons"], "refused")

    # ---- invariants, bench, demo, mutation, tamper, scale ----
    inv = load("INVARIANTS.json")
    C.check("invariants.count_at_least_150", inv["checked"] >= 150 and inv["checked"] == len(inv["checks"]),
            inv["checked"])
    C.check("invariants.all_hold", inv["all_hold"] and not inv["failed"] and all(c["holds"] for c in inv["checks"]),
            inv["failed"])
    C.check("invariants.ids_unique", len({c["id"] for c in inv["checks"]}) == len(inv["checks"]), "unique")
    C.check("invariants.constitutional_set_present", all(f"D{i}" in {c["id"] for c in inv["checks"]}
                                                         for i in range(1, 101)), "D1-D100")
    bm = load("ATTACK_MANIFEST.json")
    at = bm["attacks"]
    C.check("bench.distinct_at_least_250", bm["distinct_attacks"] >= 250 and bm["distinct_attacks"] ==
            bm["total"] - len(bm["alias_entries"]), bm["distinct_attacks"])
    C.check("bench.all_contained", bm["all_contained"] and bm["contained"] == bm["total"] == len(at) and
            all(a["contained"] and a["result"] == "CONTAINED" for a in at.values()), bm["contained"])
    C.check("bench.attack_digests", all(dig(D["adversarial"], strip(a, "digest")) == a["digest"] for a in at.values()),
            "digests")
    C.check("bench.no_duplicate_names", not bm["duplicate_names"] and set(bm["alias_entries"]) <= set(at), "names")
    cats = {}
    for a in at.values():
        cats[a["category"]] = cats.get(a["category"], 0) + 1
    C.check("bench.category_counts", cats == bm["categories"], "categories")
    C.check("bench.required_categories", all(c in cats for c in REQUIRED_CATEGORIES),
            [c for c in REQUIRED_CATEGORIES if c not in cats])
    C.check("bench.loophole_answer_no", bm["loophole_answer"] == "NO" and cats.get("governance_loophole", 0) >= 5 and
            all(a["contained"] for a in at.values() if a["category"] == "governance_loophole"), bm["loophole_answer"])
    C.check("bench.every_attack_names_an_invariant", all(re.fullmatch(r"D\d+", a["expected_invariant"]) and
                                                         a["defense"] for a in at.values()), "named")
    dr = load("DISCOVERY_RESULTS.json")["demonstration"]
    C.check("demo.required_steps", sorted(s["step"] for s in dr["steps"]) == sorted(REQUIRED_DEMO),
            [s["step"] for s in dr["steps"]])
    C.check("demo.all_steps_ok", dr["all_steps_ok"] and all(s["ok"] for s in dr["steps"]), "ok")
    C.check("demo.self_authorization_refused", dr["all_self_authorization_refused"] and len(
        dr["self_authorization_attempts"]) >= 10 and all(x["refused"] for x in dr["self_authorization_attempts"]),
        len(dr["self_authorization_attempts"]))
    st = {s["step"]: s for s in dr["steps"]}
    C.check("demo.hypothesis_rejected_and_kept", len(st["REJECT_HYPOTHESIS"]["detail"]["retired"]) >= 1 and
            st["REJECT_HYPOTHESIS"]["detail"]["kept"], "reject")
    C.check("demo.prediction_vs_outcome", st["PREDICTION_VS_OUTCOME"]["detail"]["abs_error"] <=
            st["PREDICTION_VS_OUTCOME"]["detail"]["tolerance"], st["PREDICTION_VS_OUTCOME"]["detail"])
    C.check("demo.simulation_labelled", st["RUN_SIMULATIONS"]["detail"]["label"] == "SIMULATION", "label")
    C.check("demo.execution_chain", dr["execution"].startswith("E21 -> E20 -> E19 -> E8"), dr["execution"])
    sev = load("SELF_EVOLUTION_RESULTS.json")["demonstration"]
    C.check("self_evolution.results_consistent", sev["ok"] and sev["decision"]["decision"] == "PROMOTED", "promoted")
    mu = load("MUTATION_RESULTS.json")
    C.check("mutation.all_caught", mu["all_mutants_caught"] is True and len(mu["rows"]) >= 6 and all(
        r["caught"] for r in mu["rows"][1:]), len(mu["rows"]))
    C.check("mutation.rows_consistent", all(r["bench_contained"] < mu["rows"][0]["bench_contained"] and
                                            r["invariants_holding"] < mu["rows"][0]["invariants_holding"]
                                            for r in mu["rows"][1:]), "rows")
    tp = load("TAMPER_RESULTS.json")
    C.check("tamper.recorded_or_pending", tp.get("pending") is True or (
        tp.get("baseline_intact") is True and tp.get("all_detected") is True and len(tp["mutations"]) >= 10 and
        all(m["detected"] for m in tp["mutations"].values())), {"pending": tp.get("pending"),
                                                                "all_detected": tp.get("all_detected")})
    sc = load("SCALE_RESULTS.json")
    C.check("scale.labelled_simulation", sc["label"] == "SIMULATION" and "not production-scale" in sc["note"],
            sc["label"])
    C.check("scale.sizes", max(r["agents"] for r in sc["agents"]) >= 10000 and
            max(r["hypotheses"] for r in sc["hypotheses"]) >= 10000, "sizes")
    C.check("scale.rows_marked_virtual", all(r["virtual"] for r in sc["agents"]) and
            all(r["simulated"] for r in sc["hypotheses"]), "virtual")
    C.check("scale.latencies_reported", all("p99_us" in r["evidence_admission"] for r in sc["agents"]), "p99")
    te = load("TEST_RESULTS.json")
    C.check("tests.ran_and_passed", not te.get("skipped") and te.get("failed", 1) == 0 and te.get("errors", 1) == 0
            and te.get("passed", 0) > 0 and te.get("exit_code") == 0, te.get("summary"))
    for name, need in (("HYPOTHESIS_RESULTS.json", "bench"), ("EXPERIMENT_RESULTS.json", "bench"),
                       ("REPLICATION_RESULTS.json", "bench"), ("KNOWLEDGE_RESULTS.json", "bench"),
                       ("CAUSAL_RESULTS.json", "bench"), ("CAPABILITY_RESULTS.json", "bench")):
        r = load(name)
        C.check(f"results.{name.split('.')[0].lower()}_consistent", r[need]["contained"] == r[need]["total"] > 0 and
                all(c["holds"] for c in r["invariants"]), r[need]["total"])

    # ---- claims, limitations, status ----
    cl = load("CAIN42_EVOLUTION21_CLAIMS.json")["claims"]
    ctext = json.dumps(cl).lower()
    C.check("claims.no_forbidden_words", not any(w in ctext for w in FORBIDDEN_WORDS),
            [w for w in FORBIDDEN_WORDS if w in ctext])
    C.check("claims.states_valid", all(c["state"] in CLAIM_STATES for c in cl), "states")
    by = {c["claim_id"]: c["state"] for c in cl}
    C.check("claims.third_party_not_performed", by.get("C42-E21-THIRD-PARTY") == "NOT_PERFORMED", "third party")
    C.check("claims.scale_is_simulated", by.get("C42-E21-SCALE") == "SIMULATED", "scale")
    C.check("claims.agi_not_implemented", by.get("C42-E21-AGI") == "NOT_IMPLEMENTED", "agi")
    C.check("claims.scientific_truth_not_implemented", by.get("C42-E21-SCIENTIFIC-TRUTH") == "NOT_IMPLEMENTED", "truth")
    C.check("claims.tested_claims_have_evidence", all(c["evidence"] and all(
        (root / f"{e}.json").exists() or e == "CLEAN_ROOM_VERIFIER" for e in c["evidence"])
        for c in cl if c["state"] in ("TESTED", "SIMULATED")), "evidence files")
    li = load("LIMITATIONS.json")["limitations"]
    C.check("limitations.classified", len(li) >= 6 and all(x["status"] in ("NOT_IMPLEMENTED", "UNKNOWN", "UNVERIFIED",
                                                                           "NOT_PERFORMED") for x in li), len(li))
    C.check("limitations.unknown_and_unverified_files", load("UNKNOWN.json")["items"] == [
        x for x in li if x["status"] == "UNKNOWN"] and load("UNVERIFIED.json")["items"] == [
        x for x in li if x["status"] in ("UNVERIFIED", "NOT_PERFORMED")], "split")
    sm = load("CAIN42_E21_EVIDENCE_BUNDLE.json")
    C.check("summary.counts_match", sm["invariants"]["checked"] == inv["checked"] and sm["attacks"]["total"] ==
            bm["total"] and sm["attacks"]["distinct"] == bm["distinct_attacks"] and sm["research_demonstration"]
            ["steps"] == len(dr["steps"]), "counts")
    gates = sm["completion_gates"]
    C.check("summary.status_gated", (sm["status"] == "COMPLETE") == all(v is True for v in gates.values()),
            sm["status"])
    C.check("summary.honest_states", sm["states"]["scientific_truth"] == "UNKNOWN" and
            sm["states"]["third_party_review"] == "NOT_PERFORMED" and sm["states"]["hosted_service"] ==
            "NOT_IMPLEMENTED" and sm["states"]["scale"] == "SIMULATED" and sm["states"]["agi"] == "NOT_IMPLEMENTED",
            "states")
    C.check("summary.loophole_answer", sm["attacks"]["loophole_answer"] == bm["loophole_answer"], "loophole")

    # ---- performance, provenance ----
    pf = load("PERFORMANCE.json")
    C.check("performance.conditions_honest", pf["conditions"]["concurrency"] == 1 and "not production-scale" in pf["note"],
            pf["note"])
    need = ("discovery_creation", "hypothesis_creation", "evidence_validation", "knowledge_graph_update",
            "causal_graph_update", "experiment_authorization", "replication_verification", "capability_promotion",
            "claim_invalidation", "knowledge_rollback", "research_agent_coordination")
    C.check("performance.operations_measured", all(k in pf["results"] and all(x in pf["results"][k] for x in
                                                                              ("p50_us", "p95_us", "p99_us",
                                                                               "throughput_per_s")) for k in need),
            [k for k in need if k not in pf["results"]])
    C.check("performance.hardware_reported", all(k in pf["conditions"] for k in ("cpu", "cpu_count", "python", "os",
                                                                                 "max_rss_kb", "dataset")), "hardware")
    pv = load("PROVENANCE.json")
    C.check("provenance.commit", bool(re.fullmatch(r"[0-9a-f]{40}", pv["commit"])), pv["commit"][:12])
    C.check("provenance.module_digests", all(re.fullmatch(r"[0-9a-f]{64}", v) for v in pv["modules"].values()) and
            "discovery_fabric" in pv["modules"], "modules")

    # ---- clean room ----
    src = (root / "verify_e21.py.txt").read_text()
    mods = re.findall(r"^\s*(?:from|import)\s+([A-Za-z_][\w.]*)", src, re.M)
    C.check("clean_room.imports_no_cain", mods and not any(m.split(".")[0] in ("cain", "cain45", "platform_gateway")
                                                           for m in mods), sorted(set(mods)))
    C.check("clean_room.sha_matches", load("CLEAN_ROOM_VERIFIER.json")["sha256"] ==
            hashlib.sha256((root / "verify_e21.py.txt").read_bytes()).hexdigest(), "sha")

    out = {"schema": "cain42.e21.verifier.v1", "result": "INTACT" if not C.problems else "FAILED",
           "checks": len(C.detail), "passed": len(C.detail) - len(C.problems), "problems": C.problems,
           "detail": C.detail}
    print(json.dumps(out))
    return 0 if not C.problems else 1


if __name__ == "__main__":
    try:
        raise SystemExit(main(Path(sys.argv[1])))
    except (KeyError, TypeError, ValueError, StopIteration, AttributeError, IndexError, json.JSONDecodeError,
            FileNotFoundError) as e:
        print(json.dumps({"schema": "cain42.e21.verifier.v1", "result": "FAILED", "checks": 0, "passed": 0,
                          "problems": [f"malformed bundle: {type(e).__name__}: {e}"]}))
        raise SystemExit(1)
