Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Service Level Indicator

observability.calculate_sli

ProductionBounded custom (Class B)Deterministicstrictfastv1.0.0
No network

Overview

You send the events, the window and a closed set of good-event predicates, and we return the indicator as a ratio in zero to one, the counts behind it, and the sub-windows that fell below your objective. Every event is good, bad or invalid, and invalid events leave the denominator and are reported, because an availability figure over a denominator that silently shrank is worse than no figure. An empty window is a verdict rather than a failure, so this can be called on a schedule at three in the morning. The window is yours: we read no clock and fetch nothing.

Writing this by hand is where availability numbers go wrong: the denominator quietly drops unparseable events, the boundary is inclusive at both ends so adjacent hours double-count, and the breach test compares an unrounded value against a rounded one.

Reliability

Fully deterministic and clock-free: the same events and window always give the same value, and nothing about the answer depends on when you asked. Rounding is half-up at your scale and the breach comparison uses the rounded value. Failures, none worth retrying unchanged: OBS_SLI_INPUT_MISSING means events or buckets was absent or empty for the kind you chose, so send the one that kind consumes. OBS_SLI_INPUT_AMBIGUOUS means both events and buckets arrived, so send one. OBS_SLI_INPUT_TOO_LARGE means the events or buckets array went past the 2097152-byte inline ceiling, so send fewer entries or fewer fields each. OBS_SLI_WINDOW_INVALID means end was not after start, the span fell outside 1 millisecond to 366 days, or the window object was missing. OBS_SLI_TIMESTAMP_INVALID means a timestamp was absent, unparseable or carried no offset, and the answer names its position. OBS_SLI_OFFSET_MIXED means the list mixed offsets under REQUIRE_UNIFORM or carried a non-UTC one under REQUIRE_UTC, and both positions are named. OBS_SLI_KIND_UNSUPPORTED means the kind is not one of the four. OBS_SLI_PREDICATE_UNSUPPORTED means a predicate type or a status class is not in the vocabulary. OBS_SLI_PREDICATE_INVALID means a predicate had the wrong shape, an empty value list or a threshold out of range. OBS_SLI_SPEC_FIELD_MISSING means kind, goodWhen, latencyField or thresholdMs was required for your kind and absent. OBS_SLI_OBJECTIVE_INVALID means the objective fell outside 0.5 to 0.999999 or carried more than 6 decimal places. OBS_SLI_BUCKET_INVALID means bucketDurationSeconds was missing, out of range or sent without an objective, or a bucket's good exceeded its total. OBS_SLI_BUCKET_LIMIT_EXCEEDED means the window divides into more than 10000 buckets, or more than 10000 counters arrived, so widen the bucket. OBS_SLI_EVENT_LIMIT_EXCEEDED means more than 50000 events arrived, so split the window and combine the counts yourself. OBS_SLI_SAMPLE_NON_FINITE means a latency field carried an infinity or a not-a-number, which is a producer defect rather than an invalid event. OBS_SLI_OPTION_UNSUPPORTED means a property, a scale or an offset policy is not one we accept. OBS_SLI_WORK_REFUSED means the projected work went past 410000 units, where a latency threshold counts as one predicate, and the answer carries the projection and the budget.

Context footprint

Echoes no event; the answer is a value, seven counts and at most 1000 breach entries, so it stays small whatever you send. A successful call costs 2 execution credits.

When to use it

When you hold the events or the counters and want a defensible ratio, its counts, and the sub-windows that breached.

When you want a burn rate against an error budget, a percentile of a latency series, or a deadline on a working calendar.

Scope

Note
Compute one ratio-valued service level indicator over one caller-declared window, and list the sub-windows that fell below the objective.

Non-goals

  • Does not fetch, scrape or store any metric or event
  • Does not read a clock — every window boundary arrives in the request
  • Does not evaluate a boolean expression language, only allOf over a closed set
  • Does not compute a deadline against a working calendar
  • Does not report a percentage; every value is a ratio between 0 and 1

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

analysis

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call2 credits

File handling

Accepts file_refProduces file_refMax input2 MB

How we handle your data

Sensitive input, safe output
What this means

This skill may receive sensitive content, but it does not target sensitive data and returns only a structured non-sensitive result.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response does not contain submitted content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
eventsarrayNoRequired unless buckets is provided. 1 to 50000 events each carrying t plus predicate fields.
bucketsarrayNoRequired unless events is provided. 1 to 10000 {t, good, total} counters for AGGREGATE_RATIO.
windowobjectYesClosed half-open window [start, end) as ISO-8601 instants with explicit offsets.
sliSpecobjectYesClosed indicator spec: kind, 1 to 8 goodWhen predicates, and latencyField plus thresholdMs only for LATENCY_THRESHOLD_COMPLIANCE.
objectivenumberNoRatio between 0.5 and 0.999999; omit it for the indicator with no verdict and an empty breaches list.
bucketDurationSecondsintegerNoRequired unless objective is omitted. Bucket width from 1 through 86400 seconds.
scaleintegerNoDecimal places from 0 through 12; omit it for 6.
offsetPolicystringNoOffset mixing rule; omit it for REQUIRE_UNIFORM.

