"""A snippet's `data` mirror survives the GENERIC note door.

`notes.data` is derived from the body. The snippet service always composed it
from the field set it had just merged, so `update_snippet` was never the
problem — the problem was every other way a snippet's body could be written.
`update_note` is a `hasattr` loop with no snippet awareness, and both doors
reach it: PATCH /api/notes/<id> and the MCP update_note tool. The Knowledge
feed handed you that path, because a snippet card there routed to /notes/:id.

The failure was silent and the wrong way round: `snippet_fields` PREFERS the
mirror, so the row went on reporting its old repo/path/symbol to the location
reverse lookup and to prior-art recall while displaying its new body — a record
surfaced with full authority and wrong, which the drift-check docstring calls
worse than having no record at all (#3128).
"""
import pytest
from tests.helpers import drive_update_note as _update
from tests.helpers import fake_note, fake_snippet

OLD_MIRROR = {
    "name": "debounce",
    "language": "javascript",
    "locations": [{"repo": "Scribe", "path": "old/place.js", "symbol": "debounce"}],
    "verification": {"status": "ok", "code_sha": "abc", "checked_at": "2026-01-01"},
    "provenance": {"commit_sha": "deadbeef"},
}

MOVED_BODY = (
    "**Locations:**\n"
    "- `Scribe` · `new/place.ts` · `debounce`\n\n"
    "```typescript\nexport const debounce = 1;\n```\n"
)


@pytest.mark.asyncio
async def test_a_body_write_moves_the_mirror_with_it():
    note = fake_snippet(data=dict(OLD_MIRROR), project_id=None)
    await _update(note, body=MOVED_BODY)
    assert note.data["locations"] == [
        {"repo": "Scribe", "path": "new/place.ts", "symbol": "debounce"}
    ], "the mirror still describes where the snippet used to live"
    assert note.data["language"] == "typescript"


@pytest.mark.asyncio
async def test_the_verdict_and_provenance_are_carried_not_dropped():
    """Neither is in the body to parse, so recomposing must carry them. An
    ordinary edit must not erase the last drift check — and it needs no
    invalidation branch either: `code_sha` is recomputed from the new code, so
    a verdict stamped against the old code expires itself on read."""
    note = fake_snippet(data=dict(OLD_MIRROR), project_id=None)
    await _update(note, body=MOVED_BODY)
    assert note.data["verification"] == OLD_MIRROR["verification"]
    assert note.data["provenance"] == OLD_MIRROR["provenance"]
    assert note.data["code_sha"] != OLD_MIRROR["verification"]["code_sha"]


@pytest.mark.asyncio
async def test_an_explicit_data_wins_over_recomposition():
    """`update_snippet` composes the mirror from the merged field set it holds
    and passes it here. That caller knows things the body cannot be re-read for
    — which locations were replaced, whether provenance survives the edit — so
    an explicit mirror must not be recomputed out from under it."""
    note = fake_snippet(data=dict(OLD_MIRROR), project_id=None)
    authoritative = {"name": "from the service", "locations": []}
    await _update(note, body=MOVED_BODY, data=authoritative)
    assert note.data == authoritative


@pytest.mark.asyncio
async def test_a_plain_note_is_left_alone():
    """Only snippets carry a mirror; a note's `data` must not be invented."""
    note = fake_note(note_type="note", data=None, project_id=None)
    await _update(note, body="just some prose")
    assert note.data is None


@pytest.mark.asyncio
async def test_a_write_that_cannot_change_the_parse_does_not_touch_the_mirror():
    """Status, priority, project — none of them is an input to the body parser,
    so recomposing on them would be work for nothing and would rebuild a mirror
    from a body nobody claimed to have changed."""
    note = fake_snippet(data=dict(OLD_MIRROR), project_id=None)
    await _update(note, project_id=4)
    assert note.data == OLD_MIRROR


@pytest.mark.asyncio
async def test_a_title_change_reaches_the_mirror_too():
    """A snippet's NAME lives in its title, not its body — `parse_snippet_fields`
    reads both, so both are triggers."""
    note = fake_snippet(data=dict(OLD_MIRROR), project_id=None)
    await _update(note, title="throttle — cap a callback's rate")
    assert note.data["name"] == "throttle"
    assert note.data["when_to_use"] == "cap a callback's rate"
