From dd578033f99a13af17676efb97bb2701ea4dabf9 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 10:19:40 +0000 Subject: [PATCH] fix(pm): render hour-scale durations in hours, so --report's calendar figures need no division `human_s` had a minute branch and nothing above it, so every duration past an hour printed in minutes. On the live `--report` that meant a span of `504m05s` and a floor age of `514m01s` -- 8h24m and 8h34m, on the two figures a reader compares against a DATE ("does this population cover my hold from the 26th?"). The report is otherwise careful to hand over arithmetic rather than leave it on the page; the arrival-depth block spells out `waiters already ahead = this minus 1` for exactly that reason. This makes the duration formatter match that standard. Presentation only. The exact second count is still printed first in every branch, so no reading here is the only copy of the number. The threshold is 3600 and the sub-hour text is untouched, which keeps the long-hold warning at `900s (15m00s)` -- it reads correctly at minute scale and pulling the hour branch below an hour would make it worse. That is pinned. Self-test: 186 -> 195 cases, all passing; no pre-existing pin moved. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw --- scripts/pm/os-verify-lock.sh | 66 +++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/scripts/pm/os-verify-lock.sh b/scripts/pm/os-verify-lock.sh index d1efb66149..0e5796aefc 100755 --- a/scripts/pm/os-verify-lock.sh +++ b/scripts/pm/os-verify-lock.sh @@ -802,9 +802,38 @@ open_file_pids() { printf 'unknown' } +# Seconds → the same seconds, plus a scaled reading a human can hold. The +# scaled part is a CONVENIENCE and the `%ss` prefix is the fact: every branch +# prints the exact second count first, so no reading here is ever the only +# copy of the number. +# +# ⚠ THE HOUR BRANCH IS NOT COSMETIC SUGAR ON THE MINUTE ONE. Two of this +# script's call sites -- `--report`'s span and the floor it reaches back to -- +# are CALENDAR-scale figures, and the question a reader brings to them ("does +# this population cover my hold from the 26th?") is answered by comparing +# against a date. Rendered minute-only, an 8h24m window prints `504m05s` and +# the reader has to divide before they can compare. The report elsewhere +# refuses to leave arithmetic on the page -- the arrival-depth block spells out +# `⇒ waiters already ahead = this minus 1` for exactly this reason -- so +# leaving a division here was the odd one out. +# +# ⛔ The 3600 threshold is deliberate and the sub-hour text is deliberately +# UNTOUCHED: the long-hold warning fires at 900s and `900s (15m00s)` reads +# correctly at minute scale. Widening the hour branch downward would "unify" +# the formats and make that warning worse. +# +# ⛔ bash 3.2 floor: plain arithmetic and `printf` only. In particular the +# minute term is `s % 3600 / 60`, NOT `s / 60` -- the latter is the natural +# typo and it prints 3661s as `1h61m01s`, a well-formed string that is wrong. human_s() { local s="$1" - if ((s >= 60)); then printf '%ss (%dm%02ds)' "$s" $((s / 60)) $((s % 60)); else printf '%ss' "$s"; fi + if ((s >= 3600)); then + printf '%ss (%dh%02dm%02ds)' "$s" $((s / 3600)) $((s % 3600 / 60)) $((s % 60)) + elif ((s >= 60)); then + printf '%ss (%dm%02ds)' "$s" $((s / 60)) $((s % 60)) + else + printf '%ss' "$s" + fi } # Epoch seconds → a UTC instant a reader can compare against a dated report, or @@ -2838,6 +2867,41 @@ mode_self_test() { st_case 'and the fleet-scale heading is gone, not merely annotated' \ "$(printf '%s\n' "$rpt" | grep -c 'this is where hold time actually goes')" 0 + # `human_s`, which supplies the AGE in that floor line and the width in the + # `spanning` line above it. Fixed inputs to fixed strings, for the same + # reason `utc_stamp` is pinned that way just below: the failure here is not + # an error, it is a well-formed duration carrying the wrong reading, and only + # a fixed expected value separates those. + st_case 'human_s leaves a sub-minute duration as bare seconds' \ + "$(human_s 45)" '45s' + st_case 'and renders a minute-scale duration in minutes, as it always did' \ + "$(human_s 754)" '754s (12m34s)' + # ⛔ Pinned because it must NOT move: the long-hold warning fires at 900s and + # reads correctly at minute scale. A future "unification" that pulls the hour + # branch below an hour would make that warning worse, not better. + st_case 'and leaves the 900s long-hold scale reading in minutes' \ + "$(human_s 900)" '900s (15m00s)' + st_case 'and keeps the last sub-hour second in minutes, not hours' \ + "$(human_s 3599)" '3599s (59m59s)' + st_case 'and switches to hours at exactly one hour' \ + "$(human_s 3600)" '3600s (1h00m00s)' + # ⛔ THE LOAD-BEARING CASE. Writing the minute term as `s / 60` instead of + # `s % 3600 / 60` renders this as `1h61m01s` -- well-formed, wrong, and + # invisible to any case that merely checks an `h` appeared. + st_case 'and carries minutes WITHIN the hour, not minutes since zero' \ + "$(human_s 3661)" '3661s (1h01m01s)' + # The two figures this card was filed over, read from a live --report. + st_case 'and renders the reported span as hours rather than 504 minutes' \ + "$(human_s 30245)" '30245s (8h24m05s)' + st_case 'and the population floor age beside it, rather than 514 minutes' \ + "$(human_s 30841)" '30841s (8h34m01s)' + # The scaled reading is a convenience; the second count is the fact. This + # asserts the fact survived in every branch, which is what lets the scaled + # part be approximate-looking without any information being lost. + st_case 'and prints the exact second count in every branch, hours included' \ + "$(human_s 45; printf ' '; human_s 754; printf ' '; human_s 30245)" \ + '45s 754s (12m34s) 30245s (8h24m05s)' + # `utc_stamp`, which supplies the instant in that floor. A KNOWN epoch mapped # to a KNOWN string, because the failure mode here is not an error: it is a # well-formed string for the wrong instant (see the helper's own comment), and