{
  "id": "monitoring",
  "title": "Uptime monitoring and status pages",
  "summary": "Turn probe results into up, degraded or down, incidents and uptime; drive a public status page; alert on thresholds, anomalies and SLO burn rates.",
  "synonyms": [
    "monitoring",
    "uptime",
    "uptime monitor",
    "status page",
    "health checks",
    "alerting",
    "alerts",
    "slo",
    "sla",
    "error budget",
    "incidents",
    "observability",
    "cron monitoring",
    "heartbeat",
    "server monitoring",
    "site monitoring"
  ],
  "apps": [
    "uptime monitor",
    "status page",
    "server monitoring dashboard",
    "alerting service",
    "cron job monitor",
    "SRE tooling",
    "website down checker"
  ],
  "language": "rust",
  "includes": [
    "dashboards",
    "dates-basics"
  ],
  "includedBy": [],
  "caveats": [],
  "sections": [
    {
      "key": "checks",
      "title": "Checks",
      "purpose": "Classify each probe and combine probes into one status per target.",
      "from": "monitoring",
      "members": [
        {
          "id": "monitor.http-check-result",
          "tier": "core",
          "why": "Classifies one HTTP probe as up, degraded or down from status, body and latency.",
          "section": "checks",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Classify one HTTP probe as up, degraded or down, with a reason and message, from status, body and latency.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "classifyHttpCheck"
          ],
          "signatures": [
            "pub fn classify_http_check(probe: &HttpProbe, expect: &HttpExpectation) -> CheckOutcome"
          ],
          "reference": "fune!(monitor.http-check-result@^1);  // then call classify_http_check(…)",
          "url": "http://www.functionalweave.com/functions/monitor.http-check-result"
        },
        {
          "id": "monitor.check-status",
          "tier": "core",
          "why": "Combines several locations' probes into one status with a quorum.",
          "section": "checks",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Combine the statuses of one target's probes from several locations into one up, degraded or down, with a quorum.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "aggregateStatus"
          ],
          "signatures": [
            "pub fn aggregate_status(statuses: &[String], down_quorum: i64) -> String"
          ],
          "reference": "fune!(monitor.check-status@^1);  // then call aggregate_status(…)",
          "url": "http://www.functionalweave.com/functions/monitor.check-status"
        },
        {
          "id": "monitor.cert-expiry",
          "tier": "optional",
          "why": "Days left on a TLS certificate and whether that is ok, warning, critical or expired.",
          "section": "checks",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "How long a TLS certificate has left before its notAfter, and whether that is ok, a warning, critical or expired.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "certExpiry"
          ],
          "signatures": [
            "pub fn cert_expiry(not_after: i64, now: i64, warn_days: i64, critical_days: i64) -> CertExpiry"
          ],
          "reference": "fune!(monitor.cert-expiry@^1);  // then call cert_expiry(…)",
          "url": "http://www.functionalweave.com/functions/monitor.cert-expiry"
        },
        {
          "id": "monitor.cert-check",
          "tier": "optional",
          "why": "A certificate's expiry state as a check status.",
          "section": "checks",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "A TLS certificate's expiry state as a check status: ok and warning are up, critical is degraded, expired is down.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "certCheck"
          ],
          "signatures": [
            "pub fn cert_check(state: &CertExpiryState) -> CheckStatus"
          ],
          "reference": "fune!(monitor.cert-check@^1);  // then call cert_check(…)",
          "url": "http://www.functionalweave.com/functions/monitor.cert-check"
        },
        {
          "id": "monitor.heartbeat",
          "tier": "optional",
          "why": "Whether a cron job that pings on a schedule is new, up, late or down.",
          "section": "checks",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Whether a cron job that pings on a schedule is new, up, late or down, from its last ping, period and grace time.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "heartbeatStatus"
          ],
          "signatures": [
            "pub fn heartbeat_status(last_ping_at: Option<i64>, now: i64, interval_seconds: i64, grace_seconds: i64) -> HeartbeatStatus"
          ],
          "reference": "fune!(monitor.heartbeat@^1);  // then call heartbeat_status(…)",
          "url": "http://www.functionalweave.com/functions/monitor.heartbeat"
        },
        {
          "id": "monitor.heartbeat-check",
          "tier": "optional",
          "why": "A heartbeat's state as a check status for the status page.",
          "section": "checks",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "A heartbeat's state as a check status for a status page: up, late as degraded, down as down, new as nothing yet.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "heartbeatCheck"
          ],
          "signatures": [
            "pub fn heartbeat_check(state: &HeartbeatState) -> Option<CheckStatus>"
          ],
          "reference": "fune!(monitor.heartbeat-check@^1);  // then call heartbeat_check(…)",
          "url": "http://www.functionalweave.com/functions/monitor.heartbeat-check"
        },
        {
          "id": "net.latency-summary",
          "tier": "optional",
          "why": "Loss, min/avg/max, p95 and jitter from ping-style probe results.",
          "section": "checks",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Summarise probe results: sent, received, loss, min/avg/max, p95 and jitter, in whole microseconds.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "summariseLatency"
          ],
          "signatures": [
            "pub fn summarise_latency(samples_us: &[Option<i64>]) -> LatencySummary"
          ],
          "reference": "fune!(net.latency-summary@^1);  // then call summarise_latency(…)",
          "url": "http://www.functionalweave.com/functions/net.latency-summary"
        },
        {
          "id": "net.device-status",
          "tier": "optional",
          "why": "Up, degraded or down from a latency summary and thresholds.",
          "section": "checks",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Classify a device as up, degraded or down from its latency summary and loss, p95 and jitter thresholds.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "deviceStatus"
          ],
          "signatures": [
            "pub fn device_status(summary: &LatencySummary, thresholds: &StatusThresholds) -> StatusResult"
          ],
          "reference": "fune!(net.device-status@^1);  // then call device_status(…)",
          "url": "http://www.functionalweave.com/functions/net.device-status"
        }
      ],
      "gaps": [
        {
          "key": "probes",
          "text": "Running the probes: HTTP requests, TLS handshakes and pings from several locations on a schedule are network I/O and yours.",
          "section": "checks",
          "from": "monitoring"
        }
      ]
    },
    {
      "key": "incidents",
      "title": "Incidents and uptime",
      "purpose": "Turn check history into incidents and uptime figures.",
      "from": "monitoring",
      "members": [
        {
          "id": "monitor.incidents",
          "tier": "core",
          "why": "Turns check series into incidents, ignoring runs too short to confirm.",
          "section": "incidents",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Turn a series of up, degraded and down checks into incidents, ignoring runs too short to confirm.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "findIncidents"
          ],
          "signatures": [
            "pub fn find_incidents(checks: &[Check], incident_status: &CheckStatus, confirm_checks: i64, now: i64) -> Vec<Incident>"
          ],
          "reference": "fune!(monitor.incidents@^1);  // then call find_incidents(…)",
          "url": "http://www.functionalweave.com/functions/monitor.incidents"
        },
        {
          "id": "monitor.uptime",
          "tier": "core",
          "why": "Time-weighted uptime over a window, with long gaps counted as unknown.",
          "section": "incidents",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Time-weighted uptime of a target over a window from its checks, with gaps longer than a limit counted as unknown.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "uptime"
          ],
          "signatures": [
            "pub fn uptime(checks: &[Check], from: i64, to: i64, max_gap_seconds: i64) -> UptimeReport"
          ],
          "reference": "fune!(monitor.uptime@^1);  // then call uptime(…)",
          "url": "http://www.functionalweave.com/functions/monitor.uptime"
        },
        {
          "id": "monitor.mttr",
          "tier": "optional",
          "why": "MTTR, MTBF, downtime and incident counts for a reporting window.",
          "section": "incidents",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "MTTR, MTBF, downtime and incident counts for a reporting window, from a list of incidents.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "reliabilityStats"
          ],
          "signatures": [
            "pub fn reliability_stats(incidents: &[Incident], from: i64, to: i64) -> ReliabilityStats"
          ],
          "reference": "fune!(monitor.mttr@^1);  // then call reliability_stats(…)",
          "url": "http://www.functionalweave.com/functions/monitor.mttr"
        },
        {
          "id": "monitor.maintenance-window",
          "tier": "optional",
          "why": "The maintenance window in force at a moment, to suppress alerts and uptime.",
          "section": "incidents",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "The scheduled maintenance window in force at a moment, if any, so alerts and uptime can be suppressed during it.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "activeMaintenance"
          ],
          "signatures": [
            "pub fn active_maintenance(windows: &[MaintenanceWindow], at: i64) -> Option<MaintenanceWindow>"
          ],
          "reference": "fune!(monitor.maintenance-window@^1);  // then call active_maintenance(…)",
          "url": "http://www.functionalweave.com/functions/monitor.maintenance-window"
        }
      ],
      "gaps": []
    },
    {
      "key": "status-page",
      "title": "Status page",
      "purpose": "The public page: overall state, components and history bars.",
      "from": "monitoring",
      "members": [
        {
          "id": "monitor.component-state",
          "tier": "core",
          "why": "A component's state from its checks: operational, degraded, partial or major outage, maintenance.",
          "section": "status-page",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "A status page component's state from its checks: operational, degraded, partial or major outage, or maintenance.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "componentState"
          ],
          "signatures": [
            "pub fn component_state(statuses: &[CheckStatus], under_maintenance: bool) -> String"
          ],
          "reference": "fune!(monitor.component-state@^1);  // then call component_state(…)",
          "url": "http://www.functionalweave.com/functions/monitor.component-state"
        },
        {
          "id": "monitor.status-page",
          "tier": "core",
          "why": "The headline, overall state and affected components at the top of the page.",
          "section": "status-page",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "The overall state, headline and affected components at the top of a status page, from each component's state.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "statusPage"
          ],
          "signatures": [
            "pub fn status_page(components: &[Component]) -> StatusSummary"
          ],
          "reference": "fune!(monitor.status-page@^1);  // then call status_page(…)",
          "url": "http://www.functionalweave.com/functions/monitor.status-page"
        },
        {
          "id": "monitor.uptime-bars",
          "tier": "core",
          "why": "One bar per UTC day of uptime history, oldest first.",
          "section": "status-page",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "One bar per UTC day for a status page's uptime history: seconds in each state, uptime and a colour state, oldest first.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "uptimeBars"
          ],
          "signatures": [
            "pub fn uptime_bars(checks: &[Check], now: i64, days: i64, max_gap_seconds: i64) -> Vec<DayBar>"
          ],
          "reference": "fune!(monitor.uptime-bars@^1);  // then call uptime_bars(…)",
          "url": "http://www.functionalweave.com/functions/monitor.uptime-bars"
        },
        {
          "id": "monitor.format-duration",
          "tier": "optional",
          "why": "Short durations like \"3h 12m\" for incident lengths.",
          "section": "status-page",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "A number of seconds as a short human duration for dashboards and alerts: \"3h 12m\", \"2d 4h\", \"45s\".",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "formatDuration"
          ],
          "signatures": [
            "pub fn format_duration(seconds: i64, max_units: i64) -> String"
          ],
          "reference": "fune!(monitor.format-duration@^1);  // then call format_duration(…)",
          "url": "http://www.functionalweave.com/functions/monitor.format-duration"
        }
      ],
      "gaps": []
    },
    {
      "key": "alerting",
      "title": "Alerting",
      "purpose": "Decide when to alert and what to send.",
      "from": "monitoring",
      "members": [
        {
          "id": "monitor.alert-rule",
          "tier": "core",
          "why": "Evaluates a threshold rule over a metric series: inactive, pending, firing or no-data.",
          "section": "alerting",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Evaluate a threshold alert rule over a metric series: inactive, pending, firing or no-data, Prometheus style.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "evaluateAlertRule"
          ],
          "signatures": [
            "pub fn evaluate_alert_rule(samples: &[MetricSample], rule: &ThresholdRule, now: i64) -> RuleEvaluation"
          ],
          "reference": "fune!(monitor.alert-rule@^1);  // then call evaluate_alert_rule(…)",
          "url": "http://www.functionalweave.com/functions/monitor.alert-rule"
        },
        {
          "id": "monitor.alert-state",
          "tier": "core",
          "why": "Steps an alert through pending, firing and resolved and says which notification to send.",
          "section": "alerting",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Step an alert through inactive, pending, firing and resolved, and say which notification to send.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "nextAlertState"
          ],
          "signatures": [
            "pub fn next_alert_state(previous: &AlertState, condition: bool, now: i64, policy: &AlertPolicy) -> AlertTransition"
          ],
          "reference": "fune!(monitor.alert-state@^1);  // then call next_alert_state(…)",
          "url": "http://www.functionalweave.com/functions/monitor.alert-state"
        },
        {
          "id": "monitor.alert-mute",
          "tier": "optional",
          "why": "Holds an alert back during maintenance or when a related alert is already firing.",
          "section": "alerting",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Whether to hold an alert back: its component is under maintenance, or a related alert on it is already firing.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "muteAlert"
          ],
          "signatures": [
            "pub fn mute_alert(kind: &str, under_maintenance: bool, firing_kinds: &[String], policy: &MutePolicy) -> AlertMute"
          ],
          "reference": "fune!(monitor.alert-mute@^1);  // then call mute_alert(…)",
          "url": "http://www.functionalweave.com/functions/monitor.alert-mute"
        },
        {
          "id": "monitor.anomaly",
          "tier": "optional",
          "why": "Flags an outlier against history by z-score or median/MAD.",
          "section": "alerting",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Is a new metric value an outlier against its history? By z-score or by the robust median/MAD modified z-score.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "detectAnomaly"
          ],
          "signatures": [
            "pub fn detect_anomaly(history: &[i64], value: i64, method: &str, threshold_hundredths: i64) -> Anomaly"
          ],
          "reference": "fune!(monitor.anomaly@^1);  // then call detect_anomaly(…)",
          "url": "http://www.functionalweave.com/functions/monitor.anomaly"
        }
      ],
      "gaps": [
        {
          "key": "notifications",
          "text": "Delivering alerts by email, SMS, Slack, PagerDuty or webhooks, with retries and on-call schedules.",
          "section": "alerting",
          "from": "monitoring"
        }
      ]
    },
    {
      "key": "slo",
      "title": "SLOs and error budgets",
      "purpose": "Track service level objectives.",
      "from": "monitoring",
      "members": [
        {
          "id": "monitor.error-budget",
          "tier": "optional",
          "why": "Error budget allowed, used and left from good and bad events.",
          "section": "slo",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "How much of an SLO's error budget is allowed, used and left, from good and bad event counts or seconds.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "errorBudget"
          ],
          "signatures": [
            "pub fn error_budget(target_basis_points: i64, total_events: i64, bad_events: i64) -> ErrorBudget"
          ],
          "reference": "fune!(monitor.error-budget@^1);  // then call error_budget(…)",
          "url": "http://www.functionalweave.com/functions/monitor.error-budget"
        },
        {
          "id": "monitor.burn-rate",
          "tier": "optional",
          "why": "How fast the error budget burns, as a multiple of the allowed rate.",
          "section": "slo",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "How fast an SLO's error budget is burning: the error rate as a multiple of the rate the SLO allows, in thousandths.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "burnRate"
          ],
          "signatures": [
            "pub fn burn_rate(target_basis_points: i64, total_events: i64, bad_events: i64) -> i64"
          ],
          "reference": "fune!(monitor.burn-rate@^1);  // then call burn_rate(…)",
          "url": "http://www.functionalweave.com/functions/monitor.burn-rate"
        },
        {
          "id": "monitor.burn-rate-alert",
          "tier": "optional",
          "why": "Multiwindow, multi-burn-rate SLO alerting rules, Google SRE style.",
          "section": "slo",
          "from": "monitoring",
          "version": "2.0.0",
          "summary": "Multiwindow, multi-burn-rate SLO alerting: which rules fire, from event counts per window (Google SRE workbook).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "burnRateAlert"
          ],
          "signatures": [
            "pub fn burn_rate_alert(target_basis_points: i64, windows: &[WindowCount], rules: Option<&[BurnRule]>, min_events: Option<i64>) -> BurnAlert"
          ],
          "reference": "fune!(monitor.burn-rate-alert@^2);  // then call burn_rate_alert(…)",
          "url": "http://www.functionalweave.com/functions/monitor.burn-rate-alert"
        }
      ],
      "gaps": []
    },
    {
      "key": "metrics",
      "title": "Metrics and logs",
      "purpose": "Shape raw metrics and access logs for charts and rules.",
      "from": "monitoring",
      "members": [
        {
          "id": "monitor.rollup",
          "tier": "optional",
          "why": "Aggregates a series into fixed time buckets: count, min, max, avg, sum, last.",
          "section": "metrics",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Aggregate a metric series into fixed time buckets (count, min, max, avg, sum, last), empty buckets included.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "rollup"
          ],
          "signatures": [
            "pub fn rollup(samples: &[MetricSample], from: i64, to: i64, bucket_seconds: i64) -> Vec<Bucket>"
          ],
          "reference": "fune!(monitor.rollup@^1);  // then call rollup(…)",
          "url": "http://www.functionalweave.com/functions/monitor.rollup"
        },
        {
          "id": "monitor.series-window",
          "tier": "optional",
          "why": "The samples between two moments, checking time order.",
          "section": "metrics",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "The samples of a time series from one moment up to (not including) another, checking they are in time order.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "seriesWindow"
          ],
          "signatures": [
            "pub fn series_window(samples: &[MetricSample], from: i64, to: i64) -> Vec<MetricSample>"
          ],
          "reference": "fune!(monitor.series-window@^1);  // then call series_window(…)",
          "url": "http://www.functionalweave.com/functions/monitor.series-window"
        },
        {
          "id": "monitor.counter-increase",
          "tier": "optional",
          "why": "Counter growth and rate per second, counting restarts.",
          "section": "metrics",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "How much a monotonic counter grew over a series of samples, counting restarts from zero, and its rate per second.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "counterIncrease"
          ],
          "signatures": [
            "pub fn counter_increase(samples: &[MetricSample]) -> CounterIncrease"
          ],
          "reference": "fune!(monitor.counter-increase@^1);  // then call counter_increase(…)",
          "url": "http://www.functionalweave.com/functions/monitor.counter-increase"
        },
        {
          "id": "monitor.parse-access-log",
          "tier": "optional",
          "why": "Parses Apache/NCSA Common or Combined log lines.",
          "section": "metrics",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Parse one Apache/NCSA Common or Combined Log Format access log line; null for a line in neither format.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "parseAccessLog"
          ],
          "signatures": [
            "pub fn parse_access_log(line: &str) -> Option<AccessLogEntry>"
          ],
          "reference": "fune!(monitor.parse-access-log@^1);  // then call parse_access_log(…)",
          "url": "http://www.functionalweave.com/functions/monitor.parse-access-log"
        },
        {
          "id": "monitor.status-code-summary",
          "tier": "optional",
          "why": "Counts status codes by class and gives server and client error rates.",
          "section": "metrics",
          "from": "monitoring",
          "version": "1.0.0",
          "summary": "Count HTTP status codes by class (1xx to 5xx) and give the server error and client error rates in basis points.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "summariseStatusCodes"
          ],
          "signatures": [
            "pub fn summarise_status_codes(statuses: &[i64]) -> StatusCodeSummary"
          ],
          "reference": "fune!(monitor.status-code-summary@^1);  // then call summarise_status_codes(…)",
          "url": "http://www.functionalweave.com/functions/monitor.status-code-summary"
        }
      ],
      "gaps": [
        {
          "key": "metrics-storage",
          "text": "Storing time series and logs (a TSDB, Prometheus, a database) and querying them.",
          "section": "metrics",
          "from": "monitoring"
        }
      ]
    },
    {
      "key": "complete-charts",
      "title": "Whole charts",
      "purpose": "Get complete chart geometry in one call, for the common charts.",
      "from": "dashboards",
      "members": [
        {
          "id": "charts.line-chart",
          "tier": "core",
          "why": "Plot area, number or date axes, gridlines, series paths, colours and legend for a line chart.",
          "section": "complete-charts",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Complete line chart geometry as data: plot area, number or date axes, gridlines, series paths, colours, legend.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "lineChart"
          ],
          "signatures": [
            "pub fn line_chart(spec: &LineChartSpec) -> LineChart"
          ],
          "reference": "fune!(charts.line-chart@^1);  // then call line_chart(…)",
          "url": "http://www.functionalweave.com/functions/charts.line-chart"
        },
        {
          "id": "charts.bar-chart",
          "tier": "core",
          "why": "Grouped or stacked bar chart geometry: axes, gridlines, bars, colours and legend.",
          "section": "complete-charts",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Complete bar chart geometry as data, grouped or stacked: plot area, axes, gridlines, bar rectangles, colours, legend.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "barChart"
          ],
          "signatures": [
            "pub fn bar_chart(spec: &BarChartSpec) -> BarChart"
          ],
          "reference": "fune!(charts.bar-chart@^1);  // then call bar_chart(…)",
          "url": "http://www.functionalweave.com/functions/charts.bar-chart"
        },
        {
          "id": "charts.sparkline",
          "tier": "optional",
          "why": "A sparkline path and end marker for a series in a small box.",
          "section": "complete-charts",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "A sparkline's SVG path and end marker from a series, fitted into a box, with gaps left as breaks.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "sparkline"
          ],
          "signatures": [
            "pub fn sparkline(values: &[Option<f64>], width: f64, height: f64, padding: f64) -> Sparkline"
          ],
          "reference": "fune!(charts.sparkline@^1);  // then call sparkline(…)",
          "url": "http://www.functionalweave.com/functions/charts.sparkline"
        }
      ],
      "gaps": []
    },
    {
      "key": "building-blocks",
      "title": "Chart building blocks",
      "purpose": "Compose charts of your own from the same parts.",
      "from": "dashboards",
      "members": [
        {
          "id": "charts.scale",
          "tier": "core",
          "why": "Maps values to positions and back: linear, log, time, band and point scales, nice domains.",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.1.0",
          "summary": "Map data values onto screen positions and back: linear, log, time, band and point scales, and nice domains.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": true,
          "functions": [
            "linearScale",
            "invertLinear",
            "niceDomain",
            "logScale",
            "timeScale",
            "bandScale",
            "pointScale"
          ],
          "signatures": [
            "pub fn linear_scale(domain: &[f64], range: &[f64], value: f64, clamp: bool) -> f64",
            "pub fn invert_linear(domain: &[f64], range: &[f64], value: f64) -> f64",
            "pub fn nice_domain(domain: &[f64], count: i64) -> NiceDomain",
            "pub fn log_scale(domain: &[f64], range: &[f64], value: f64, clamp: bool) -> f64",
            "pub fn time_scale(domain: &[String], range: &[f64], value: &str, clamp: bool) -> f64",
            "pub fn band_scale(domain: &[String], range: &[f64], value: &str, padding_inner: f64, padding_outer: f64, align: f64) -> Band",
            "pub fn point_scale(domain: &[String], range: &[f64], value: &str, padding: f64, align: f64) -> f64"
          ],
          "reference": "fune!(charts.scale@^1);  // then call linear_scale, invert_linear, nice_domain, log_scale, time_scale, band_scale, point_scale",
          "url": "http://www.functionalweave.com/functions/charts.scale"
        },
        {
          "id": "charts.ticks",
          "tier": "core",
          "why": "Round tick steps and calendar ticks from days to years.",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Axis ticks: a round step (1, 2 or 5 x 10^k), the ticks on it, and calendar ticks from days to years.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": true,
          "functions": [
            "tickStep",
            "niceTicks",
            "timeTickInterval",
            "timeTicks"
          ],
          "signatures": [
            "pub fn tick_step(start: f64, stop: f64, count: i64) -> f64",
            "pub fn nice_ticks(start: f64, stop: f64, count: i64) -> Vec<f64>",
            "pub fn time_tick_interval(start: &str, stop: &str, count: i64) -> TimeTickInterval",
            "pub fn time_ticks(start: &str, stop: &str, interval: &str, step: i64) -> Vec<String>"
          ],
          "reference": "fune!(charts.ticks@^1);  // then call tick_step, nice_ticks, time_tick_interval, time_ticks",
          "url": "http://www.functionalweave.com/functions/charts.ticks"
        },
        {
          "id": "charts.axis",
          "tier": "core",
          "why": "Tick positions, labels and gridlines for number, time and category axes.",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.0.1",
          "summary": "Axis geometry as data: tick positions, tick marks, label anchors and gridlines for number, time and category axes.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": true,
          "functions": [
            "axisFromTicks",
            "numberAxis",
            "timeAxis",
            "bandAxis",
            "gridLines"
          ],
          "signatures": [
            "pub fn axis_from_ticks(positions: &[f64], labels: &[String], range: &[f64], orient: &str, position: f64, tick_size: f64) -> Axis",
            "pub fn number_axis(domain: &[f64], range: &[f64], count: i64, orient: &str, position: f64, tick_size: f64) -> Axis",
            "pub fn time_axis(domain: &[String], range: &[f64], count: i64, orient: &str, position: f64, tick_size: f64) -> Axis",
            "pub fn band_axis(domain: &[String], range: &[f64], padding_inner: f64, padding_outer: f64, orient: &str, position: f64, tick_size: f64) -> Axis",
            "pub fn grid_lines(axis: &Axis, length: f64) -> Vec<Line>"
          ],
          "reference": "fune!(charts.axis@^1);  // then call axis_from_ticks, number_axis, time_axis, band_axis, grid_lines",
          "url": "http://www.functionalweave.com/functions/charts.axis"
        },
        {
          "id": "charts.shape",
          "tier": "optional",
          "why": "SVG paths for lines, areas, steps, curves, bars, arcs and pie slices.",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.0.1",
          "summary": "SVG path strings for lines, areas, steps, monotone curves, bars, arcs and pie slices, identical in every language.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": true,
          "functions": [
            "linePath",
            "areaPath",
            "stepPath",
            "monotoneCurve",
            "barRects",
            "arcPath",
            "pieAngles"
          ],
          "signatures": [
            "pub fn line_path(points: &[Point]) -> String",
            "pub fn area_path(points: &[AreaPoint]) -> String",
            "pub fn step_path(points: &[Point], position: &str) -> String",
            "pub fn monotone_curve(points: &[Point]) -> String",
            "pub fn bar_rects(bars: &[BarSpec], orientation: &str) -> Vec<Rect>",
            "pub fn arc_path(arc: &Arc) -> String",
            "pub fn pie_angles(values: &[f64], start_angle: f64, end_angle: f64, pad_angle: f64) -> Vec<PieSlice>"
          ],
          "reference": "fune!(charts.shape@^1);  // then call line_path, area_path, step_path, monotone_curve, bar_rects, arc_path, pie_angles",
          "url": "http://www.functionalweave.com/functions/charts.shape"
        },
        {
          "id": "charts.stack",
          "tier": "optional",
          "why": "Stacks series on zero, normalised to 100% or diverging.",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Stack several series for stacked bars and areas: on zero, normalised to 100%, or diverging around zero.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "stack"
          ],
          "signatures": [
            "pub fn stack(series: &[Vec<f64>], offset: &str) -> Vec<Vec<StackedValue>>"
          ],
          "reference": "fune!(charts.stack@^1);  // then call stack(…)",
          "url": "http://www.functionalweave.com/functions/charts.stack"
        },
        {
          "id": "charts.layout",
          "tier": "optional",
          "why": "Plot area inside margins, legend rows, label collision avoidance.",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.0.1",
          "summary": "Chart layout: the plot area inside margins, legend items wrapped into rows, and greedy label collision avoidance.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": true,
          "functions": [
            "plotArea",
            "legendRows",
            "avoidCollisions"
          ],
          "signatures": [
            "pub fn plot_area(width: f64, height: f64, margins: &Margins) -> PlotArea",
            "pub fn legend_rows(labels: &[String], max_width: f64, char_width: f64, swatch_size: f64, gap: f64, row_height: f64) -> Vec<LegendItem>",
            "pub fn avoid_collisions(boxes: &[LabelBox], padding: f64) -> Vec<bool>"
          ],
          "reference": "fune!(charts.layout@^1);  // then call plot_area, legend_rows, avoid_collisions",
          "url": "http://www.functionalweave.com/functions/charts.layout"
        },
        {
          "id": "charts.extent",
          "tier": "optional",
          "why": "Min and max of a series, skipping gaps.",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.0.1",
          "summary": "The minimum and maximum of a series as [min, max], skipping gaps (null), or null when there is no value.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "extent"
          ],
          "signatures": [
            "pub fn extent(values: &[Option<f64>]) -> Option<Vec<f64>>"
          ],
          "reference": "fune!(charts.extent@^1);  // then call extent(…)",
          "url": "http://www.functionalweave.com/functions/charts.extent"
        },
        {
          "id": "charts.histogram-bins",
          "tier": "optional",
          "why": "Bins values for a histogram (Sturges, Freedman-Diaconis or fixed width).",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Bin values into histogram bins on round edges, by Sturges' rule, Freedman-Diaconis, or a fixed width.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "histogramBins"
          ],
          "signatures": [
            "pub fn histogram_bins(values: &[f64], method: &str, bin_width: Option<f64>) -> Vec<Bin>"
          ],
          "reference": "fune!(charts.histogram-bins@^1);  // then call histogram_bins(…)",
          "url": "http://www.functionalweave.com/functions/charts.histogram-bins"
        },
        {
          "id": "charts.downsample",
          "tier": "optional",
          "why": "Thins a long series by LTTB so it draws fast but keeps its shape.",
          "section": "building-blocks",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Reduce a long series to a few points that keep its visual shape, by Largest-Triangle-Three-Buckets (LTTB).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "downsample"
          ],
          "signatures": [
            "pub fn downsample(points: &[Sample], threshold: i64) -> Vec<Sample>"
          ],
          "reference": "fune!(charts.downsample@^1);  // then call downsample(…)",
          "url": "http://www.functionalweave.com/functions/charts.downsample"
        }
      ],
      "gaps": []
    },
    {
      "key": "colour",
      "title": "Colour",
      "purpose": "Readable, colour-blind-safe colours.",
      "from": "dashboards",
      "members": [
        {
          "id": "charts.palette",
          "tier": "core",
          "why": "n colour-blind-safe series colours (Okabe-Ito or Tol bright).",
          "section": "colour",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "A categorical palette of n colour-blind-safe colours for chart series: Okabe-Ito or Paul Tol's bright scheme.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "palette"
          ],
          "signatures": [
            "pub fn palette(scheme: &str, count: i64, cycle: bool) -> Vec<String>"
          ],
          "reference": "fune!(charts.palette@^1);  // then call palette(…)",
          "url": "http://www.functionalweave.com/functions/charts.palette"
        },
        {
          "id": "charts.interpolate-color",
          "tier": "optional",
          "why": "Colour along a sequential or diverging ramp, for heatmaps.",
          "section": "colour",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "The colour at a point along a sequential or diverging ramp, mixed in OKLab so steps look even; hex in, hex out.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "interpolateColor"
          ],
          "signatures": [
            "pub fn interpolate_color(ramp: &[String], t: f64) -> String"
          ],
          "reference": "fune!(charts.interpolate-color@^1);  // then call interpolate_color(…)",
          "url": "http://www.functionalweave.com/functions/charts.interpolate-color"
        },
        {
          "id": "charts.contrast",
          "tier": "optional",
          "why": "WCAG contrast ratio and the readable text colour on a background.",
          "section": "colour",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "WCAG 2.x contrast ratio between two colours, and which text colour reads best on a background.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": true,
          "functions": [
            "contrastRatio",
            "readableTextColor"
          ],
          "signatures": [
            "pub fn contrast_ratio(foreground: &str, background: &str) -> f64",
            "pub fn readable_text_color(background: &str, candidates: &[String]) -> String"
          ],
          "reference": "fune!(charts.contrast@^1);  // then call contrast_ratio, readable_text_color",
          "url": "http://www.functionalweave.com/functions/charts.contrast"
        },
        {
          "id": "charts.color",
          "tier": "optional",
          "why": "Hex to RGB and back, and sRGB to linear light.",
          "section": "colour",
          "from": "dashboards",
          "version": "1.0.1",
          "summary": "Hex colours to RGB and back, and sRGB channels to linear light and back, identically in every language.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": true,
          "functions": [
            "parseHex",
            "toHex",
            "srgbToLinear",
            "linearToSrgb"
          ],
          "signatures": [
            "pub fn parse_hex(hex: &str) -> Rgb",
            "pub fn to_hex(rgb: &Rgb) -> String",
            "pub fn srgb_to_linear(channel: i64) -> f64",
            "pub fn linear_to_srgb(value: f64) -> i64"
          ],
          "reference": "fune!(charts.color@^1);  // then call parse_hex, to_hex, srgb_to_linear, linear_to_srgb",
          "url": "http://www.functionalweave.com/functions/charts.color"
        }
      ],
      "gaps": []
    },
    {
      "key": "figures",
      "title": "Figures and statistics",
      "purpose": "The numbers in the tiles and tooltips.",
      "from": "dashboards",
      "members": [
        {
          "id": "charts.format",
          "tier": "core",
          "why": "Tick and label text: SI prefixes (1.2k), percentages, dates and money.",
          "section": "figures",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Axis and label text for charts: tick numbers, SI prefixes (1.2k, 3.4M), percentages, dates and money.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": true,
          "functions": [
            "formatTick",
            "formatSi",
            "formatPercent",
            "formatDate",
            "formatMoneyTick"
          ],
          "signatures": [
            "pub fn format_tick(value: f64, step: f64) -> String",
            "pub fn format_si(value: f64, significant: i64) -> String",
            "pub fn format_percent(value: f64, decimals: i64) -> String",
            "pub fn format_date(iso: &str, label: &str) -> String",
            "pub fn format_money_tick(minor: f64, currency: &str) -> String"
          ],
          "reference": "fune!(charts.format@^1);  // then call format_tick, format_si, format_percent, format_date, format_money_tick",
          "url": "http://www.functionalweave.com/functions/charts.format"
        },
        {
          "id": "stats.mean-median",
          "tier": "optional",
          "why": "Mean, median and mode, exactly.",
          "section": "figures",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Mean, median and mode of a list of integers, with the mean and median as exact fractions.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "meanMedianMode"
          ],
          "signatures": [
            "pub fn mean_median_mode(values: &[i64]) -> CentralTendency"
          ],
          "reference": "fune!(stats.mean-median@^1);  // then call mean_median_mode(…)",
          "url": "http://www.functionalweave.com/functions/stats.mean-median"
        },
        {
          "id": "stats.percentile",
          "tier": "optional",
          "why": "Percentiles (nearest-rank or linear), for p95 tiles.",
          "section": "figures",
          "from": "dashboards",
          "version": "2.0.0",
          "summary": "Percentile of a list of numbers by a named method: nearest-rank, or linear interpolation (R-7, Excel PERCENTILE.INC).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "percentile"
          ],
          "signatures": [
            "pub fn percentile(values: &[f64], p: f64, method: &str, decimals: i64) -> f64"
          ],
          "reference": "fune!(stats.percentile@^2);  // then call percentile(…)",
          "url": "http://www.functionalweave.com/functions/stats.percentile"
        },
        {
          "id": "stats.moving-average",
          "tier": "optional",
          "why": "Simple and exponential moving averages for trend lines.",
          "section": "figures",
          "from": "dashboards",
          "version": "2.0.0",
          "summary": "Simple or exponential moving average over a series, one value per full window, rounded to stated decimals.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "movingAverage"
          ],
          "signatures": [
            "pub fn moving_average(values: &[f64], window: i64, kind: &str, decimals: i64) -> Vec<f64>"
          ],
          "reference": "fune!(stats.moving-average@^2);  // then call moving_average(…)",
          "url": "http://www.functionalweave.com/functions/stats.moving-average"
        },
        {
          "id": "stats.standard-deviation",
          "tier": "optional",
          "why": "Standard deviation, for bands and variability.",
          "section": "figures",
          "from": "dashboards",
          "version": "2.0.0",
          "summary": "Population or sample standard deviation of a list of numbers, two-pass, rounded to stated decimals.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "standardDeviation"
          ],
          "signatures": [
            "pub fn standard_deviation(values: &[f64], kind: &str, decimals: i64) -> f64"
          ],
          "reference": "fune!(stats.standard-deviation@^2);  // then call standard_deviation(…)",
          "url": "http://www.functionalweave.com/functions/stats.standard-deviation"
        },
        {
          "id": "stats.weighted-average",
          "tier": "optional",
          "why": "Weighted averages with explicit rounding.",
          "section": "figures",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Weighted average of integers, computed exactly and rounded once to stated decimals with an explicit rounding mode.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "weightedAverage"
          ],
          "signatures": [
            "pub fn weighted_average(values: &[i64], weights: &[i64], decimals: i64, mode: &RoundingMode) -> f64"
          ],
          "reference": "fune!(stats.weighted-average@^1);  // then call weighted_average(…)",
          "url": "http://www.functionalweave.com/functions/stats.weighted-average"
        },
        {
          "id": "math.percent-change",
          "tier": "optional",
          "why": "Change between two values in basis points, for \"up 4.2%\".",
          "section": "figures",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Percentage change from one value to another, in basis points, with an explicit rounding mode.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "percentChange"
          ],
          "signatures": [
            "pub fn percent_change(from_value: i64, to_value: i64, mode: &RoundingMode) -> Option<i64>"
          ],
          "reference": "fune!(math.percent-change@^1);  // then call percent_change(…)",
          "url": "http://www.functionalweave.com/functions/math.percent-change"
        },
        {
          "id": "text.format-decimal",
          "tier": "optional",
          "why": "Plain decimal text with fixed places and grouping.",
          "section": "figures",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Format a float as plain decimal text with fixed or trimmed places and optional grouping, identically in every language.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "formatDecimal"
          ],
          "signatures": [
            "pub fn format_decimal(value: f64, decimals: i64, trim_zeros: bool, group_separator: &str) -> String"
          ],
          "reference": "fune!(text.format-decimal@^1);  // then call format_decimal(…)",
          "url": "http://www.functionalweave.com/functions/text.format-decimal"
        },
        {
          "id": "money.format",
          "tier": "optional",
          "why": "Money values in tiles with the currency's real decimals.",
          "section": "figures",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Render a monetary amount as text, using the currency's real minor-unit precision.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "formatMoney"
          ],
          "signatures": [
            "pub fn format_money(amount: &Money) -> String"
          ],
          "reference": "fune!(money.format@^1);  // then call format_money(…)",
          "url": "http://www.functionalweave.com/functions/money.format"
        },
        {
          "id": "collections.group-by-key",
          "tier": "optional",
          "why": "Groups records by a key before charting them.",
          "section": "figures",
          "from": "dashboards",
          "version": "1.0.0",
          "summary": "Group records by the value at one key, preserving input order inside each group.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "groupByKey"
          ],
          "signatures": [
            "pub fn group_by_key(records: &[Value], key: &str) -> Vec<(String, Vec<Value>)>"
          ],
          "reference": "fune!(collections.group-by-key@^1);  // then call group_by_key(…)",
          "url": "http://www.functionalweave.com/functions/collections.group-by-key"
        }
      ],
      "gaps": []
    },
    {
      "key": "date-arithmetic",
      "title": "Calendar arithmetic",
      "purpose": "Move and measure ISO dates exactly, with no date library and no clock reads.",
      "from": "dates-basics",
      "members": [
        {
          "id": "dates.add-days",
          "tier": "core",
          "why": "Shifts a date by whole days, for due dates and windows.",
          "section": "date-arithmetic",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Shift an ISO date by a whole number of days, forwards or backwards, with exact calendar arithmetic.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "addDays"
          ],
          "signatures": [
            "pub fn add_days(iso: &str, days: i64) -> String"
          ],
          "reference": "fune!(dates.add-days@^1);  // then call add_days(…)",
          "url": "http://www.functionalweave.com/functions/dates.add-days"
        },
        {
          "id": "dates.add-months",
          "tier": "core",
          "why": "Adds months clamping to month end, so 31 January plus a month is the end of February.",
          "section": "date-arithmetic",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Add calendar months to an ISO date, clamping to the month end: 31 Jan + 1 month is 28 or 29 Feb.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "addMonths"
          ],
          "signatures": [
            "pub fn add_months(iso: &str, months: i64) -> String"
          ],
          "reference": "fune!(dates.add-months@^1);  // then call add_months(…)",
          "url": "http://www.functionalweave.com/functions/dates.add-months"
        },
        {
          "id": "dates.days-between",
          "tier": "core",
          "why": "Signed calendar days between two dates, for ages of invoices and stays.",
          "section": "date-arithmetic",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Calendar days from one ISO date to another, signed: negative when the second date is earlier.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "daysBetween"
          ],
          "signatures": [
            "pub fn days_between(start_iso: &str, end_iso: &str) -> i64"
          ],
          "reference": "fune!(dates.days-between@^1);  // then call days_between(…)",
          "url": "http://www.functionalweave.com/functions/dates.days-between"
        },
        {
          "id": "dates.month-boundaries",
          "tier": "core",
          "why": "First and last day of a date's month, for monthly periods and statements.",
          "section": "date-arithmetic",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "The first day, last day and length of the calendar month containing a date.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "monthBoundaries"
          ],
          "signatures": [
            "pub fn month_boundaries(iso: &str) -> MonthBoundaries"
          ],
          "reference": "fune!(dates.month-boundaries@^1);  // then call month_boundaries(…)",
          "url": "http://www.functionalweave.com/functions/dates.month-boundaries"
        },
        {
          "id": "dates.day-of-week",
          "tier": "core",
          "why": "ISO weekday of a date, for weekend rules and opening hours.",
          "section": "date-arithmetic",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "The ISO 8601 day of the week for a date: 1 is Monday through 7 is Sunday.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "dayOfWeek"
          ],
          "signatures": [
            "pub fn day_of_week(iso: &str) -> i64"
          ],
          "reference": "fune!(dates.day-of-week@^1);  // then call day_of_week(…)",
          "url": "http://www.functionalweave.com/functions/dates.day-of-week"
        },
        {
          "id": "dates.is-leap-year",
          "tier": "optional",
          "why": "Whether a year is a leap year, for 365/366-day calculations.",
          "section": "date-arithmetic",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Whether a year is a Gregorian leap year: every 4th, except centuries, except every 400th.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "isLeapYear"
          ],
          "signatures": [
            "pub fn is_leap_year(year: i64) -> bool"
          ],
          "reference": "fune!(dates.is-leap-year@^1);  // then call is_leap_year(…)",
          "url": "http://www.functionalweave.com/functions/dates.is-leap-year"
        },
        {
          "id": "dates.overlap",
          "tier": "optional",
          "why": "Days two date ranges share, for prorating and clash checks.",
          "section": "date-arithmetic",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Days two date ranges have in common, with the end of each range stated as inclusive or exclusive.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "overlapDays"
          ],
          "signatures": [
            "pub fn overlap_days(a_start: &str, a_end: &str, b_start: &str, b_end: &str, end_inclusive: bool) -> i64"
          ],
          "reference": "fune!(dates.overlap@^1);  // then call overlap_days(…)",
          "url": "http://www.functionalweave.com/functions/dates.overlap"
        },
        {
          "id": "dates.age",
          "tier": "optional",
          "why": "Age in whole years on a date, handling 29 February birthdays.",
          "section": "date-arithmetic",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Age in whole years on a given date, with 29 February birthdays ageing on 1 March in other years.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "age"
          ],
          "signatures": [
            "pub fn age(birth_date: &str, on_date: &str) -> i64"
          ],
          "reference": "fune!(dates.age@^1);  // then call age(…)",
          "url": "http://www.functionalweave.com/functions/dates.age"
        }
      ],
      "gaps": []
    },
    {
      "key": "reporting-periods",
      "title": "Periods and reporting dates",
      "purpose": "Put dates into the periods reports are grouped by.",
      "from": "dates-basics",
      "members": [
        {
          "id": "dates.quarter",
          "tier": "core",
          "why": "Calendar and fiscal quarter of a date for any year-start month.",
          "section": "reporting-periods",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Calendar quarter and fiscal quarter of a date, with the fiscal year and quarter date ranges, for any start month.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "quarter"
          ],
          "signatures": [
            "pub fn quarter(iso: &str, fiscal_year_start_month: i64) -> Quarter"
          ],
          "reference": "fune!(dates.quarter@^1);  // then call quarter(…)",
          "url": "http://www.functionalweave.com/functions/dates.quarter"
        },
        {
          "id": "dates.week-number",
          "tier": "optional",
          "why": "ISO week number and week-year, for weekly reports.",
          "section": "reporting-periods",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "ISO 8601 week number and week-numbering year of a date: weeks start Monday, week 1 holds the first Thursday.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "weekNumber"
          ],
          "signatures": [
            "pub fn week_number(iso: &str) -> IsoWeek"
          ],
          "reference": "fune!(dates.week-number@^1);  // then call week_number(…)",
          "url": "http://www.functionalweave.com/functions/dates.week-number"
        },
        {
          "id": "dates.day-count-fraction",
          "tier": "optional",
          "why": "Year fraction by ACT/365F, ACT/360, 30/360 or ACT/ACT, for interest periods.",
          "section": "reporting-periods",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Year fraction between two dates by ACT/365F, ACT/360, 30/360, 30E/360 or ACT/ACT ISDA, as an exact fraction.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "dayCountFraction"
          ],
          "signatures": [
            "pub fn day_count_fraction(start_iso: &str, end_iso: &str, convention: &str) -> YearFraction"
          ],
          "reference": "fune!(dates.day-count-fraction@^1);  // then call day_count_fraction(…)",
          "url": "http://www.functionalweave.com/functions/dates.day-count-fraction"
        }
      ],
      "gaps": []
    },
    {
      "key": "working-days",
      "title": "Working days and holidays",
      "purpose": "Skip weekends and public holidays when counting or adding days.",
      "from": "dates-basics",
      "members": [
        {
          "id": "dates.bank-holidays",
          "tier": "core",
          "why": "UK bank holidays for a region and year, as gov.uk publishes them.",
          "section": "working-days",
          "from": "dates-basics",
          "version": "1.0.1",
          "summary": "UK bank and public holidays for a region and year, as published by gov.uk, including one-off holidays.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "bankHolidays"
          ],
          "signatures": [
            "pub fn bank_holidays(region: &str, year: i64) -> Vec<BankHoliday>"
          ],
          "reference": "fune!(dates.bank-holidays@^1);  // then call bank_holidays(…)",
          "url": "http://www.functionalweave.com/functions/dates.bank-holidays"
        },
        {
          "id": "dates.add-business-days",
          "tier": "core",
          "why": "Moves a date by working days, skipping weekends and a holiday list.",
          "section": "working-days",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Move a date forward or back by working days, skipping weekends and a caller-supplied holiday list.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "addBusinessDays"
          ],
          "signatures": [
            "pub fn add_business_days(iso: &str, days: i64, holidays: &[String]) -> String"
          ],
          "reference": "fune!(dates.add-business-days@^1);  // then call add_business_days(…)",
          "url": "http://www.functionalweave.com/functions/dates.add-business-days"
        },
        {
          "id": "dates.business-days-between",
          "tier": "core",
          "why": "Working days between two dates, for SLAs and notice periods.",
          "section": "working-days",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Working days between two dates, excluding weekends and a caller-supplied holiday list.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "businessDaysBetween"
          ],
          "signatures": [
            "pub fn business_days_between(start_iso: &str, end_iso: &str, holidays: &[String]) -> i64"
          ],
          "reference": "fune!(dates.business-days-between@^1);  // then call business_days_between(…)",
          "url": "http://www.functionalweave.com/functions/dates.business-days-between"
        }
      ],
      "gaps": []
    },
    {
      "key": "repeating-dates",
      "title": "Repeating schedules",
      "purpose": "Generate the dates of something that repeats.",
      "from": "dates-basics",
      "members": [
        {
          "id": "dates.recurrence",
          "tier": "optional",
          "why": "The next n dates of a rule: monthly on the 31st, last Friday, every two weeks.",
          "section": "repeating-dates",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "The next n dates of a repeating rule: monthly on a day, last weekday of the month, every k days or weeks, yearly.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "recurrence"
          ],
          "signatures": [
            "pub fn recurrence(rule: &RecurrenceRule, start_iso: &str, count: i64) -> Vec<String>"
          ],
          "reference": "fune!(dates.recurrence@^1);  // then call recurrence(…)",
          "url": "http://www.functionalweave.com/functions/dates.recurrence"
        }
      ],
      "gaps": []
    },
    {
      "key": "times",
      "title": "Times and durations",
      "purpose": "Work with times of day, durations and timestamps.",
      "from": "dates-basics",
      "members": [
        {
          "id": "time.duration",
          "tier": "optional",
          "why": "Parses and adds durations like 1h30m in whole minutes, and formats the total.",
          "section": "times",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Parse durations written as 1h30m, 90m or 01:30, add them up in whole minutes, and format the total.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "duration"
          ],
          "signatures": [
            "pub fn duration(parts: &[String]) -> Duration"
          ],
          "reference": "fune!(time.duration@^1);  // then call duration(…)",
          "url": "http://www.functionalweave.com/functions/time.duration"
        },
        {
          "id": "time.minutes-between",
          "tier": "optional",
          "why": "Minutes between two local date-times, across midnight.",
          "section": "times",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Minutes from one local date and time to another, correct across midnight; wall-clock time, no time zones.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "minutesBetween"
          ],
          "signatures": [
            "pub fn minutes_between(start_date: &str, start_time: &str, end_date: &str, end_time: &str) -> i64"
          ],
          "reference": "fune!(time.minutes-between@^1);  // then call minutes_between(…)",
          "url": "http://www.functionalweave.com/functions/time.minutes-between"
        },
        {
          "id": "time.round-to-increment",
          "tier": "optional",
          "why": "Rounds minutes to a billing increment such as 6 or 15.",
          "section": "times",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Round a duration in minutes to a billing increment such as 6 or 15 minutes, up, down or to nearest.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "roundToIncrement"
          ],
          "signatures": [
            "pub fn round_to_increment(minutes: i64, increment: i64, mode: &RoundingMode) -> i64"
          ],
          "reference": "fune!(time.round-to-increment@^1);  // then call round_to_increment(…)",
          "url": "http://www.functionalweave.com/functions/time.round-to-increment"
        },
        {
          "id": "time.iso-to-unix",
          "tier": "optional",
          "why": "RFC 3339 timestamps to Unix seconds.",
          "section": "times",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "An RFC 3339 timestamp with a Z or offset, such as 2026-09-26T13:00:00+01:00, to Unix time in whole seconds.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "isoToUnix"
          ],
          "signatures": [
            "pub fn iso_to_unix(timestamp: &str) -> i64"
          ],
          "reference": "fune!(time.iso-to-unix@^1);  // then call iso_to_unix(…)",
          "url": "http://www.functionalweave.com/functions/time.iso-to-unix"
        },
        {
          "id": "time.unix-to-iso",
          "tier": "optional",
          "why": "Unix seconds to an ISO 8601 UTC timestamp.",
          "section": "times",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Unix time in seconds to an ISO 8601 UTC timestamp such as 2026-09-26T12:00:00Z, for years 0001 to 9999.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "unixToIso"
          ],
          "signatures": [
            "pub fn unix_to_iso(seconds: i64) -> String"
          ],
          "reference": "fune!(time.unix-to-iso@^1);  // then call unix_to_iso(…)",
          "url": "http://www.functionalweave.com/functions/time.unix-to-iso"
        },
        {
          "id": "time.countdown",
          "tier": "optional",
          "why": "Seconds left until a moment and a 4:05 style timer text.",
          "section": "times",
          "from": "dates-basics",
          "version": "1.0.0",
          "summary": "Seconds left until a Unix time, whether it has passed, and a timer text like 4:05, for tokens or retry waits.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "countdown"
          ],
          "signatures": [
            "pub fn countdown(until: i64, now: i64) -> Countdown"
          ],
          "reference": "fune!(time.countdown@^1);  // then call countdown(…)",
          "url": "http://www.functionalweave.com/functions/time.countdown"
        }
      ],
      "gaps": []
    }
  ],
  "gaps": [
    {
      "key": "probes",
      "text": "Running the probes: HTTP requests, TLS handshakes and pings from several locations on a schedule are network I/O and yours.",
      "section": "checks",
      "from": "monitoring"
    },
    {
      "key": "notifications",
      "text": "Delivering alerts by email, SMS, Slack, PagerDuty or webhooks, with retries and on-call schedules.",
      "section": "alerting",
      "from": "monitoring"
    },
    {
      "key": "metrics-storage",
      "text": "Storing time series and logs (a TSDB, Prometheus, a database) and querying them.",
      "section": "metrics",
      "from": "monitoring"
    },
    {
      "key": "scheduler",
      "text": "The loop that runs checks every minute and keeps state between runs.",
      "section": null,
      "from": "monitoring"
    },
    {
      "key": "subscriber-updates",
      "text": "Status page subscriptions and incident updates written by people.",
      "section": null,
      "from": "monitoring"
    },
    {
      "key": "rendering",
      "text": "Drawing: caps returns numbers and SVG path strings; putting them in SVG, canvas or a chart component is yours.",
      "section": null,
      "from": "dashboards"
    },
    {
      "key": "interactivity",
      "text": "Tooltips, zoom, pan, brushing and animation.",
      "section": null,
      "from": "dashboards"
    },
    {
      "key": "data-queries",
      "text": "Querying and aggregating the data at source (SQL, a metrics store); monitor.rollup covers time buckets in memory.",
      "section": null,
      "from": "dashboards"
    },
    {
      "key": "pie-donut-chart",
      "text": "A complete pie or donut chart: charts.shape gives pieAngles and arcPath, assembling legend and labels is yours.",
      "section": null,
      "from": "dashboards"
    },
    {
      "key": "time-zones",
      "text": "Time axes in local time zones: charts work in UTC dates and times.",
      "section": null,
      "from": "dashboards"
    },
    {
      "key": "locale-formatting",
      "text": "Showing dates in a user's language and format (\"3 octobre 2026\"): caps returns ISO dates, not localised text.",
      "section": null,
      "from": "dates-basics"
    },
    {
      "key": "non-uk-holidays",
      "text": "Public holidays outside the UK: dates.bank-holidays is UK only; pass another country's list to the working-day functions yourself.",
      "section": null,
      "from": "dates-basics"
    }
  ],
  "counts": {
    "members": 75,
    "core": 25,
    "optional": 50,
    "unreviewed": 0,
    "deprecated": [],
    "unavailable": [],
    "missing": [],
    "gaps": 12
  },
  "warnings": [],
  "url": "http://www.functionalweave.com/suites/monitoring",
  "owner": null
}
