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