monitor.status-page
The overall state, headline and affected components at the top of a status page, from each component's state.
1.0.0 · published 2026-10-03 by charlie · Anterra
Pinned by 14 tests, run in TypeScript, Python and Rust.
What it does
The banner at the top of a status page: one overall state, a headline, and the components that are not operational. Each component's state comes from `monitor.component-state` (Atlassian Statuspage's vocabulary).
## Worst wins
For example
status_page(components ×2)→ state operational, headline All systems operational, affected every component operational is all systems operationalstatus_page(components ×2)→ state degraded, headline Degraded performance, affected Search one degraded component makes the page degraded and names itstatus_page(components ×3)→ state partial-outage, headline Partial outage, affected Search, API a partial outage beats degraded; affected keeps input order
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 status_page(components: &[Component]) -> StatusSummary
| components | Component[] | every component on the page, at least one, names unique |
| returns | StatusSummary |
The types it declares, generated into your project
/// One row of a status page.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Component {
pub name: String,
pub state: String,
}
/// The banner at the top of the page.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StatusSummary {
/// the worst component state
pub state: String,
/// "All systems operational", "Degraded performance", "Partial outage", "Major outage" or "Scheduled maintenance"
pub headline: String,
/// names of the components not operational, in input order
pub affected: Vec<String>,
}
Your code names it in one line, in the file that uses it
fune!(monitor.status-page@^1); // then call status_page(…)
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
// Worst last. Maintenance ranks below every real problem: an outage elsewhere
// during planned work is still the headline.
const RANK: [&str; 5] = ["operational", "maintenance", "degraded", "partial-outage", "major-outage"];
const HEADLINE: [&str; 5] = [
"All systems operational",
"Scheduled maintenance",
"Degraded performance",
"Partial outage",
"Major outage",
];
/// The banner for a whole status page: the worst component state wins.
///
/// # Panics
/// Panics on no components, an empty or duplicate name, or an unknown state.
pub fn status_page(components: &[Component]) -> StatusSummary {
if components.is_empty() {
panic!("components must not be empty");
}
let mut seen: Vec<&str> = Vec::new();
let mut worst = 0usize;
let mut affected: Vec<String> = Vec::new();
for c in components {
if c.name.is_empty() {
panic!("component name must not be empty");
}
if seen.contains(&c.name.as_str()) {
panic!("duplicate component name: {}", c.name);
}
seen.push(&c.name);
let rank = match RANK.iter().position(|r| *r == c.state) {
Some(r) => r,
None => panic!("unknown component state: {}", c.state),
};
if rank > worst {
worst = rank;
}
if rank > 0 {
affected.push(c.name.clone());
}
}
StatusSummary {
state: RANK[worst].to_string(),
headline: HEADLINE[worst].to_string(),
affected,
}
}
/// A `Component` from its JSON form, for adapters of capabilities built on this one.
pub fn component_from_value(v: &Value) -> Component {
Component { name: v.get("name").as_str().to_string(), state: v.get("state").as_str().to_string() }
}
pub fn status_summary_to_value(s: &StatusSummary) -> Value {
Value::obj(vec![
("state", Value::str(&s.state)),
("headline", Value::str(&s.headline)),
("affected", Value::Arr(s.affected.iter().map(|a| Value::str(a)).collect())),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
let components: Vec<Component> = args[0].as_arr().iter().map(component_from_value).collect();
status_summary_to_value(&status_page(&components))
}Install
fune build
With that line in your source, in a Rust project (language rust in fune.project), fune build resolves it and its 1 dependency, 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.status-page
The manifest, vectors and README with only the Rust implementation. Install it without the registry with fune add ./monitor.status-page-1.0.0-rust.fune, or fetch it from a terminal with fune pull monitor.status-page@1.0.0:rust.
The whole function, every language, is one file too: monitor.status-page-1.0.0.fune, 13,298 bytes, sha256 d9db4b93cf50e564dd970817a68ff904dff2740c164187a2bb320660670351ae. 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.status-page
after — your function gets the result and the arguments, and returns the final result.
// fune: after monitor.status-page
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.component-state in monitor.status-page
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.status-page --steps.
// fune: step monitor.status-page 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.
| Case | Arguments | Expected | |
|---|---|---|---|
| every component operational is all systems operational | components ×2 | → | state operational, headline All systems operational, affected |
| one degraded component makes the page degraded and names it | components ×2 | → | state degraded, headline Degraded performance, affected Search |
| a partial outage beats degraded; affected keeps input order | components ×3 | → | state partial-outage, headline Partial outage, affected Search, API |
| a major outage beats everything | components ×3 | → | state major-outage, headline Major outage, affected API, Database, Docs |
| maintenance alone is the headline and the component is affected | components ×2 | → | state maintenance, headline Scheduled maintenance, affected Billing |
| degraded outranks maintenance, a naive enum order gets this wrong | components ×2 | → | state degraded, headline Degraded performance, affected Billing, API |
| a single operational component | components ×1 | → | state operational, headline All systems operational, affected |
| a single component in major outage | components ×1 | → | state major-outage, headline Major outage, affected API |
| names differing only in case are different components | components ×2 | → | state degraded, headline Degraded performance, affected API |
| a page with no components is an error | → | error: components must not be empty |
Show the other 4 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| a duplicate name is an error | components ×2 | → | error: duplicate component name: API |
| an empty name is an error | components ×1 | → | error: component name must not be empty |
| an unknown state is an error | components ×1 | → | error: unknown component state: down |
| Statuspage's snake_case spelling is not accepted | components ×1 | → | error: unknown component state: major_outage |
More from the author
major-outage > partial-outage > degraded > maintenance > operational
| state | headline | | --- | --- | | `major-outage` | Major outage | | `partial-outage` | Partial outage | | `degraded` | Degraded performance | | `maintenance` | Scheduled maintenance | | `operational` | All systems operational |
Maintenance ranks below every real problem: a component that is degraded while another is under planned maintenance is the news. It still ranks above operational, and a component under maintenance is listed in `affected`, so readers know it may be unavailable.
`affected` is in input order (the order the page lists its components), not sorted by severity, so it matches the page.
## Decisions
- **No components is an error**, not "All systems operational": a page with nothing on it is a configuration mistake, and claiming all is well would hide it. - **Names must be unique and non-empty.** Duplicates would make `affected` ambiguous. Names are compared exactly, so `api` and `API` are different. - States use the registry's kebab-case (`major-outage`); Statuspage's API spelling (`major_outage`) is refused rather than guessed at.
## Errors
- `components must not be empty` - `component name must not be empty` - `duplicate component name: X` - `unknown component state: X`
## Sources
- Atlassian Support, "Show service status with components": https://support.atlassian.com/statuspage/docs/show-service-status-with-components/ - Statuspage Status API, page status and component statuses: https://metastatuspage.com/api. Statuspage's own overall indicator is `none | minor | major | critical`; this capability reports the worst component state instead, which says more and maps onto it directly.
Files
| Path | Bytes |
|---|---|
| README.md | 1,977 |
| impl/python.py | 1,419 |
| impl/rust.rs | 2,282 |
| impl/typescript.ts | 1,489 |
| vectors.json | 3,076 |