bootsinthepark · everything up to 2026-08-03 · every figure double-checked
What this meansCut in the typical time to close a ticket — AI alone now, against the old email threads from before Easol. Both numbers behind it are in the charts below. Rounding can shift the last decimal. Checked 2026-08-03T16:10:59Z.
AI closes tickets in hours, not days
Half of AI-only tickets close within 8.3 hours. Before Easol the middle ticket took 144.6 hours. That is 94.2% off.
3,831 AI-only tickets and 571 from before Easol have a close time. Averages say the same thing: 26.6 hours against 285.2.
Staff-only tickets get a first reply slightly sooner: 6.6 hours, against 7.6 for AI alone and 6.8 when AI helped. All far below the 100.5 hours before Easol.
The weekly lines are not flat. AI-only first replies sat between 1.6 and 9.7 hours from late February to late April, then peaked at 144.6 hours in the week of 22 June, with time to close peaking at 166.0 hours the same week. Staff-only tickets peaked too, at 81.3 hours in the week of 6 July. Festival season filled the inbox; this is not an AI problem. Even the worst week sits inside the 97.6 to 170.2 hour range that was normal before Easol.
Middle time each week, by the week a ticket came in. Quiet weeks (under 10 tickets) are left out. Before and after cover different months, so they are two charts on two scales, not one line.
Middle time each week, by the week a ticket came in. Quiet weeks (under 10 tickets) are left out. Before and after cover different months, so they are two charts on two scales, not one line.
One entry per figure: what it means, the SQL that made it, and when it was last re-checked.
Cut in the typical time to close a ticket — AI alone now, against the old email threads from before Easol
WITH r AS (
SELECT
CASE
WHEN imported THEN 'pre_easol'
WHEN ai_resolved THEN 'full_ai'
WHEN (ai_draft_sent_count > 0 OR booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS bucket,
resolution_time_seconds
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND resolution_time_seconds IS NOT NULL
)
SELECT ROUND((100.0 * (1 -
(SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY resolution_time_seconds) FROM r WHERE bucket = 'full_ai')
/ (SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY resolution_time_seconds) FROM r WHERE bucket = 'pre_easol')
))::numeric, 1) AS value
Source: app/models/reporting/inbox/ticket.rb:148 (Reporting::Inbox::Ticket::AttributesBuilder#resolution_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's time from first message to close, split by who handled them
Both clocks start at the first message. Easol tickets stop when marked resolved; old imported threads stop at the last email out, so a long email chain reads as one slow ticket
SELECT
CASE
WHEN imported THEN 'pre_easol'
WHEN ai_resolved THEN 'full_ai'
WHEN (ai_draft_sent_count > 0 OR booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY resolution_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND resolution_time_seconds IS NOT NULL
GROUP BY 1 ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:148 (Reporting::Inbox::Ticket::AttributesBuilder#resolution_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's wait from the customer's message to the first reply, split by who handled them
SELECT
CASE
WHEN imported THEN 'pre_easol'
WHEN ai_resolved THEN 'full_ai'
WHEN (ai_draft_sent_count > 0 OR booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY first_response_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND first_response_time_seconds IS NOT NULL
GROUP BY 1 ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:142 (Reporting::Inbox::Ticket::AttributesBuilder#first_response_time_seconds)
Verified: 2026-08-03T16:10:59Z
Mean time from first message to close, split by who handled them
A few old threads that sat open for months drag this up, which is why the claims use the middle ticket instead
SELECT
CASE
WHEN imported THEN 'pre_easol'
WHEN ai_resolved THEN 'full_ai'
WHEN (ai_draft_sent_count > 0 OR booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS label,
ROUND((AVG(resolution_time_seconds)/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND resolution_time_seconds IS NOT NULL
GROUP BY 1 ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:148 (Reporting::Inbox::Ticket::AttributesBuilder#resolution_time_seconds)
Verified: 2026-08-03T16:10:59Z
Tickets we can time from open to close, split by who handled them
SELECT
CASE
WHEN imported THEN 'pre_easol'
WHEN ai_resolved THEN 'full_ai'
WHEN (ai_draft_sent_count > 0 OR booking_action_performed_by_ai_count > 0) THEN 'partial_ai'
WHEN sent_message_count > 0 THEN 'no_ai'
ELSE 'no_reply'
END AS label,
COUNT(resolution_time_seconds) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2
GROUP BY 1 ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:148 (Reporting::Inbox::Ticket::AttributesBuilder#resolution_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's first reply for each week's tickets, before easol only. Weeks with under 10 tickets are left out so a handful cannot swing the line
Weeks are labelled by their Monday, and a ticket counts in the week it arrived
SELECT
DATE_TRUNC('week', created_at)::date::text AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY first_response_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND first_response_time_seconds IS NOT NULL
AND (imported)
GROUP BY 1
HAVING COUNT(*) >= 10
ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:142 (Reporting::Inbox::Ticket::AttributesBuilder#first_response_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's time to close for each week's tickets, before easol only. Weeks with under 10 tickets are left out so a handful cannot swing the line
Weeks are labelled by their Monday, and a ticket counts in the week it arrived
SELECT
DATE_TRUNC('week', created_at)::date::text AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY resolution_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND resolution_time_seconds IS NOT NULL
AND (imported)
GROUP BY 1
HAVING COUNT(*) >= 10
ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:148 (Reporting::Inbox::Ticket::AttributesBuilder#resolution_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's first reply for each week's tickets, ai alone only. Weeks with under 10 tickets are left out so a handful cannot swing the line
Weeks are labelled by their Monday, and a ticket counts in the week it arrived
SELECT
DATE_TRUNC('week', created_at)::date::text AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY first_response_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND first_response_time_seconds IS NOT NULL
AND (NOT imported AND ai_resolved)
GROUP BY 1
HAVING COUNT(*) >= 10
ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:142 (Reporting::Inbox::Ticket::AttributesBuilder#first_response_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's time to close for each week's tickets, ai alone only. Weeks with under 10 tickets are left out so a handful cannot swing the line
Weeks are labelled by their Monday, and a ticket counts in the week it arrived
SELECT
DATE_TRUNC('week', created_at)::date::text AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY resolution_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND resolution_time_seconds IS NOT NULL
AND (NOT imported AND ai_resolved)
GROUP BY 1
HAVING COUNT(*) >= 10
ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:148 (Reporting::Inbox::Ticket::AttributesBuilder#resolution_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's first reply for each week's tickets, ai helped only. Weeks with under 10 tickets are left out so a handful cannot swing the line
Weeks are labelled by their Monday, and a ticket counts in the week it arrived
SELECT
DATE_TRUNC('week', created_at)::date::text AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY first_response_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND first_response_time_seconds IS NOT NULL
AND (NOT imported AND NOT ai_resolved AND (ai_draft_sent_count > 0 OR booking_action_performed_by_ai_count > 0))
GROUP BY 1
HAVING COUNT(*) >= 10
ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:142 (Reporting::Inbox::Ticket::AttributesBuilder#first_response_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's time to close for each week's tickets, ai helped only. Weeks with under 10 tickets are left out so a handful cannot swing the line
Weeks are labelled by their Monday, and a ticket counts in the week it arrived
SELECT
DATE_TRUNC('week', created_at)::date::text AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY resolution_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND resolution_time_seconds IS NOT NULL
AND (NOT imported AND NOT ai_resolved AND (ai_draft_sent_count > 0 OR booking_action_performed_by_ai_count > 0))
GROUP BY 1
HAVING COUNT(*) >= 10
ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:148 (Reporting::Inbox::Ticket::AttributesBuilder#resolution_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's first reply for each week's tickets, staff only only. Weeks with under 10 tickets are left out so a handful cannot swing the line
Weeks are labelled by their Monday, and a ticket counts in the week it arrived
SELECT
DATE_TRUNC('week', created_at)::date::text AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY first_response_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND first_response_time_seconds IS NOT NULL
AND (NOT imported AND NOT ai_resolved AND ai_draft_sent_count = 0 AND booking_action_performed_by_ai_count = 0 AND sent_message_count > 0)
GROUP BY 1
HAVING COUNT(*) >= 10
ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:142 (Reporting::Inbox::Ticket::AttributesBuilder#first_response_time_seconds)
Verified: 2026-08-03T16:10:59Z
The middle ticket's time to close for each week's tickets, staff only only. Weeks with under 10 tickets are left out so a handful cannot swing the line
Weeks are labelled by their Monday, and a ticket counts in the week it arrived
SELECT
DATE_TRUNC('week', created_at)::date::text AS label,
ROUND(((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY resolution_time_seconds))/3600.0)::numeric, 1) AS value
FROM reporting.inbox_tickets
WHERE company_id = $1 AND created_at < $2 AND resolution_time_seconds IS NOT NULL
AND (NOT imported AND NOT ai_resolved AND ai_draft_sent_count = 0 AND booking_action_performed_by_ai_count = 0 AND sent_message_count > 0)
GROUP BY 1
HAVING COUNT(*) >= 10
ORDER BY 1
Source: app/models/reporting/inbox/ticket.rb:148 (Reporting::Inbox::Ticket::AttributesBuilder#resolution_time_seconds)
Verified: 2026-08-03T16:10:59Z