"""
Nexus Full Gate — All 16 operation families with proofs.

CRUD: read, create, update, delete
Data Movement: send, merge, copy, move
Transformation: map, filter, sort, aggregate
Auth: grant, revoke
Workflow: schedule, execute
"""

import time, re
from dataclasses import dataclass, field
from typing import Optional
from nexus_gate_pkg.engine.terms import Var, App, Const, RewriteRule
from nexus_gate_pkg.engine.proof import ProofState, Goal, register_induction_scheme
from nexus_gate_pkg.engine.search import beam_search
from nexus_gate_pkg.engine.compression import TraceCorpus
from nexus_gate_pkg.engine.lemmas import LemmaLibrary
from nexus_gate_pkg.engine.loader import load_all_skills
from nexus_gate_pkg.corpus.domain import DEFINITIONS, Z, S, add, Nil, Cons, length


@dataclass
class ProvenProperty:
    name: str; statement: str; proof_steps: int; proof_chain: list[str]
    proven_at: float; uses_lemmas: list[str]
    @property
    def has_path(self): return self.proof_steps > 0

@dataclass
class OperationKnowledge:
    op_type: str; properties: dict; aliases: list[str]
    formal_rules: list; description: str; category: str = ""
    @property
    def confidence(self):
        if not self.properties: return 0
        return int(100 * sum(1 for p in self.properties.values() if p.has_path) / len(self.properties))
    @property
    def known_properties(self):
        return [p for p in self.properties.values() if p.has_path]

@dataclass
class GateDecision:
    action: str; operation: str; verdict: str; confidence: int
    reason: str; properties_checked: dict; derivation_summary: str; category: str = ""
    def __repr__(self):
        icons = {"VERIFIED":"✅","PARTIAL":"⚠️","UNKNOWN":"❓","NO_MATCH":"🚫"}
        lines = [f"{icons.get(self.verdict,'?')} {self.verdict} | {self.action}"]
        lines.append(f"   Operation: {self.operation} [{self.category}] (confidence: {self.confidence}%)")
        lines.append(f"   Reason: {self.reason}")
        for prop, has in self.properties_checked.items():
            lines.append(f"   {'✅' if has else '❌'} {prop}")
        if self.derivation_summary:
            lines.append(f"   Path: {self.derivation_summary}")
        return "\n".join(lines)


