import { describe, expect, it } from 'vitest' import { overall, validateReport } from '@extant2000/evidence-record' import { ambiguousAttribution, formatPane, unify, type Signal } from '../src/index.js' const NOW = '2026-08-01T12:00:00Z' const fresh = '2026-08-01T11:58:00Z' const old = '2026-08-01T09:00:00Z' const sig = (p: Partial = {}): Signal => ({ source: 'gatus', subject: 'crm', metric: 'availability', value: 100, health: 'up', observedAt: fresh, where: 'https://status.example.com', ...p, }) describe('silence is not health', () => { it('a stale panel is NOT ASSESSED, not green', () => { // An error board can show zero events because ingestion stopped, not // because nothing went wrong. const r = unify([sig({ observedAt: old })], { now: NOW }) expect(r.findings[0]!.determination).toBe('not-assessed') expect(overall(r)).toBe('not-assessed') const text = formatPane([sig({ observedAt: old })], { now: NOW }) expect(text).toContain('Silence is not health') expect(text).toContain('showing its last reading') expect(text).not.toContain('✓') }) it('passes a reading inside the freshness window', () => { expect(overall(unify([sig()], { now: NOW }))).toBe('pass') }) it('honours a custom freshness window', () => { // 2 minutes old, with a 60-second window. expect(overall(unify([sig()], { now: NOW, maxAgeSeconds: 60 }))).toBe('not-assessed') }) it('treats an unstamped reading as indistinguishable from a stale one', () => { const r = unify([sig({ observedAt: undefined })], { now: NOW }) expect(r.findings[0]!.determination).toBe('not-assessed') expect(r.findings[0]!.detail).toContain('may be current; nothing here establishes that') }) it('reports an expected subject with no signal at all', () => { const r = unify([sig({ subject: 'crm' })], { now: NOW, expectedSubjects: ['crm', 'hr', 'desk'] }) const missing = r.findings.filter(f => f.id.endsWith('/missing')) expect(missing).toHaveLength(2) expect(missing[0]!.detail).toContain('green because nothing was ever wired to it') }) }) describe('shared identity is not per-subject evidence', () => { // Several products reporting through ONE error-tracking project. A // per-product search returning nothing means "not separable", not "no errors". const shared = [ sig({ source: 'sentry', subject: 'crm', metric: 'errors', value: 0, attributedTo: 'shared-project' }), sig({ source: 'sentry', subject: 'hr', metric: 'errors', value: 0, attributedTo: 'shared-project' }), sig({ source: 'sentry', subject: 'desk', metric: 'errors', value: 0, attributedTo: 'shared-project' }), ] it('names the entangled subjects rather than saying "ambiguous"', () => { const groups = ambiguousAttribution(shared) expect(groups).toHaveLength(1) expect(groups[0]!.subjects).toEqual(['crm', 'desk', 'hr']) }) it('refuses to read a shared-identity zero as a per-subject pass', () => { const r = unify(shared, { now: NOW }) expect(overall(r)).toBe('not-assessed') for (const f of r.findings.filter(f => f.id.startsWith('crm/'))) { expect(f.determination).toBe('not-assessed') } }) it('says what a search returning nothing actually means', () => { const text = formatPane(shared, { now: NOW }) expect(text).toContain('absence of attributed events is not absence of events') expect(text).toContain('crm, desk, hr') }) it('leaves a uniquely-attributed signal alone', () => { const distinct = [ sig({ source: 'sentry', subject: 'crm', attributedTo: 'crm-prod' }), sig({ source: 'sentry', subject: 'hr', attributedTo: 'hr-prod' }), ] expect(ambiguousAttribution(distinct)).toEqual([]) expect(overall(unify(distinct, { now: NOW }))).toBe('pass') }) it('does not entangle the same identity across different sources', () => { // gatus/"prod" and sentry/"prod" are unrelated namespaces. const r = ambiguousAttribution([ sig({ source: 'gatus', subject: 'crm', attributedTo: 'prod' }), sig({ source: 'sentry', subject: 'hr', attributedTo: 'prod' }), ]) expect(r).toEqual([]) }) }) describe('health states', () => { it('reports down as critical and degraded as high', () => { expect(unify([sig({ health: 'down' })], { now: NOW }).findings[0]!.severity).toBe('critical') expect(unify([sig({ health: 'degraded' })], { now: NOW }).findings[0]!.severity).toBe('high') expect(overall(unify([sig({ health: 'down' })], { now: NOW }))).toBe('fail') }) it('reports an uncomputable value as not-assessed, not zero', () => { const r = unify([sig({ value: null, health: undefined })], { now: NOW }) expect(r.findings[0]!.determination).toBe('not-assessed') }) it('carries the sample count into the citation for a null value', () => { const text = formatPane([sig({ value: null, health: undefined })], { now: NOW, evidence: 'inline' }) expect(text).toContain('not computable') expect(text).toContain('0 samples') }) }) describe('conformance with the evidence-record standard', () => { it('an empty board is not-assessed, never healthy', () => { const r = unify([], { now: NOW }) expect(overall(r)).toBe('not-assessed') expect(formatPane([], { now: NOW })).toContain('An empty board is not a healthy one') }) it('every conclusion carries a citation', () => { expect(validateReport(unify([sig(), sig({ subject: 'hr', health: 'down' })], { now: NOW }))).toEqual([]) }) })