hive-sh4re: one saturating_age for every loose-end producer

`age_seconds` is documented on the LooseEnd enum as saturating to zero on
any clock anomaly, but the derivation was in three places: hive-c0re had a
named `saturating_age` helper with tests, and the in-agent socket server
hand-rolled the same two lines twice, untested.

Move the helper to hive-sh4re::inbox, beside the enum whose contract it
implements and inside the one crate both producers already depend on. Its
three tests move with it (not dropped) and gain two arms: the whole-i64
range, where the saturating_sub is what stops the subtraction overflowing,
and a far-past control so those zeros are the clamp firing rather than the
function bottoming out on large inputs.

The two clamps are not redundant, which is what `to_loose_end`'s doc got
wrong: it credited "saturating" for the zero, but saturating_sub bottoms
out at i64::MIN, still negative. The try_from is what yields 0.

Also cover the two projections themselves, which is the part the shared
helper cannot: that a reminder ages from created_at rather than due_at,
and a todo from updated_at, with a future timestamp reading 0 through
both and a past-timestamp control on each.
This commit is contained in:
atlas 2026-09-02 13:47:26 +02:00 committed by mara
commit 1e67f56249
3 changed files with 193 additions and 36 deletions

View file

@ -20,7 +20,7 @@
use anyhow::Result;
use chrono::Utc;
use hive_sh4re::inbox::LooseEnd;
use hive_sh4re::inbox::{LooseEnd, saturating_age};
use crate::coordinator::Coordinator;
@ -93,32 +93,3 @@ pub fn hive_wide(coord: &Coordinator) -> Result<Vec<LooseEnd>> {
}
Ok(out)
}
fn saturating_age(now: i64, then: i64) -> u64 {
let delta = now.saturating_sub(then);
u64::try_from(delta).unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn saturating_age_handles_clock_back_step() {
// `now` < `then`: caller's clock went backwards between rows.
// We saturate to 0 rather than returning a negative or
// wrapping around to ~u64::MAX (which would render as "27
// billion years ago" in the wake prompt).
assert_eq!(saturating_age(100, 200), 0);
}
#[test]
fn saturating_age_normal_case() {
assert_eq!(saturating_age(1_000_000, 999_990), 10);
}
#[test]
fn saturating_age_zero_when_equal() {
assert_eq!(saturating_age(42, 42), 0);
}
}