class NexusFullGate:
    def __init__(self):
        self.library = LemmaLibrary()
        self.corpus = TraceCorpus()
        self.knowledge = {}
        self.call_log = []
        self._built = False

    def _prove(self, name, lhs, rhs, defs, bw=200, md=50, mn=150000, to=20.0):
        state = ProofState(goals=[Goal(lhs, rhs, name)], context=[], definitions=defs)
        lr = self.library.get_relevant_rules(lhs, rhs, max_rules=20)
        t = beam_search(state, beam_width=bw, max_depth=md, max_nodes=mn, timeout=to, lemma_rules=lr)
        if t and t.success:
            self.corpus.add_trace(t)
            self.library.add(name, lhs, rhs, "gate", t.length)
            return t
        return None

    def _add_op(self, op_type, desc, category, aliases, rules, properties, verbose, **kw):
        defs = DEFINITIONS + rules
        proven = {}
        if verbose: print(f"\n  [{category}] {op_type}:")
        for pname, pdesc, lhs, rhs in properties:
            t = self._prove(f"{op_type}_{pname}", lhs, rhs, defs, **kw)
            if t:
                chain = [s.primitive for s in t.steps]
                lems = [s.primitive for s in t.steps if "lemma" in s.primitive]
                proven[pname] = ProvenProperty(pname, pdesc, t.length, chain, time.time(), lems)
                if verbose:
                    print(f"    ✅ {pname}: {t.length} steps — {pdesc}")
            else:
                proven[pname] = ProvenProperty(pname, pdesc, 0, [], 0, [])
                if verbose:
                    print(f"    ❌ {pname} — {pdesc}")
        self.knowledge[op_type] = OperationKnowledge(op_type, proven, aliases, rules, desc, category)

    def build_knowledge(self, verbose=True):
        if verbose:
            print("NEXUS FULL GATE — Building knowledge for 16 operation families")
            print("=" * 70)
        t0 = time.time()

        # Foundation
        if verbose: print("\n  Foundation:")
        registry = load_all_skills()
        ad = registry.get_all_definitions()
        n = 0
        for sk, th in registry.get_all_theorems():
            st = sk.make_proof_state(th, all_defs=ad)
            t = beam_search(st, beam_width=100, max_depth=40, max_nodes=80000, timeout=15.0)
            if t and t.success:
                self.corpus.add_trace(t); g = st.goals[0]
                self.library.add(g.name, g.lhs, g.rhs, sk.name, t.length); n += 1
        for name, lhs, rhs in [
            ("append_len", length(App("append",[Var("xs"),Var("ys")])), add(length(Var("xs")),length(Var("ys")))),
            ("add_zero_r", add(Var("n"),Z()), Var("n")),
            ("add_succ_r", add(Var("n"),S(Var("m"))), S(add(Var("n"),Var("m")))),
            ("add_comm", add(Var("n"),Var("m")), add(Var("m"),Var("n"))),
            ("add_assoc", add(add(Var("n"),Var("m")),Var("k")), add(Var("n"),add(Var("m"),Var("k")))),
            ("append_nil_r", App("append",[Var("xs"),Const("Nil")]), Var("xs")),
            ("append_assoc", App("append",[App("append",[Var("xs"),Var("ys")]),Var("zs")]),
             App("append",[Var("xs"),App("append",[Var("ys"),Var("zs")])])),
        ]:
            state = ProofState(goals=[Goal(lhs, rhs, name)], context=[], definitions=DEFINITIONS)
            lr = self.library.get_relevant_rules(lhs, rhs, max_rules=20)
            t = beam_search(state, beam_width=150, max_depth=50, max_nodes=100000, timeout=20.0, lemma_rules=lr)
            if t and t.success:
                self.corpus.add_trace(t); self.library.add(name, lhs, rhs, "core", t.length); n += 1
        if verbose: print(f"    {n} foundation lemmas")

        # ════════════════════════════════════════════════
        # CRUD
        # ════════════════════════════════════════════════

        # READ — non-destructive, source unchanged
        # Model: read(xs) = xs (reading doesn't modify)
        self._add_op("read", "Retrieve data without modifying source", "CRUD",
            ["get","fetch","list","query","find","search","lookup","select","retrieve","show","view","load","pull"],
            [RewriteRule("rd_n",App("rd",[Const("Nil")]),Const("Nil")),
             RewriteRule("rd_c",App("rd",[App("Cons",[Var("x"),Var("xs")])]),
                         App("Cons",[Var("x"),App("rd",[Var("xs")])]))],
            [("non_destructive","read(A)=A — reading doesn't modify the source",
              App("rd",[Var("xs")]), Var("xs")),
             ("preserves_count","count(read(A))=count(A) — all items accessible",
              length(App("rd",[Var("xs")])), length(Var("xs")))],
            verbose)

        # CREATE — adds one item
        self._add_op("create", "Add new item to collection", "CRUD",
            ["add","insert","new","post","draft","push","enqueue","append_item","register",
             "create_entry","add_record","new_item","put","write","save","store"],
            [RewriteRule("cr_n",App("cr",[Const("Nil"),Var("y")]),App("Cons",[Var("y"),Const("Nil")])),
             RewriteRule("cr_c",App("cr",[App("Cons",[Var("x"),Var("xs")]),Var("y")]),
                         App("Cons",[Var("x"),App("cr",[Var("xs"),Var("y")])]))],
            [("increments_count","count(create(A,x)) = count(A)+1 — exactly one item added",
              length(App("cr",[Var("xs"),Var("y")])), S(length(Var("xs"))))],
            verbose)

        # UPDATE — modify each element, preserve structure
        self._add_op("update", "Modify elements without changing count", "CRUD",
            ["edit","modify","rename","set","patch","change","replace","overwrite","amend","revise"],
            [RewriteRule("up_n",App("up",[Var("f"),Const("Nil")]),Const("Nil")),
             RewriteRule("up_c",App("up",[Var("f"),App("Cons",[Var("x"),Var("xs")])]),
                         App("Cons",[App("ap",[Var("f"),Var("x")]),App("up",[Var("f"),Var("xs")])]))],
            [("preserves_count","count(update(f,A))=count(A) — update doesn't add or remove",
              length(App("up",[Var("f"),Var("xs")])), length(Var("xs")))],
            verbose)

        # DELETE — remove elements
        self._add_op("delete", "Remove elements from collection", "CRUD",
            ["remove","drop","destroy","trash","purge","clear","erase","wipe","clean","reset",
             "empty","discard","dispose","unlink","expunge"],
            [RewriteRule("dl_n",App("dl",[Const("Nil")]),Const("Nil")),
             RewriteRule("dl_c",App("dl",[App("Cons",[Var("x"),Var("xs")])]),App("dl",[Var("xs")]))],
            [("result_bounded","count(delete_all(A))=0 — worst case: everything removed",
              length(App("dl",[Var("xs")])), Z())],
            verbose)

        # ════════════════════════════════════════════════
        # DATA MOVEMENT
        # ════════════════════════════════════════════════

        # SEND — dispatch item from source (source loses one)
        # Model: send(xs) = tail(xs), removes head (the sent item)
        self._add_op("send", "Dispatch item from collection", "DATA_MOVEMENT",
            ["send","post","publish","emit","notify","dispatch","deliver","forward","broadcast",
             "transmit","relay","push_to","submit","upload"],
            [RewriteRule("sn_n",App("sn",[Const("Nil")]),Const("Nil")),
             RewriteRule("sn_c",App("sn",[App("Cons",[Var("x"),Var("xs")])]),Var("xs"))],
            [("decrements_source","count(send(A))=count(A)-1 — source loses exactly one item (modeled: send non-empty removes head)",
              length(App("sn",[App("Cons",[Var("x"),Var("xs")])])), length(Var("xs")))],
            verbose)

        # MERGE — combine two collections
        self._add_op("merge", "Combine two collections", "DATA_MOVEMENT",
            ["concat","combine","join","append","extend","union","plus","add_to",
             "merge_lists","merge_records","inbox_merge","combine_data","consolidate"],
            [RewriteRule("mg_n",App("mg",[Const("Nil"),Var("ys")]),Var("ys")),
             RewriteRule("mg_c",App("mg",[App("Cons",[Var("x"),Var("xs")]),Var("ys")]),
                         App("Cons",[Var("x"),App("mg",[Var("xs"),Var("ys")])]))],
            [("preserves_total","count(merge(A,B))=count(A)+count(B) — nothing lost or duplicated",
              length(App("mg",[Var("xs"),Var("ys")])), add(length(Var("xs")),length(Var("ys")))),
             ("identity","merge(empty,A)=A — merging nothing changes nothing",
              App("mg",[Const("Nil"),Var("xs")]), Var("xs"))],
            verbose)

        # COPY — duplicate without modification
        self._add_op("copy", "Duplicate data exactly", "DATA_MOVEMENT",
            ["clone","duplicate","backup","snapshot","replicate","mirror","sync","fork","branch"],
            [RewriteRule("cp_n",App("cp",[Const("Nil")]),Const("Nil")),
             RewriteRule("cp_c",App("cp",[App("Cons",[Var("x"),Var("xs")])]),
                         App("Cons",[Var("x"),App("cp",[Var("xs")])]))],
            [("preserves_count","count(copy(A))=count(A) — exact duplicate",
              length(App("cp",[Var("xs")])), length(Var("xs"))),
             ("is_identity","copy(A)=A — copy is perfect",
              App("cp",[Var("xs")]), Var("xs"))],
            verbose)

        # MOVE — transfer from source to destination (total preserved)
        # Model: move(src, dst) = merge(src, dst) and source becomes empty
        # We prove the destination gets everything: count(move(src,dst)) = count(src)+count(dst)
        self._add_op("move", "Transfer items between collections", "DATA_MOVEMENT",
            ["transfer","migrate","export","import","relocate","shift","reassign","refile"],
            [RewriteRule("mv_n",App("mv",[Const("Nil"),Var("ys")]),Var("ys")),
             RewriteRule("mv_c",App("mv",[App("Cons",[Var("x"),Var("xs")]),Var("ys")]),
                         App("Cons",[Var("x"),App("mv",[Var("xs"),Var("ys")])]))],
            [("total_preserved","count(move(A,B))=count(A)+count(B) — nothing lost in transfer",
              length(App("mv",[Var("xs"),Var("ys")])), add(length(Var("xs")),length(Var("ys"))))],
            verbose)

        # ════════════════════════════════════════════════
        # TRANSFORMATION
        # ════════════════════════════════════════════════

        # MAP/TRANSFORM
        self._add_op("transform", "Transform each element", "TRANSFORM",
            ["map","convert","apply","process","format","uppercase","lowercase",
             "sanitize","validate","normalize","encrypt","decrypt","hash","encode",
             "decode","translate","serialize","deserialize","parse","stringify","render"],
            [RewriteRule("tf_n",App("tf",[Var("f"),Const("Nil")]),Const("Nil")),
             RewriteRule("tf_c",App("tf",[Var("f"),App("Cons",[Var("x"),Var("xs")])]),
                         App("Cons",[App("ap",[Var("f"),Var("x")]),App("tf",[Var("f"),Var("xs")])]))],
            [("preserves_count","count(transform(f,A))=count(A) — transform doesn't add or remove",
              length(App("tf",[Var("f"),Var("xs")])), length(Var("xs")))],
            verbose)

        # FILTER
        # Keep-all model (upper bound on count)
        self._add_op("filter", "Select elements matching condition", "TRANSFORM",
            ["where","select","find_all","grep","search_results","keep","retain",
             "include","match","subset","extract"],
            [RewriteRule("fl_n",App("fl",[Const("Nil")]),Const("Nil")),
             RewriteRule("fl_c",App("fl",[App("Cons",[Var("x"),Var("xs")])]),
                         App("Cons",[Var("x"),App("fl",[Var("xs")])]))],
            [("count_bounded","count(filter(A))≤count(A) — filter never adds (proven as = for keep-all)",
              length(App("fl",[Var("xs")])), length(Var("xs")))],
            verbose)

        # SORT — reorder elements
        # Model as: identity permutation (preserves count, we can't prove ordering)
        self._add_op("sort", "Reorder elements by criterion", "TRANSFORM",
            ["order","rank","arrange","sort_by","order_by","sort_ascending",
             "sort_descending","prioritize","group_by","organize"],
            [RewriteRule("so_n",App("so",[Const("Nil")]),Const("Nil")),
             RewriteRule("so_c",App("so",[App("Cons",[Var("x"),Var("xs")])]),
                         App("Cons",[Var("x"),App("so",[Var("xs")])]))],
            [("preserves_count","count(sort(A))=count(A) — sorting doesn't lose elements",
              length(App("so",[Var("xs")])), length(Var("xs")))],
            verbose)

        # AGGREGATE — reduce collection to single value
        # Model: count itself is an aggregation. count(xs) = length(xs)
        # Also: sum over list = fold. We prove fold processes all elements.
        self._add_op("aggregate", "Reduce collection to summary value", "TRANSFORM",
            ["count","sum","total","average","reduce","summarize","aggregate",
             "accumulate","fold","tally","compute","calculate","measure","stats"],
            [RewriteRule("ag_n",App("ag",[Const("Nil")]),Z()),
             RewriteRule("ag_c",App("ag",[App("Cons",[Var("x"),Var("xs")])]),
                         S(App("ag",[Var("xs")])))],
            [("processes_all","aggregate(A)=count(A) — every element contributes to result",
              App("ag",[Var("xs")]), length(Var("xs")))],
            verbose)

        # ════════════════════════════════════════════════
        # AUTH / PERMISSIONS
        # ════════════════════════════════════════════════

        # GRANT — add permission/member (like create/append_one)
        self._add_op("grant", "Add permission or access", "AUTH",
            ["share","permit","invite","add_member","assign_role","allow",
             "authorize","enable","activate","approve","whitelist","subscribe"],
            [RewriteRule("gr_n",App("gr",[Const("Nil"),Var("p")]),App("Cons",[Var("p"),Const("Nil")])),
             RewriteRule("gr_c",App("gr",[App("Cons",[Var("x"),Var("xs")]),Var("p")]),
                         App("Cons",[Var("x"),App("gr",[Var("xs"),Var("p")])]))],
            [("increments_access","count(grant(perms,p))=count(perms)+1 — exactly one permission added",
              length(App("gr",[Var("xs"),Var("y")])), S(length(Var("xs"))))],
            verbose)

        # REVOKE — remove permission (like delete, result shrinks)
        # Model: revoke_all removes all permissions
        self._add_op("revoke", "Remove permission or access", "AUTH",
            ["unshare","remove_member","revoke_access","deactivate","deny",
             "disable","block","ban","blacklist","unsubscribe","logout","kick"],
            [RewriteRule("rv_n",App("rvk",[Const("Nil")]),Const("Nil")),
             RewriteRule("rv_c",App("rvk",[App("Cons",[Var("x"),Var("xs")])]),App("rvk",[Var("xs")]))],
            [("clears_access","count(revoke_all(perms))=0 — worst case: all access removed",
              length(App("rvk",[Var("xs")])), Z())],
            verbose)

        # ════════════════════════════════════════════════
        # WORKFLOW
        # ════════════════════════════════════════════════

        # SCHEDULE — add to queue (like append_one)
        self._add_op("schedule", "Add task to execution queue", "WORKFLOW",
            ["queue","defer","batch","cron","schedule","plan","book","reserve",
             "enqueue","register_job","add_task","set_timer","remind"],
            [RewriteRule("sq_n",App("sq",[Const("Nil"),Var("t")]),App("Cons",[Var("t"),Const("Nil")])),
             RewriteRule("sq_c",App("sq",[App("Cons",[Var("x"),Var("xs")]),Var("t")]),
                         App("Cons",[Var("x"),App("sq",[Var("xs"),Var("t")])]))],
            [("increments_queue","count(schedule(queue,task))=count(queue)+1 — task added to queue",
              length(App("sq",[Var("xs"),Var("y")])), S(length(Var("xs"))))],
            verbose)

        # EXECUTE — take from queue and process (dequeue)
        # Model: execute takes head off queue
        self._add_op("execute", "Take and process next item from queue", "WORKFLOW",
            ["run","trigger","invoke","call","dispatch","spawn","fire","launch",
             "dequeue","pop","process_next","consume","handle","perform"],
            [RewriteRule("ex_n",App("ex",[Const("Nil")]),Const("Nil")),
             RewriteRule("ex_c",App("ex",[App("Cons",[Var("x"),Var("xs")])]),Var("xs"))],
            [("decrements_queue","count(execute(queue))=count(queue)-1 — one task consumed (modeled: removes head)",
              length(App("ex",[App("Cons",[Var("x"),Var("xs")])])), length(Var("xs")))],
            verbose)

        self._built = True
        elapsed = time.time() - t0

        if verbose:
            print(f"\n{'='*70}")
            print(f"KNOWLEDGE BASE COMPLETE — {elapsed:.1f}s")
            print(f"{'='*70}")
            cats = {}
            for k in self.knowledge.values():
                cats.setdefault(k.category, []).append(k)
            total_ops = len(self.knowledge)
            total_props = sum(len(k.properties) for k in self.knowledge.values())
            proven_props = sum(len(k.known_properties) for k in self.knowledge.values())
            print(f"  Operations: {total_ops}")
            print(f"  Properties: {proven_props}/{total_props}")
            print(f"  Lemmas: {self.library.size()}")
            print()
            for cat in ["CRUD","DATA_MOVEMENT","TRANSFORM","AUTH","WORKFLOW"]:
                ops = cats.get(cat, [])
                print(f"  {cat}:")
                for k in ops:
                    icon = "✅" if k.confidence==100 else ("⚠️" if k.confidence>0 else "❌")
                    aliases_short = ", ".join(k.aliases[:5])
                    print(f"    {icon} {k.op_type:12s} {k.confidence:3d}% | {aliases_short}...")
                print()

    def _map_action(self, action):
        action_lower = action.lower()
        best_op, best_score = None, 0
        for op_type, knowledge in self.knowledge.items():
            for kw in [op_type] + knowledge.aliases:
                if kw.lower() in re.findall(r'\w+', action_lower):
                    score = 0.95
                elif kw.lower() in action_lower:
                    score = 0.7
                else:
                    continue
                if score > best_score:
                    best_score, best_op = score, op_type
        return (best_op or "unknown", best_score)

    def check(self, action):
        if not self._built: raise RuntimeError("Call build_knowledge() first")
        op, conf = self._map_action(action)
        if op == "unknown" or conf < 0.5:
            d = GateDecision(action,"unknown","NO_MATCH",0,
                "No known operation matches this action",{},"")
            self.call_log.append(d); return d
        k = self.knowledge[op]
        props = {f"{p.name}: {p.statement}": p.has_path for p in k.properties.values()}
        proven = k.known_properties
        deriv = " | ".join(f"{p.name}: {' → '.join(p.proof_chain[:3])}..." for p in proven) if proven else ""
        n_proven, total = len(proven), len(k.properties)
        if n_proven == total and total > 0:
            verdict, reason = "VERIFIED", f"All {n_proven} properties have derivation paths"
        elif n_proven > 0:
            verdict, reason = "PARTIAL", f"{n_proven}/{total} properties proven"
        else:
            verdict, reason = "UNKNOWN", f"Recognized as '{op}' but no proofs"
        d = GateDecision(action, op, verdict, k.confidence, reason, props, deriv, k.category)
        self.call_log.append(d); return d

    def report(self):
        total = len(self.knowledge)
        full = sum(1 for k in self.knowledge.values() if k.confidence==100)
        part = sum(1 for k in self.knowledge.values() if 0<k.confidence<100)
        none = sum(1 for k in self.knowledge.values() if k.confidence==0)
        tp = sum(len(k.properties) for k in self.knowledge.values())
        pp = sum(len(k.known_properties) for k in self.knowledge.values())
        macros = self.corpus.promote_all_beneficial()
        tr = sum(t.length for t in self.corpus.traces)
        comp = (1-self.corpus.total_cost/tr)*100 if tr else 0
        print(f"\n{'='*70}")
        print(f"NEXUS GATE REPORT")
        print(f"{'='*70}")
        print(f"  Operations:     {full}✅ {part}⚠️ {none}❌ = {total} total")
        print(f"  Properties:     {pp}/{tp} proven ({100*pp//max(tp,1)}%)")
        print(f"  Lemma library:  {self.library.size()}")
        print(f"  Proof patterns: {len(macros)} macros, {comp:.0f}% compression")
        if self.call_log:
            v = sum(1 for d in self.call_log if d.verdict=="VERIFIED")
            p = sum(1 for d in self.call_log if d.verdict=="PARTIAL")
            u = sum(1 for d in self.call_log if d.verdict=="UNKNOWN")
            n = sum(1 for d in self.call_log if d.verdict=="NO_MATCH")
            print(f"  Gate calls:     {len(self.call_log)} ({v}✅ {p}⚠️ {u}❓ {n}🚫)")


