bootsinthepark · everything up to 2026-08-03 · every figure double-checked
What this meansHow much more often a conversation ends in a better mood than it started — AI alone now, against before Easol. Small on both sides — 3.6% before Easol against 5.7% on AI-only tickets, and the before-Easol side is 20 tickets. Both numbers behind it are in the charts below. Rounding can shift the last decimal. Checked 2026-08-04T12:48:25Z.
Conversations are more likely to end on a better note than they start
AI scores the mood of the first and last message on a −2 to +2 scale. Before Easol, 3.6% of conversations closed on a higher score than they opened on — 20 of 563. On AI-only tickets it is 5.7%, 219 of 3,846. That is 60.3% more often.
AI-only and before-Easol tickets both open at 0.37. They close at 0.39 and 0.31. AI-helped tickets open and close at 0.33.
14.5% of staff-only tickets and 14.7% of AI-helped tickets end higher than they started — but 16.9% and 13.6% end lower. Those threads run 3.9 and 3.4 messages against 2.4 for AI alone, so there is more room for the mood to move either way.
One entry per figure: what it means, the SQL that made it, and when it was last re-checked.
How much more often a conversation ends in a better mood than it started — AI alone now, against before Easol
Small on both sides — 3.6% before Easol against 5.7% on AI-only tickets, and the before-Easol side is 20 tickets
WITH s AS (
SELECT
CASE
WHEN t.imported THEN 'pre_easol'
WHEN t.ai_resolved THEN 'full_ai'
WHEN (t.ai_draft_sent_count > 0 OR t.booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN t.sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS bucket,
sen.opening, sen.closing
FROM reporting.inbox_tickets t
JOIN inbox_ticket_sentiments sen ON sen.ticket_id = t.id
WHERE t.company_id = $1 AND t.created_at < $2
),
rates AS (
SELECT bucket, COUNT(*) FILTER (WHERE closing > opening)::numeric / COUNT(*) AS lift
FROM s GROUP BY bucket
)
SELECT ROUND(100.0 * (
(SELECT lift FROM rates WHERE bucket = 'full_ai')
/ (SELECT lift FROM rates WHERE bucket = 'pre_easol') - 1
), 1) AS value
Source: app/models/inbox/ticket_sentiment.rb:17-18 (opening/closing columns); written at app/workers/inbox/analyze_sentiment_worker.rb:22-23
Verified: 2026-08-04T12:48:25Z
The exact pair behind the headline — share of conversations that end better than they started, AI alone now against before Easol
WITH s AS (
SELECT
CASE
WHEN t.imported THEN 'pre_easol'
WHEN t.ai_resolved THEN 'full_ai'
WHEN (t.ai_draft_sent_count > 0 OR t.booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN t.sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS bucket,
sen.opening, sen.closing
FROM reporting.inbox_tickets t
JOIN inbox_ticket_sentiments sen ON sen.ticket_id = t.id
WHERE t.company_id = $1 AND t.created_at < $2
)
SELECT bucket AS label,
ROUND(100.0 * COUNT(*) FILTER (WHERE closing > opening) / COUNT(*), 1) AS value
FROM s WHERE bucket IN ('full_ai', 'pre_easol')
GROUP BY 1 ORDER BY 1
Source: app/models/inbox/ticket_sentiment.rb:17-18 (Inbox::TicketSentiment opening/closing columns); derived, no dedicated scope
Verified: 2026-08-04T12:48:25Z
Of scored tickets, the share where the closing mood is above the opening mood, split by who handled them
Most conversations never move, so these shares are small on every side. Before Easol this is 20 tickets out of 563
SELECT
CASE
WHEN t.imported THEN 'pre_easol'
WHEN t.ai_resolved THEN 'full_ai'
WHEN (t.ai_draft_sent_count > 0 OR t.booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN t.sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS label,
ROUND(100.0 * COUNT(*) FILTER (WHERE s.closing > s.opening) / COUNT(*), 1) AS value
FROM reporting.inbox_tickets t
JOIN inbox_ticket_sentiments s ON s.ticket_id = t.id
WHERE t.company_id = $1 AND t.created_at < $2
GROUP BY 1 ORDER BY 1
Source: app/models/inbox/ticket_sentiment.rb:17-18 (Inbox::TicketSentiment opening/closing columns); derived, no dedicated scope
Verified: 2026-08-04T12:48:25Z
Average mood of the customer's opening message, on a −2 to +2 scale, split by who handled the ticket
SELECT
CASE
WHEN t.imported THEN 'pre_easol'
WHEN t.ai_resolved THEN 'full_ai'
WHEN (t.ai_draft_sent_count > 0 OR t.booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN t.sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS label,
ROUND(AVG(s.opening)::numeric, 2) AS value
FROM reporting.inbox_tickets t
JOIN inbox_ticket_sentiments s ON s.ticket_id = t.id
WHERE t.company_id = $1 AND t.created_at < $2
GROUP BY 1 ORDER BY 1
Source: app/models/inbox/ticket_sentiment.rb:17 (Inbox::TicketSentiment validates :opening); written at app/workers/inbox/analyze_sentiment_worker.rb:22
Verified: 2026-08-04T12:48:25Z
Average mood at the end of the conversation, on a −2 to +2 scale, split by who handled the ticket
SELECT
CASE
WHEN t.imported THEN 'pre_easol'
WHEN t.ai_resolved THEN 'full_ai'
WHEN (t.ai_draft_sent_count > 0 OR t.booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN t.sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS label,
ROUND(AVG(s.closing)::numeric, 2) AS value
FROM reporting.inbox_tickets t
JOIN inbox_ticket_sentiments s ON s.ticket_id = t.id
WHERE t.company_id = $1 AND t.created_at < $2
GROUP BY 1 ORDER BY 1
Source: app/models/inbox/ticket_sentiment.rb:18 (Inbox::TicketSentiment validates :closing); written at app/workers/inbox/analyze_sentiment_worker.rb:23
Verified: 2026-08-04T12:48:25Z
How many tickets each group has a mood score for. Every happiness figure is a share of these
WITH s AS (
SELECT
CASE
WHEN t.imported THEN 'pre_easol'
WHEN t.ai_resolved THEN 'full_ai'
WHEN (t.ai_draft_sent_count > 0 OR t.booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN t.sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS bucket,
sen.inferred_satisfaction
FROM reporting.inbox_tickets t
JOIN inbox_ticket_sentiments sen ON sen.ticket_id = t.id
WHERE t.company_id = $1 AND t.created_at < $2
)
SELECT bucket AS label, COUNT(*) AS value
FROM s
GROUP BY 1 ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb
Verified: 2026-08-04T12:48:25Z