alot more changes
Build and Publish / Metadata (push) Successful in 8s
Build and Publish / BuildAndDeployAmd64 (push) Failing after 36s

This commit is contained in:
mats committed 2026-09-21 18:59:13 +02:00
1 parent 23243ddbdc
commit 0ed2935f04
40 files changed
+2889 -115

No files matched your search

+39 -2
View File
@@ -25,6 +25,42 @@ export function trendPoints(issue: Issue, hours = 24): TrendPoint[] {
return points
}
/**
* Picks a compact chart window around real activity. A quiet 24-hour period
* remains a useful context, but a short burst should not be reduced to a tiny
* pair of points at the edge of a mostly empty chart.
*/
export function trendWindow(issue: Issue, maxHours = 24): { start: Date; hours: number } {
const activeHours = Object.entries(issue.trend ?? {})
.filter(([, count]) => count > 0)
.map(([hour]) => new Date(`${hour}:00Z`))
.filter((date) => !Number.isNaN(date.getTime()))
.sort((a, b) => a.getTime() - b.getTime())
const now = new Date()
const currentHour = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours()))
if (activeHours.length === 0) return { start: new Date(currentHour.getTime() - (maxHours - 1) * 3_600_000), hours: maxHours }
const first = activeHours[0]
const last = activeHours[activeHours.length - 1]
const activityHours = Math.floor((last.getTime() - first.getTime()) / 3_600_000) + 1
const hours = Math.min(maxHours, Math.max(6, activityHours + 2))
const start = new Date(first.getTime() - Math.floor((hours - activityHours) / 2) * 3_600_000)
return { start, hours }
}
/** Dense points for the adaptive issue-card window, oldest first. */
export function trendWindowPoints(issue: Issue, maxHours = 24): TrendPoint[] {
const { start, hours } = trendWindow(issue, maxHours)
const points: TrendPoint[] = []
for (let i = 0; i < hours; i++) {
const d = new Date(start.getTime() + i * 3_600_000)
const hour = d.toISOString().slice(0, 13) + ":00"
points.push({ hour, count: issue.trend?.[hour] ?? 0 })
}
return points
}
/** True when the issue has at least one occurrence in the last hour. */
export function isSpike(issue: Issue): boolean {
const points = trendPoints(issue, 1)
@@ -167,6 +203,7 @@ export function strongestCorrelate(issue: Issue): Correlate | null {
export interface SparklineSeries {
points: TrendPoint[]
hours: number
max: number
/** Reference level (mean occurrence/hour) drawn as the expected band. */
reference: number
@@ -181,7 +218,7 @@ export interface SparklineSeries {
* over real occurrence counts, not a forecast or ML-derived expected band.
*/
export function sparklineSeries(issue: Issue, hours = 24): SparklineSeries {
const points = trendPoints(issue, hours)
const points = trendWindowPoints(issue, hours)
const max = Math.max(...points.map((p) => p.count), 1)
const mean = points.reduce((sum, p) => sum + p.count, 0) / points.length
const threshold = Math.max(mean * 1.5, mean + 1)
@@ -192,7 +229,7 @@ export function sparklineSeries(issue: Issue, hours = 24): SparklineSeries {
break
}
}
return { points, max, reference: mean, breachIndex }
return { points, hours: points.length, max, reference: mean, breachIndex }
}
/** One row per trace (all its samples grouped), plus one per traceless sample; newest first. */
+1
View File
@@ -9,6 +9,7 @@ export const TAB_PATHS: Record<string, string> = {
"/issues": "tab0",
"/patterns": "tab8",
"/rollouts": "tab9",
"/ips": "tab10",
"/traces": "tab1",
"/metrics": "tab2",
"/logs": "tab3",
+33
View File
@@ -301,3 +301,36 @@ export interface IssueTracesResponse {
/** false when the server only had the bounded in-memory samples. */
complete: boolean;
}
export interface SourceIp {
ip: string
firstSeen: string
lastSeen: string
requests: number
errors: number
services: string[]
userAgent?: string
uaClass?: string
/** false for loopback/private/reserved addresses (usually a proxy hop) */
public: boolean
/** matched bad-actor rule over the last 7 days ("" when none) */
badActor?: BadActorReason
probePaths?: number
}
export interface SourceIpEvent {
timestamp: string
service: string
method?: string
host?: string
route?: string
spanName?: string
statusCode: number
isError: boolean
traceId: string
spanId: string
userAgent?: string
}
/** Reason from the server's bad-actor rules (features.MarkBadActors). */
export type BadActorReason = "" | "probe-scanner" | "enumerator" | "bot-4xx"