All lessons › Function E — The Agentic SOC › Understand — Correlation, Intel and the Hunt
E3.1

From alert queue to loop operator

E3

This starts chapter E3. Its course guide is E3 in the Function E course guide →

▶
Lightboard recording

Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.

Video placeholderpublishes automatically from recordings/E3.1.mp4
Risk

Supervising by re-reading everything the loop did.

Control

Know what the loop must escalate and sample the rest.

The lab

Run a triage loop over Wazuh alerts and supervise by exception.

◉Use case relevance

The queue does not go away; it changes shape. Instead of triaging alerts you are supervising something that triages alerts, which is a different skill with a different quality bar and a much worse failure mode: confident, fast, and wrong at volume.

At CyberTravels. supervise() wraps D1.7's triage with the list of alerts that bypass ranking entirely. A canary read is not a scoring question — D1.8 built it precisely so that it needs no triage — and the sample below the line is what makes the closing rule testable rather than trusted.

◴What this lesson is — Day 0, Day 1, Day 2

Supervising a triage loop rather than re-reading it: the list of alerts that bypass ranking entirely, and a sample of what the loop closed, so the closing rule is measured rather than trusted.

Day 0 — why

Supervising a loop by re-reading everything it did is not supervision, and a loop that closes a true positive does so silently.

Day 1 — how

Decide what the loop may conclude, what it may do unsupervised, and which sample of its closures a human reads.

Day 2 — measure

Alerts escalated versus closed against ground truth, and the severity floor no automatic closure may cross.

Measure this

what to measuredenominator or target
alerts escalated against those closed, versus ground truthtwo rates
severity floor no automatic closure may crossthe floor itself

▦The framework, and how it works

   before                          after
   +------------------+            +---------------------------+
   | alert -> analyst |            | alert -> loop -> analyst  |
   |          decides |            |          proposes  reviews|
   +------------------+            +---------------------------+
      100 alerts/day                  1000 alerts/day, 40 reviewed

   new failure mode: confident, fast, and wrong at volume

The classic SOC job is a queue: alerts arrive, an analyst reads each one, decides, and moves on. The constraint is human attention, and it does not scale — which is why tier-1 burnout and alert fatigue are structural rather than cultural problems.

The agentic version replaces "read every alert" with "operate a loop that reads every alert". The analyst's job becomes:

  • deciding what the loop is allowed to conclude (the verifier, C2.0),
  • deciding what it may do about it (the tool policy, B3.5),
  • and handling the cases it escalates.

The skill that transfers is not triage speed. It is knowing which signals the loop may believe — because a triage loop with a weak verifier closes true positives at machine speed, and closing a true positive is silent.

Anchor → E1.0. The understand interval stops being one analyst's reading speed and becomes the loop's, which moves the work rather than removing it: deciding what the loop may conclude, what it may do unsupervised, and which sample of the rest gets read.

2 · Demo — the queue, and the loop that reads it

3 · Where it breaks — closing a true positive is silent

Every triage decision has two error directions and they are not symmetric. Escalating a false positive costs an analyst ten minutes. Closing a true positive costs you the incident, and nothing tells you it happened.

4 · The control — the loop may close, but not silently

Three rules make an agentic triage loop safe to run, and none of them is about model quality.

5 · The procedure, as a skill

The skill scores a triage loop against ground truth, sweeps the confidence bar so the trade between analyst minutes and missed incidents is made explicitly, and adds the severity floor that no automatic closure may cross whatever its confidence.

▶Real time execution as skill

The skill — skills/detection/triage-loop-with-floor/SKILL.md

name: triage-loop-with-floor
description: >-
  Run an alert triage loop against ground truth, measure the confusion matrix,
  and bound it with a confidence bar and a severity floor no automatic closure
  may cross. Use when automating triage, or when deciding what an agent may
  close on its own.
allowed-tools: Read, Grep, Glob

The floor is the part that makes the loop deployable

A triage loop that matches ground truth on a sample is a promising loop. What makes it something you can run is the pair of bounds around it: a confidence bar that decides when it defers, and a severity floor it may never close through, whatever its confidence.

When to use this

Before an agent closes anything, and when tuning how much of a queue is automated.

Procedure

1 — Score against ground truth, as a confusion matrix. Escalated and closed, against true and false. Accuracy alone hides the direction of the errors, and only one direction matters here.

2 — Sweep the confidence bar. For each setting, record analyst minutes saved and incidents missed. This is the trade being made, and it should be made explicitly by whoever owns the queue rather than implicitly by a default.

3 — Set the severity floor separately. Any alert above it is escalated regardless of confidence. A confident wrong closure on a critical alert is the failure this exists to prevent, and no confidence threshold protects against it.

4 — Check what the floor costs. How many alerts it forces to a human per day. If that number is above the reading budget, the floor is theatre and the queue needs a different cut.

