perf(database): replace listSnapshot+JS filter with scoped SQL in getStandupReport
Replace 17-table snapshot fetch + per-agent JS filters with:
- scoped agents row read (excluding terminated/pending_approval)
- tasks GROUP BY assignee_agent_id with conditional sums for
in_progress / blocked / done-in-24h counts
- runs GROUP BY agent_id over 24h window with correlated subquery
for last status, plus max(created_at) for last run timestamp
- cost_entries GROUP BY agent_id over 24h window for cost
- activity GROUP BY actor for review-cycle counts
- single SELECTs for company-level counters (completed tasks, run
aggregates, blocked tasks, pending approvals, urgent unread, active
sprint)
Return shape unchanged.
This commit is contained in:
1 parent
8f7054630b
commit
19c575933d
1 file changed
+137
-89
@@ -185,128 +185,176 @@ export function buildCompanySettingsMethods(
|
|||||||
},
|
},
|
||||||
|
|
||||||
getStandupReport(companyId: string): StandupReport {
|
getStandupReport(companyId: string): StandupReport {
|
||||||
const snapshot = deps.listSnapshot({ companyId });
|
const db = getDb();
|
||||||
const agents = snapshot.agents.filter(
|
|
||||||
(a) => a.status !== "terminated" && a.status !== "pending_approval",
|
|
||||||
);
|
|
||||||
const tasks = snapshot.tasks;
|
|
||||||
const runs = snapshot.runs;
|
|
||||||
const costs = snapshot.costs;
|
|
||||||
|
|
||||||
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
||||||
const recentActivity = snapshot.activity.filter(
|
|
||||||
(a) => a.companyId === companyId && a.createdAt > oneDayAgo,
|
type AgentRow = {
|
||||||
|
id: string; name: string; role: string; status: StandupReport["agentReports"][number]["status"];
|
||||||
|
budgetMonthlyUsd: number; spentMonthlyUsd: number;
|
||||||
|
};
|
||||||
|
const agents = readAll<AgentRow>(
|
||||||
|
`select id, name, role, status,
|
||||||
|
budget_monthly_usd as budgetMonthlyUsd,
|
||||||
|
spent_monthly_usd as spentMonthlyUsd
|
||||||
|
from agents
|
||||||
|
where company_id = ? and status != 'terminated' and status != 'pending_approval'
|
||||||
|
order by created_at asc`,
|
||||||
|
companyId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const recentCompletedTasksCount = (db.prepare(
|
||||||
|
"select count(*) as c from tasks where company_id = ? and status = 'done' and updated_at > ?",
|
||||||
|
).get(companyId, oneDayAgo) as { c: number }).c;
|
||||||
|
|
||||||
|
const recentRunStats = db.prepare(
|
||||||
|
`select
|
||||||
|
count(*) as total,
|
||||||
|
sum(case when status = 'succeeded' then 1 else 0 end) as succeeded,
|
||||||
|
sum(case when status = 'failed' or status = 'timed_out' then 1 else 0 end) as failed
|
||||||
|
from runs where company_id = ? and created_at > ?`,
|
||||||
|
).get(companyId, oneDayAgo) as { total: number; succeeded: number | null; failed: number | null };
|
||||||
|
const recentRunsTotal = recentRunStats.total ?? 0;
|
||||||
|
const successfulRuns = recentRunStats.succeeded ?? 0;
|
||||||
|
const failedRuns = recentRunStats.failed ?? 0;
|
||||||
|
|
||||||
|
const blockedTaskRows = readAll<{ id: string; title: string; assigneeAgentId: string | null }>(
|
||||||
|
`select id, title, assignee_agent_id as assigneeAgentId
|
||||||
|
from tasks where company_id = ? and status = 'blocked'`,
|
||||||
|
companyId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const pendingApprovals = (db.prepare(
|
||||||
|
"select count(*) as c from approvals where company_id = ? and state = 'pending'",
|
||||||
|
).get(companyId) as { c: number }).c;
|
||||||
|
|
||||||
|
const activeSprint = db.prepare(
|
||||||
|
`select name, velocity_points as velocityPoints, completed_points as completedPoints
|
||||||
|
from sprints where company_id = ? and status = 'active' order by start_date desc limit 1`,
|
||||||
|
).get(companyId) as { name: string; velocityPoints: number; completedPoints: number } | undefined;
|
||||||
|
|
||||||
|
const urgentUnread = (db.prepare(
|
||||||
|
`select count(*) as c
|
||||||
|
from agent_messages messages
|
||||||
|
left join agent_message_reads reads
|
||||||
|
on reads.message_id = messages.id and reads.agent_id = '__board__'
|
||||||
|
where messages.company_id = ?
|
||||||
|
and reads.read_at is null
|
||||||
|
and (messages.priority = 'urgent' or messages.channel = 'incident')`,
|
||||||
|
).get(companyId) as { c: number }).c;
|
||||||
|
|
||||||
|
const tasksByAgentRows = readAll<{
|
||||||
|
agentId: string; inProgress: number; blocked: number; completed24h: number;
|
||||||
|
}>(
|
||||||
|
`select assignee_agent_id as agentId,
|
||||||
|
sum(case when status = 'in_progress' then 1 else 0 end) as inProgress,
|
||||||
|
sum(case when status = 'blocked' then 1 else 0 end) as blocked,
|
||||||
|
sum(case when status = 'done' and updated_at > ? then 1 else 0 end) as completed24h
|
||||||
|
from tasks
|
||||||
|
where company_id = ? and assignee_agent_id is not null
|
||||||
|
group by assignee_agent_id`,
|
||||||
|
oneDayAgo,
|
||||||
|
companyId,
|
||||||
|
);
|
||||||
|
const tasksByAgent = new Map(tasksByAgentRows.map((row) => [row.agentId, row]));
|
||||||
|
|
||||||
|
const recentRunsByAgent = readAll<{
|
||||||
|
agentId: string; runCount: number; lastStatus: string | null; lastAt: string | null;
|
||||||
|
}>(
|
||||||
|
`select agent_id as agentId,
|
||||||
|
count(*) as runCount,
|
||||||
|
(select status from runs r2 where r2.agent_id = runs.agent_id and r2.company_id = runs.company_id and r2.created_at > ? order by created_at desc limit 1) as lastStatus,
|
||||||
|
max(created_at) as lastAt
|
||||||
|
from runs
|
||||||
|
where company_id = ? and created_at > ?
|
||||||
|
group by agent_id`,
|
||||||
|
oneDayAgo,
|
||||||
|
companyId,
|
||||||
|
oneDayAgo,
|
||||||
|
);
|
||||||
|
const runsByAgent = new Map(recentRunsByAgent.map((row) => [row.agentId, row]));
|
||||||
|
|
||||||
|
const costByAgentRows = readAll<{ agentId: string; cost24h: number }>(
|
||||||
|
`select agent_id as agentId, coalesce(sum(amount_usd), 0) as cost24h
|
||||||
|
from cost_entries
|
||||||
|
where company_id = ? and agent_id is not null and created_at > ?
|
||||||
|
group by agent_id`,
|
||||||
|
companyId,
|
||||||
|
oneDayAgo,
|
||||||
|
);
|
||||||
|
const costByAgent = new Map(costByAgentRows.map((row) => [row.agentId, row.cost24h]));
|
||||||
|
|
||||||
|
const reviewByAgentRows = readAll<{ actor: string; cycles: number }>(
|
||||||
|
`select actor, count(*) as cycles
|
||||||
|
from activity
|
||||||
|
where company_id = ? and created_at > ?
|
||||||
|
and action in ('task.status_changed', 'task.updated', 'task.auto_assigned')
|
||||||
|
group by actor`,
|
||||||
|
companyId,
|
||||||
|
oneDayAgo,
|
||||||
|
);
|
||||||
|
const reviewByAgent = new Map(reviewByAgentRows.map((row) => [row.actor, row.cycles]));
|
||||||
|
|
||||||
|
const agentNameMap = new Map(agents.map((a) => [a.id, a.name]));
|
||||||
|
|
||||||
const companyHighlights: string[] = [];
|
const companyHighlights: string[] = [];
|
||||||
const blockers: string[] = [];
|
const blockers: string[] = [];
|
||||||
|
if (recentCompletedTasksCount > 0) {
|
||||||
const recentCompletedTasks = tasks.filter(
|
companyHighlights.push(`${recentCompletedTasksCount} task(s) completed in last 24h`);
|
||||||
(t) => t.status === "done" && t.updatedAt > oneDayAgo,
|
|
||||||
);
|
|
||||||
if (recentCompletedTasks.length > 0) {
|
|
||||||
companyHighlights.push(`${recentCompletedTasks.length} task(s) completed in last 24h`);
|
|
||||||
}
|
}
|
||||||
|
if (recentRunsTotal > 0) {
|
||||||
const recentRuns = runs.filter((r) => r.createdAt > oneDayAgo);
|
|
||||||
const successfulRuns = recentRuns.filter((r) => r.status === "succeeded").length;
|
|
||||||
const failedRuns = recentRuns.filter(
|
|
||||||
(r) => r.status === "failed" || r.status === "timed_out",
|
|
||||||
).length;
|
|
||||||
if (recentRuns.length > 0) {
|
|
||||||
companyHighlights.push(
|
companyHighlights.push(
|
||||||
`${recentRuns.length} runs (${successfulRuns} succeeded, ${failedRuns} failed)`,
|
`${recentRunsTotal} runs (${successfulRuns} succeeded, ${failedRuns} failed)`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
for (const task of blockedTaskRows) {
|
||||||
const blockedTasks = tasks.filter((t) => t.status === "blocked");
|
const assigneeName = task.assigneeAgentId ? agentNameMap.get(task.assigneeAgentId) ?? null : null;
|
||||||
for (const task of blockedTasks) {
|
blockers.push(`${task.title} — blocked (${assigneeName ?? "unassigned"})`);
|
||||||
const assignee = agents.find((a) => a.id === task.assigneeAgentId);
|
|
||||||
blockers.push(`${task.title} — blocked (${assignee?.name ?? "unassigned"})`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pendingApprovals = snapshot.approvals.filter(
|
|
||||||
(a) => a.companyId === companyId && a.state === "pending",
|
|
||||||
).length;
|
|
||||||
const totalBudget = agents.reduce((sum, a) => sum + a.budgetMonthlyUsd, 0);
|
|
||||||
const totalSpent = agents.reduce((sum, a) => sum + a.spentMonthlyUsd, 0);
|
|
||||||
const budgetUtilization =
|
|
||||||
totalBudget > 0 ? Math.round((totalSpent / totalBudget) * 100) : 0;
|
|
||||||
|
|
||||||
// Active sprint progress
|
|
||||||
const activeSprint = snapshot.sprints.find(
|
|
||||||
(s) => s.companyId === companyId && s.status === "active",
|
|
||||||
);
|
|
||||||
if (activeSprint) {
|
if (activeSprint) {
|
||||||
const pct =
|
const pct = activeSprint.velocityPoints > 0
|
||||||
activeSprint.velocityPoints > 0
|
? Math.round((activeSprint.completedPoints / activeSprint.velocityPoints) * 100)
|
||||||
? Math.round(
|
: 0;
|
||||||
(activeSprint.completedPoints / activeSprint.velocityPoints) * 100,
|
|
||||||
)
|
|
||||||
: 0;
|
|
||||||
companyHighlights.push(
|
companyHighlights.push(
|
||||||
`Sprint "${activeSprint.name}": ${activeSprint.completedPoints}/${activeSprint.velocityPoints} pts (${pct}%)`,
|
`Sprint "${activeSprint.name}": ${activeSprint.completedPoints}/${activeSprint.velocityPoints} pts (${pct}%)`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unread messages requiring attention
|
|
||||||
const urgentUnread = snapshot.agentMessages.filter(
|
|
||||||
(m) =>
|
|
||||||
m.companyId === companyId &&
|
|
||||||
!m.readAt &&
|
|
||||||
(m.priority === "urgent" || m.channel === "incident"),
|
|
||||||
).length;
|
|
||||||
if (urgentUnread > 0) {
|
if (urgentUnread > 0) {
|
||||||
blockers.push(`${urgentUnread} urgent unread message(s) need attention`);
|
blockers.push(`${urgentUnread} urgent unread message(s) need attention`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const totalBudget = agents.reduce((sum, a) => sum + a.budgetMonthlyUsd, 0);
|
||||||
|
const totalSpent = agents.reduce((sum, a) => sum + a.spentMonthlyUsd, 0);
|
||||||
|
const budgetUtilization = totalBudget > 0 ? Math.round((totalSpent / totalBudget) * 100) : 0;
|
||||||
|
|
||||||
const agentReports = agents.map((agent) => {
|
const agentReports = agents.map((agent) => {
|
||||||
const agentTasks = tasks.filter((t) => t.assigneeAgentId === agent.id);
|
const taskAgg = tasksByAgent.get(agent.id);
|
||||||
const agentRuns = runs.filter((r) => r.agentId === agent.id);
|
const runAgg = runsByAgent.get(agent.id);
|
||||||
const agentRecentRuns = agentRuns.filter((r) => r.createdAt > oneDayAgo);
|
const completed24h = taskAgg?.completed24h ?? 0;
|
||||||
const agentCosts = costs.filter(
|
const runs24h = runAgg?.runCount ?? 0;
|
||||||
(c) => c.agentId === agent.id && c.createdAt > oneDayAgo,
|
const reviewedTasks = reviewByAgent.get(agent.id) ?? 0;
|
||||||
);
|
|
||||||
const lastRun = agentRecentRuns.sort(
|
|
||||||
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
|
|
||||||
)[0];
|
|
||||||
|
|
||||||
const highlights: string[] = [];
|
const highlights: string[] = [];
|
||||||
const completedRecently = agentTasks.filter(
|
if (completed24h > 0) highlights.push(`Completed ${completed24h} task(s)`);
|
||||||
(t) => t.status === "done" && t.updatedAt > oneDayAgo,
|
if (runs24h > 0) highlights.push(`${runs24h} run(s) in last 24h`);
|
||||||
);
|
|
||||||
if (completedRecently.length > 0)
|
|
||||||
highlights.push(`Completed ${completedRecently.length} task(s)`);
|
|
||||||
if (agentRecentRuns.length > 0)
|
|
||||||
highlights.push(`${agentRecentRuns.length} run(s) in last 24h`);
|
|
||||||
const reviewedTasks = recentActivity.filter(
|
|
||||||
(a) =>
|
|
||||||
a.actor === agent.id &&
|
|
||||||
(a.action === "task.status_changed" ||
|
|
||||||
a.action === "task.updated" ||
|
|
||||||
a.action === "task.auto_assigned"),
|
|
||||||
).length;
|
|
||||||
if (reviewedTasks > 0) highlights.push(`${reviewedTasks} status update(s)`);
|
if (reviewedTasks > 0) highlights.push(`${reviewedTasks} status update(s)`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
agentId: agent.id,
|
agentId: agent.id,
|
||||||
agentName: agent.name,
|
agentName: agent.name,
|
||||||
role: agent.role,
|
role: agent.role,
|
||||||
status: agent.status,
|
status: agent.status,
|
||||||
tasksInProgress: agentTasks.filter((t) => t.status === "in_progress").length,
|
tasksInProgress: taskAgg?.inProgress ?? 0,
|
||||||
tasksCompleted24h: completedRecently.length,
|
tasksCompleted24h: completed24h,
|
||||||
tasksBlocked: agentTasks.filter((t) => t.status === "blocked").length,
|
tasksBlocked: taskAgg?.blocked ?? 0,
|
||||||
lastRunStatus: (lastRun?.status ?? null) as RunStatus | null,
|
lastRunStatus: (runAgg?.lastStatus ?? null) as RunStatus | null,
|
||||||
lastRunAt: lastRun?.createdAt ?? null,
|
lastRunAt: runAgg?.lastAt ?? null,
|
||||||
costLast24h: agentCosts.reduce((sum, c) => sum + (c.amountUsd ?? 0), 0),
|
costLast24h: costByAgent.get(agent.id) ?? 0,
|
||||||
highlights,
|
highlights,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const summaryParts: string[] = [];
|
const summaryParts: string[] = [];
|
||||||
if (agents.length > 0) summaryParts.push(`${agents.length} active agents`);
|
if (agents.length > 0) summaryParts.push(`${agents.length} active agents`);
|
||||||
summaryParts.push(`${recentCompletedTasks.length} tasks done`);
|
summaryParts.push(`${recentCompletedTasksCount} tasks done`);
|
||||||
if (blockedTasks.length > 0) summaryParts.push(`${blockedTasks.length} blocked`);
|
if (blockedTaskRows.length > 0) summaryParts.push(`${blockedTaskRows.length} blocked`);
|
||||||
if (pendingApprovals > 0) summaryParts.push(`${pendingApprovals} pending approvals`);
|
if (pendingApprovals > 0) summaryParts.push(`${pendingApprovals} pending approvals`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in new issue
Block a user