Skip to content

fix: fleet node health — use actual node status instead of hardcoded UNKNOWN#104

Open
TerrifiedBug wants to merge 2 commits intomainfrom
Priya/VF-5-fix-fleet-node-health-uptime-s
Open

fix: fleet node health — use actual node status instead of hardcoded UNKNOWN#104
TerrifiedBug wants to merge 2 commits intomainfrom
Priya/VF-5-fix-fleet-node-health-uptime-s

Conversation

@TerrifiedBug
Copy link
Owner

Summary

  • getStatusTimeline router now returns { events, nodeStatus } — fetches the node's current DB status in parallel with events
  • getUptime router falls back to nodeForStatus?.status before "UNKNOWN" when no prior event exists
  • StatusTimeline component uses data.nodeStatus as the segment status when there are no events in range, instead of hardcoding "UNKNOWN"

Root Cause

Nodes that have been healthy since before the selected time range have no NodeStatusEvent records in that window. The original code defaulted to "UNKNOWN" in this case, causing:

  • Timeline to render grey (unknown) instead of green (healthy)
  • Uptime to calculate 0.00% (treating UNKNOWN time as non-healthy)

Test plan

  • Open a node that has no status events in the selected time range — timeline should show the node's actual current status color (green if HEALTHY), not grey/UNKNOWN
  • Open a node with events — behavior unchanged
  • Check uptime % for a node with no prior events — should reflect current status rather than defaulting UNKNOWN (0% healthy)

Closes VF-5

🤖 Generated with Claude Code

- getStatusTimeline returns { events, nodeStatus } — fetches node's current
  DB status in parallel so the timeline shows actual status when no events exist
- getUptime falls back to nodeForStatus.status before "UNKNOWN" for nodes
  with no prior event history, preventing 0.00% uptime for healthy nodes
- StatusTimeline uses data.nodeStatus for the empty-range segment instead
  of hardcoded "UNKNOWN", fixing the grey/unknown display for healthy nodes

Fixes VF-5: uptime shows 0.00 (red) and status timeline shows unknown

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added the fix label Mar 15, 2026
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 15, 2026

Greptile Summary

This PR fixes fleet node health display by fetching the node's actual DB status instead of hardcoding "UNKNOWN" when no status events exist in the selected time range. The getStatusTimeline and getUptime routers now query the node's current status in parallel and use it as a fallback, so the timeline renders the correct color and uptime calculates accurately.

  • getStatusTimeline return type changed from a flat array to { events, nodeStatus }StatusTimeline component updated accordingly
  • getUptime falls back to the node's current status (nodeForStatus?.status) before "UNKNOWN" when no prior event exists
  • Bug: EventLog component (event-log.tsx) was not updated for the new getStatusTimeline return shape and will crash at runtime with TypeError: events is not iterable

Confidence Score: 2/5

  • This PR will cause a runtime crash in the EventLog component due to an unconverted consumer of the changed return type.
  • The core fix logic is correct, but the getStatusTimeline return type change was not propagated to all consumers. The EventLog component still destructures the response as a flat array, which will throw a TypeError at runtime. This is a breaking regression that affects the node detail page.
  • src/components/fleet/event-log.tsx — must be updated to handle the new { events, nodeStatus } return shape from getStatusTimeline

Important Files Changed

Filename Overview
src/server/routers/fleet.ts Correctly fetches node status in parallel for both getStatusTimeline and getUptime. Return type change is sound, but the new shape breaks an unconverted consumer (event-log.tsx).
src/components/fleet/status-timeline.tsx Correctly updated to destructure data.events and data.nodeStatus from the new return shape. Memo dependencies updated appropriately.

Sequence Diagram

sequenceDiagram
    participant UI as StatusTimeline / EventLog
    participant tRPC as getStatusTimeline
    participant DB as PostgreSQL

    UI->>tRPC: queryOptions({ nodeId, range })
    tRPC->>DB: Promise.all([findMany NodeStatusEvent, findUnique VectorNode])
    DB-->>tRPC: [events[], node]
    tRPC-->>UI: { events, nodeStatus: node?.status ?? "UNKNOWN" }
    Note over UI: StatusTimeline uses data.events + data.nodeStatus ✅
    Note over UI: EventLog still expects flat array ❌
Loading

Comments Outside Diff (1)

  1. src/components/fleet/event-log.tsx, line 35-50 (link)

    EventLog not updated for new return type — runtime crash

    The getStatusTimeline router now returns { events, nodeStatus } instead of a flat array, but this component still destructures the response as data: events. This means events on line 50 is the entire { events, nodeStatus } object, not an array.

    [...events].reverse() will throw TypeError: events is not iterable at runtime because a plain object is not iterable.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/components/fleet/event-log.tsx
Line: 35-50

Comment:
**`EventLog` not updated for new return type — runtime crash**

The `getStatusTimeline` router now returns `{ events, nodeStatus }` instead of a flat array, but this component still destructures the response as `data: events`. This means `events` on line 50 is the entire `{ events, nodeStatus }` object, not an array.

`[...events].reverse()` will throw `TypeError: events is not iterable` at runtime because a plain object is not iterable.

```suggestion
  const { data, isLoading } = useQuery({
    ...trpc.fleet.getStatusTimeline.queryOptions({ nodeId, range }),
    refetchInterval: 15_000,
  });

  if (isLoading) {
    return (
      <div className="space-y-2">
        <Skeleton className="h-8 w-full rounded" />
        <Skeleton className="h-8 w-full rounded" />
        <Skeleton className="h-8 w-full rounded" />
      </div>
    );
  }

  const reversed = data?.events ? [...data.events].reverse() : [];
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: f023f77

getStatusTimeline now returns { events, nodeStatus } instead of a plain
array. EventLog was still treating data as an array, causing it to always
render empty. Destructure data.events to restore correct behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant