fix: count only live dashboard sessions

This commit is contained in:
William Valentin
2026-04-30 17:07:17 -07:00
parent fd17628e94
commit 476c0e347f
2 changed files with 53 additions and 19 deletions
+8 -1
View File
@@ -160,7 +160,14 @@ function renderSummaryCards() {
const fws = Object.keys(s.by_framework || {}); const fws = Object.keys(s.by_framework || {});
if (fws.length > 0) { if (fws.length > 0) {
const sub = document.getElementById('dash-active-sub'); const sub = document.getElementById('dash-active-sub');
if (sub) sub.textContent = fws.map(f => `${f} ${(s.by_framework[f].runs || 0)}`).join(' · '); if (sub) {
const activeByFramework = fws
.map(f => [f, s.by_framework[f].active_sessions || 0])
.filter(([, count]) => count > 0);
sub.textContent = activeByFramework.length > 0
? activeByFramework.map(([f, count]) => `${f} ${count}`).join(' · ')
: 'no live sessions';
}
} }
const errEl = document.getElementById('dash-errors'); const errEl = document.getElementById('dash-errors');
+45 -18
View File
@@ -6,9 +6,10 @@ import (
) )
type FrameworkStats struct { type FrameworkStats struct {
Runs int `json:"runs"` ActiveSessions int `json:"active_sessions"`
Tools int `json:"tools"` Runs int `json:"runs"`
Errors int `json:"errors"` Tools int `json:"tools"`
Errors int `json:"errors"`
} }
type Summary struct { type Summary struct {
@@ -44,23 +45,47 @@ func (d *DB) GetSummary(ctx context.Context) (*Summary, error) {
now := time.Now() now := time.Now()
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
// Active sessions: sessions with a session.start but no session.end (last 7 days) // Active sessions are open sessions with recent activity. Some hook sources can
// miss session.end, so "started but never ended" alone overstates live work.
activeQ := ` activeQ := `
SELECT COUNT(DISTINCT e.session_id) WITH session_groups AS (
FROM events e SELECT
WHERE e.type = 'session.start' session_id,
AND e.session_id IS NOT NULL COALESCE(MAX(source_framework), 'unknown') AS framework,
AND e.ts >= $1 MAX(ts) AS last_event_at,
AND NOT EXISTS ( BOOL_OR(type = 'session.start') AS has_start,
SELECT 1 BOOL_OR(type = 'session.end') AS has_end
FROM events e2 FROM events
WHERE e2.type = 'session.end' WHERE session_id IS NOT NULL
AND e2.session_id = e.session_id GROUP BY session_id
) )
SELECT framework, COUNT(*)
FROM session_groups
WHERE has_start
AND NOT has_end
AND last_event_at >= $1
GROUP BY framework
` `
activeRows, err := d.sql.QueryContext(ctx, activeQ, now.Add(-15*time.Minute))
if err != nil {
return nil, err
}
defer activeRows.Close()
byFramework := make(map[string]FrameworkStats)
var activeSessions int var activeSessions int
activeSessionsSince := time.Now().Add(-7 * 24 * time.Hour) for activeRows.Next() {
if err := d.sql.QueryRowContext(ctx, activeQ, activeSessionsSince).Scan(&activeSessions); err != nil { var fw string
var count int
if err := activeRows.Scan(&fw, &count); err != nil {
return nil, err
}
fs := byFramework[fw]
fs.ActiveSessions = count
byFramework[fw] = fs
activeSessions += count
}
if err := activeRows.Err(); err != nil {
return nil, err return nil, err
} }
@@ -83,7 +108,6 @@ func (d *DB) GetSummary(ctx context.Context) (*Summary, error) {
} }
defer rows.Close() defer rows.Close()
byFramework := make(map[string]FrameworkStats)
var totalRuns, totalTools, totalErrors int var totalRuns, totalTools, totalErrors int
for rows.Next() { for rows.Next() {
@@ -92,6 +116,9 @@ func (d *DB) GetSummary(ctx context.Context) (*Summary, error) {
if err := rows.Scan(&fw, &fs.Runs, &fs.Tools, &fs.Errors); err != nil { if err := rows.Scan(&fw, &fs.Runs, &fs.Tools, &fs.Errors); err != nil {
return nil, err return nil, err
} }
if existing, ok := byFramework[fw]; ok {
fs.ActiveSessions = existing.ActiveSessions
}
byFramework[fw] = fs byFramework[fw] = fs
totalRuns += fs.Runs totalRuns += fs.Runs
totalTools += fs.Tools totalTools += fs.Tools