+60.3% more conversations end happier than they started, against before Easol

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

3.6% before Easol, 5.7% with AI alone

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.

They start in the same place and close higher

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.

Longer tickets move more in both directions

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.

Worth knowing
  • The before-Easol side is 20 tickets out of 563. This claim rests on a smaller base than the sour-endings one and is the weaker of the two.
  • Roughly nine in ten conversations end on the exact score they opened on, so both sides are small shares.
  • Different tickets in different months, not a controlled test.
  • Mood is read by AI from the conversation, not asked in a survey.
  • Imported before-Easol threads were never scored at the −2 or +2 extremes; Easol tickets sometimes are.
Before Easol On Easol

Happier endings: AI alone vs before Easol

Before Easol 3.6% AI alone 5.7%

Share ending better than they started

Before Easol 3.6% Staff only 14.5% AI helped 14.7% AI alone 5.7%

Mood at the start

Before Easol 0.37 Staff only 0.29 AI helped 0.33 AI alone 0.37

Mood at the end

Before Easol 0.31 Staff only 0.25 AI helped 0.33 AI alone 0.39

Scored tickets by who handled them

Before Easol 563 Staff only 1,007 AI helped 1,319 AI alone 3,846

Where the numbers come from

One entry per figure: what it means, the SQL that made it, and when it was last re-checked.

More conversations end happier than they started mood_lift_uplift_vs_pre_easol_pct

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

Happier endings: AI alone vs before Easol mood_improved_pct_full_ai_vs_pre_easol

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

Share ending better than they started mood_improved_pct_by_bucket

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

Mood at the start avg_opening_sentiment_by_bucket

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

Mood at the end avg_closing_sentiment_by_bucket

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

Scored tickets by who handled them sentiment_scored_tickets_by_bucket

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