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
|
observed = request.observed if request.observed is not None else request.observer
|
||||||
dream_type = request.dream_type
|
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(
|
count_stmt = select(func.count(models.Document.id)).where(
|
||||||
models.Document.workspace_name == workspace_id,
|
models.Document.workspace_name == workspace_id,
|
||||||
models.Document.observer == observer,
|
models.Document.observer == observer,
|
||||||
models.Document.observed == observed,
|
models.Document.observed == observed,
|
||||||
|
models.Document.level == "explicit",
|
||||||
)
|
)
|
||||||
document_count = int(await db.scalar(count_stmt) or 0)
|
document_count = int(await db.scalar(count_stmt) or 0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
from nanoid import generate as generate_nanoid
|
from nanoid import generate as generate_nanoid
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from src import models
|
||||||
from src.models import Peer, Workspace
|
from src.models import Peer, Workspace
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -569,3 +572,96 @@ def test_delete_workspace_after_session_deletion(client: TestClient):
|
||||||
# Now workspace deletion should succeed
|
# Now workspace deletion should succeed
|
||||||
response = client.delete(f"/v3/workspaces/{workspace_name}")
|
response = client.delete(f"/v3/workspaces/{workspace_name}")
|
||||||
assert response.status_code == 202
|
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