5 — Record every automatic closure with its reason and confidence. The loop will be wrong sometimes; the question at review is whether you can find out how.

Example

Input — the fixture committed at the top of scripts/triage_loop_with_floor.py. Edit it and re-run: the buckets, counts and verdicts below are derived from it, not hard-coded.

Output — the opening lines of a real run:

queue: 8 alerts, 4 true positives
   A-01 medium   impossible travel        dana@corp
   A-02 critical metadata service access  patch-agent
   A-03 medium   failed logins x40        svc-etl
   A-04 high     secret path read         patch-agent
   A-05 high     new admin group member   sam@corp
   A-06 low      port scan detected       scanner-01
   A-07 high     egress to unlisted host  triage-agent

The run continues past this. test_skills.py executes the script on every build, with no model configured — so what CI proves is that it runs and refuses legibly, not that it prints these lines. The output above is a recorded run against a real model, and nothing re-diffs it: a model's answer is not reproducible, and this repository does not claim otherwise anywhere it can be checked.

Output contract

{
  "confusion": {"tp": 0, "fp": 0, "tn": 0, "fn": 0},
  "confidence_sweep": [{"bar": 0.0, "analyst_minutes_saved": 0, "incidents_missed": 0}],
  "floor": {"severity": "str", "escalated_regardless": 0, "per_day": 0},
  "audit": {"closures_logged": true, "fields": ["reason", "confidence", "rule"]}
}

Failure modes

  • Reporting accuracy. The direction of the error is the whole question.
  • A floor set above the reading budget. It routes to a person who will not read it.
  • Unlogged closures. You cannot review what the loop decided.

Three ways to do this lesson. Pick one. They run the same procedure against the same code — what changes is who drives it, and how much you see.

1In your AI agent — you are taught

The agent reads the lesson, explains the idea, fetches the code, runs the check and answers your questions as you go. This is the one to take if you are here to learn.

Install it, once. From the folder you cloned. --all does every agent it finds on your machine:

python3 scripts/install_skills.py --all --lessons E3.1

Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.

Then pick e3-1-from-alert-queue-to-loop-operator:

agentinstall just for this agentstart it
Claude Codepython3 scripts/install_skills.py --tool claude --lessons E3.1type /e3-1-from-alert-queue-to-loop-operator
GitHub Copilot (VS Code)python3 scripts/install_skills.py --tool copilot --lessons E3.1type /e3-1-from-alert-queue-to-loop-operator in Chat
Cursorpython3 scripts/install_skills.py --tool cursor --lessons E3.1type / in Agent chat and search for it
Codexpython3 scripts/install_skills.py --tool agents --lessons E3.1type $e3-1-from-alert-queue-to-loop-operator, or run /skills

2As one Python command — you just run it

No agent, no conversation. The same lesson executes and prints the same readback. Take this one if you have no assistant, if you are reviewing rather than learning, or if you want the result without the teaching around it.

python3 scripts/lesson.py E3.1

3Read the code, and the difference — nothing runs

Neither of the above, and no model needed. The first command writes CyberTravels exactly as it stood at the end of this lesson; the second prints the diff — the lines this lesson added or changed, and nothing from any later one.

python3 scripts/checkpoint.py --at E3.1 --out work/cybertravels
python3 scripts/checkpoint.py --at E3.1 --diff

On Windows, type python wherever these say python3 — and use \ instead of / in the paths. Everything else is identical. A0.0 step 2 explains why.

Ways 1 and 2 need a model; way 3 does not. A signed-in Claude Code CLI needs no API key, and any OpenAI-compatible endpoint works too. With neither, the audit exits 2 and says so rather than inventing an answer. A0.0 sets this up.

Ways 1 and 2 both end with the same readback: What I did, What changed, The number and Read this next. A step that was skipped or refused is reported as exactly that, never as a pass.

If you did the last lesson’s challenge, expect this to stop. Most challenges ask you to edit the code, and ways 1 and 2 will not overwrite your edits: you get stopped, not a failure, with two options — --out for a fresh folder that keeps your work, or --force to discard it and start this lesson clean.

✓What you just proved

The triage loop escalates 4 alerts and closes 4, matching ground truth on all 8. Lowering the confidence bar trades analyst minutes against missed incidents. The severity floor converts any high or critical closure into an escalation, and the closure sampling routes a fraction of routine closures to a human for quality measurement.

✎Your turn

Ask your SOC one question: when an incident is confirmed, does anyone check whether an earlier alert about it was closed? If nobody does, you have no measurement of your false-negative rate — with or without an agent.

Tools used

WazuhOpenSearchGLM-4.6Claude Haiku 4.5

Skill source: skills/detection/triage-loop-with-floor

← PreviousE2.6 · Honeypots, canaries and deception — the detector with no threshold