Files
one-pane/README.md
T
2026-09-28 14:49:01 -04:00

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).