Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name = "webcompat_diagnosis_lifecycle"
description = "Webcompat Diagnosis Lifecycle"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[from]
title = "From"
type = "date"
value = "2026-01-01"

[to]
title = "To"
type = "date"
value = "2026-04-30"

[metric]
title = "Metric"
type = "enum"
enum_options = [ {% for metric in metrics.values() %} "{{ metric.pretty_name }}", {% endfor %}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name = "Webcompat Bugs - Diagnosis Lifetime Percentiles"
id = 119310
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
WITH
diagnosis_enter AS (
SELECT
history.number,
history.change_time,
changes.added
FROM moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.bugs_history history,
UNNEST (history.changes) as changes
WHERE changes.field_name LIKE '%keywords%'
AND changes.added LIKE'%webcompat:needs_diagnosis%'
ORDER BY history.number
),
diagnosis_exit AS (
SELECT
history.number,
history.change_time,
changes.removed
FROM moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.bugs_history history,
UNNEST (history.changes) as changes
WHERE changes.field_name LIKE '%keywords%'
AND changes.removed LIKE'%webcompat:needs_diagnosis%'
ORDER BY history.number
),
diagnosis_lifetimes AS (
SELECT
site_reports.webcompat_priority,
DATE_DIFF(diagnosis_exit.change_time, diagnosis_enter.change_time, DAY) as lifetime_days
FROM diagnosis_enter diagnosis_enter
JOIN diagnosis_exit diagnosis_exit on diagnosis_enter.number = diagnosis_exit.number
JOIN moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.scored_site_reports site_reports ON site_reports.number = diagnosis_enter.number
WHERE site_reports.webcompat_priority IN ('P1', 'P2', 'P3')
AND DATE(site_reports.creation_time) BETWEEN DATE('{{from}}') AND DATE('{{to}}')
AND
CASE "{{ param("metric") }}" {% for metric in metrics.values() %}
WHEN "{{ metric.pretty_name }}" THEN {{ metric.condition("site_reports") }}
{%- endfor %}
),
stats AS (
SELECT
webcompat_priority,
COUNT(*) as total_bugs,
AVG(lifetime_days) as avg_lifetime,
APPROX_QUANTILES(lifetime_days, 100)[OFFSET(10)] as p10_days,
APPROX_QUANTILES(lifetime_days, 100)[OFFSET(25)] as p25_days,
APPROX_QUANTILES(lifetime_days, 100)[OFFSET(50)] as p50_days,
APPROX_QUANTILES(lifetime_days, 100)[OFFSET(75)] as p75_days,
APPROX_QUANTILES(lifetime_days, 100)[OFFSET(90)] as p90_days,
APPROX_QUANTILES(lifetime_days, 100)[OFFSET(100)] as p100_days
FROM diagnosis_lifetimes
GROUP BY webcompat_priority
),
unpivoted AS (
SELECT
webcompat_priority,
percentile,
resolved_in_days
FROM stats
CROSS JOIN UNNEST([
STRUCT('p10' as percentile, p10_days as resolved_in_days),
STRUCT('p25', p25_days),
STRUCT('p50', p50_days),
STRUCT('p75', p75_days),
STRUCT('p90', p90_days),
STRUCT('p100', p100_days)
])
)

SELECT
percentile,
MAX(CASE WHEN webcompat_priority = 'P1' THEN resolved_in_days END) as P1,
MAX(CASE WHEN webcompat_priority = 'P2' THEN resolved_in_days END) as P2,
MAX(CASE WHEN webcompat_priority = 'P3' THEN resolved_in_days END) as P3
FROM unpivoted
GROUP BY percentile
;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name = "Webcompat - Diagnosis Survival Rate"
id = 119317
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
WITH
diagnosis_enter AS (
SELECT
history.number,
MIN(history.change_time) as enter_time
FROM `moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.bugs_history` history,
UNNEST (history.changes) as changes
WHERE changes.field_name LIKE '%keywords%'
AND changes.added LIKE '%webcompat:needs_diagnosis%'
GROUP BY history.number
),
diagnosis_exit AS (
SELECT
history.number,
MIN(history.change_time) as exit_time
FROM `moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.bugs_history` history,
UNNEST (history.changes) as changes
WHERE changes.field_name LIKE '%keywords%'
AND changes.removed LIKE '%webcompat:needs_diagnosis%'
GROUP BY history.number
),
diagnosis_durations AS (
SELECT
site_reports.webcompat_priority,
diagnosis_enter.number,
diagnosis_enter.enter_time,
diagnosis_exit.exit_time,
TIMESTAMP_DIFF(diagnosis_exit.exit_time, diagnosis_enter.enter_time, SECOND)/(3600*24) as days_in_status
FROM diagnosis_enter
inner JOIN diagnosis_exit ON diagnosis_enter.number = diagnosis_exit.number
JOIN `moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.scored_site_reports` site_reports ON site_reports.number = diagnosis_enter.number
WHERE site_reports.webcompat_priority IN ('P1', 'P2', 'P3')
AND DATE(site_reports.creation_time) BETWEEN DATE('{{from}}') AND DATE('{{to}}')
AND
CASE "{{ param("metric") }}" {% for metric in metrics.values() %}
WHEN "{{ metric.pretty_name }}" THEN {{ metric.condition("site_reports") }}
{%- endfor %}
),
totals AS (
SELECT
webcompat_priority, COUNT(*) as total
FROM diagnosis_durations
GROUP BY webcompat_priority
),
counts AS (
SELECT
day,
COUNTIF(d.webcompat_priority = 'P1' AND d.days_in_status >= day) as open_p1,
COUNTIF(d.webcompat_priority = 'P2' AND d.days_in_status >= day) as open_p2,
COUNTIF(d.webcompat_priority = 'P3' AND d.days_in_status >= day) as open_p3
FROM UNNEST(GENERATE_ARRAY(0, 90)) as day
LEFT JOIN diagnosis_durations d ON TRUE
GROUP BY day
)

SELECT
day,
SAFE_DIVIDE(open_p1, (SELECT total FROM totals WHERE webcompat_priority = 'P1')) as P1,
SAFE_DIVIDE(open_p2, (SELECT total FROM totals WHERE webcompat_priority = 'P2')) as P2,
SAFE_DIVIDE(open_p3, (SELECT total FROM totals WHERE webcompat_priority = 'P3')) as P3
FROM counts
ORDER BY day
;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name = "Webcompat Diagnosis lifetime statistics"
id = 119315
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
WITH
diagnosis_enter AS (
SELECT
bugs_history.number,
MIN(bugs_history.change_time) as change_time
FROM moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.bugs_history bugs_history,
UNNEST (bugs_history.changes) as changes
WHERE changes.field_name LIKE '%keywords%'
AND changes.added LIKE'%webcompat:needs_diagnosis%'
GROUP BY bugs_history.number
),
diagnosis_exit AS (
SELECT
bugs_history.number,
MAX(bugs_history.change_time) as change_time
FROM moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.bugs_history bugs_history,
UNNEST (bugs_history.changes) as changes
WHERE changes.field_name LIKE '%keywords%'
AND changes.removed LIKE'%webcompat:needs_diagnosis%'
GROUP BY bugs_history.number
),
lifetimes AS (
SELECT
site_reports.webcompat_priority as priority,
COUNT(1) as bug_count,
APPROX_QUANTILES(DATETIME_DIFF(diagnosis_exit.change_time, diagnosis_enter.change_time, HOUR)/24, 100)[OFFSET(50)] as median_lifetime,
AVG(DATETIME_DIFF(diagnosis_exit.change_time, diagnosis_enter.change_time, HOUR)/24) as avg_lifetime,
MIN(DATETIME_DIFF(diagnosis_exit.change_time, diagnosis_enter.change_time, HOUR)/24) as min_lifetime,
MAX(DATETIME_DIFF(diagnosis_exit.change_time, diagnosis_enter.change_time, HOUR)/24) as max_lifetime,
FROM diagnosis_enter
JOIN diagnosis_exit ON diagnosis_enter.number = diagnosis_exit.number
JOIN moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.scored_site_reports as site_reports ON site_reports.number = diagnosis_enter.number
WHERE site_reports.webcompat_priority IN ('P1', 'P2', 'P3')
AND DATE(site_reports.creation_time) BETWEEN DATE('{{from}}') AND DATE('{{to}}')
AND
CASE "{{ param("metric") }}" {% for metric in metrics.values() %}
WHEN "{{ metric.pretty_name }}" THEN {{ metric.condition("site_reports") }}
{%- endfor %}
GROUP BY site_reports.webcompat_priority
),
totals AS (
SELECT
site_reports.webcompat_priority as priority,
COUNT(1) as total
FROM `moz-fx-dev-dschubert-wckb.webcompat_knowledge_base.scored_site_reports` site_reports
WHERE site_reports.webcompat_priority IN ('P1', 'P2', 'P3')
AND DATE(site_reports.creation_time) BETWEEN DATE('{{from}}') AND DATE('{{to}}')
AND
CASE "{{ param("metric") }}" {% for metric in metrics.values() %}
WHEN "{{ metric.pretty_name }}" THEN {{ metric.condition("site_reports") }}
{%- endfor %}
GROUP BY priority
)

SELECT
lifetimes.priority as Priority,
totals.total as `Total created`,
lifetimes.bug_count as `Total diagnosed`,
lifetimes.bug_count/total * 100 as Ratio,
lifetimes.median_lifetime as `Median lifetime`,
lifetimes.avg_lifetime as `Average`,
lifetimes.min_lifetime as `Min`,
lifetimes.max_lifetime as `Max`
FROM lifetimes lifetimes
JOIN totals ON lifetimes.priority = totals.priority
ORDER BY priority
;