fix(dreamer): explicit-only count on manual schedule_dream route

The third caller of enqueue_dream — POST /workspaces/{id}/schedule_dream —
was passing an all-levels document count as the baseline, breaking symmetry
with check_and_schedule_dream and execute_dream after Loop 2's filter fixes.
Filter the manual route's count to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
lilyplasticlabs 2026-04-17 19:13:43 -04:00
parent 0a7bde7341
commit d76627a8a4
2 changed files with 99 additions and 1 deletions

View File

@ -224,11 +224,13 @@ async def schedule_dream(
observed = request.observed if request.observed is not None else request.observer
dream_type = request.dream_type
# Count documents in the collection
# Explicit-only count, matching dream_scheduler.check_and_schedule_dream and
# execute_dream — document_count becomes last_dream_document_count (the baseline).
count_stmt = select(func.count(models.Document.id)).where(
models.Document.workspace_name == workspace_id,
models.Document.observer == observer,
models.Document.observed == observed,
models.Document.level == "explicit",
)
document_count = int(await db.scalar(count_stmt) or 0)

View File

@ -1,9 +1,12 @@
from typing import Any
from unittest.mock import AsyncMock, patch
import pytest
from fastapi.testclient import TestClient
from nanoid import generate as generate_nanoid
from sqlalchemy.ext.asyncio import AsyncSession
from src import models
from src.models import Peer, Workspace
@ -569,3 +572,96 @@ def test_delete_workspace_after_session_deletion(client: TestClient):
# Now workspace deletion should succeed
response = client.delete(f"/v3/workspaces/{workspace_name}")
assert response.status_code == 202
@pytest.mark.asyncio
async def test_schedule_dream_passes_explicit_only_document_count(
client: TestClient,
db_session: AsyncSession,
sample_data: tuple[Workspace, Peer],
):
"""POST /schedule_dream must count only explicit-level docs.
Regression test for the third caller of `enqueue_dream`. The manual
schedule_dream endpoint computes `document_count` and passes it to
`enqueue_dream`, where it becomes `last_dream_document_count` the
baseline that `check_and_schedule_dream` and `execute_dream` subtract
against to compute the NEW-doc delta.
Both of those callers filter to `level == "explicit"` (see Loop 2's
fixes). If this route doesn't match, the next auto-scheduled dream
sees a negative/suppressed delta because the baseline was inflated by
deductive/inductive docs.
Seeds 5 explicit + 10 deductive (total 15) and asserts the count
passed to enqueue_dream is 5, not 15.
"""
workspace, peer = sample_data
# Seed collection + mixed-level documents. Must commit so the
# endpoint's DB session sees them (separate tracked_db path under
# some configs; safe regardless).
collection = models.Collection(
observer=peer.name,
observed=peer.name,
workspace_name=workspace.name,
internal_metadata={},
)
db_session.add(collection)
await db_session.flush()
for _ in range(5):
db_session.add(
models.Document(
content="explicit doc",
level="explicit",
workspace_name=workspace.name,
observer=peer.name,
observed=peer.name,
)
)
for _ in range(10):
db_session.add(
models.Document(
content="deductive doc",
level="deductive",
workspace_name=workspace.name,
observer=peer.name,
observed=peer.name,
)
)
await db_session.commit()
# Capture kwargs passed to enqueue_dream (patched at the router's
# import site — the route does `from src.deriver.enqueue import
# enqueue_dream` at module load, so patching the symbol on the
# router module is what actually intercepts the call).
captured: dict[str, Any] = {}
async def fake_enqueue_dream(*args: Any, **kwargs: Any) -> None:
captured["args"] = args
captured["kwargs"] = kwargs
with (
patch("src.routers.workspaces.settings.DREAM.ENABLED", True),
patch(
"src.routers.workspaces.enqueue_dream",
new=AsyncMock(side_effect=fake_enqueue_dream),
),
):
response = client.post(
f"/v3/workspaces/{workspace.name}/schedule_dream",
json={
"observer": peer.name,
"observed": peer.name,
"dream_type": "omni",
},
)
assert response.status_code == 204, response.text
assert "kwargs" in captured, "enqueue_dream was not called"
assert captured["kwargs"]["document_count"] == 5, (
"schedule_dream must pass explicit-only count (5), "
f"got {captured['kwargs']['document_count']} — the unfiltered "
"count would be 15 and would inflate last_dream_document_count."
)