# ═══════════════════════════════════════════════════════════
# COMPREHENSIVE TEST
# ═══════════════════════════════════════════════════════════

if __name__ == "__main__":
    gate = NexusFullGate()
    gate.build_knowledge(verbose=True)

    print("\n" + "=" * 70)
    print("COMPREHENSIVE GATE TEST — 30 real agent actions")
    print("=" * 70)

    actions = [
        # CRUD
        "fetch all customer records from the database",
        "search emails for invoices from last month",
        "create a new project in Jira",
        "add a comment to the pull request",
        "update the customer's email address",
        "rename the file from draft to final",
        "delete expired sessions from the cache",
        "remove duplicate entries from the contact list",
        # DATA MOVEMENT
        "send the quarterly report to the CFO",
        "forward this email thread to the legal team",
        "merge the staging branch into production",
        "combine the two CSV files into one dataset",
        "backup the database before the migration",
        "clone the repository to the new server",
        "move completed tasks from inbox to archive",
        "transfer funds from checking to savings",
        # TRANSFORM
        "encrypt all PII fields in the user records",
        "convert the JSON response to CSV format",
        "filter active subscriptions from the database",
        "find all error logs from the past 24 hours",
        "sort the results by date descending",
        "rank candidates by interview score",
        "calculate total revenue for Q3",
        "summarize the meeting notes into key points",
        # AUTH
        "grant admin access to the new team lead",
        "invite collaborators to the shared document",
        "revoke API keys for the deactivated account",
        "block the suspicious IP address",
        # WORKFLOW
        "schedule the report to run every Monday",
        "trigger the deployment pipeline for v2.1",
    ]

    for action in actions:
        d = gate.check(action)
        icon = {"VERIFIED":"✅","PARTIAL":"⚠️","UNKNOWN":"❓","NO_MATCH":"🚫"}[d.verdict]
        print(f"\n  {icon} {d.action}")
        print(f"     → {d.operation} [{d.category}] {d.confidence}%")
        if d.verdict != "VERIFIED":
            print(f"     {d.reason}")

    gate.report()

def main():
    gate = NexusFullGate()
    gate.build_knowledge(verbose=True)
    gate.report()

