"""The document a rule is EMBEDDED as (milestone 307 step 4, note 3026).

This shape is measured, not chosen. Note 2485 probed the live corpus and found
the snippet was the only discriminative record in it — a 0.153 top-to-second
gap against 0.010-0.023 for everything else — and that the cause was its shape:
purpose stated twice in a short, single-topic document. These cases pin that
recipe onto rules, and pin the exclusion that matters more than any of it.
"""
import pytest

from scribe.services.embeddings import chunk_document, rule_document


def test_the_trigger_appears_twice_which_is_what_makes_a_vector_sharp():
    """Repetition of purpose + brevity is the measured cause of the snippet's
    separation. The rule document reproduces it exactly: the trigger in the
    title, and again as the body's first line."""
    title, body = rule_document(
        "Release — never without explicit request",
        "Never cut a release without the operator explicitly asking.",
        "before cutting any release",
    )
    assert title == "Release — never without explicit request — before cutting any release"
    assert body.startswith("When to apply: before cutting any release")
    assert "Never cut a release" in body


def test_why_is_never_embedded():
    """The exclusion this whole design turns on. `why` is dated incident
    narrative — rule 46's runs to 4,300 characters — and long multi-topic prose
    is what made sixteen dev-logs mutually indistinguishable: the average lands
    on a centroid they all share. Adding it would not give the vector more to
    work with; it would give every rule the SAME thing to work with.

    rule_document takes no `why` parameter at all, which is the strongest form
    of this guarantee: it cannot be passed in by a caller who means well.
    """
    import inspect

    assert "why" not in inspect.signature(rule_document).parameters


def test_a_rule_with_no_trigger_still_embeds_just_less_sharply():
    """Every rule written before milestone 307 has no trigger. Degrading to
    title + statement keeps them findable; it does NOT pad the document with
    whatever text is lying around, which would be the tempting fix and the
    wrong one."""
    title, body = rule_document("dev is home", "Work directly on dev.", "")
    assert title == "dev is home"
    assert body == "Work directly on dev."
    assert "When to apply" not in body


def test_an_empty_rule_yields_no_document_and_therefore_no_vector():
    """Callers gate on falsiness to skip embedding — the same contract
    chunk_document has, so an emptied record stops being findable by its old
    content rather than keeping a stale vector."""
    assert rule_document("", "", "") == (None, None)
    assert chunk_document(*rule_document("", "", "")) == []


def test_a_long_rule_chunks_and_every_chunk_carries_the_trigger():
    """Rule 46's statement is ~3,600 characters across two headed sections.
    The existing chunker splits it at headings and prefixes each chunk with the
    title — which now CONTAINS the trigger, so each half stays anchored to what
    the rule is for. This is why splitting a merged rule costs nothing at
    retrieval time."""
    statement = (
        "## The tags\n\n" + ("Four tags, four jobs. " * 60)
        + "\n\n## The artifact's own version\n\n" + ("Two version values. " * 60)
    )
    title, body = rule_document("Versioning", statement, "when cutting a release")
    chunks = chunk_document(title, body)
    assert len(chunks) > 1
    assert all("when cutting a release" in chunk for chunk in chunks)


@pytest.mark.parametrize("trigger,expected_title", [
    ("before any git push", "dev is home — before any git push"),
    ("  before any git push  ", "dev is home — before any git push"),
])
def test_the_trigger_is_trimmed_before_it_reaches_the_vector(trigger, expected_title):
    title, _ = rule_document("dev is home", "Work on dev.", trigger)
    assert title == expected_title
