monitor.maintenance-window
The scheduled maintenance window in force at a moment, if any, so alerts and uptime can be suppressed during it.
1.0.0 · published 2026-10-03 by charlie · Anterra
Pinned by 14 tests, run in TypeScript, Python and Rust.
What it does
Which scheduled maintenance window, if any, is in force at a moment. A monitoring app asks this before paging someone or counting a check as downtime, and a status page uses it to say "Scheduled maintenance".
## Decisions
For example
activeMaintenance(, 1,000)→ — no windows, nothing activeactiveMaintenance(windows ×1, 2,000)→ name db upgrade, start 1,000, end 4,600 inside the only windowactiveMaintenance(windows ×1, 1,000)→ name db upgrade, start 1,000, end 4,600 the start second is inside
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.
export function activeMaintenance(windows: readonly MaintenanceWindow[], at: number): MaintenanceWindow | null
| windows | MaintenanceWindow[] | the scheduled windows, in any order; each must end after it starts |
| at | int | the moment to check, Unix seconds |
| returns | MaintenanceWindow? | the active window that started first; null when none is active |
The type it declares, generated into your project
/** A scheduled period when a target is expected to be down. */
export interface MaintenanceWindow {
readonly name: string;
/** Unix seconds, the first second included */
readonly start: number;
/** Unix seconds, the first second excluded */
readonly end: number;
}
Your code names it in one line, in the file that uses it
import { activeMaintenance } from "#fune/monitor.maintenance-window@^1";
import { type MaintenanceWindow } from "./monitor_maintenance_window_types.ts";
/**
* The window with start <= at < end. Half-open, so a window ending at 02:00
* and the next starting at 02:00 never both apply. When several overlap, the
* one that started first wins (ties: the first in the list), so the answer
* does not depend on how the caller happened to sort them. Every window is
* checked, not only the active ones: a backwards window is a config error
* that would otherwise silently never apply.
*/
export function activeMaintenance(windows: readonly MaintenanceWindow[], at: number): MaintenanceWindow | null {
if (!Number.isSafeInteger(at)) throw new RangeError(`at must be a whole second, received ${at}`);
let best: MaintenanceWindow | null = null;
for (const w of windows) {
if (w.end <= w.start) {
throw new RangeError(`maintenance window "${w.name}" must end after it starts: start ${w.start}, end ${w.end}`);
}
if (w.start <= at && at < w.end && (best === null || w.start < best.start)) best = w;
}
return best === null ? null : { name: best.name, start: best.start, end: best.end };
}Install
fune build
With that line in your source, in a TypeScript project (language typescript in fune.project), fune build resolves it and nothing else, pins them in fune.lock, downloads only the TypeScript 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. Or pin a range in fune.project and build in one step:
fune add monitor.maintenance-window
The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./monitor.maintenance-window-1.0.0-typescript.fune, or fetch it from a terminal with fune pull monitor.maintenance-window@1.0.0:typescript.
The whole function, every language, is one file too: monitor.maintenance-window-1.0.0.fune, 10,867 bytes, sha256 2be593f1b02aa7c8f811132adb9151be5f7527287fc2fb9fb90100f77531e111. 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.maintenance-window
after — your function gets the result and the arguments, and returns the final result.
// fune: after monitor.maintenance-window
replace — it requires no other capability, so there is no dependency to replace.
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.maintenance-window --steps.
// fune: step monitor.maintenance-window 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 | |
|---|---|---|---|
| no windows, nothing active | , 1,000 | → | — |
| inside the only window | windows ×1, 2,000 | → | name db upgrade, start 1,000, end 4,600 |
| the start second is inside | windows ×1, 1,000 | → | name db upgrade, start 1,000, end 4,600 |
| the end second is outside | windows ×1, 4,600 | → | — |
| the last second before the end is inside | windows ×1, 4,599 | → | name db upgrade, start 1,000, end 4,600 |
| before the window starts | windows ×1, 999 | → | — |
| back-to-back windows: at the boundary only the later one applies | windows ×2, 3,600 | → | name second, start 3,600, end 7,200 |
| overlapping: the one that started first wins even when listed second | windows ×2, 3,000 | → | name network, start 1,000, end 9,000 |
| same start: the first in the list wins | windows ×2, 1,500 | → | name a, start 1,000, end 2,000 |
| only the window containing the moment counts, not the earliest one | windows ×2, 600 | → | name now, start 500, end 900 |
Show the other 4 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| times before 1970 work | windows ×1, -5,000 | → | name old, start -7,200, end -3,600 |
| a window that ends when it starts is an error | windows ×1, 50 | → | error: maintenance window "empty" must end after it starts: start 1000, end 1000 |
| a backwards window is an error even when not active | windows ×2, 50 | → | error: maintenance window "typo" must end after it starts: start 9000, end 8000 |
| a fractional moment is an error | , 1.5 | → | error: at must be a whole second, received 1.5 |
More from the author
- **Half-open**: a window covers `start <= at < end`. A window ending at 02:00 and the next starting at 02:00 never both apply, and the end second itself is outside. - **Overlaps**: when several windows are active, the one that **started first** is returned (on a tie, the first in the list). The answer then does not depend on how the caller sorted the list, and the name shown is the maintenance that caused the outage in the first place. - **Every window is checked**, not only the active one: a window that does not end after it starts is a typo that would silently never apply, so it is an error wherever it sits in the list. - Returns `null` when nothing is active; returns a copy, never the caller's object.
## Errors
- `maintenance window "NAME" must end after it starts: start S, end E` - `at must be a whole second, received X`
Files
| Path | Bytes |
|---|---|
| README.md | 1,110 |
| impl/python.py | 1,191 |
| impl/rust.rs | 2,246 |
| impl/typescript.ts | 1,140 |
| vectors.json | 2,581 |