"""Tests for the prune logic — both rolling (pin_kind IS NULL) and the auto-pin bucket (pin_kind='auto'). Design: docs/superpowers/specs/2026-05-13-note-version-pinning-design.md """ from unittest.mock import AsyncMock, MagicMock, patch async def test_create_version_prune_sql_filters_to_unpinned(): """The DELETE statement issued by create_version's prune step must include `pin_kind IS NULL` in the inner SELECT so pinned versions aren't counted toward MAX_VERSIONS and can't be pruned by it.""" mock_session = AsyncMock() select_result = MagicMock() # No prior version → skips the throttle/dedupe early-return paths and # proceeds straight to insert + prune. select_result.scalars.return_value.first.return_value = None mock_session.add = MagicMock() mock_session.commit = AsyncMock() mock_session.refresh = AsyncMock() mock_session.__aenter__ = AsyncMock(return_value=mock_session) mock_session.__aexit__ = AsyncMock(return_value=False) captured_sql: list[str] = [] async def execute_capture(stmt, *args, **kwargs): captured_sql.append(str(stmt)) if len(captured_sql) == 1: return select_result return MagicMock() mock_session.execute = AsyncMock(side_effect=execute_capture) with patch( "scribe.services.note_versions.async_session", return_value=mock_session, ): from scribe.services.note_versions import create_version await create_version( user_id=1, note_id=42, body="content", title="t", tags=["a"], ) assert any("pin_kind IS NULL" in s for s in captured_sql), ( f"Expected prune SQL to filter pin_kind IS NULL; got: {captured_sql!r}" ) async def test_prune_auto_pins_filters_to_auto_kind(): """prune_auto_pins must filter to pin_kind='auto' so manual pins and rolling rows aren't touched, and must bind MAX_AUTO_PINS as the OFFSET.""" mock_session = AsyncMock() mock_session.commit = AsyncMock() mock_session.__aenter__ = AsyncMock(return_value=mock_session) mock_session.__aexit__ = AsyncMock(return_value=False) captured_sql: list[str] = [] captured_params: list[dict] = [] async def execute_capture(stmt, *args, **kwargs): captured_sql.append(str(stmt)) try: captured_params.append(dict(stmt.compile().params)) except Exception: captured_params.append({}) return MagicMock() mock_session.execute = AsyncMock(side_effect=execute_capture) with patch( "scribe.services.version_pinning.async_session", return_value=mock_session, ): from scribe.services.version_pinning import ( prune_auto_pins, MAX_AUTO_PINS, ) await prune_auto_pins(user_id=1, note_id=42) assert any("pin_kind = 'auto'" in s for s in captured_sql), ( f"expected auto-bucket filter in SQL; got: {captured_sql!r}" ) assert any( p.get("max_auto_pins") == MAX_AUTO_PINS for p in captured_params ), f"bound params: {captured_params!r}"