mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
perf(panel): kanban virtualization + row memoization + scorecards batch endpoint (#594)
* perf(panel): kanban virtualization + row memoization + scorecards batch endpoint The audit's remaining phases: the kanban card lists render through @tanstack/react-virtual windows (columns are the dnd drop targets, cards only drag — no sortable conflict) with memoized columns/cards and a stabilized handleAction; the task table's desktop row and mobile card are extracted and memoized (the table itself already client-paginates to 100). Backend: the per-member scorecard N+1 (~20 requests x 3 queries per poll) collapses into GET /dashboard/metrics/members backed by get_all_member_scorecards with grouped rollup/overlay SQL shared with the single-agent path. * test(metrics): shared-DB-safe scorecard tests — unique seeds, delta assertions The two new batch-scorecard tests assumed a private DB: fixed ceo/system slugs collided with other tests' seeds (ix_agents_slug) and a global exactly-one CEO lookup + exact roster count broke in the one-process suite. Unique slugs, subset/disjoint assertions, dead count constant dropped. --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
@@ -452,6 +452,52 @@ async def test_org_scorecard_endpoint(dashboard_client: AsyncClient) -> None:
|
||||
assert set(body) >= {"member_count", "tasks_completed", "first_pass_yield"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_all_member_scorecards_endpoint(
|
||||
dashboard_client: AsyncClient, db_session: AsyncSession
|
||||
) -> None:
|
||||
"""The batch scorecard route (N+1 fix) returns one MemberScorecard per
|
||||
non-CEO/non-system agent — the CEO seeded by the fixture is excluded."""
|
||||
dev = AgentTable(
|
||||
id=uuid4(),
|
||||
name="be-dev-1",
|
||||
slug=f"be-dev-{uuid4().hex[:8]}",
|
||||
role=AgentRole.DEVELOPER,
|
||||
team=Team.BACKEND,
|
||||
status=AgentStatus.ACTIVE,
|
||||
model_config={},
|
||||
system_prompt="dev",
|
||||
capabilities=[],
|
||||
permissions={},
|
||||
metrics={},
|
||||
)
|
||||
db_session.add(dev)
|
||||
await db_session.flush()
|
||||
|
||||
resp = await dashboard_client.get("/api/dashboard/metrics/members", headers=_HDR)
|
||||
assert resp.status_code == HTTPStatus.OK
|
||||
body = resp.json()
|
||||
assert isinstance(body, list)
|
||||
ids = {card["id"] for card in body}
|
||||
assert str(dev.id) in ids
|
||||
# The shared per-run DB can hold several CEO rows (other tests seed
|
||||
# their own); every one of them must be excluded from the batch.
|
||||
ceo_ids = (
|
||||
(
|
||||
await db_session.execute(
|
||||
select(AgentTable.id).where(AgentTable.role == AgentRole.CEO)
|
||||
)
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
assert ceo_ids
|
||||
assert ids.isdisjoint({str(cid) for cid in ceo_ids})
|
||||
for card in body:
|
||||
assert card["scope"] == "member"
|
||||
assert card["member_kind"] == "agent"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_task_metrics_404_for_missing_task(
|
||||
dashboard_client: AsyncClient,
|
||||
|
||||
Reference in New Issue
Block a user