When implementing observability detections/parsers, ensure alerts/fields are (1) schema-correct and vendor-correct, and (2) triage-ready with the exact raw context that triggered the signal.
Apply these rules: 1) Validate against the target platform’s allowed schema/values
2) Make anomaly-based alerts actionable
KQL pattern (join-back for triage context):
// 1) Build anomaly signal (score) per user/type
let BinTime = 1h;
let RunTime = 1h;
let LearningPeriod = 7d;
let EndLearningTime = ago(LearningPeriod);
let EndRunTime = ago(RunTime);
let sensitivity = 2.5;
let signal =
tableName
| where TimeGenerated between (EndLearningTime .. ago(0))
| where AppDisplayName =~ "GitHub.com" and ResultType != 0
| make-series FailedLogins=count() on TimeGenerated from EndLearningTime to EndRunTime step BinTime
by UserPrincipalName, Type
| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(FailedLogins, sensitivity, -1, 'linefit')
| mv-expand TimeGenerated to typeof(datetime), Anomalies to typeof(double)
| where TimeGenerated >= EndRunTime and Anomalies > 0;
// 2) Join back to raw events at the anomaly time for triage context
signal
| join kind=innerunique (
tableName
| where AppDisplayName =~ "GitHub.com" and ResultType != 0
| summarize RawEventCount=count() by UserPrincipalName, Type, bin(TimeGenerated, BinTime)
) on UserPrincipalName, Type, $left.TimeGenerated == $right.TimeGenerated
Practical checklist for PRs