"""provenance.py — the faithfulness audit + geometry->section trace.

A document projected from geometry is only worth anything if every claim traces
back. This module walks the DocumentIR and proves the discipline held:

  * ZERO ungrounded claims (every fact/interpretation has a real node id),
  * every emitted sentence maps to a geometry edge (or is a marked connective),
  * SACRED polarity survived (negations are reported, never silently dropped),
  * COHERE introduced no new geometry (connectives carry no claim).

It emits both a machine verdict and a human-readable geometry->section table.
"""
from __future__ import annotations

from document_ir import DocumentIR


def audit(doc: DocumentIR) -> dict:
    provs = doc.all_provenance()
    facts = [p for p in provs if p.kind in ("fact", "interpretation")]
    connectives = [p for p in provs if p.kind == "connective"]
    ungrounded = [p for p in facts if not p.node_id]
    negations = [p for p in facts if p.polarity == "neg"]
    node_ids = sorted({p.node_id for p in facts if p.node_id})
    return {
        "claims": len(facts),
        "connectives": len(connectives),
        "ungrounded_claims": len(ungrounded),
        "negations_preserved": len(negations),
        "distinct_source_nodes": len(node_ids),
        "faithful": len(ungrounded) == 0,
        "source_nodes": node_ids,
    }


def trace_table(doc: DocumentIR) -> str:
    """Human-readable geometry -> section -> claim provenance table."""
    lines = ["# Provenance — every claim traces geometry", ""]
    lines.append(f"**Document:** {doc.title}")
    a = audit(doc)
    lines.append(f"**Claims:** {a['claims']}  ·  **Ungrounded:** "
                 f"{a['ungrounded_claims']}  ·  **Negations preserved:** "
                 f"{a['negations_preserved']}  ·  **Source nodes:** "
                 f"{a['distinct_source_nodes']}  ·  **Faithful:** "
                 f"{'YES' if a['faithful'] else 'NO'}")
    lines.append("")
    for si, sec in enumerate(doc.sections, 1):
        lines.append(f"## {si}. {sec.heading}")
        lines.append(f"_seed nodes: {', '.join(i[:8] for i in sec.seed_ids)}_")
        lines.append("")
        lines.append("| # | realized claim | traces geometry edge |")
        lines.append("|---|----------------|----------------------|")
        n = 0
        for block in sec.blocks:
            for sent, prov in zip(block.sentences, block.provenance):
                if prov.kind == "connective":
                    continue
                n += 1
                edge = prov.trace().replace("|", "\\|")
                s = sent.replace("|", "\\|")
                lines.append(f"| {n} | {s} | {edge} |")
        lines.append("")
    return "\n".join(lines) + "\n"
