[HDX-4997] Alert evaluations read model + GET /alerts/:id/evaluations - #2833
Conversation
🦋 Changeset detectedLatest commit: c32b78e The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🟡 Tier 3 — StandardIntroduces new logic, modifies core functionality, or touches areas with non-trivial risk. Why this tier:
Review process: Full human review — logic, architecture, edge cases. Stats
|
Greptile SummaryThis PR adds the read model and team-scoped API endpoint for retrieving per-window alert evaluations, while extending shared and persistence types for future evaluation errors and analytics.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains in the current changeset.
|
| Filename | Overview |
|---|---|
| packages/api/src/controllers/alertHistory.ts | Adds bounded, cursor-paginated evaluation aggregation with grouped results, error merging, analytics resolution, and ERROR-aware transition filtering. |
| packages/api/src/routers/api/alerts.ts | Adds the authenticated, team-scoped evaluations endpoint with validated limits and retention-clamped time ranges. |
| packages/api/src/models/alertHistory.ts | Extends AlertHistory persistence with optional structured errors and evaluation analytics. |
| packages/api/src/models/alert.ts | Adds the history-only ERROR state; no current write path creates that state in this changeset. |
| packages/common-utils/src/types.ts | Defines the shared evaluation, error, analytics, pagination, and alert group-by response contracts. |
| packages/app/src/components/alerts/AlertHistoryCards.tsx | Extends alert-state presentation to render the new ERROR state consistently. |
Sequence Diagram
sequenceDiagram
participant Client
participant API as GET /alerts/:id/evaluations
participant Alert as Alert model
participant History as AlertHistory
Client->>API: id, time range, limit, before
API->>Alert: Load alert scoped to caller's team
Alert-->>API: Alert interval and metadata
API->>History: Aggregate bounded createdAt slice
History-->>API: Grouped evaluation windows
API-->>Client: data, hasMore, nextBefore
Reviews (4): Last reviewed commit: "feat(alerts): evaluations read model — E..." | Re-trigger Greptile
E2E Test Results✅ All tests passed • 276 passed • 1 skipped • 1105s
Tests ran across 4 shards in parallel. |
|
<!-- deep-review --> Deep Review🔴 P0/P1 — must fix
🟡 P2 — recommended
🔵 P3 nitpicks (9)
Reviewers (9): correctness, adversarial, testing, api-contract, performance, security, reliability, maintainability, kieran-typescript. Testing gaps:
Environment note: |
50d2a33 to
8b31195
Compare
Deep ReviewScope: ✅ No critical issues found. Pagination cursor math was traced end-to-end by two independent reviewers with no stall/skip/duplication; auth and tenant isolation mirror the sibling 🟡 P2 -- recommended
🔵 P3 nitpicks (6)
Pre-existing (not introduced by this diff; excluded from verdict)
Agent-Native Gaps
Reviewers (12): correctness, adversarial, security, api-contract, performance, reliability, testing, maintainability, kieran-typescript, project-standards, agent-native, learnings-researcher. Testing gaps:
Residual risks: new aggregations set no |
| // firing transitions for chart annotations, which is a different shape. | ||
| const EVALUATIONS_LIMIT = 200; | ||
| type AlertEvaluationsExpRes = express.Response<AlertEvaluationsApiResponse>; | ||
| router.get( |
…up windows (HDX-4997) AlertHistory read-side support for the alert detail page: - Types (common-utils) for evaluation errors (AlertError/AlertErrorType incl. QUERY_TIMEOUT), per-window evaluations with per-group breakdown (capped at ALERT_EVALUATION_GROUPS_LIMIT, firing-first), and evaluation analytics (queryDurationMs, webhookDurationMs, backfilledBuckets). - AlertHistory schema gains optional errors + analytics fields, and AlertState gains ERROR (only ever used on history rows). - GET /alerts/:id/evaluations: per-window evaluation history scoped to a startTime/endTime range (clamped to the 31d retention window), grouped across group-by groups newest-first with a hard-bounded scan of at most ~(limit+1) intervals per request and a server-provided nextBefore cursor that always advances past the scanned slice, so paging progresses across gaps instead of stalling. - Windows with ERROR rows surface their errors (deduped, newest-first) and rank as ERROR; firing-transition annotations exclude ERROR rows. Nothing writes ERROR rows or analytics yet — the alert task's write side lands separately.
a4b448b to
c32b78e
Compare
Linear Issue: HDX-4997
Stack (1/3)
This is the base of a 3-PR stack that splits #2786 for reviewability:
PRs 2 and 3 both base on this branch but are independent of each other; once this merges they can land in either order (GitHub retargets them to
mainautomatically when this branch is deleted on merge).Why
To surface alert evaluation history (including failures) on a per-alert detail page, we need a read model over
AlertHistorythat can answer "what happened in each evaluation window?" — including windows that errored, per-group results for group-by alerts, and evaluation analytics. TodayAlertHistoryonly stores OK/ALERT rows and there is no per-alert evaluations API.What
common-utils) for evaluation errors (AlertError/AlertErrorTypeincl.QUERY_TIMEOUT), per-window evaluations with per-group breakdown (capped atALERT_EVALUATION_GROUPS_LIMIT, firing-first), and evaluation analytics (queryDurationMs,webhookDurationMs,backfilledBuckets).AlertHistoryschema gains optionalerrors+analyticsfields, andAlertStategainsERROR(only ever used on history rows).GET /alerts/:id/evaluations: per-window evaluation history scoped to astartTime/endTimerange (clamped to the 31d retention window), grouped across group-by groups newest-first, with a hard-bounded scan of at most ~(limit+1) intervals per request and a server-providednextBeforecursor that always advances past the scanned slice so paging progresses across gaps instead of stalling.Nothing writes ERROR rows or analytics yet — the alert task's write side lands in PR 2 of the stack.
Testing
packages/api+packages/common-utils:ci:lint(eslint + tsc),ci:unitgreenalertHistory.int.test.ts(new, 80 cases),routers/api/alerts.int.test.ts, and the full*alerts.int*set pass locally (278 tests)