5419330633
New services/consolidation.py module with maybe_consolidate() — the debounced trigger gate. Two reasons: - log_added: gated by DEFAULT_LOG_THRESHOLD (3) counted since the task's consolidated_at timestamp. - task_closed: bypasses the count gate; fires whenever status flips to done/cancelled. Both reasons gated by the auto_consolidate_tasks user setting (default on). Per-task asyncio.Lock prevents two simultaneous passes for the same task. consolidate_task is a stub here — full implementation in the next commit.
109 lines
4.0 KiB
Python
109 lines
4.0 KiB
Python
"""Tests for the task-body consolidation pipeline (gate + full pass).
|
|
|
|
Design: docs/superpowers/specs/2026-05-13-task-as-durable-record-design.md
|
|
"""
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
|
|
# ── Gate logic ───────────────────────────────────────────────────────────────
|
|
|
|
|
|
async def test_maybe_consolidate_below_threshold_does_not_fire():
|
|
"""log_added with only 2 logs since last pass → no consolidation."""
|
|
from fabledassistant.services import consolidation
|
|
|
|
with patch.object(
|
|
consolidation, "_logs_since_last_consolidation",
|
|
new=AsyncMock(return_value=2),
|
|
), patch.object(
|
|
consolidation, "consolidate_task", new=AsyncMock(),
|
|
) as mock_consolidate, patch.object(
|
|
consolidation, "_auto_consolidate_enabled", new=AsyncMock(return_value=True),
|
|
):
|
|
await consolidation.maybe_consolidate(
|
|
user_id=1, task_id=42, reason="log_added",
|
|
)
|
|
|
|
mock_consolidate.assert_not_awaited()
|
|
|
|
|
|
async def test_maybe_consolidate_at_threshold_fires():
|
|
"""log_added with N logs since last pass → consolidation scheduled."""
|
|
from fabledassistant.services import consolidation
|
|
|
|
# asyncio.create_task is the actual scheduler; replace it so the test
|
|
# doesn't need an event-loop background task to settle.
|
|
with patch.object(
|
|
consolidation, "_logs_since_last_consolidation",
|
|
new=AsyncMock(return_value=3),
|
|
), patch.object(
|
|
consolidation, "_auto_consolidate_enabled", new=AsyncMock(return_value=True),
|
|
), patch(
|
|
"fabledassistant.services.consolidation.asyncio.create_task",
|
|
) as mock_create_task:
|
|
await consolidation.maybe_consolidate(
|
|
user_id=1, task_id=42, reason="log_added",
|
|
)
|
|
|
|
mock_create_task.assert_called_once()
|
|
|
|
|
|
async def test_maybe_consolidate_task_closed_always_fires():
|
|
"""task_closed bypasses the log-count gate."""
|
|
from fabledassistant.services import consolidation
|
|
|
|
with patch.object(
|
|
consolidation, "_logs_since_last_consolidation",
|
|
new=AsyncMock(return_value=0),
|
|
), patch.object(
|
|
consolidation, "_auto_consolidate_enabled", new=AsyncMock(return_value=True),
|
|
), patch(
|
|
"fabledassistant.services.consolidation.asyncio.create_task",
|
|
) as mock_create_task:
|
|
await consolidation.maybe_consolidate(
|
|
user_id=1, task_id=42, reason="task_closed",
|
|
)
|
|
|
|
mock_create_task.assert_called_once()
|
|
|
|
|
|
async def test_maybe_consolidate_setting_off_blocks_both_reasons():
|
|
"""auto_consolidate_tasks=false → neither trigger fires."""
|
|
from fabledassistant.services import consolidation
|
|
|
|
with patch.object(
|
|
consolidation, "_logs_since_last_consolidation",
|
|
new=AsyncMock(return_value=5),
|
|
), patch.object(
|
|
consolidation, "_auto_consolidate_enabled", new=AsyncMock(return_value=False),
|
|
), patch(
|
|
"fabledassistant.services.consolidation.asyncio.create_task",
|
|
) as mock_create_task:
|
|
await consolidation.maybe_consolidate(
|
|
user_id=1, task_id=42, reason="log_added",
|
|
)
|
|
await consolidation.maybe_consolidate(
|
|
user_id=1, task_id=42, reason="task_closed",
|
|
)
|
|
|
|
mock_create_task.assert_not_called()
|
|
|
|
|
|
async def test_maybe_consolidate_unknown_reason_is_noop():
|
|
"""Unknown reasons get logged and skipped — not raised."""
|
|
from fabledassistant.services import consolidation
|
|
|
|
with patch.object(
|
|
consolidation, "_logs_since_last_consolidation",
|
|
new=AsyncMock(return_value=99),
|
|
), patch.object(
|
|
consolidation, "_auto_consolidate_enabled", new=AsyncMock(return_value=True),
|
|
), patch(
|
|
"fabledassistant.services.consolidation.asyncio.create_task",
|
|
) as mock_create_task:
|
|
await consolidation.maybe_consolidate(
|
|
user_id=1, task_id=42, reason="some_other_reason",
|
|
)
|
|
|
|
mock_create_task.assert_not_called()
|