From c964f53288eef0a761a9aa7e4a64ee2f3dfa10af Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 1 Jul 2026 15:01:26 +0530 Subject: [PATCH] fix: match captain reopens to their resolve event --- .../builders/captain/assistant_stats_builder.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/enterprise/app/builders/captain/assistant_stats_builder.rb b/enterprise/app/builders/captain/assistant_stats_builder.rb index 99980e356..7ccc01977 100644 --- a/enterprise/app/builders/captain/assistant_stats_builder.rb +++ b/enterprise/app/builders/captain/assistant_stats_builder.rb @@ -188,14 +188,16 @@ class Captain::AssistantStatsBuilder def reopen_rate(range) resolved_scope = account.reporting_events.where(name: RESOLVED_EVENT_NAMES, created_at: range, conversation_id: handled_scope(range).select(:conversation_id)) - # event_start_time on a reopen is the preceding resolve's timestamp, so requiring it - # within the window keeps only reopens that followed the in-window resolve, not an - # earlier resolve/reopen cycle on the same conversation. + # event_start_time on a reopen is the preceding resolve's timestamp. Join it to the conversation's + # own Captain resolves and keep only reopens at/after one of them, so a human resolve/reopen + # earlier in the same window isn't mistaken for a reopen-after-Captain-resolve. reopened = account.reporting_events - .where(name: 'conversation_opened', conversation_id: resolved_scope.select(:conversation_id)) + .where(name: 'conversation_opened') .where('reporting_events.value > 0') - .where('reporting_events.event_start_time >= ?', range.first) - .distinct.count(:conversation_id) + .joins("INNER JOIN (#{resolved_scope.to_sql}) resolves " \ + 'ON resolves.conversation_id = reporting_events.conversation_id ' \ + 'AND reporting_events.event_start_time >= resolves.event_end_time') + .distinct.count('reporting_events.conversation_id') rate(reopened, resolved_scope.distinct.count(:conversation_id)) end