diff --git a/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/meta.toml b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/meta.toml new file mode 100644 index 00000000..fc00b66d --- /dev/null +++ b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/meta.toml @@ -0,0 +1,2 @@ +name = "webcompat_diagnosis_lifecycle" +description = "Webcompat Diagnosis Lifecycle" diff --git a/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/parameters.toml b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/parameters.toml new file mode 100644 index 00000000..ed820a31 --- /dev/null +++ b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/parameters.toml @@ -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 %}] \ No newline at end of file diff --git a/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_lifetime_percentiles/meta.toml b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_lifetime_percentiles/meta.toml new file mode 100644 index 00000000..9e3bb3f2 --- /dev/null +++ b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_lifetime_percentiles/meta.toml @@ -0,0 +1,2 @@ +name = "Webcompat Bugs - Diagnosis Lifetime Percentiles" +id = 119310 \ No newline at end of file diff --git a/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_lifetime_percentiles/query.sql b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_lifetime_percentiles/query.sql new file mode 100644 index 00000000..6f154416 --- /dev/null +++ b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_lifetime_percentiles/query.sql @@ -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 +; diff --git a/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_survival/meta.toml b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_survival/meta.toml new file mode 100644 index 00000000..2e39071f --- /dev/null +++ b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_survival/meta.toml @@ -0,0 +1,2 @@ +name = "Webcompat - Diagnosis Survival Rate" +id = 119317 \ No newline at end of file diff --git a/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_survival/query.sql b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_survival/query.sql new file mode 100644 index 00000000..0a3a0a96 --- /dev/null +++ b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_bugs_diagnosis_survival/query.sql @@ -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 +; diff --git a/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_diagnosis_lifetime_statistics/meta.toml b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_diagnosis_lifetime_statistics/meta.toml new file mode 100644 index 00000000..59f1822d --- /dev/null +++ b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_diagnosis_lifetime_statistics/meta.toml @@ -0,0 +1,2 @@ +name = "Webcompat Diagnosis lifetime statistics" +id = 119315 \ No newline at end of file diff --git a/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_diagnosis_lifetime_statistics/query.sql b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_diagnosis_lifetime_statistics/query.sql new file mode 100644 index 00000000..fd3cc361 --- /dev/null +++ b/jobs/webcompat-kb/data/redash/webcompat_diagnosis_lifetime/webcompat_diagnosis_lifetime_statistics/query.sql @@ -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 +; \ No newline at end of file