From 29d0b92f1c8b00b74686d89d389405185bdda5d0 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 7 Jul 2026 19:16:24 +0530 Subject: [PATCH] fix: captain hours saved metric (#14948) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reworks the Captain assistant "hours saved" metric so it produces a believable number. It previously multiplied assistant reply count by customer reply-wait time, which inflated the figure into the millions of hours. It now estimates saved time as replies × a fixed ~2 min per-reply effort assumption. On the overview card the value renders in days once it passes 100 hours, and the label/hint copy was updated to match. ## How to test 1. Open the Captain assistant overview page. 2. Check the "Time saved" card shows a sensible value (hours, or days past 100h). 3. Hover the hint and confirm it reflects the per-reply estimate. --- .../i18n/locale/en/integrations.json | 4 +-- .../captain/assistants/overview/Index.vue | 9 ++++-- .../captain/assistant_stats_builder.rb | 29 ++++++++----------- .../reports/assistant_conversation_creator.rb | 4 +-- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/app/javascript/dashboard/i18n/locale/en/integrations.json b/app/javascript/dashboard/i18n/locale/en/integrations.json index a39165268..a6f3ef2f2 100644 --- a/app/javascript/dashboard/i18n/locale/en/integrations.json +++ b/app/javascript/dashboard/i18n/locale/en/integrations.json @@ -427,8 +427,8 @@ "HINT": "Share of handled conversations escalated to a human agent." }, "HOURS_SAVED": { - "LABEL": "Hours saved", - "HINT": "Estimate: Captain replies times the team's average response time. Directional, not measured labor." + "LABEL": "Time saved", + "HINT": "Estimate: Captain replies times ~2 minutes of assumed agent effort per reply. Directional, not measured labor." }, "REOPEN": { "LABEL": "Reopen rate", diff --git a/app/javascript/dashboard/routes/dashboard/captain/assistants/overview/Index.vue b/app/javascript/dashboard/routes/dashboard/captain/assistants/overview/Index.vue index 687e97286..b9cc6ae35 100644 --- a/app/javascript/dashboard/routes/dashboard/captain/assistants/overview/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/captain/assistants/overview/Index.vue @@ -49,6 +49,11 @@ const resolveTrendGood = (trendValue, direction) => { // :point, and a plain number for :absolute counts like conversation depth. const TREND_SUFFIX = { percent: '%', point: ' pts', absolute: '' }; +// Hours-saved is reported in hours, but large values read better as days. Past +// 100h we switch the unit so the card stays legible. +const formatDuration = hours => + hours >= 100 ? `${Math.round(hours / 24)}d` : `${hours}h`; + const metricFor = (statKey, formatValue, direction, trendKind = 'percent') => { const data = stats.value?.[statKey]; if (!data) return { value: '—', trend: '', trendGood: null }; @@ -84,7 +89,7 @@ const metrics = computed(() => [ key: 'hoursSaved', label: t('CAPTAIN.OVERVIEW.METRICS.HOURS_SAVED.LABEL'), hint: t('CAPTAIN.OVERVIEW.METRICS.HOURS_SAVED.HINT'), - ...metricFor('hours_saved', v => `${v}h`, 'up'), + ...metricFor('hours_saved', formatDuration, 'up'), }, { key: 'reopen', @@ -121,7 +126,7 @@ const metrics = computed(() => [