diff --git a/haiku_rag_slim/haiku/rag/ingester/api/static/index.html b/haiku_rag_slim/haiku/rag/ingester/api/static/index.html
index 9fdc3261..c1ed1bf5 100644
--- a/haiku_rag_slim/haiku/rag/ingester/api/static/index.html
+++ b/haiku_rag_slim/haiku/rag/ingester/api/static/index.html
@@ -338,6 +338,11 @@
$("stat-breakdown").innerHTML = parts.join("
");
}
+ const SKIP_REASON_LABELS = {
+ pending_work: "queue busy",
+ circuit_open: "breaker open",
+ };
+
function renderSources(sources) {
$("sources-count").textContent = "(" + sources.length + ")";
if (!sources.length) {
@@ -351,17 +356,30 @@
if (s.circuit_breaker_open) {
circuitBadge = 'OPEN';
}
- let skipBadge = "";
- if (s.last_skip_reason) {
- skipBadge =
- ' ' +
- escapeHtml(s.last_skip_reason) +
- "";
- }
+ // Combine last_polled with skip_reason in one cell. Three cases:
+ // (a) polled OK → "5m ago"
+ // (b) polled + skipped → "5m ago [queue busy]" (sweep ran then
+ // backpressure kicked in)
+ // (c) never polled but → "[queue busy]" alone — em-dash would
+ // skipped read as broken; the badge tells the
+ // real story (restart with work still
+ // in queue).
+ const reason = s.last_skip_reason;
+ const label = reason
+ ? SKIP_REASON_LABELS[reason] || reason
+ : null;
+ const skipBadge = reason
+ ? ` ${escapeHtml(label)}`
+ : "";
+ const polledCell = s.last_polled_at
+ ? relTime(s.last_polled_at) + skipBadge
+ : reason
+ ? skipBadge.trim()
+ : "—";
return `