Functional Weave
Code in Rust

monitor.uptime-bars

One bar per UTC day for a status page's uptime history: seconds in each state, uptime and a colour state, oldest first.

1.0.0 · published 2026-10-03 by charlie · Anterra

Pinned by 17 tests, run in TypeScript, Python and Rust.

What it does

The row of daily bars under each component on a status page ("90 days ago ... today"): one `DayBar` per UTC day, oldest first, each with the seconds up, degraded, down and unknown, the day's uptime in basis points and a state to colour it by.

Each day is measured by `monitor.uptime` over that day's window, with the same `maxGapSeconds` rule: a check's status holds until the next check, for at most `maxGapSeconds`, and the latest check before midnight carries into the day. So an outage that crosses midnight shows on both days.

For example

  • uptime_bars(checks ×1, 1,728,003,600, 3, 259,200) → ×3 three days of up: two full days and today up to now
  • uptime_bars(checks ×5, 1,728,007,200, 3, 86,400) → ×3 an hour down shows an outage bar at 95.83%, a slow hour a degraded bar at 100%
  • uptime_bars(, 1,728,000,100, 2, 60) → ×2 days with no checks are no-data bars, not operational ones

The function

The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.

pub fn uptime_bars(checks: &[Check], now: i64, days: i64, max_gap_seconds: i64) -> Vec<DayBar>
checksCheck[]in strictly ascending time order
nowintUnix seconds; today's bar ends here, not at midnight
daysinthow many UTC days ending with today, 1 to 366 (90 is the usual status page)
max_gap_secondsinthow long one check's status is trusted before time counts as unknown, as in monitor.uptime
returnsDayBar[]oldest day first

The types it declares, generated into your project

// BarState is a string in Rust, one of: "operational", "degraded", "outage", "no-data".
// Parameters take it as &str and results hold it as String.

/// One UTC day of a status page's uptime history.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DayBar {
    pub date: String,
    /// null when nothing that day is known
    pub uptime_basis_points: Option<i64>,
    pub up_seconds: i64,
    pub degraded_seconds: i64,
    pub down_seconds: i64,
    pub unknown_seconds: i64,
    /// outage if any down second, else degraded if any degraded, else operational; no-data when nothing is known
    pub state: String,
}

Your code names it in one line, in the file that uses it

fune!(monitor.uptime-bars@^1);  // then call uptime_bars(…)
impl/rust.rs · 74 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::monitor_check_status::{checks_from_value, Check};  ← from monitor.check-status ^1.0.0 · built alongside by fune
use super::monitor_uptime::uptime;  ← from monitor.uptime ^1.0.0 · built alongside by fune
use super::time_unix_to_iso::unix_to_iso;  ← from time.unix-to-iso ^1.0.0 · built alongside by fune

const DAY: i64 = 86400;

/// The last `days` UTC days ending with today, oldest first, each measured by
/// monitor.uptime. Today's bar ends at `now`, so it never shows the rest of
/// today as unknown.
///
/// # Panics
/// Panics when days is outside 1..=366, and on anything monitor.uptime refuses.
pub fn uptime_bars(checks: &[Check], now: i64, days: i64, max_gap_seconds: i64) -> Vec<DayBar> {
    if !(1..=366).contains(&days) {
        panic!("days must be 1 to 366, received {}", days);
    }
    // Floored, not truncated: before 1970 today starts on the earlier midnight.
    let today_start = now - now.rem_euclid(DAY);
    let mut bars = Vec::new();
    for i in (0..days).rev() {
        let start = today_start - i * DAY;
        let end = if i == 0 { now } else { start + DAY };
        let r = uptime(checks, start, end, max_gap_seconds);
        let state = if r.uptime_basis_points.is_none() {
            "no-data"
        } else if r.down_seconds > 0 {
            "outage"
        } else if r.degraded_seconds > 0 {
            "degraded"
        } else {
            "operational"
        };
        bars.push(DayBar {
            date: unix_to_iso(start)[..10].to_string(),
            uptime_basis_points: r.uptime_basis_points,
            up_seconds: r.up_seconds,
            degraded_seconds: r.degraded_seconds,
            down_seconds: r.down_seconds,
            unknown_seconds: r.unknown_seconds,
            state: state.to_string(),
        });
    }
    bars
}

