From 4e30822fc02bb7253e7e7967685d94f7513a672e Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 24 Mar 2026 14:56:31 +0000 Subject: [PATCH] Drop monitored system reason alias fallback --- .../v6/internal/subsystems/api-contracts.md | 5 +- .../__tests__/monitoredSystemLedger.test.ts | 49 ------------------- .../src/api/monitoredSystemLedger.ts | 3 +- .../monitoredSystemModelGuardrails.test.ts | 2 +- 4 files changed, 4 insertions(+), 55 deletions(-) diff --git a/docs/release-control/v6/internal/subsystems/api-contracts.md b/docs/release-control/v6/internal/subsystems/api-contracts.md index 184d95e7f..e9a934bc2 100644 --- a/docs/release-control/v6/internal/subsystems/api-contracts.md +++ b/docs/release-control/v6/internal/subsystems/api-contracts.md @@ -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 diff --git a/frontend-modern/src/api/__tests__/monitoredSystemLedger.test.ts b/frontend-modern/src/api/__tests__/monitoredSystemLedger.test.ts index b4bef5f1f..dae7a2e3f 100644 --- a/frontend-modern/src/api/__tests__/monitoredSystemLedger.test.ts +++ b/frontend-modern/src/api/__tests__/monitoredSystemLedger.test.ts @@ -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: [ diff --git a/frontend-modern/src/api/monitoredSystemLedger.ts b/frontend-modern/src/api/monitoredSystemLedger.ts index 50e51d39c..91f45da3f 100644 --- a/frontend-modern/src/api/monitoredSystemLedger.ts +++ b/frontend-modern/src/api/monitoredSystemLedger.ts @@ -89,7 +89,6 @@ interface MonitoredSystemLedgerRawStatusExplanation interface MonitoredSystemLedgerRawStatusReason extends Omit { 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, }; } diff --git a/frontend-modern/src/components/Settings/__tests__/monitoredSystemModelGuardrails.test.ts b/frontend-modern/src/components/Settings/__tests__/monitoredSystemModelGuardrails.test.ts index 01b3cffe1..6d647b6a3 100644 --- a/frontend-modern/src/components/Settings/__tests__/monitoredSystemModelGuardrails.test.ts +++ b/frontend-modern/src/components/Settings/__tests__/monitoredSystemModelGuardrails.test.ts @@ -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.', );