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:
Renzo F
2026-07-19 19:42:24 +02:00
committed by GitHub
co-authored by Renn F
parent db04674342
commit bab53e31ca
14 changed files with 1009 additions and 442 deletions
@@ -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,