Output schema

FieldTypeRequiredDescription
valuenumberYesIndicator as a ratio between 0 and 1 at your scale, or JSON null when the window held no valid event.
verdictstringYesMET, BREACHED, UNDEFINED_EMPTY_WINDOW, UNDEFINED_NO_VALID_EVENTS, or JSON null when you supplied no objective.
windowobjectYesParsed window as we applied it, with the inclusivity literal and durationSeconds added so a stored verdict names the interval it judged.
countsobjectYesClosed counters: examined, inWindow, outOfWindow, good, bad, valid and invalid.
invalidRationumberYesInvalid events over in-window events at your scale, or JSON null for an empty window.
breachesarrayYesUp to 1000 sub-windows below the objective, each {bucketStart, bucketEnd, value, validCount, shortfall}; empty without an objective.
summaryobjectYesClosed publication receipt with kind, optional objective, bucketDurationSeconds, bucketCount, breachCount, breachesTruncated, undefinedBucketCount, scale and roundingMode.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"observability.calculate_sli","input":{"events":[{"t":"2026-07-29T10:00:00Z","status":200}],"window":{"start":"2026-07-29T10:00:00Z","end":"2026-07-29T11:00:00Z"},"sliSpec":{"kind":"AVAILABILITY_RATIO","goodWhen":[{"type":"statusCodeIn","field":"status","values":[200]}]}}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("observability.calculate_sli", {"events":[{"status":200,"t":"2026-07-29T10:00:00Z"},{"status":200,"t":"2026-07-29T10:15:00Z"},{"status":503,"t":"2026-07-29T10:30:00Z"},{"status":200,"t":"2026-07-29T11:00:00Z"}],"objective":0.99,"window":{"start":"2026-07-29T10:00:00Z","end":"2026-07-29T11:00:00Z"},"sliSpec":{"goodWhen":[{"type":"statusCodeClassIn","field":"status","classes":["S2XX","S3XX"]}],"kind":"AVAILABILITY_RATIO"},"bucketDurationSeconds":1800});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
OBS_SLI_INPUT_MISSING400NoThe request payload failed this skill's input validation.
OBS_SLI_INPUT_AMBIGUOUS400NoThe request payload failed this skill's input validation.
OBS_SLI_INPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.
OBS_SLI_WINDOW_INVALID400NoThe request payload failed this skill's input validation.
OBS_SLI_TIMESTAMP_INVALID400NoThe request payload failed this skill's input validation.
OBS_SLI_OFFSET_MIXED400NoThe request payload failed this skill's input validation.
OBS_SLI_KIND_UNSUPPORTED400NoThe skill does not support the requested variant.
OBS_SLI_PREDICATE_UNSUPPORTED400NoThe skill does not support the requested variant.
OBS_SLI_PREDICATE_INVALID400NoThe request payload failed this skill's input validation.
OBS_SLI_SPEC_FIELD_MISSING400NoThe request payload failed this skill's input validation.
OBS_SLI_OBJECTIVE_INVALID400NoThe request payload failed this skill's input validation.
OBS_SLI_BUCKET_INVALID400NoThe request payload failed this skill's input validation.
OBS_SLI_BUCKET_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
OBS_SLI_EVENT_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
OBS_SLI_SAMPLE_NON_FINITE400NoThe request payload failed this skill's input validation.
OBS_SLI_OPTION_UNSUPPORTED400NoThe skill does not support the requested variant.
OBS_SLI_WORK_REFUSED429NoA size, quota, rate, or time limit was exceeded.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not fetch, scrape or store any metric or event
  • Does not read a clock — every window boundary arrives in the request
  • Does not evaluate a boolean expression language, only allOf over a closed set
  • Does not compute a deadline against a working calendar
  • Does not report a percentage; every value is a ratio between 0 and 1
  • Computing when a support agreement's clock runs out, which business.sla_deadline answers
  • Comparing an observed value against a burn-rate alert, which observability.evaluate_slo_burn answers

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "observability.calculate_sli",
  "input": {
    "events": [
      {
        "status": 200,
        "t": "2026-07-29T10:00:00Z"
      },
      {
        "status": 200,
        "t": "2026-07-29T10:15:00Z"
      },
      {
        "status": 503,
        "t": "2026-07-29T10:30:00Z"
      },
      {
        "status": 200,
        "t": "2026-07-29T11:00:00Z"
      }
    ],
    "objective": 0.99,
    "window": {
      "start": "2026-07-29T10:00:00Z",
      "end": "2026-07-29T11:00:00Z"
    },
    "sliSpec": {
      "goodWhen": [
        {
          "type": "statusCodeClassIn",
          "field": "status",
          "classes": [
            "S2XX",
            "S3XX"
          ]
        }
      ],
      "kind": "AVAILABILITY_RATIO"
    },
    "bucketDurationSeconds": 1800
  }
}

