From a3d46e5f1c992f61f3c55bd3768db6587558d414 Mon Sep 17 00:00:00 2001 From: Lewis Buckley Date: Wed, 1 Jul 2026 15:10:08 +0100 Subject: [PATCH] Show uptime to three decimals; never round an outage up to 100% MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A service's overall uptime was averaged and shown as "%.2f", so a real outage too small to register at two decimals (e.g. a 1-minute blip over 90 days ≈ 99.99923%) displayed as "100.00%" — contradicting the degraded day in its own bar chart. Show three decimals and floor rather than round, so any real downtime reads as 99.999% while a flawless window still shows a bare "100%". Co-Authored-By: Claude Opus 4.8 (1M context) --- app/helpers/upright/public/services_helper.rb | 7 ++++-- .../upright/public/services/_service.html.erb | 5 ++-- .../upright/public/services_helper_test.rb | 25 +++++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 test/helpers/upright/public/services_helper_test.rb diff --git a/app/helpers/upright/public/services_helper.rb b/app/helpers/upright/public/services_helper.rb index 26f2460..3fc8279 100644 --- a/app/helpers/upright/public/services_helper.rb +++ b/app/helpers/upright/public/services_helper.rb @@ -29,9 +29,12 @@ def feed_item_guid(issue) [ issue[:service].code, issue[:started_at]&.to_i ].compact.join("-") end - def average_uptime_percentage(fractions) + def uptime_percentage_label(fractions) if fractions.present? - (fractions.sum.to_f / fractions.size) * 100 + percentage = fractions.sum.fdiv(fractions.size) * 100 + # Round down so a real outage never reads as 100%; strip zeros so a + # flawless window is a bare "100%", not "100.000%". + number_to_percentage(percentage, precision: 3, round_mode: :down, strip_insignificant_zeros: true) end end end diff --git a/app/views/upright/public/services/_service.html.erb b/app/views/upright/public/services/_service.html.erb index 24abffc..37f7fef 100644 --- a/app/views/upright/public/services/_service.html.erb +++ b/app/views/upright/public/services/_service.html.erb @@ -1,5 +1,4 @@ <% today_status = history.last.status %> -<% avg = average_uptime_percentage(history.map(&:uptime_fraction).compact) %>
@@ -20,8 +19,8 @@
<%= history.size %> days ago - <% if avg %> - <%= '%.2f' % avg %>% uptime + <% if uptime = uptime_percentage_label(history.map(&:uptime_fraction).compact) %> + <%= uptime %> uptime <% else %> No data yet <% end %> diff --git a/test/helpers/upright/public/services_helper_test.rb b/test/helpers/upright/public/services_helper_test.rb new file mode 100644 index 0000000..5890ac3 --- /dev/null +++ b/test/helpers/upright/public/services_helper_test.rb @@ -0,0 +1,25 @@ +require "test_helper" + +class Upright::Public::ServicesHelperTest < ActionView::TestCase + test "no data yields nil" do + assert_nil uptime_percentage_label([]) + end + + test "a flawless window reads as a bare 100%" do + assert_equal "100%", uptime_percentage_label([ 1.0, 1.0, 1.0 ]) + end + + test "a tiny outage never rounds up to 100%" do + # One 1-minute outage over 90 days ≈ 99.99923% — must not display as 100%. + fractions = [ 1.0 - 1.0 / 1440 ] + Array.new(89, 1.0) + assert_equal "99.999%", uptime_percentage_label(fractions) + end + + test "trailing zeros are trimmed" do + assert_equal "99.5%", uptime_percentage_label([ 0.995 ]) + end + + test "floors rather than rounds to three decimals" do + assert_equal "99.999%", uptime_percentage_label([ 0.9999995 ]) + end +end