86 lines
3.5 KiB
Markdown
86 lines
3.5 KiB
Markdown
# OnePane
|
|
|
|
Rolls health signals from different tools and stacks into one report, and
|
|
refuses to show a signal as healthy when it cannot be trusted.
|
|
|
|
## What it does and why
|
|
|
|
Collecting status from an uptime checker, an error tracker, CI and each
|
|
service's own endpoints into one board is mostly plumbing. The part that is
|
|
not plumbing is knowing when a green panel is lying. It lies in two specific
|
|
ways, and OnePane is built against both.
|
|
|
|
### Silence shown as health
|
|
|
|
An error board shows zero events for every product. They are not healthy:
|
|
the ingestion quota ran out and nothing is being recorded. Every panel is
|
|
green because no signal arrived, and that is the one state a dashboard must
|
|
never draw the same as "fine". So a reading older than the freshness window
|
|
(15 minutes by default) is reported as not assessed, with the note that the
|
|
panel is showing its last reading, not the current state. A reading with no
|
|
timestamp is treated the same way, because it cannot be told apart from a
|
|
stale one.
|
|
|
|
### Shared identity taken as per-subject evidence
|
|
|
|
Several products report through one error-tracking project. A per-product
|
|
search returns nothing and reads as "zero errors in this product", when it
|
|
means "this product cannot be separated in the data". Absence of attributed
|
|
events is not absence of events. When two subjects from the same source
|
|
share an `attributedTo` value, `ambiguousAttribution()` names them ("errors
|
|
cannot separate api, shop"), and every per-subject reading from that source
|
|
is reported as not assessed. A named list is something you can act on;
|
|
"attribution ambiguous" is not.
|
|
|
|
The rest of the rules:
|
|
|
|
- a subject in `expectedSubjects` with no signal at all is reported, since it
|
|
is green only because nothing was ever wired to it;
|
|
- a `null` value with no health state is not assessed, never coerced to zero;
|
|
- `down` fails at critical severity and `degraded` at high;
|
|
- an empty board is not assessed, never healthy.
|
|
|
|
The library is pure: no HTTP and no clock. `now` is a parameter, because a
|
|
freshness check that reads the clock cannot be tested and its output cannot
|
|
be reproduced. Reports use the `@extant2000/evidence-record` format.
|
|
|
|
## Usage
|
|
|
|
```ts
|
|
import { unify, formatPane, ambiguousAttribution, type Signal } from '@extant2000/one-pane'
|
|
|
|
const signals: Signal[] = [
|
|
{ source: 'uptime', subject: 'shop', metric: 'availability', value: 100, health: 'up',
|
|
observedAt: '2026-09-28T11:58:00Z', where: 'https://status.example.com' },
|
|
{ source: 'errors', subject: 'shop', metric: 'errors', value: 0, health: 'up',
|
|
observedAt: '2026-09-28T11:59:00Z', attributedTo: 'shared-project', where: 'error tracker search' },
|
|
{ source: 'errors', subject: 'api', metric: 'errors', value: 0, health: 'up',
|
|
observedAt: '2026-09-28T11:59:00Z', attributedTo: 'shared-project', where: 'error tracker search' },
|
|
{ source: 'ci', subject: 'billing', metric: 'last-deploy', value: 1, health: 'up',
|
|
observedAt: '2026-09-26T08:00:00Z', where: 'ci pipeline' },
|
|
]
|
|
|
|
const opts = {
|
|
now: '2026-09-28T12:00:00Z', // injected, never read from the clock
|
|
maxAgeSeconds: 900,
|
|
expectedSubjects: ['shop', 'api', 'billing', 'docs'],
|
|
}
|
|
|
|
const report = unify(signals, opts)
|
|
console.log(formatPane(signals, opts))
|
|
```
|
|
|
|
In this example only the shop availability reading passes. The two error
|
|
counts of zero are not assessed because both products share one project, the
|
|
billing reading is two days old, and `docs` has no signal at all.
|
|
|
|
## Install
|
|
|
|
```
|
|
npm install @extant2000/one-pane
|
|
```
|
|
|
|
## License
|
|
|
|
MIT. See [LICENSE](LICENSE).
|