Examples

Availability over four events, one of them out of the window

Inputjson
{
  "events": [
    {
      "status": 200,
      "t": "2026-07-29T10:00:00Z"
    },
    {
      "status": 200,
      "t": "2026-07-29T10:15:00Z"
    },
    {
      "status": 503,
      "t": "2026-07-29T10:30:00Z"
    },
    {
      "status": 200,
      "t": "2026-07-29T11:00:00Z"
    }
  ],
  "objective": 0.99,
  "window": {
    "start": "2026-07-29T10:00:00Z",
    "end": "2026-07-29T11:00:00Z"
  },
  "sliSpec": {
    "goodWhen": [
      {
        "type": "statusCodeClassIn",
        "field": "status",
        "classes": [
          "S2XX",
          "S3XX"
        ]
      }
    ],
    "kind": "AVAILABILITY_RATIO"
  },
  "bucketDurationSeconds": 1800
}
Expected outputjson
{
  "value": 0.666667,
  "invalidRatio": 0,
  "counts": {
    "examined": 4,
    "inWindow": 3,
    "outOfWindow": 1,
    "good": 2,
    "bad": 1,
    "valid": 3,
    "invalid": 0
  },
  "verdict": "BREACHED",
  "breaches": [
    {
      "bucketStart": "2026-07-29T10:30:00Z",
      "bucketEnd": "2026-07-29T11:00:00Z",
      "value": 0,
      "validCount": 1,
      "shortfall": 0.99
    }
  ],
  "summary": {
    "kind": "AVAILABILITY_RATIO",
    "objective": 0.99,
    "bucketDurationSeconds": 1800,
    "bucketCount": 2,
    "breachCount": 1,
    "breachesTruncated": false,
    "undefinedBucketCount": 0,
    "scale": 6,
    "roundingMode": "HALF_UP"
  },
  "window": {
    "start": "2026-07-29T10:00:00Z",
    "end": "2026-07-29T11:00:00Z",
    "inclusivity": "[start,end)",
    "durationSeconds": 3600
  }
}
Tip
The event exactly on the window end is excluded by the half-open rule, so two of three in-window events are good and the second half-hour is reported as the bucket that breached.

Latency compliance against a threshold, with the breaching half-hour

Inputjson
{
  "events": [
    {
      "latencyMs": 120,
      "status": 200,
      "t": "2026-07-29T10:00:00Z"
    },
    {
      "latencyMs": 800,
      "status": 200,
      "t": "2026-07-29T10:10:00Z"
    },
    {
      "latencyMs": 90,
      "status": 200,
      "t": "2026-07-29T10:20:00Z"
    },
    {
      "latencyMs": 250,
      "status": 200,
      "t": "2026-07-29T10:40:00Z"
    }
  ],
  "objective": 0.95,
  "window": {
    "start": "2026-07-29T10:00:00Z",
    "end": "2026-07-29T11:00:00Z"
  },
  "sliSpec": {
    "kind": "LATENCY_THRESHOLD_COMPLIANCE",
    "latencyField": "latencyMs",
    "goodWhen": [
      {
        "type": "statusCodeClassIn",
        "field": "status",
        "classes": [
          "S2XX"
        ]
      }
    ],
    "thresholdMs": 300
  },
  "bucketDurationSeconds": 1800
}
Expected outputjson
{
  "value": 0.75,
  "invalidRatio": 0,
  "counts": {
    "examined": 4,
    "inWindow": 4,
    "outOfWindow": 0,
    "good": 3,
    "bad": 1,
    "valid": 4,
    "invalid": 0
  },
  "verdict": "BREACHED",
  "breaches": [
    {
      "bucketStart": "2026-07-29T10:00:00Z",
      "bucketEnd": "2026-07-29T10:30:00Z",
      "value": 0.666667,
      "validCount": 3,
      "shortfall": 0.283333
    }
  ],
  "summary": {
    "kind": "LATENCY_THRESHOLD_COMPLIANCE",
    "objective": 0.95,
    "bucketDurationSeconds": 1800,
    "bucketCount": 2,
    "breachCount": 1,
    "breachesTruncated": false,
    "undefinedBucketCount": 0,
    "scale": 6,
    "roundingMode": "HALF_UP"
  },
  "window": {
    "start": "2026-07-29T10:00:00Z",
    "end": "2026-07-29T11:00:00Z",
    "inclusivity": "[start,end)",
    "durationSeconds": 3600
  }
}
Tip
Compliance is the share of requests at or under the threshold, and the shortfall on the breaching bucket is the distance to your objective rather than a restatement of the value.
  • Turn a batch of request events into an availability figure with visible counts
  • Find which five-minute buckets of an hour fell below the objective

Avoid for

  • Computing when a support agreement's clock runs out, which business.sla_deadline answers
  • Comparing an observed value against a burn-rate alert, which observability.evaluate_slo_burn answers

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

analysissreobservabilitymetrics