Drop monitored system reason alias fallback

This commit is contained in:
rcourtman 2026-03-24 14:56:31 +00:00
parent c9b3ade048
commit 4e30822fc0
4 changed files with 4 additions and 55 deletions

View file

@ -260,9 +260,8 @@ The backend payload contract now emits only that structured object, and the
frontend monitored-system client should parse that canonical wire contract
directly rather than keeping flat alias fallback for
`latest_included_signal_at`, `latest_included_signal_source`, or `last_seen`.
The canonical nested status-reason timestamp is `reported_at`; older raw
payloads may map a legacy nested `last_seen` input forward during rollout, but
the normalized client contract must expose only `reported_at`.
The canonical nested status-reason timestamp is `reported_at`, and the
normalized client contract must expose only that field.
That client contract must also fail closed when older or partial payloads omit
the nested explanation object: the frontend may normalize missing explanation
fields to empty reasons/surfaces plus a safe default summary, but it must not

View file

@ -242,55 +242,6 @@ describe('MonitoredSystemLedgerAPI', () => {
]);
});
it('maps legacy status reason last_seen fields onto the canonical reported_at contract', async () => {
vi.mocked(apiFetchJSON).mockResolvedValueOnce({
systems: [
{
name: 'Tower',
type: 'host',
status: 'warning',
status_explanation: {
summary: 'At least one included source is stale, so Pulse marks this monitored system as warning.',
reasons: [
{
kind: 'source-stale',
name: 'Tower',
type: 'host',
source: 'agent',
status: 'stale',
last_seen: '2026-03-23T11:55:00Z',
summary: 'Agent data for Tower is stale (last reported 2026-03-23T11:55:00Z).',
},
],
},
latest_included_signal: {
name: 'tower.local',
type: 'docker-host',
source: 'docker',
at: '2026-03-23T11:59:50Z',
},
source: 'multiple',
},
],
total: 1,
limit: 5,
});
const result = await MonitoredSystemLedgerAPI.getLedger();
expect(result.systems[0]?.status_explanation?.reasons).toEqual([
{
kind: 'source-stale',
name: 'Tower',
type: 'host',
source: 'agent',
status: 'stale',
reported_at: '2026-03-23T11:55:00Z',
summary: 'Agent data for Tower is stale (last reported 2026-03-23T11:55:00Z).',
},
]);
});
it('fails closed to unknown for unsupported status values', async () => {
vi.mocked(apiFetchJSON).mockResolvedValueOnce({
systems: [

View file

@ -89,7 +89,6 @@ interface MonitoredSystemLedgerRawStatusExplanation
interface MonitoredSystemLedgerRawStatusReason
extends Omit<MonitoredSystemLedgerStatusReason, 'reported_at'> {
reported_at?: string;
last_seen?: string;
}
export class MonitoredSystemLedgerAPI {
@ -154,7 +153,7 @@ function normalizeMonitoredSystemLedgerStatusReason(
type: reason.type,
source: reason.source,
status: normalizeMonitoredSystemLedgerStatusReasonStatus(reason.status),
reported_at: reason.reported_at ?? reason.last_seen ?? '',
reported_at: reason.reported_at ?? '',
summary: reason.summary,
};
}

View file

@ -256,7 +256,7 @@ describe('monitored-system model guardrails', () => {
expect(monitoredSystemLedgerApiSource).not.toContain('last_seen: string;');
expect(monitoredSystemLedgerApiSource).not.toContain('latest_included_signal_at?: string;');
expect(monitoredSystemLedgerApiSource).not.toContain('latest_included_signal_source?: string;');
expect(monitoredSystemLedgerApiSource).toContain('last_seen?: string;');
expect(monitoredSystemLedgerApiSource).not.toContain('last_seen?: string;');
expect(monitoredSystemLedgerApiSource).not.toContain(
'All included top-level collection paths currently report online status.',
);