Awesome Reviewers expert instructions

domains / / Azure/Azure-Sentinel

Triage-Ready Telemetry

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.

raw .md Observability Yaml

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

  • If a field has an explicit allowed set (e.g., eventseverity), map upstream values into only those supported values.
  • Example guidance (severity mapping):
    • Confirm allowed target values (e.g., Informational/Low/Medium/High).
    • Consult the vendor’s priority/severity documentation.
    • Map each vendor level to a supported target value, and document the rationale (e.g., “CEF Critical→High”).

2) Make anomaly-based alerts actionable

  • If you compute anomalies/scores, the alert output should include or join the raw events (or raw aggregates at the anomaly time window) so analysts can immediately see what triggered the anomaly.

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

  • Are all normalized fields mapped only to the platform’s supported values?
  • Is upstream/vender semantics verified with a cited source?
  • Does the detection output include raw triggering context at the anomaly time (not only anomaly score)?
  • Is the mapping rationale documented so future changes don’t regress triage quality?