mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
The full-suite CI run executes every test tree in one process against one database, so other suites' committed rows are visible to the Today-brief queries and the "empty company" / absolute-count assertions failed (assert 4 == 0). The suite now snapshots a pre-seed baseline and asserts deltas, seeds at priority 0 so its rows stay inside the brief's item caps, and uses a unique agent slug (the fixed be-dev-1 could collide with leaked rows). Verified by co-running with the known-polluting integration suites in one process. Co-authored-by: Renn F <rennf93@users.noreply.github.com>
196 lines
6.1 KiB
Python
196 lines
6.1 KiB
Python
"""TgCockpitService coverage: the /telegram/today aggregate composes
|
|
needs-you counts, fleet snapshot, spend, and ship state from seeded rows.
|
|
|
|
Assertions are DELTAS against a pre-seed baseline, never absolute counts —
|
|
CI runs the whole test tree in one process against one database, so other
|
|
suites' committed rows are visible here and an "empty company" cannot be
|
|
assumed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, cast
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
from roboco.config import settings
|
|
from roboco.db.tables import AgentTable, TaskTable
|
|
from roboco.foundation import identity as _foundation
|
|
from roboco.foundation.policy.content import markers
|
|
from roboco.models.base import (
|
|
AgentRole,
|
|
AgentStatus,
|
|
Complexity,
|
|
Team,
|
|
)
|
|
from roboco.models.base import TaskNature as TN
|
|
from roboco.models.base import TaskStatus as TS
|
|
from roboco.models.base import TaskType as TT
|
|
from roboco.services.task import (
|
|
RELEASE_MANAGER_SOURCE,
|
|
ROADMAP_SOURCE,
|
|
VIDEO_POST_SOURCE,
|
|
X_POST_SOURCE,
|
|
)
|
|
from roboco.services.tg_cockpit import get_tg_cockpit_service
|
|
|
|
if TYPE_CHECKING:
|
|
from uuid import UUID
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
SYSTEM_UUID = _foundation.AGENTS["system"].uuid
|
|
|
|
CI_WATCH_SOURCE = "ci_watch"
|
|
|
|
# 1 awaiting + 1 blocked + 4 held drafts (release/x/video/roadmap-item).
|
|
EXPECTED_NEEDS_YOU_TOTAL = 6
|
|
|
|
|
|
async def _seed_system_agent(session: AsyncSession) -> None:
|
|
if await session.get(AgentTable, SYSTEM_UUID) is None:
|
|
session.add(
|
|
AgentTable(
|
|
id=SYSTEM_UUID,
|
|
name="system",
|
|
slug="system",
|
|
role=AgentRole.SYSTEM,
|
|
team=None,
|
|
status=AgentStatus.ACTIVE,
|
|
model_config={},
|
|
system_prompt="x",
|
|
capabilities=[],
|
|
permissions={},
|
|
metrics={},
|
|
)
|
|
)
|
|
await session.flush()
|
|
|
|
|
|
def _task(
|
|
title: str,
|
|
task_status: TS,
|
|
*,
|
|
source: str | None = None,
|
|
team: Team = Team.BACKEND,
|
|
) -> TaskTable:
|
|
# priority 0 (critical) sorts seeded rows ahead of any leaked ones, so
|
|
# they stay inside the brief's per-section item caps.
|
|
return TaskTable(
|
|
id=uuid4(),
|
|
title=title,
|
|
description="A description long enough to satisfy any length floor.",
|
|
acceptance_criteria=["it is visible on the Today brief"],
|
|
status=task_status,
|
|
priority=0,
|
|
task_type=TT.ADMINISTRATIVE,
|
|
nature=TN.NON_TECHNICAL,
|
|
estimated_complexity=Complexity.LOW,
|
|
created_by=SYSTEM_UUID,
|
|
team=team,
|
|
source=source,
|
|
confirmed_by_human=True,
|
|
)
|
|
|
|
|
|
async def _seed_working_agent(session: AsyncSession, current_task_id: UUID) -> str:
|
|
slug = f"be-dev-{uuid4().hex[:6]}"
|
|
session.add(
|
|
AgentTable(
|
|
id=uuid4(),
|
|
name=slug,
|
|
slug=slug,
|
|
role=AgentRole.DEVELOPER,
|
|
team=Team.BACKEND,
|
|
status=AgentStatus.ACTIVE,
|
|
model_config={},
|
|
system_prompt="x",
|
|
capabilities=[],
|
|
permissions={},
|
|
metrics={},
|
|
current_task_id=current_task_id,
|
|
)
|
|
)
|
|
await session.flush()
|
|
return slug
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_today_brief_shape(db_session: AsyncSession) -> None:
|
|
"""Structure + invariants that hold regardless of shared-DB residue."""
|
|
brief = await get_tg_cockpit_service(db_session).today()
|
|
|
|
assert set(brief) == {"needs_you", "fleet", "spend", "ship"}
|
|
needs = brief["needs_you"]
|
|
assert needs["total"] == (
|
|
needs["awaiting_ceo_count"]
|
|
+ needs["blocked_count"]
|
|
+ sum(needs["held_drafts"].values())
|
|
)
|
|
assert isinstance(brief["spend"]["tokens_today"], int)
|
|
assert isinstance(brief["spend"]["cost_today_usd"], float)
|
|
assert brief["ship"]["version"] == settings.app_version
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_today_composes_needs_you_fleet_and_ship(
|
|
db_session: AsyncSession,
|
|
) -> None:
|
|
await _seed_system_agent(db_session)
|
|
baseline = await get_tg_cockpit_service(db_session).today()
|
|
|
|
awaiting = _task("Root PR ready", TS.AWAITING_CEO_APPROVAL)
|
|
blocked = _task("Stuck on infra", TS.BLOCKED)
|
|
x_draft = _task("X draft", TS.PENDING, source=X_POST_SOURCE, team=Team.BOARD)
|
|
video_draft = _task(
|
|
"Video draft", TS.PENDING, source=VIDEO_POST_SOURCE, team=Team.BOARD
|
|
)
|
|
release_prop = _task(
|
|
"Release 0.26.0", TS.PENDING, source=RELEASE_MANAGER_SOURCE, team=Team.BOARD
|
|
)
|
|
ci_fix = _task("Fix red CI", TS.PENDING, source=CI_WATCH_SOURCE)
|
|
cycle = _task("Roadmap cycle", TS.PENDING, source=ROADMAP_SOURCE, team=Team.BOARD)
|
|
for row in (
|
|
awaiting,
|
|
blocked,
|
|
x_draft,
|
|
video_draft,
|
|
release_prop,
|
|
ci_fix,
|
|
cycle,
|
|
):
|
|
db_session.add(row)
|
|
await db_session.flush()
|
|
markers.set_roadmap_cycle(
|
|
cycle,
|
|
{
|
|
"goal": "g",
|
|
"items": [
|
|
{"id": "item-0", "status": "proposed"},
|
|
{"id": "item-1", "status": "approved"},
|
|
],
|
|
},
|
|
)
|
|
agent_slug = await _seed_working_agent(db_session, cast("UUID", awaiting.id))
|
|
|
|
brief = await get_tg_cockpit_service(db_session).today()
|
|
|
|
needs, base_needs = brief["needs_you"], baseline["needs_you"]
|
|
assert needs["awaiting_ceo_count"] == base_needs["awaiting_ceo_count"] + 1
|
|
seeded = next(
|
|
item for item in needs["awaiting_ceo"] if item["title"] == "Root PR ready"
|
|
)
|
|
assert seeded["status"] == "awaiting_ceo_approval"
|
|
assert needs["blocked_count"] == base_needs["blocked_count"] + 1
|
|
for key in ("release_proposals", "x_posts", "video_posts", "roadmap_items"):
|
|
assert needs["held_drafts"][key] == base_needs["held_drafts"][key] + 1
|
|
assert needs["total"] == base_needs["total"] + EXPECTED_NEEDS_YOU_TOTAL
|
|
|
|
workers = {
|
|
agent["name"]: agent.get("task_title") for agent in brief["fleet"]["working"]
|
|
}
|
|
assert workers.get(agent_slug) == "Root PR ready"
|
|
|
|
assert brief["ship"]["open_release_proposal"] is True
|
|
assert brief["ship"]["ci_fix_tasks"] == baseline["ship"]["ci_fix_tasks"] + 1
|