"""REC-31 (A1) Phase 1: assert the grounding map's cited symbols exist in the live tree.
Grep-based, zero spend. Guards against the stale-citation failure mode."""
from pathlib import Path

REPO = Path(__file__).resolve().parents[2]  # recoil/tests → repo root

CITATIONS = [
    ("recoil/core/ref_resolver.py", "def resolve_entity_refs("),
    ("recoil/core/ref_resolver.py", 'parsed["subject"] != slug.replace("_", "-")'),
    ("recoil/core/ref_resolver.py", "def slugify_asset_id("),
    ("recoil/pipeline/_lib/taxonomy.py", "def slugify_asset_id("),  # cycle-free source ref_stem imports from
    ("recoil/core/paths.py", "def resolve_ref("),
    ("recoil/core/paths.py", "def _candidate_stems("),
    ("recoil/pipeline/_lib/taxonomy.py", "ASSET_FILENAME_RE = re.compile("),
    ("recoil/pipeline/_lib/taxonomy.py", "VALID_TYPES = frozenset("),
    ("recoil/workspace/sidecar.py", "def promote_to_canonical("),
    ("recoil/pipeline/_lib/dispatch_payload.py", "def _collect_reference_images("),
    ("recoil/pipeline/_lib/dispatch_payload.py", "def _assert_ref_gate("),
    ("recoil/pipeline/_lib/dispatch_payload.py", "def _build_audit_payload("),
    ("recoil/pipeline/_lib/dispatch_payload.py", "def build_unified_payload("),
    ("recoil/pipeline/_lib/dispatch_payload.py", "def _collect_sheet_refs("),
    ("recoil/pipeline/tools/audit_dispatch.py", '"--self-check"'),
    ("recoil/pipeline/tools/audit_dispatch.py", "def _prepare_self_check_project("),
]

def test_all_rec31_citations_present():
    missing = []
    for rel, needle in CITATIONS:
        text = (REPO / rel).read_text(encoding="utf-8")
        if needle not in text:
            missing.append(f"{rel} :: {needle!r}")
    assert not missing, "Stale citations (re-ground before building):\n" + "\n".join(missing)
