Skip to content

feat: add home system status sparklines - #97

Open
a-effort wants to merge 12 commits into
mainfrom
6430-home-system-status-sparklines
Open

feat: add home system status sparklines#97
a-effort wants to merge 12 commits into
mainfrom
6430-home-system-status-sparklines

Conversation

@a-effort

@a-effort a-effort commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Implements IBM/mcp-context-forge#6430. Adds the 24 hour trend card to the resting home state: executions plus p50/p95/p99 latency, polled every 30s. Replaces the all-time stats card there, which stays on the System view. Design

sparklines.mp4

Testing
Needs OBSERVABILITY_ENABLED=true; it defaults false and the endpoints return empty series rather than erroring. Only /rpc, /sse, /mcp and A2A invocation are traced, so browsing the UI will not populate the card. Use a tool Try-it panel, or point an MCP client at it.

Follow-ups

Replaces the all-time stats card on the resting home state with a 24 hour
trend card: executions and p50/p95/p99 latency, polled every 30s.

The metrics endpoints return sparse buckets, so each series is aligned onto
a full 24 slot grid before plotting. Counts fill gaps with zero, latencies
with null so an idle hour does not read as 0ms.

formatResponseTime now scales precision with magnitude, since percentiles
reach hundreds of milliseconds and rendered as "123.930ms".

recharts is isolated in a vendor-charts chunk.

Closes #6430

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Latency rows stopped at their first populated bucket, so they rendered as
short stubs against a full-width executions line. connectNulls bridges
between known points but does not extend to the edges.

Idle slots are now flattened to 0 for drawing only. The headline number
still reads the nullable series, so an idle window reports the last real
measurement rather than 0ms.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Each slot now reports its hour, its value, and the request count behind it.
The count is the point: a p95 taken over three samples is not a meaningful
percentile, and nothing else on the card showed that.

Idle slots report "No requests" rather than the zero they are drawn at. The
row value stays text beside the chart, so the tooltip adds a pointer-only
path to detail rather than becoming the only route to it.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Hour, value and request count each get their own line, at a uniform
light weight.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Each row's chart wrapper is position:relative with z-index auto, so the
wrappers paint in document order and an upper row's tooltip landed behind
the rows underneath. Only the last row looked correct.

Gives the tooltip wrapper z-50, matching the ui/ overlays.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Reads "8 executions" rather than a bare "8". The card passes a pluralized
formatter, so the tooltip stays unaware of what it is rendering.

Promotes the count line to the foreground colour so the quantities carry
more weight than the timestamp above them.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Splits py-4 into pt-4/pb-6 so the last row's line is not tight against
the card edge.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Per Figma 5863-13032. The bare "Last 24 hours" marker becomes a titled
header, "Traffic, last 24 hours", with a System status button routing to
?view=system. That view has no entry point from the resting home otherwise,
since the default row carries only the four source cards.

The error and empty messages move below the title, which now owns the left
slot they used.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
--status-icon is cyan-500, only 2.43:1 on the white light-theme background.
cyan-700 matches the MCP server catalog link and clears AA. Dark keeps the
brand cyan from the design.

Also nudges the card padding and the button's vertical offset.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
Adds --sparkline-stroke rather than reusing --status-icon: the lines are
non-text graphics needing 3:1, and cyan-500 gave 2.33:1 on the light card.
cyan-700 gives 5.13:1. Dark keeps the brand cyan at 14.23:1.

Restores aria-hidden on the chart, dropped in 95e7f3a when the tooltip
landed, which exposed four unnamed SVGs per card. Marks the button icon
decorative, since it sits beside its own text label.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
The UI does not use the word in rendered copy. 'restart ContextForge' rather
than 'the server', which is ambiguous next to MCP servers and Virtual servers
in the nav.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
@a-effort a-effort changed the title 6430 home system status sparklines feat: add home system status sparklines Sep 2, 2026
@a-effort
a-effort marked this pull request as ready for review September 2, 2026 01:38
Branch coverage landed at 89.95% against the 90% global threshold. The
uncovered paths were all in this PR's new code: the metrics query builder
had no test file, and useMetrics left the abort-after-resolve, non-Error
rejection and visibility-refetch paths untested.

Also drops the interval ref in useMetrics; it was written but never read
once the id is captured in the effect closure.

Signed-off-by: Anna Effort <anna.effort@ibm.com>
@a-effort a-effort self-assigned this Sep 2, 2026

@marekdano marekdano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1. 🟠 Medium — src/components/dashboard/SystemSparklinesCard.tsx:55

Latency tooltip's request count can mismatch its own percentile bucket

The "N requests" qualifier is derived only from the executions endpoint's populated buckets, but the file's own comment notes that executions and percentiles endpoints can disagree on which buckets are populated.

  • Failure scenario: If percentiles has a bucket for an hour (e.g. p95 = 0.472ms) but executions has no matching bucket, counts[i] = 0 for that slot. The tooltip then shows a real latency value next to "0 requests," contradicting the tooltip's stated purpose of flagging low-sample percentiles.
  • Why: User-visible, misleading data display — but cosmetic, not a data-integrity or crash issue.

2. 🟠 Medium — src/components/dashboard/systemMetrics.ts:152

Precision change leaks to unrelated call sites

formatResponseTime's new magnitude-based precision silently changes output for other call sites outside this PR's scope (SystemStatsCard, VirtualServersCard).

  • Failure scenario: A user viewing System view all-time stats or the Virtual Servers avg response time sees fewer decimal digits than before (e.g. "123.930ms" becomes "124ms"), with no test or changelog covering the behavior change for those unrelated call sites.
  • Why: Unintended scope creep affecting shared behavior — no data loss, but an undocumented regression risk elsewhere in the app.

3. 🟡 Low — src/components/dashboard/systemMetrics.ts:156

Magnitude computed pre-rounding causes inconsistent precision

Decimal-place selection uses the pre-rounded value's magnitude, so values that round up across a magnitude boundary get the wrong decimal count.

  • Failure scenario: formatResponseTime(9.996) picks 2 decimals (magnitude < 10) → "10.00ms" instead of the 1-decimal "10.0ms" a true ≥10 value would get. Similarly formatResponseTime(99.96)"100.0ms" instead of "100ms".
  • Why: Narrow edge case, purely cosmetic formatting inconsistency at specific boundary values.

🧹 Simplification

4. ⚪ Nit — vite.config.ts:51

Dead package-name alternatives in chunk regex

The vendor-charts manualChunks regex includes robust-predicates and delaunator, neither of which appears in package-lock.json's dependency tree for this PR.

  • Failure scenario: Not a functional break today, but misleads future maintainers into thinking these are real transitive deps - risking missed cleanup or masking a real config gap if a similarly-named package is added later.
  • Why: No functional impact whatsoever; pure maintenance/readability debt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants