Files
Paul HittandClaude Opus 5.5 520ae2b206 Publish to the GitLab package registry on version tags
The README's install line failed: the package was never published, and
nothing told npm where the @extant2000 scope lives. A tag like v1.2.3 now
publishes to this project's registry with CI_JOB_TOKEN, and the README
sets the scope's registry before installing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:42:19 -04:00

102 lines
4.0 KiB
Markdown

# ProofOfUp
Computes availability for uptime and SLA statements from probe samples, and
refuses to report a number the samples do not support. It is used in Hitt
Hosting products.
## What it does and why
An uptime figure is only as good as the samples behind it, and the common
failures all flatter the service. ProofOfUp computes availability over
samples you have already loaded and handles the edge cases in the direction
of saying less.
**Zero samples is not 100%.** With no samples, `uptime_pct` is `null`, and
the report says availability cannot be computed. A statement that answers
"100%" when nothing was measured is worse than one that abstains. It also
does not say the SLA was missed: when a target applies but nothing was
measured, the report is not assessed and states that the target was neither
met nor missed. (The raw `met` field stays `false` in that case.)
"No SLA target" is not "SLA met". With no target, `met` is `null` and the
report says no SLA target applies to this plan, so a free plan never gets a
statement that reads as a failure.
The rest of the arithmetic:
- the window is half-open, `[from, to)`, so adjacent monthly statements never
count a boundary sample twice;
- samples outside the window or with bad timestamps are dropped, not counted;
- each failing sample is charged the gap to the next sample, capped at one
probe interval (300 seconds by default), so a long reporting gap after one
failure cannot inflate downtime; the last sample is charged one interval;
- samples inside scheduled maintenance windows are removed from the math as if
the probe never ran; cancelled windows are ignored, overlapping windows are
merged, and windows are clipped to the period;
- uptime is rounded to one decimal, and the result does not depend on the
order of the input.
The functions are pure, with no I/O and no clock, so the same samples always
give the same numbers. That is what makes an availability figure evidence and
not a reading taken at a moment. Reports use the `@extant2000/evidence-record`
format. The availability citation carries its sample count, so 100% over zero
samples cannot be mistaken for 100% over thousands, and excluded maintenance
is reported as not applicable with its own measurement so planned downtime
stays visible.
## Usage
```ts
import { slaReport, formatSla, describeAvailability, describeTarget, type Check } from '@extant2000/proof-of-up'
// One probe result every five minutes, loaded from wherever you store them.
const checks: Check[] = [
{ ts: '2026-08-01T00:00:00Z', ok: true },
{ ts: '2026-08-01T00:05:00Z', ok: false },
// ...
]
const report = slaReport(checks, {
from: '2026-08-01T00:00:00Z',
to: '2026-09-01T00:00:00Z',
target: 99.9, // omit or null for no SLA
intervalSeconds: 300,
excludeWindows: [{ starts_at: '2026-08-10T02:00:00Z', ends_at: '2026-08-10T03:00:00Z' }],
})
describeAvailability(report) // e.g. 'Availability 99.8% over 8916 samples, 100 minutes down.'
describeTarget(report) // e.g. 'Target 99.9% was NOT met.'
console.log(formatSla(report, { subject: 'app.example.com' }))
```
For a month of five-minute samples with 20 failures and one hour of
maintenance, `formatSla()` printed this (header line omitted):
```
NOT MET · 8916 items examined · 2 findings
Availability 99.8% over 8916 samples, 100 minutes down.
Target 99.9% was NOT met.
✗ CRITICAL Availability 99.8% over 8916 samples, 100 minutes down. [NOT MET]
Target 99.9% was NOT met.
evidence: Availability = 99.8% (8916 samples, 2026-08-01 → 2026-09-01)
◦ info 60 minutes of scheduled maintenance excluded (12 samples) [N/A]
```
With no samples, the same call reports NOT ASSESSED and "No samples in this
period; availability cannot be computed."
## Install
The package is published to the GitLab package registry, so point the
`@extant2000` scope there first:
```
npm config set @extant2000:registry https://gitlab.com/api/v4/packages/npm/
npm install @extant2000/proof-of-up
```
## License
MIT. See [LICENSE](LICENSE).