@query-ai/digital-workers 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,838 @@
1
+ ---
2
+ name: alert-investigation
3
+ description: Use when investigating security alerts, triaging detection findings, or running the Incident Discovery workflow — master orchestrator that invokes specialized skills
4
+ ---
5
+
6
+ # Alert Investigation
7
+
8
+ ## ABSOLUTE RULES — Read These First
9
+
10
+ **1. NEVER use Bash, cat, python, jq, or any shell command to process data.** Not for MCP results. Not for saved files. Not for "just extracting a summary." NEVER. If results overflow to a file, your query was too broad — re-query with specific field selectors or tighter filters.
11
+
12
+ **2. NEVER use `**` on broad queries.** The `**` wildcard returns entire OCSF events (millions of characters). Use specific field selectors: `detection_finding.message, detection_finding.severity_id, detection_finding.time, detection_finding.observables`. Use `**` only when scoped to a single host or single event type with a narrow filter.
13
+
14
+ **3. ALWAYS validate before execute.** Every FSQL query goes through `Validate_FSQL_Query` before `Execute_FSQL_Query`. No exceptions.
15
+
16
+ **4. ALWAYS pivot to telemetry.** For Standard and Deep tiers, you MUST query at least one telemetry event type (`process_activity`, `file_activity`, `network_activity`, `authentication`) in Gate 2. Detection findings are alerts, not evidence. If you reach Gate 3 having only queried `detection_finding`, you skipped the most important step. Go back.
17
+
18
+ **5. ALWAYS save artifacts.** Write evidence files at every gate exit using the Write tool.
19
+
20
+ **6. RESPECT THE QUERY BUDGET.** Every tier has a hard cap on `Execute_FSQL_Query` calls. When you hit the cap, stop gathering and work with what you have. Better to write a solid report on 12 queries than run 30 queries and take 26 minutes.
21
+
22
+ | Tier | Execute Query Budget |
23
+ |------|---------------------|
24
+ | **Triage** | 5 max |
25
+ | **Standard** | 15 max |
26
+ | **Deep** | 25 max |
27
+
28
+ If you approach the budget (2 queries remaining), stop enrichment and proceed to the next gate with your current evidence. Document "query budget reached — further enrichment deferred" in `queries.md`. The analyst can always say "go deeper" to upgrade the tier and unlock more queries.
29
+
30
+ **7. LOG EVERY QUERY.** Every `Execute_FSQL_Query` call — whether it succeeds, fails, or returns empty — MUST be appended to `queries.md` with the query text, result count, and a 1-line summary. No undocumented queries. The audit trail is incomplete if even one query is missing.
31
+
32
+ These rules are non-negotiable. If you find yourself reaching for cat, python, or `**` on a broad query, STOP and re-read this section.
33
+
34
+ ## Iron Law
35
+
36
+ **EVERY INVESTIGATION FOLLOWS ITS TIER'S PROCESS. NO SKIPPING GATES WITHIN A TIER.**
37
+
38
+ The process exists because shortcuts cause missed incidents. Tiers control scope — not rigor. Even Triage runs its gates properly.
39
+
40
+ ## Overview
41
+
42
+ You are the master orchestrator for the Digital Workers Incident Discovery workflow. Before running gates, you select an **investigation tier** based on the analyst's prompt. The tier determines which gates run, how deep each gate goes, and what output is produced.
43
+
44
+ ## Step 0: Select Investigation Tier
45
+
46
+ **Read the analyst's prompt and select a tier. Announce it and start immediately — do not wait for confirmation.**
47
+
48
+ ### Tier Definitions
49
+
50
+ | Tier | Gates | Query Budget (hard cap) | Output | Time |
51
+ |------|-------|------------------------|--------|------|
52
+ | **Triage** | 1 → 2 (basic) | **5 max** | Inline summary table, no files | ~5 min |
53
+ | **Standard** | 1 → 2 → 3 → 4 → 5 → 6 | **15 max** | Inline report + files (report.md, queries.md, iocs.md) | ~15 min |
54
+ | **Deep** | 1 → 2 → 3 → 4 → 5 → 6 + specialists + senior review | **25 max** | Full report + files + review.md | ~25 min |
55
+
56
+ ### Tier Selection Rules
57
+
58
+ **Parse the prompt for these signals:**
59
+
60
+ | Signal | Tier | Examples |
61
+ |--------|------|---------|
62
+ | Questions, checks, scans — "any", "what's", "show me", "check for", "are there" | **Triage** | "Any suspicious PowerShell in the last 12 hours?", "What alerts fired overnight?", "Check for lateral movement", "Show me what's going on" |
63
+ | Action verbs — "investigate", "look into", "triage", unqualified requests | **Standard** | "Investigate the unfamiliar sign-in alerts", "Look into this hash", "Triage the new HIGH alerts" |
64
+ | Explicit depth — "full", "deep", "thorough", "complete", incident language | **Deep** | "Full investigation on these PowerShell findings", "Deep dive on BD-3263", "This looks like an incident — investigate everything" |
65
+
66
+ **When ambiguous, default to the lighter tier.** Upgrading after seeing results costs 2-3 minutes. Starting Deep when the analyst wanted Triage wastes 25+ minutes.
67
+
68
+ **Announce format — one line, then start immediately:**
69
+ > "**Triage** — PowerShell findings, last 12 hours."
70
+
71
+ > "**Standard investigation** — unfamiliar sign-in alerts, 24h."
72
+
73
+ > "**Deep investigation** — full analysis of lateral movement indicators."
74
+
75
+ ### What Each Tier Runs
76
+
77
+ **Triage:**
78
+ - Gate 1: Pull alerts, classify, extract IOCs
79
+ - Gate 2 (basic): Layer 1a discovery scans only — no per-host deep dives, no telemetry pivots, no threat intel, no evidence quality checker
80
+ - Output: Inline summary table with alert list, severity, hosts, IOCs, event types hit
81
+ - No file artifacts — triage is ephemeral
82
+ - If results look concerning, end with: "Found [N] indicators that warrant closer examination. Say 'investigate' or 'go deeper' to run a Standard/Deep investigation."
83
+
84
+ **Standard:**
85
+ - All 6 gates
86
+ - Gate 2: Full enrichment — Layer 1a/1b, telemetry pivots, per-host deep dives, threat intel
87
+ - Gate 3: Severity scoring (AUTO-CLOSE / STANDARD / DEEP routing still applies within Standard tier)
88
+ - Gate 4: Specialists only if severity routes to DEEP
89
+ - Gate 6: Report + files, NO senior analyst review (unless analyst requests it)
90
+
91
+ **Deep:**
92
+ - All 6 gates at maximum depth
93
+ - Gate 2: Full enrichment + extended lookback (7d default instead of 24h)
94
+ - Gate 4: Always invoke specialists based on alert type
95
+ - Gate 6: Full report + files + mandatory senior analyst review
96
+ - Cross-reference with prior investigations in `docs/investigations/`
97
+
98
+ ### Tier Upgrades
99
+
100
+ Tiers upgrade but never downgrade mid-investigation.
101
+
102
+ **Auto-upgrade triggers (Triage → Standard):**
103
+ - Any alert is CRITICAL or FATAL severity
104
+ - IOC appears in 3+ event types (broad footprint)
105
+ - IOC matches a prior investigation's IOCs
106
+
107
+ When auto-upgrading, do NOT stop to ask. Announce and continue:
108
+ > "Upgrading to **Standard** — CRITICAL severity indicators found on 3 hosts."
109
+
110
+ **Analyst-driven upgrades:**
111
+ - "Go deeper" / "full investigation" → upgrade to next tier
112
+ - "Just triage" / "quick look only" → stays at current tier even if triggers fire
113
+ - "Standard is fine" → caps at Standard
114
+
115
+ The upgrade reuses all work already done. Gate 1 and Gate 2 (basic) artifacts from Triage feed directly into Standard's Gate 2 — no repeated queries.
116
+
117
+ ## The Incident Discovery Workflow
118
+
119
+ ```
120
+ STEP 0: SELECT TIER (from analyst prompt)
121
+ │ Triage / Standard / Deep
122
+ │ Announce and start immediately
123
+
124
+ Gate 1: ALERTS INTAKE (ALL TIERS)
125
+ │ Invoke: digital-workers:alert-classifier
126
+ │ Invoke: digital-workers:fsql-expert (pull alerts)
127
+
128
+ Gate 2: GATHER INFORMATION
129
+ │ TRIAGE: Layer 1a discovery scans only → present summary → STOP
130
+ │ STANDARD/DEEP: Full enrichment (Layer 1a/1b, telemetry pivots,
131
+ │ per-host deep dives, threat intel, evidence quality checker)
132
+
133
+ Gate 3: ANALYZE SITUATION (STANDARD + DEEP only)
134
+ │ Invoke: digital-workers:severity-scorer
135
+ │ Invoke: digital-workers:evidence-quality-checker (analytical reasoning)
136
+ │ Route to depth: AUTO-CLOSE / STANDARD / DEEP
137
+
138
+ Gate 4: DECIDE & ACT (STANDARD + DEEP only)
139
+ │ STANDARD: Specialists only if severity routes to DEEP
140
+ │ DEEP: Always invoke specialists based on alert type
141
+ │ Assign disposition: Critical Threat / Policy Violation / False Positive / Benign
142
+
143
+ Gate 5: BUILD & PRIORITIZE CASE (STANDARD + DEEP only)
144
+ │ Assemble evidence package
145
+ │ Prioritize relative to other active investigations
146
+
147
+ Gate 6: INCIDENT NOTIFICATION (STANDARD + DEEP only)
148
+ │ Invoke: digital-workers:report-writer
149
+ │ DEEP only: invoke digital-workers:senior-analyst-review
150
+ │ (review MUST complete before presenting to analyst)
151
+ │ If INCIDENT CRITERIA MET: recommend escalation to Incident Response track
152
+ │ Present to analyst
153
+
154
+ COMPLETE
155
+ ```
156
+
157
+ ## Investigation Artifacts
158
+
159
+ Artifacts depend on the investigation tier:
160
+
161
+ | Tier | Files | Directory |
162
+ |------|-------|-----------|
163
+ | **Triage** | No files — results presented inline only | No directory created |
164
+ | **Standard** | `report.md`, `queries.md`, `iocs.md` | `docs/investigations/YYYY-MM-DD-<brief-description>/` |
165
+ | **Deep** | `report.md`, `queries.md`, `iocs.md`, `review.md` | `docs/investigations/YYYY-MM-DD-<brief-description>/` |
166
+
167
+ **For Standard and Deep tiers:**
168
+
169
+ Create the investigation directory at the start of Gate 1. **Use the Write tool** (never Bash/echo) to save artifacts. Write markdown, not JSON.
170
+
171
+ **The `queries.md` log is mandatory.** After every FSQL query execution, append the query text, result count, and a 1-2 line summary. This is the audit trail.
172
+
173
+ **The `iocs.md` list is mandatory.** After every IOC extraction, append the IOC with type, source, and reputation (if known).
174
+
175
+ **The `review.md` file is written by the senior analyst review** (Deep tier only, or when manually requested).
176
+
177
+ ---
178
+
179
+ ## Gate 1: Alerts Intake
180
+
181
+ ### Entry: New alerts exist or user requests investigation
182
+
183
+ **Org-policy check:** If an org-policy skill is loaded, read its Alert Scope section for severity filter, time range, and connector scope. Adjust the intake query accordingly.
184
+
185
+ **Step 1: Pull alerts from the mesh**
186
+
187
+ Invoke `digital-workers:fsql-expert` to query for new alerts. **Use this exact query** (adjust time range if user requests, but DO NOT change the field selectors to `**`):
188
+
189
+ ```
190
+ QUERY detection_finding.message, detection_finding.severity_id, detection_finding.status_id, detection_finding.time, detection_finding.observables, detection_finding.attacks
191
+ WITH detection_finding.severity_id IN HIGH, CRITICAL, FATAL AND detection_finding.status_id = NEW AFTER 24h
192
+ ```
193
+
194
+ **The `status_id = NEW` filter is critical.** Without it, you get hundreds of alerts (including already-resolved ones) and the investigation drowns in noise. With it, you get the actionable set — typically 5-15 alerts. This is the single biggest factor in investigation quality.
195
+
196
+ **DO NOT use `detection_finding.**` — it returns millions of characters and will overflow.** The fields above are all you need for triage. Additional fields can be queried in follow-up queries during Gate 2 enrichment.
197
+
198
+ **Step 1.5: Extract IOCs — max 2 additional queries**
199
+
200
+ If the intake query returned populated `observables` and `attacks` fields, extract IOCs directly. You're done — skip to Step 2.
201
+
202
+ If `observables` and `attacks` are empty (skeleton-mapped alerts), run ONE `raw_data` query per distinct alert type to extract IOCs:
203
+
204
+ ```
205
+ QUERY detection_finding.message, detection_finding.time, detection_finding.raw_data
206
+ WITH detection_finding.message = '<alert_message>' AND detection_finding.status_id = NEW AFTER 24h
207
+ ```
208
+
209
+ **Gate 1 IOC extraction is capped at 2 additional queries (1 per alert type).** If raw_data is also empty, document "skeleton-mapped — no IOC data available" and move on. The IOCs will come from Layer 1a discovery scans in Gate 2 instead.
210
+
211
+ **DO NOT probe multiple field paths** (actor.user.name, finding_info, evidences, unmapped, resources) trying to find IOC data. This is the #1 source of query bloat — one investigation burned 12 queries in Gate 1 probing fields that don't exist. If the intake query + one raw_data query don't yield IOCs, the data isn't there.
212
+
213
+ **Step 2: Deduplicate and filter**
214
+
215
+ Review returned alerts. Group alerts that:
216
+ - Share the same IOCs (same IP, same user, same hash)
217
+ - Fired within minutes of each other from different tools
218
+ - Describe the same underlying event from different perspectives
219
+
220
+ Treat grouped alerts as a single investigation.
221
+
222
+ **Filter profile-known noise:** If the environment profile is loaded, check each alert message against `known_false_positives` and `systemic_patterns`:
223
+ - **`known_false_positives`** with `last_verified` < 7 days ago → auto-close as False Positive, log in queries.md: "Auto-closed per profile (verified YYYY-MM-DD, N samples)"
224
+ - **`systemic_patterns`** → fast-track through investigation (skip per-host deep dives, skip telemetry pivots, skip threat intel). Still include in the report with disposition and profile citation.
225
+ - **`infrastructure_noise`** entries → auto-close at Gate 1, no further investigation. Log: "Filtered per profile — infrastructure noise (verified YYYY-MM-DD)"
226
+
227
+ This filtering happens BEFORE Gate 2 enrichment. Queries saved here are the highest-value profile optimization.
228
+
229
+ **Step 3: Classify each alert**
230
+
231
+ Invoke `digital-workers:alert-classifier` for each unique alert/group:
232
+ - OCSF category
233
+ - MITRE ATT&CK technique
234
+ - Alert type (Identity/Network/Endpoint/etc.)
235
+ - Initial IOC extraction
236
+
237
+ **Gate 1 Exit — Save artifacts (Standard + Deep only):**
238
+ 1. Create the investigation directory: `docs/investigations/YYYY-MM-DD-<brief-description>/`
239
+ 2. Append to `queries.md` — the intake query with result count
240
+ 3. Write initial `iocs.md` — IOC list with type and source alert
241
+
242
+ (Triage tier: no files — proceed directly to Gate 2 basic.)
243
+
244
+ **Gate 1 Exit Criteria:** All alerts classified, deduplicated, IOCs extracted. **Continue immediately to Gate 2.**
245
+
246
+ ---
247
+
248
+ ## Gate 2: Gather Information
249
+
250
+ ### Entry: Alerts classified with initial IOCs
251
+
252
+ **Step 0: Read environment profile and connector registry.**
253
+
254
+ Before authoring ANY enrichment queries (including Triage tier):
255
+
256
+ 1. Call `FSQL_Connectors` to get the current connector landscape.
257
+ 2. Read `digital-workers/learned/environment-profile.json` if it exists.
258
+ 3. Cross-reference: for each event type needed in this investigation, check which connectors produce it and what the profile says about each.
259
+ 4. Apply the behavioral rules:
260
+ - **Skip** queries where ALL connectors for an event type are profiled as `unpopulated` / `no_data` (cite profile as source, document as known gap with last_verified date)
261
+ - **Probe** event types where SOME connectors are `untested` — try one targeted `FROM <connector_id>` query before declaring a gap
262
+ - **Skip re-verification** for `known_false_positives` entries verified < 7 days ago (cite profile: message, last_verified, sample_size)
263
+ - **Fast-track** `systemic_patterns` entries — run minimal enrichment (1 discovery scan to confirm pattern persists), then proceed directly to Gate 4 with profile-cited disposition
264
+ - **Apply** `query_performance` hints (batch size limits, known overflow patterns, %ip single-query rule)
265
+ - **Use workarounds** from `field_population` entries (e.g., `%ip` instead of `device.hostname`)
266
+ 5. Pass the profile context to fsql-expert with each query request so it can apply connector-specific knowledge.
267
+
268
+ If the profile doesn't exist, skip this step and proceed normally. The investigation will create one.
269
+
270
+ ### Triage Tier: Basic Enrichment Only
271
+
272
+ If the tier is **Triage**, follow this exact query sequence and then present the summary. **Target: 5 queries maximum.**
273
+
274
+ **Triage Query Sequence:**
275
+
276
+ 1. **Query 1 — Severity-filtered intake** (already done in Gate 1):
277
+ ```
278
+ QUERY detection_finding.message, detection_finding.severity_id, detection_finding.status_id,
279
+ detection_finding.time, detection_finding.observables, detection_finding.attacks
280
+ WITH detection_finding.severity_id IN HIGH, CRITICAL, FATAL AND detection_finding.status_id = NEW AFTER 24h
281
+ ```
282
+
283
+ 2. **Query 2 — Full landscape scan** (ALL new alerts, no severity filter):
284
+ ```
285
+ QUERY detection_finding.message, detection_finding.severity_id, detection_finding.status_id,
286
+ detection_finding.time
287
+ WITH detection_finding.status_id = NEW AFTER 24h
288
+ ```
289
+ This reveals the complete alert picture — MEDIUM and LOW alerts often form patterns (persistence + execution + discovery clusters) that matter more than individual HIGH alerts.
290
+
291
+ 3. **Queries 3-5 — Layer 1a discovery scans** on the top 2-3 IOCs extracted from Gate 1:
292
+ ```
293
+ QUERY *.message, *.time WITH %hash = '<ioc>' AFTER 7d
294
+ QUERY *.message, *.time WITH %ip = '<ioc>' AFTER 24h
295
+ ```
296
+
297
+ 4. **Query 6 (optional) — SUMMARIZE for triage distribution** when Layer 1a discovery shows high volume:
298
+ ```
299
+ -- If Layer 1a shows 50+ detection_finding hits, get the distribution instead of reading each one
300
+ SUMMARIZE COUNT detection_finding.message GROUP BY detection_finding.message, detection_finding.severity_id, detection_finding.status_id
301
+ WITH detection_finding.severity_id IN HIGH, CRITICAL AFTER 24h
302
+ ```
303
+ This replaces manually counting alert types from QUERY results. Use when Layer 1a results suggest dozens of alerts across multiple types.
304
+
305
+ > **Constraints:** SUMMARIZE has known execution limits — `status_id` filtering fails on detection_finding (use GROUP BY instead), `FROM` not supported, high-cardinality GROUP BY can overflow. If SUMMARIZE returns empty, fall back to QUERY. See fsql-expert Layer 1c for workarounds and check `summarize_support` in the environment profile.
306
+
307
+ **Dead-end rule: If IOC fields come back empty on an alert type (e.g., observables are null, actor fields are null), do NOT retry with different field paths.** Note it as a data gap (e.g., "skeleton-mapped alerts — no IOC data available") and move on to the next query. Spending multiple queries probing empty fields is the #1 way Triage runs over budget.
308
+
309
+ **After these queries, present the Triage Output and stop.** Do not run Layer 1b, telemetry pivots, per-host deep dives, threat intel, authentication queries, or evidence quality checks. Those are Standard tier.
310
+
311
+ **Triage Output:**
312
+
313
+ ```
314
+ TRIAGE SUMMARY — [date] — [description]
315
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
316
+
317
+ Alerts: [N] total ([N] CRITICAL, [N] HIGH, [N] MEDIUM, [N] LOW)
318
+
319
+ HIGH/CRITICAL:
320
+ [table: alert name, count, hosts, key IOCs]
321
+
322
+ MEDIUM (summarized):
323
+ [table: alert name, count, MITRE mapping if obvious]
324
+
325
+ LOW (summarized):
326
+ [one-line summary]
327
+
328
+ Data Gaps:
329
+ [any skeleton-mapped alerts, empty IOC fields, etc.]
330
+
331
+ Key Observations:
332
+ - [2-4 bullet points: patterns, clusters, concerns]
333
+
334
+ Upgrade? Say "investigate" for Standard or "deep dive" for Deep.
335
+ ```
336
+
337
+ **Check auto-upgrade triggers before presenting.** If any trigger fires (CRITICAL/FATAL alerts, IOC in 3+ event types, prior investigation match), auto-upgrade to Standard — announce and continue without stopping.
338
+
339
+ **If no auto-upgrade triggers fire, present the summary and STOP.** The investigation is complete for Triage tier.
340
+
341
+ ---
342
+
343
+ ### Standard + Deep Tiers: Full Enrichment
344
+
345
+ **Step 1: Enrich IOCs**
346
+
347
+ For each IOC extracted in Gate 1, invoke `digital-workers:fsql-expert`. Use a **layered query approach** — broad-but-lightweight first, then targeted deep dives.
348
+
349
+ **Layer 1a: Discovery scan (always start here)**
350
+
351
+ Search IOCs across the entire mesh using `*.message, *.time`. This returns one lightweight row per matching event with the `__event` field showing which event type it came from — without overflowing.
352
+
353
+ **BATCH same-type IOCs into single queries using `IN`.** This is the single biggest efficiency win — 5 individual queries become 1:
354
+
355
+ ```
356
+ -- WRONG: 5 separate queries for 5 IPs (wastes 4 queries from budget)
357
+ QUERY *.message, *.time WITH %ip = '172.16.16.70' AFTER 7d
358
+ QUERY *.message, *.time WITH %ip = '172.16.16.58' AFTER 7d
359
+ QUERY *.message, *.time WITH %ip = '172.16.16.43' AFTER 7d
360
+ ...
361
+
362
+ -- RIGHT: 1 query for all IPs
363
+ QUERY *.message, *.time WITH %ip IN '172.16.16.70', '172.16.16.58', '172.16.16.43', '172.16.16.94', '172.16.16.13' AFTER 7d
364
+
365
+ -- RIGHT: 1 query for all usernames
366
+ QUERY *.message, *.time WITH %username IN 'jacob.mason', 'edward.holmes', 'patricia.porter' AFTER 7d
367
+
368
+ -- RIGHT: 1 query for all hashes
369
+ QUERY *.message, *.time WITH %hash IN 'abc123', 'def456' AFTER 7d
370
+ ```
371
+
372
+ **One Layer 1a query per IOC type.** If Gate 1 extracted 5 IPs, 3 usernames, and 2 hashes, that's 3 discovery queries (one per type), not 10.
373
+
374
+ Read the `__event` field in results to discover all event types where the IOCs appear (e.g., `detection_finding`, `email_activity`, `osint_inventory_info`, `process_activity`). This is how you find event types you wouldn't have thought to query.
375
+
376
+ **MANDATORY: Log every event type seen in `__event` results.** After each Layer 1a scan, note in `queries.md` which event types appeared. If an event type appears that isn't followed up with a Layer 1b query, document why (e.g., "email_activity: 0 hits" or "email_activity: 12 hits — followed up in Query N" or "osint_inventory_info: skipped — inventory data, not actionable").
377
+
378
+ **NEVER use bare `QUERY %hash = 'x'` or `QUERY ** WITH %hash = 'x'` — these return full OCSF events and will overflow.**
379
+
380
+ **Run independent queries concurrently.** These can always run in parallel:
381
+ - Layer 1a discovery scans for different IOC types
382
+ - Per-host deep dives on different hosts
383
+ - Threat intel enrichment alongside specialist investigation queries
384
+
385
+ **Layer 1b: Targeted detail (narrow, specific fields)**
386
+
387
+ Based on Layer 1a results, query specific event types with field selectors for the details you need. Run `Search_FSQL_SCHEMA` first if you haven't queried this event type before:
388
+
389
+ ```
390
+ -- Detection findings for an IOC (always include status_id)
391
+ QUERY detection_finding.message, detection_finding.severity_id, detection_finding.status_id,
392
+ detection_finding.time, detection_finding.observables, detection_finding.attacks
393
+ WITH %ip = '<ioc>' AND detection_finding.status_id = NEW AFTER 24h
394
+
395
+ -- Email activity (when Layer 1a shows email_activity hits)
396
+ QUERY email_activity.message, email_activity.time, email_activity.actor.user.email_addr,
397
+ email_activity.email.subject
398
+ WITH %hash = '<ioc>' AFTER 7d
399
+
400
+ -- Process activity for a specific host (when Layer 1a shows process events)
401
+ QUERY process_activity.message, process_activity.time, process_activity.device.hostname,
402
+ process_activity.process.cmd_line
403
+ WITH process_activity.device.hostname = '<hostname>' AFTER 24h
404
+ ```
405
+
406
+ **Layer 1c: Aggregation (when you need counts, not individual events)**
407
+
408
+ After Layer 1a/1b, use SUMMARIZE when you need distributions rather than reading individual events:
409
+
410
+ ```
411
+ -- Scope assessment: how many hosts are affected? (GROUP BY status_id to filter in results)
412
+ SUMMARIZE COUNT detection_finding.device.hostname
413
+ GROUP BY detection_finding.device.hostname, detection_finding.status_id
414
+ WITH detection_finding.severity_id IN HIGH, CRITICAL AFTER 24h
415
+
416
+ -- Status distribution on expanded lookback (separates active from resolved)
417
+ SUMMARIZE COUNT detection_finding.status_id GROUP BY detection_finding.status_id
418
+ WITH detection_finding.message = '<alert_name>' AFTER 7d
419
+
420
+ -- Per-host alert count (prioritize deep dives)
421
+ SUMMARIZE COUNT detection_finding.message GROUP BY detection_finding.device.hostname, detection_finding.status_id
422
+ AFTER 7d
423
+ ```
424
+
425
+ Use SUMMARIZE when you catch yourself manually counting results from a QUERY. If you need individual events (for IOC extraction, timeline reconstruction, raw_data), stay with QUERY.
426
+
427
+ > **Constraints:** SUMMARIZE has known execution limits — `status_id` filtering fails on detection_finding (use GROUP BY instead), `FROM` not supported, high-cardinality GROUP BY can overflow. If SUMMARIZE returns empty, fall back to QUERY. See fsql-expert Layer 1c for workarounds and check `summarize_support` in the environment profile.
428
+
429
+ **Layer 2: Category with key fields**
430
+
431
+ When investigating a class of activity rather than a single IOC:
432
+
433
+ ```
434
+ QUERY #network.src_endpoint.ip, #network.dst_endpoint.ip, #network.message, #network.time
435
+ WITH #network.src_endpoint.ip = '<ip>' AFTER 48h
436
+ ```
437
+
438
+ **Layer 3: Full event (rare, scoped)**
439
+
440
+ Use `**` only when scoped to a single host AND single event type AND narrow time window:
441
+
442
+ ```
443
+ QUERY process_activity.** WITH process_activity.device.hostname = 'BD-2578' AFTER 24h
444
+ ```
445
+
446
+ **Never use `**` on broad observable searches.** If a query result overflows to a file, DO NOT read the file — re-query with specific field selectors or tighter filters.
447
+
448
+ **Step 1.5: Pivot from findings to telemetry (MANDATORY — Gate 2 cannot exit without this)**
449
+
450
+ **THIS IS THE MOST COMMONLY SKIPPED STEP. DO NOT SKIP IT.** Every investigation that skipped this step produced a shallow report. Every investigation that ran it found critical evidence (command lines, login patterns, network flows) that detection findings alone did not reveal.
451
+
452
+ **Do not stay in `detection_finding` for the entire investigation.** Detection findings tell you what an alert fired on. Telemetry event types (`process_activity`, `file_activity`, `authentication`, `network_activity`, etc.) tell you what actually happened. You need both.
453
+
454
+ After Layer 1a/1b discovery, pivot to the underlying telemetry based on the alert type:
455
+
456
+ | Alert Type | Query These Event Types |
457
+ |------------|------------------------|
458
+ | Process/script execution | `process_activity` — command lines, parent processes, execution chains |
459
+ | Malware/file-based | `file_activity` — file creation, drops, staging |
460
+ | C2/lateral movement | `network_activity`, `dns_activity`, `http_activity` — traffic flows, DNS, HTTP |
461
+ | Identity/auth anomaly | `authentication` — login patterns, source IPs, failures |
462
+ | Phishing/email | `email_activity` — delivery chain, recipients, attachments |
463
+ | Cloud/API abuse | `api_activity` — API calls, callers, sources |
464
+
465
+ See the **"Event-Type Query Patterns by Investigation Need"** section in `fsql-reference.md` for exact queries for each event type.
466
+
467
+ Example pivot for a PowerShell alert:
468
+ ```
469
+ -- You found: detection_finding about "powershell.exe fileless script" on BD-3263
470
+ -- PIVOT to process_activity:
471
+ QUERY process_activity.message, process_activity.time,
472
+ process_activity.process.name, process_activity.process.cmd_line,
473
+ process_activity.actor.process.name, process_activity.device.hostname
474
+ WITH process_activity.device.hostname = 'BD-3263'
475
+ AND %process_name = 'powershell.exe' AFTER 7d
476
+ ```
477
+
478
+ This tells you what the PowerShell process actually did (command lines, parent processes) — not just that an alert fired.
479
+
480
+ **Step 1.6: Per-host deep dives (REQUIRED for priority hosts)**
481
+
482
+ After Layers 1-3 identify the most suspicious hosts, run a per-host deep dive. **Cap the number of hosts by tier:**
483
+
484
+ | Tier | Max Priority Hosts |
485
+ |------|--------------------|
486
+ | **Standard** | 3 hosts |
487
+ | **Deep** | 5 hosts |
488
+
489
+ Select hosts with the highest severity alerts, most diverse alert types, or most IOC overlap. If all hosts show the same pattern (e.g., same alert type, same subnet), deep-dive 2 and note "remaining N hosts show identical pattern — sampled 2."
490
+
491
+ For each priority host:
492
+
493
+ ```
494
+ -- For each priority host, get ALL alerts including status_id to distinguish active vs. resolved
495
+ QUERY detection_finding.message, detection_finding.severity_id, detection_finding.status_id, detection_finding.device.hostname
496
+ WITH detection_finding.device.hostname = '<hostname>' AFTER 7d
497
+
498
+ -- Get device owner context
499
+ QUERY detection_finding.device.hostname, detection_finding.device.ip, detection_finding.device.os.name,
500
+ detection_finding.device.owner.ldap_person.given_name,
501
+ detection_finding.device.owner.ldap_person.surname,
502
+ detection_finding.device.owner.ldap_person.job_title, detection_finding.message
503
+ WITH detection_finding.device.hostname = '<hostname>' AFTER 24h
504
+ ```
505
+
506
+ **CRITICAL: Always include `status_id` in deep dive queries.** When expanding the time range beyond 24h, you will pull in historical alerts. You MUST check `status_id` to distinguish between:
507
+ - `NEW` — unresolved, actionable alerts (these matter)
508
+ - `RESOLVED` with `status_detail = "Benign"` — already investigated and closed as false positives (do NOT treat these as active threats)
509
+ - `null` — status unknown, treat with caution
510
+
511
+ **Building an investigation narrative on RESOLVED/Benign alerts is the #1 way to produce a false escalation.** The senior analyst review will catch this, but you should catch it first.
512
+
513
+ This is where critical findings emerge — the first two successful investigations found full kill chains, multi-day persistence, and multi-malware compromise because they deep-dived each host. Skipping this step produces shallow investigations.
514
+
515
+ **Step 2: Threat intelligence**
516
+
517
+ If IOCs include IPs, hashes, or domains, invoke `digital-workers:threat-intel-enricher` for reputation and campaign correlation.
518
+
519
+ **Step 3: Populate the Five W's**
520
+
521
+ From enrichment results, begin answering:
522
+ - **Who**: Which users, accounts, or actors are involved?
523
+ - **What**: What exactly happened? What actions were taken?
524
+ - **When**: What's the timeline? When did it start?
525
+ - **Where**: Which systems, IPs, networks, locations?
526
+ - **Why**: Initial assessment — attack, mistake, policy violation, automation?
527
+
528
+ **Gate 2 Exit — Save artifacts:**
529
+ 1. Append to `queries.md` — all enrichment queries with result counts and key findings
530
+ 2. Append to `iocs.md` — any new IOCs discovered with type, source, and reputation
531
+
532
+ **Step 4: Evidence quality check — data quality**
533
+
534
+ Invoke `digital-workers:evidence-quality-checker` (Gate 2 pass). Append the check results (PASS/FAIL per check) to `queries.md` so the audit trail shows the quality gate ran. If any check fails, fix before proceeding to Gate 3. **Once all checks pass (or failures are fixed), continue immediately to Gate 3 — do not stop or wait for user input.**
535
+
536
+ **Gate 2 Exit Criteria (ALL must be true before proceeding to Gate 3):**
537
+ 1. IOCs enriched via Layer 1a/1b discovery
538
+ 2. Per-host deep dives completed on priority hosts
539
+ 3. **At least one telemetry pivot query executed** (process_activity, file_activity, network_activity, or authentication) — if you have not queried any telemetry event type, STOP and run Step 1.5 now
540
+ 4. Five W's populated (at least partially)
541
+ 5. Threat intel gathered
542
+ 6. Evidence quality verified
543
+
544
+ ---
545
+
546
+ ## Gate 3: Analyze Situation (Standard + Deep only)
547
+
548
+ ### Entry: Enrichment complete
549
+
550
+ **Org-policy check:** If an org-policy skill is loaded, pass its Severity Weights and Crown Jewels sections to the severity-scorer. These override the default weights, thresholds, and asset criticality assignments.
551
+
552
+ **Step 1: Score severity**
553
+
554
+ Invoke `digital-workers:severity-scorer` with all gathered context:
555
+ - Alert severity (from source)
556
+ - Asset criticality (inferred from enrichment)
557
+ - Business impact (potential)
558
+ - Confidence (based on evidence quality)
559
+ - Threat context (from threat intel)
560
+
561
+ **Step 2: Route to depth**
562
+
563
+ Based on composite score and override rules:
564
+
565
+ | Depth | Next Action |
566
+ |-------|------------|
567
+ | **AUTO-CLOSE** | Skip to Gate 4 with disposition: False Positive or Benign Activity |
568
+ | **STANDARD** | Proceed to Gate 4 with current evidence (no deep investigation) |
569
+ | **DEEP** | Invoke specialist investigators in Gate 4 before disposition |
570
+
571
+ **Step 3: Evidence quality check — analytical reasoning**
572
+
573
+ Invoke `digital-workers:evidence-quality-checker` (Gate 3 pass). Append the check results to `queries.md`. If any check fails, fix before proceeding to Gate 4. **Once all checks pass (or failures are fixed), continue immediately to Gate 4 — do not stop or wait for user input.**
574
+
575
+ **Gate 3 Exit Criteria:** Severity scored, depth routed, evidence quality verified, ATT&CK mapped.
576
+
577
+ ---
578
+
579
+ ## Gate 4: Decide & Act (Standard + Deep only)
580
+
581
+ ### Entry: Analysis complete, depth determined
582
+
583
+ **For AUTO-CLOSE:**
584
+ - Propose disposition (False Positive or Benign Activity)
585
+ - Document reasoning with evidence
586
+ - If an org-policy skill is loaded and specifies `autonomy_level: recommend-close`, note the disposition as a recommendation (the analyst will see it in the report) — do not stop for confirmation here
587
+ - Continue to Gate 5
588
+
589
+ **For STANDARD:**
590
+ - Review Five W's — are they complete enough for a verdict?
591
+ - If yes: assign disposition with evidence
592
+ - If no: run targeted follow-up queries via `digital-workers:fsql-expert`, then decide
593
+
594
+ **Org-policy check:** If an org-policy skill is loaded, read its Incident Criteria (for escalation thresholds), Autonomy Level (auto-close vs. recommend-close), Custom Dispositions (additional categories), and Custom Runbooks (org-specific investigation procedures for matching alert types).
595
+
596
+ **For DEEP:**
597
+
598
+ Check if the org-policy defines a custom runbook for this alert type. If a match is found, invoke the runbook skill. Otherwise, invoke specialist investigators based on alert type from classification:
599
+
600
+ | Alert Type | Skill to Invoke |
601
+ |-----------|----------------|
602
+ | Identity/Access | `digital-workers:identity-investigator` |
603
+ | Network/Lateral | `digital-workers:network-investigator` |
604
+ | Malware/Endpoint | (future: `endpoint-investigator` — use `fsql-expert` for manual process/file queries) |
605
+ | Phishing/Email | (future: `email-investigator` — use `fsql-expert` for manual email queries) |
606
+ | Cloud/Application | (future: `cloud-investigator` — use `fsql-expert` for manual API queries) |
607
+
608
+ For alert types without a dedicated investigator in V1, use `digital-workers:fsql-expert` to run investigation queries manually following the patterns in the reference.
609
+
610
+ **Always invoke the matched specialist, even when data gaps are expected.** The specialist is designed to discover and document gaps — that documentation is itself a finding. Skipping the specialist because "the data probably isn't there" means gaps get documented ad hoc instead of through the structured specialist process. If the specialist finds no data, it will report that as a finding with impact assessment.
611
+
612
+ **Concurrency:** When multiple specialists are needed (e.g., Identity + Network), or when specialist investigation and threat intel enrichment are independent, invoke them in parallel using concurrent tool calls. Don't serialize work that has no dependencies.
613
+
614
+ **After specialist investigation, propose disposition:**
615
+
616
+ | Disposition | Criteria |
617
+ |-------------|---------|
618
+ | **Critical Threat** | Confirmed malicious activity. Evidence of compromise. Immediate response needed. |
619
+ | **Policy Violation** | Real activity violating policy. May not be malicious. Remediation needed. |
620
+ | **False Positive** | Detection logic triggered incorrectly. No actual security event. |
621
+ | **Benign Activity** | Real activity that is expected or authorized. No action needed. |
622
+
623
+ **INCIDENT ESCALATION RECOMMENDATION**: If proposed disposition is Critical Threat AND any of the following:
624
+ - Active ongoing compromise
625
+ - Data exfiltration confirmed or in progress
626
+ - Lateral movement to high-value assets
627
+ - Credential compromise with privilege escalation
628
+
629
+ Then: **RECOMMEND INCIDENT ESCALATION**. Present evidence mapped against incident criteria. The analyst decides whether to formally declare an incident — that decision has compliance and business implications that require human judgment.
630
+
631
+ **Gate 4 Exit — Save artifacts:**
632
+ 1. Append to `queries.md` — all specialist queries with result counts and findings
633
+ 2. Append to `iocs.md` — any new IOCs from specialist investigation
634
+
635
+ **Gate 4 Exit Criteria:** Disposition proposed with supporting evidence. Incident escalation recommended if criteria met. **Continue immediately to Gate 5 — do not stop or wait for user input.**
636
+
637
+ ---
638
+
639
+ ## Gate 5: Build & Prioritize Case (Standard + Deep only)
640
+
641
+ ### Entry: Disposition assigned
642
+
643
+ **Step 1: Assemble evidence package**
644
+
645
+ Compile all investigation artifacts:
646
+ - Original alert(s)
647
+ - Classification (OCSF, ATT&CK)
648
+ - Severity score with dimension breakdown
649
+ - All FSQL queries run and their results
650
+ - IOCs with reputation
651
+ - Five W's with confidence levels
652
+ - Specialist investigation findings (if DEEP)
653
+ - Disposition with supporting evidence
654
+
655
+ **Step 2: Prioritize**
656
+
657
+ If investigating multiple alerts, prioritize by:
658
+ 1. Critical Threats first (always)
659
+ 2. Then by composite severity score (highest first)
660
+ 3. Then by timestamp (oldest unresolved first)
661
+
662
+ **Gate 5 Exit Criteria:** Evidence package complete, priority assigned. **Continue immediately to Gate 6 — do not stop or wait for user input.**
663
+
664
+ ---
665
+
666
+ ## Gate 6: Incident Notification (Standard + Deep only)
667
+
668
+ ### Entry: Case built and prioritized
669
+
670
+ **Org-policy check:** If an org-policy skill is loaded, read its Escalation Targets (notification routing per disposition) and Report Format (section preferences). Pass these to the report-writer.
671
+
672
+ **Step 1: Generate report**
673
+
674
+ Invoke `digital-workers:report-writer` with the complete evidence package.
675
+
676
+ The report will include:
677
+ - Business summary (plain English, always present)
678
+ - Technical investigation (Five W's, IOCs, ATT&CK, evidence chain)
679
+ - Recommended next steps
680
+ - Show-your-work section (available on request)
681
+
682
+ **Step 2: Save investigation**
683
+
684
+ Save the report to the investigation directory as `report.md`
685
+
686
+ **Step 3: Senior Analyst Review (BEFORE presenting to analyst)**
687
+
688
+ **THIS STEP IS PART OF GATE 6, NOT OPTIONAL.** Do not present the report to the analyst until the review is complete. The investigation is not finished until the review runs.
689
+
690
+ **Trigger:** If the investigation tier is **Deep**, OR the proposed disposition is Critical Threat (regardless of tier), you MUST invoke `digital-workers:senior-analyst-review` now — before presenting to the analyst. Standard tier skips this unless the analyst explicitly requests it.
691
+
692
+ **Configurable:** If an org-policy skill is loaded, check its `review_trigger` setting:
693
+ - `all` — review every investigation
694
+ - `high_critical` — review HIGH and CRITICAL only (default)
695
+ - `critical_only` — review only CRITICAL
696
+ - `manual` — never auto-trigger, analyst invokes manually
697
+
698
+ **If review identifies gaps:**
699
+ 1. Run the suggested follow-up queries via `digital-workers:fsql-expert`
700
+ 2. Update the evidence package, Five W's, and disposition if warranted
701
+ 3. Re-run `digital-workers:report-writer` with updated findings
702
+ 4. Save updated `report.md`
703
+ 5. Re-run `digital-workers:senior-analyst-review` on the updated investigation (max 2 cycles)
704
+
705
+ **If review approves:**
706
+ - Note "Senior Analyst Review: APPROVED" in the report
707
+ - Proceed immediately to Step 4
708
+
709
+ **Save:** Write `review.md` — the senior analyst review output (verdict, checks, any gaps identified)
710
+
711
+ **Step 4: Present to analyst**
712
+
713
+ Only after the review is complete (or if review was not triggered), present the report to the analyst.
714
+
715
+ **Display the full report inline in the conversation.** The analyst should be able to read the complete investigation — business summary, disposition, Five W's, IOCs, evidence chain, and recommended next steps — without opening any files. The files (`report.md`, `queries.md`, `iocs.md`, `review.md`) are the durable record; the conversation is where the analyst reads and acts.
716
+
717
+ If multiple alerts were investigated, present a summary table first, then the full report for each alert in priority order:
718
+
719
+ ```
720
+ INVESTIGATION SUMMARY — [date]
721
+ ┌─────┬──────────────┬──────────┬─────────────┬───────────────┐
722
+ │ # │ Alert │ Severity │ Disposition │ Action Needed │
723
+ ├─────┼──────────────┼──────────┼─────────────┼───────────────┤
724
+ │ 1 │ [title] │ CRITICAL │ Crit Threat │ ESCALATE │
725
+ │ 2 │ [title] │ HIGH │ Policy Viol │ Remediate │
726
+ │ 3 │ [title] │ HIGH │ False Pos │ Tune rule │
727
+ │ ...│ │ │ │ │
728
+ └─────┴──────────────┴──────────┴─────────────┴───────────────┘
729
+
730
+ Starting with Alert #1 (highest priority)...
731
+ ```
732
+
733
+ **Step 5: Incident escalation recommendation (if applicable)**
734
+
735
+ If any alerts meet incident criteria, present the evidence for analyst review:
736
+
737
+ ```
738
+ ⚠️ INCIDENT CRITERIA MET: [alert title]
739
+ Confidence: [HIGH/CONFIRMED]
740
+
741
+ Evidence supporting incident declaration:
742
+ 1. [Specific criterion met with evidence reference]
743
+ 2. [Specific criterion met with evidence reference]
744
+ 3. [Specific criterion met with evidence reference]
745
+
746
+ Proposed disposition: Critical Threat — Recommend Incident Escalation
747
+ Recommended IR actions:
748
+ 1. [Specific containment recommendation]
749
+ 2. [Specific remediation step]
750
+ 3. [Notification recommendation]
751
+
752
+ ⚡ ANALYST ACTION REQUIRED: Review evidence and confirm whether to formally declare an incident.
753
+ ```
754
+
755
+ **Step 4: Update environment profile with known false positives**
756
+
757
+ After the report is finalized, review all detection messages that were dispositioned as **False Positive** or **Benign Activity** in this investigation. For each such message:
758
+
759
+ 1. Check if it already exists in `digital-workers/learned/environment-profile.json` under `known_false_positives`
760
+ 2. If it exists: update `last_verified` to today's date, increment `sample_size` if new samples were found, add this investigation ID to `investigations_confirmed`
761
+ 3. If it does NOT exist and the investigation confirmed ALL instances as RESOLVED/Benign with sample size ≥ 5: add a new entry:
762
+
763
+ ```json
764
+ {
765
+ "known_false_positives": {
766
+ "<detection message text>": {
767
+ "status": "all_resolved_benign",
768
+ "connectors_seen": ["<connector_ids>"],
769
+ "sample_size": <count>,
770
+ "sample_window": "<time range queried>",
771
+ "last_verified": "<today's date>",
772
+ "investigations_confirmed": ["<this investigation ID>"],
773
+ "note": "<brief explanation of why this is benign>"
774
+ }
775
+ }
776
+ }
777
+ ```
778
+
779
+ **Why Gate 6 and not inline:** Known-FP entries suppress future verification queries. Writing them prematurely (before the investigation is complete) risks suppressing a detection that turns out to be a true positive after deeper analysis in Gates 4-5. Gate 6 writes are safe because the full investigation has concluded and the disposition is final.
780
+
781
+ **Gate 6 Exit Criteria:** Report generated, senior analyst review completed (if triggered), investigation saved to `report.md` and `review.md`, analyst notified, escalation recommendation presented if applicable, environment profile updated with verified known false positives.
782
+
783
+ **The investigation is now COMPLETE.** If there are more alerts to process, continue to the next alert. If this was the only alert (or the last in a batch), the workflow is finished.
784
+
785
+ ---
786
+
787
+ ## Processing Multiple Alerts
788
+
789
+ When investigating a batch of alerts:
790
+
791
+ 1. Run Gates 1-3 for ALL alerts first (intake, enrich, score)
792
+ 2. Sort by priority (Critical Threats first, then by severity score)
793
+ 3. Run Gates 4-6 for each alert in priority order
794
+ 4. Continue to the next alert automatically — do not stop between alerts
795
+
796
+ Present all reports at the end. The analyst can ask to dive deeper on any alert after reviewing the full batch.
797
+
798
+ ## Loop Mode Behavior
799
+
800
+ When running in `/loop` mode for continuous monitoring:
801
+
802
+ 1. Query for new alerts since last check
803
+ 2. Run **Triage** on all new alerts (fast scan, no files)
804
+ 3. Present concise summary in conversation:
805
+ ```
806
+ [LOOP] 3 new alerts triaged:
807
+ - Alert A: 2 LOW findings, likely benign (no upgrade triggers)
808
+ - Alert B: 1 HIGH finding, single host (no upgrade triggers)
809
+ - Alert C: 3 CRITICAL findings, 5 hosts — AUTO-UPGRADING to Standard
810
+ ```
811
+ 4. Auto-upgrade to Standard for any alert that hits upgrade triggers
812
+ 5. For recommended escalations, break out of loop behavior and present full advisory
813
+
814
+ ## Red Flags
815
+
816
+ | Red Flag | Correct Action |
817
+ |----------|---------------|
818
+ | "This alert is obviously a false positive, skip investigation" | STOP. Run the tier's gates. Document the evidence. The documentation IS the value. |
819
+ | Running Deep when the analyst asked a question ("Any...?", "What's...?") | STOP. Questions = Triage. Don't waste 30 minutes when they wanted a 5-minute scan. |
820
+ | Running Triage when the analyst said "investigate" or "full" | STOP. "Investigate" = Standard minimum. "Full"/"deep"/"thorough" = Deep. |
821
+ | Stopping to ask which tier to use | STOP. Parse the prompt, select, announce, and go. The analyst can interrupt if wrong. |
822
+ | Retrying empty fields with different field paths | STOP. If IOC/actor/observable fields are null, the data isn't there. Note the gap and move on. Don't spend 5 queries probing a skeleton-mapped alert. |
823
+ | "I already know what this is" | STOP. You're skipping Gate 2 (gather information). Assumptions kill. |
824
+ | "Let me just check the severity and decide" | STOP. Severity alone doesn't determine depth. Score all five dimensions. |
825
+ | "No data found, closing as benign" | STOP. No data ≠ benign. It might mean the data source is unavailable. Document as Insufficient Data. |
826
+ | "I'll write the report later" | STOP. The report is part of the investigation, not an afterthought. Gate 6 is mandatory. |
827
+ | "This is low priority, I'll skip the specialist" | STOP. If the severity scorer routed to DEEP, run the specialist. Override requires explicit analyst direction. |
828
+ | Jumping straight to Gate 4 without Gates 1-3 | STOP. Every investigation starts at Gate 1. No exceptions. |
829
+ | Using Bash, cat, python, or jq to process data | STOP. **Never use shell commands to process investigation data.** Analyze MCP results directly as an LLM. Use the Read tool for files. Write more specific queries to reduce payload size. |
830
+ | Lookback query without `status_id` in fields | STOP. Historical alerts may be RESOLVED/Benign. Always include `status_id` so you can distinguish active threats from closed false positives. |
831
+ | Citing RESOLVED/Benign alerts as active threats | STOP. Check `status_id` and `status_detail`. RESOLVED+Benign means the source platform already investigated and closed it. Do not build an APT narrative on closed alerts. |
832
+ | Skipping the senior analyst review on a DEEP investigation | STOP. The review is Step 5 of Gate 6 — it runs BEFORE you present to the analyst. It is not optional. |
833
+ | Skipping the evidence-quality-checker because "the data looks fine" | STOP. The checker exists because data that looks fine can still produce false escalations. Run it. |
834
+ | Only querying `detection_finding` and never pivoting to telemetry | STOP. Detection findings are alerts, not evidence. Pivot to `process_activity`, `file_activity`, `authentication`, etc. to see what actually happened. See Step 1.5 in Gate 2. |
835
+ | Running individual queries for each IOC instead of batching | STOP. Use `%ip IN '1.2.3.4', '5.6.7.8'` to search multiple IOCs in one query. 5 separate IP queries = 5 queries burned. 1 batched query = 1. |
836
+ | Probing multiple field paths in Gate 1 (actor, finding_info, unmapped, resources, raw_data...) | STOP. Gate 1 gets 2 IOC extraction queries max. If the intake + one raw_data query don't yield IOCs, move to Gate 2. |
837
+ | 20+ queries on a Standard investigation | STOP. Standard budget is 15. You're over-investigating. Stop enrichment and write the report with what you have. |
838
+ | Investigation taking >20 min at Standard tier | STOP. Check your query count. You've probably been field-path chasing or running per-IOC queries that should be batched. |