Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/src/features/dashboard/schemas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ describe("DashboardOverviewSchema", () => {
cachedInputTokens: 300,
errorRate: 0.02,
errorCount: 10,
cancelledCount: 3,
topError: null,
},
comparison: {
Expand All @@ -81,6 +82,7 @@ describe("DashboardOverviewSchema", () => {

expect(parsed.accounts).toHaveLength(0);
expect(parsed.summary.comparison?.previous.requests).toBe(250);
expect(parsed.summary.metrics?.cancelledCount).toBe(3);
});

it("drops legacy request_logs field from parse result", () => {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/features/dashboard/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const DashboardMetricsSchema = z.object({
cachedInputTokens: z.number().nullable(),
errorRate: z.number().nullable(),
errorCount: z.number().nullable(),
cancelledCount: z.number().int().nonnegative().nullable().optional(),
topError: z.string().nullable(),
conversations: z.number().int().nullable().optional().default(null),
conversationRequests: z.number().int().nonnegative().optional().default(0),
Expand Down
44 changes: 44 additions & 0 deletions openspec/changes/preserve-dashboard-cancelled-count/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## Context

The backend overview response already carries a nullable `cancelledCount`.
`DashboardOverviewSchema` is the frontend trust boundary, and Zod strips
unknown object keys there. The omission is therefore isolated to the typed
consumer contract; no calculation or transport change is required.

## Goals / Non-Goals

**Goals:**

- Keep the frontend overview contract aligned with the backend response.
- Lock the documented requests/error/cancelled breakdown with a focused test.

**Non-Goals:**

- Change cancellation classification or aggregation.
- Add a new dashboard card or navigation surface.
- Change backward compatibility for payloads that omit the field.

## Decisions

- Declare `cancelledCount` as nullable and optional, matching the additive
backend response and preserving compatibility with older servers.
- Test the field through `DashboardOverviewSchema.parse`, the actual API
boundary, rather than testing the nested schema in isolation.

Alternative considered: configure the metrics object with `.passthrough()`.
That would weaken the trust boundary for every unknown metric, so the explicit
field is the smaller and safer change.

## Risks / Trade-offs

- [Risk] Frontend and backend optionality drift → Mirror the existing additive
metric pattern and cover a payload that includes the field.

## Migration Plan

Ship as an additive frontend contract change. Rollback is removal of the field;
backend responses remain compatible in either direction.

## Open Questions

None.
28 changes: 28 additions & 0 deletions openspec/changes/preserve-dashboard-cancelled-count/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Why

The dashboard overview API emits `cancelledCount`, but the frontend Zod
boundary omits that field and silently strips it from otherwise valid metrics
payloads. Operators therefore cannot distinguish a window with no
cancellations from one whose cancellation count was discarded client-side.

## What Changes

- Preserve `cancelledCount` when the dashboard parses overview metrics.
- Add a frontend contract regression covering the backend's documented
requests/error/cancelled breakdown.

## Capabilities

### New Capabilities

None.

### Modified Capabilities

- `usage-error-metrics`: The dashboard frontend preserves the overview
cancellation count emitted by the API.

## Impact

Frontend dashboard schema and its focused tests only. No backend, database, or
navigation changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## MODIFIED Requirements

### Requirement: Cancelled counts surface alongside error counts

Metric surfaces that expose an error count MUST also expose the window's
cancelled count as an additive field: the dashboard overview metrics
(`cancelledCount`), the usage summary metrics (`cancelled7d`), the reports
daily rows (`cancelled_count`) and summary (`total_cancelled`), and the fleet
pressure metrics (`cancelledCount`). The dashboard overview cancelled total
MUST be sourced from the demand quarter rollup (status grain) for the folded
segment plus the raw tail, so it stays accurate across history already folded
without the hourly `cancelled_count` measure. The dashboard frontend MUST
preserve `cancelledCount` when parsing the overview response.

#### Scenario: Dashboard overview preserves the status breakdown

- **GIVEN** the dashboard overview API returns `requests=4`, `errorCount=1`,
and `cancelledCount=2`
- **WHEN** the frontend parses the overview response
- **THEN** the parsed metrics expose all three values unchanged
11 changes: 11 additions & 0 deletions openspec/changes/preserve-dashboard-cancelled-count/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## 1. Frontend contract

- [x] 1.1 Add a failing dashboard schema test that requires `cancelledCount`
to survive parsing
- [x] 1.2 Add `cancelledCount` to the dashboard metrics Zod schema

## 2. Validation

- [x] 2.1 Run the focused dashboard schema tests
- [x] 2.2 Run frontend typecheck and build
- [x] 2.3 Validate OpenSpec
Loading