pub fn day_bar_to_value(b: &DayBar) -> Value {
    Value::obj(vec![
        ("date", Value::str(&b.date)),
        ("uptimeBasisPoints", b.uptime_basis_points.map(Value::Int).unwrap_or(Value::Null)),
        ("upSeconds", Value::Int(b.up_seconds)),
        ("degradedSeconds", Value::Int(b.degraded_seconds)),
        ("downSeconds", Value::Int(b.down_seconds)),
        ("unknownSeconds", Value::Int(b.unknown_seconds)),
        ("state", Value::str(&b.state)),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    let checks = checks_from_value(&args[0]);
    let now = match &args[1] {
        Value::Int(i) => *i,
        _ => panic!("now must be whole seconds"),
    };
    let days = match &args[2] {
        Value::Int(i) => *i,
        other => panic!("days must be 1 to 366, received {}", other),
    };
    let gap = match &args[3] {
        Value::Int(i) => *i,
        other => panic!("maxGapSeconds must be a whole number of at least 1, received {}", other),
    };
    Value::Arr(uptime_bars(&checks, now, days, gap).iter().map(day_bar_to_value).collect())
}

Install

fune build

With that line in your source, in a Rust project (language rust in fune.project), fune build resolves it and its 3 dependencies, pins them in fune.lock, downloads only the Rust package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. A crate’s build.rs runs it before every compile. Or pin a range in fune.project and build in one step:

fune add monitor.uptime-bars
Download for Rust monitor.uptime-bars-1.0.0-rust.fune · 13,847 bytes sha256 50d0be3e43776694e80ce1d1f3eb855f9d526ed3a72e0054ba9c8d682078f061

The manifest, vectors and README with only the Rust implementation. Install it without the registry with fune add ./monitor.uptime-bars-1.0.0-rust.fune, or fetch it from a terminal with fune pull monitor.uptime-bars@1.0.0:rust.

The whole function, every language, is one file too: monitor.uptime-bars-1.0.0.fune, 17,393 bytes, sha256 acd1ac7feb44a8df71bcace52d4de9ffefbaaa76498627388340399962540227. It installs into a project of any language.

Customise it in your app

The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.

before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.

// fune: before monitor.uptime-bars

after — your function gets the result and the arguments, and returns the final result.

// fune: after monitor.uptime-bars

replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.

// fune: replace monitor.check-status in monitor.uptime-bars
// fune: replace monitor.uptime in monitor.uptime-bars
// fune: replace time.unix-to-iso in monitor.uptime-bars

step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show monitor.uptime-bars --steps.

// fune: step monitor.uptime-bars after <n|label>

Tests

A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.

CaseArgumentsExpected
three days of up: two full days and today up to now checks ×1, 1,728,003,600, 3, 259,200 → ×3
an hour down shows an outage bar at 95.83%, a slow hour a degraded bar at 100% checks ×5, 1,728,007,200, 3, 86,400 → ×3
days with no checks are no-data bars, not operational ones , 1,728,000,100, 2, 60 → ×2
at exactly midnight today's bar is empty and no-data checks ×1, 1,728,000,000, 2, 86,400 → ×2
one day: a check from before midnight carries into today checks ×2, 1,728,000,120, 1, 300 → ×1
unknown time alone does not make a bar degraded checks ×1, 1,728,001,000, 1, 600 → ×1
before 1970 the day is floored, so today starts at the earlier midnight checks ×1, -1, 2, 200,000 → ×2
down outranks degraded on the same day; uptime floors 2/3 to 6666 checks ×3, 1,728,000,300, 1, 100 → ×1
checks after now are ignored checks ×2, 1,728,000,100, 1, 1,000 → ×1
a down check at 23:59:59 marks only that day checks ×2, 1,728,000,010, 2, 60 → ×2
Show the other 7 tests
CaseArgumentsExpected
zero days is an error , 1,728,000,000, 0, 60 → error: days must be 1 to 366, received 0
more than 366 days is an error , 1,728,000,000, 367, 60 → error: days must be 1 to 366, received 367
a fractional day count is an error , 1,728,000,000, 1.5, 60 → error: days must be 1 to 366, received 1.5
a fractional now is an error , 0.5, 1, 60 → error: now must be whole seconds
a maxGapSeconds of zero is an error , 1,728,000,000, 1, 0 → error: maxGapSeconds must be a whole number of at least 1, received 0
misordered checks are an error checks ×2, 1,728,000,010, 1, 60 → error: checks must be in strictly ascending time order: 1727999995 follows 1728000000
an unknown status is an error checks ×1, 1,728,000,010, 1, 60 → error: unknown check status: offline

More from the author

## Days

- Days are UTC calendar days, `date` is `YYYY-MM-DD`. Status pages that show local days shift `now` first. - The last bar is today, and it ends at `now`, not midnight, so the part of today that has not happened yet is not reported as unknown. At exactly midnight today's bar is empty (`no-data`). - Midnight is found by flooring, so a `now` before 1970 still lands on the right day (`-1` is 1969-12-31). - Checks after `now` are ignored. - `days` is 1 to 366; 90 is the usual status page.

## State

In order: `no-data` when nothing that day is known; `outage` if any second was down; `degraded` if any second was degraded; otherwise `operational`. Unknown time alone does not change the colour of a day that has some known time: a monitor gap is not an outage. The worst moment decides, the way status pages colour their bars; the uptime figure says how bad the day was.

## Errors

- `now must be whole seconds` - `days must be 1 to 366, received X` - Everything `monitor.uptime` refuses: `maxGapSeconds must be a whole number of at least 1`, `checks must be in strictly ascending time order`, `unknown check status: X`.

Files

PathBytes
README.md1,701
impl/python.py1,761
impl/rust.rs2,745
impl/typescript.ts1,628
vectors.json5,686