Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/D1.7.mp4Run a triage loop with a severity floor, and sample its auto-closures so the false-negative rate is measured rather than assumed.
The delegation graph is multi-threaded and the agents self-correct deceptively: a loop that scores evidence only on support confirms its first theory and closes the wrong case at machine speed, silently.
triage() ranks, cuts at capacity, and — the part that makes it a control rather than a strategy — takes a deterministic sample from below the line. floor_miss_rate() then says what the sample found. A non-zero rate means the ranking is wrong and the queue is being cut in the wrong place, which is a different fix from hiring.Triage when the queue is longer than the day: ranking, an explicit capacity cut, and the sample taken from below the line so the rule that closes most of the queue is itself measured rather than trusted.
An agent that scores evidence only on support confirms its first theory and closes the wrong case at machine speed, silently.
Run triage as a loop with a severity floor and a stable-seeded sample of whatever it auto-closed.
Closures sampled to a human, and agreement on that sample — which is the only measurement of the loop's false-negative rate you will get.
Measure this
| what to measure | denominator or target |
|---|---|
| closures sampled to a human | share of closures |
| agreement on that sample | rate; it is the only measure of the loop's false-negative rate you get |
the loop triages a fleet of alerts
evidence supports theory-1 -> confirm
evidence supports nothing -> an agent scoring SUPPORT reads noise
and confirms theory-1 anyway <- deceptive
the control:
may close yes
may close SILENTLY no (sampled to a human)
may close ABOVE the floor no (high/critical -> escalate)When the swarm has fired, triage is where a non-deterministic actor defeats a human queue. The delegation graph is multi-threaded and the agents self-correct deceptively — an investigating loop that scores evidence only on support will confirm its first theory and close the wrong case at machine speed.
Triaging the swarm means running the triage as a loop with a floor: the loop may close, but not silently, and never above a severity it is not allowed to conclude on its own. The skill is knowing which signals the loop may believe.
The skill does three things to CyberTravels' alert queue.
1. It runs an agentic triage loop over the alerts.
2. It samples whatever the loop closed by itself. The sample uses a fixed seed, so you get the same sample every run and can compare.
3. It sets a severity floor. Above that line nothing may be closed automatically, however confident the loop is.
The skill — skills/secops/detection-triage/SKILL.md
name: detection-triage
description: >-
Triage security alerts with the context needed to reach a defensible verdict,
and sample what is auto-closed so the closing rule stays honest. Use when
working an alert queue, deciding whether an alert is a true positive, tuning
a noisy detection, or designing automated alert handling.
allowed-tools: Read, Grep, BashAn analyst reading an alert in isolation is guessing. The verdict comes from the alert plus the context that makes it normal or abnormal, and most triage automation fails because it automated the guess instead of the context.
Working an alert queue, building an auto-close rule, or reviewing why a detection produces verdicts nobody trusts.
1 — Gather the context before judging. For every alert, assemble:
A verdict issued without history will re-litigate a decision the team already made, which is the most common way triage automation loses trust.
2 — Reach a verdict, with the reason. One of true_positive, false_positive, benign_true_positive (it really happened and it is fine), or needs_human. Record which context field decided it. "Benign true positive" is a distinct category and collapsing it into false-positive corrupts every tuning decision made from the data afterwards.
3 — Attach confidence, and let it gate automation. Only high-confidence verdicts may auto-close. Everything else queues.
4 — Sample the auto-closed. Automation that closes alerts must be audited by re-opening a fraction of them for human review. This is the control that catches a closing rule that has quietly started closing real incidents.
Seed the sampler from something stable — a checksum of the alert id, never hash(), which Python randomises per process. A sampling rule that picks a different subset every run cannot be audited, because you cannot tell whether a change in findings came from the rule or from the dice.
5 — Feed tuning from verdicts, not volume. A detection is noisy if its false-positive rate is high, not if it fires often. Rank tuning candidates by false_positive_rate × volume, with a full tiebreak so the list is stable between runs.
Input — the fixture committed at the top of scripts/detection_triage.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:
BARE ALERT (what most SOCs receive):
patch-agent read /vault/.env
rotator-agent read /vault/.env
→ identical. An analyst cannot tell these apart.
ENRICHED ALERT:
actor patch-agent
on behalf of dana@corp
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.
{
"triaged": [
{"alert_id": "str", "verdict": "true_positive|false_positive|benign_true_positive|needs_human",
"deciding_context": "asset|identity|history|change|peers",
"reason": "str", "confidence": 0.0,
"auto_closed": false, "sampled_for_review": false}
],
"sampling": {"rate": 0.0, "seed_source": "str", "reviewed": 0, "disagreements": 0},
"tuning": [{"rule": "str", "fp_rate": 0.0, "volume": 0, "priority": 0.0}]
}
disagreements is the number that matters: it is the measured error rate of the automation, and it belongs in every report about it.
hash(). Non-reproducible sampling is not a control.needs_human. Forced verdicts under uncertainty are how a queue becomes an incident.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.
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 D1.7Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick d1-7-triaging-the-non-deterministic-swarm:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons D1.7 | type /d1-7-triaging-the-non-deterministic-swarm |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons D1.7 | type /d1-7-triaging-the-non-deterministic-swarm in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons D1.7 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons D1.7 | type $d1-7-triaging-the-non-deterministic-swarm, or run /skills |
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 D1.7Neither 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 D1.7 --out work/cybertravels
python3 scripts/checkpoint.py --at D1.7 --diffOn 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.
The loop matches ground truth on the routine alerts, the severity floor converts every high closure into an escalation, and the closure sample routes a fraction to a human so the false-negative rate is measured rather than assumed.
Ask your SOC whether anyone checks, when an incident is confirmed, whether an earlier alert about it was auto-closed. If not, your loop's error rate is invisible.
Tools used
Skill source: skills/secops/detection-triage