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:
parent
0a7bde7341
commit
d76627a8a4
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue