All lessons › Function E — The Agentic SOC › Discover — the Sensors, and the Agent-Shaped Hole in Them
E1.2

Drift monitoring — behaviour that changes without a code change

E1
▶
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/E1.2.mp4
Risk

A detection that worked last month is silently degraded.

Control

Watch model updates, prompt changes, index refreshes, tool versions.

The lab

Change the model underneath and catch the detection regression.

◉Use case relevance

Nothing was attacked. The model was upgraded, a prompt was edited, a tool changed its output format — and the behaviour of the system moved. Drift is the failure mode with no adversary, and it is far more common than the ones with one.

At CyberTravels. Six surfaces change what your agent does and only one of them is in this repository. drift() reports which moved and, in its own column, which have no approver — the model version on the vendor's schedule, the retrieval corpus anyone can add a template to, and the MCP tool descriptions B1.9 says can be rewritten after you approved them.

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

The surfaces that change an agent's behaviour without a commit — model version, system prompt, retrieval index, tool descriptions, memory — baselined and diffed, with the column that makes it a finding: which of them anybody approves.

Day 0 — why

A detection that worked last month is silently degraded, because the model, the prompt or the tool list changed and none of it was a code change.

Day 1 — how

Sign off a baseline, then watch the four surfaces that move without raising a ticket.

Day 2 — measure

Time between a behaviour change and its detection — and the share of controls currently outside their freshness window.

Measure this

what to measuredenominator or target
time between a behaviour change and its detectionminutes
controls outside their freshness windowshare of controls

▦The framework, and how it works

   nothing was attacked

   model upgraded ----+
   prompt edited  ----+---> behaviour moves ---> baselines stale
   tool changed   ----+                          detections silent

   drift is the failure mode with no adversary, and the common one
   the control: a fixed probe suite, run on every change

Drift monitoring answers what changes an agent's behaviour without going through the change management process built for code: a new model version, an edited prompt, an added tool. All of them invalidate the testing your controls were signed off against.

That is the precise claim: the control was tested against a behaviour that no longer exists. It has not failed; it is unevidenced, which is a different and more honest state.

Two things are needed:

  1. A signed-off baseline — what normal looked like when the control passed.
  2. A freshness window on the control test, derived from how fast the thing it tests actually drifts.

F1.7 turns the second into a compliance posture. This lesson produces the signal.

Anchor → E1.0. Drift lengthens every interval at once, silently. The model was upgraded, a prompt was edited, and the control is now unevidenced against behaviour that no longer exists — so the discover clock restarts without anybody starting it.

2 · Demo — drift across a quarter

3 · Where it breaks — none of these was a code change

change surfacein change management?what happens today
application codeyespull request, review, CI
agent promptnoedited in a console
tool manifestnoa config change, with no threat-model diff
model versionnoprovider-side; you may not be told
policyyesif it is in git — often it is not
approval settingsnoa toggle in an admin UI
Four of six surfaces bypass change management entirely. Drift is the failure mode with no adversary, and this table is why it is also the failure mode with no ticket.

4 · The control — freshness derived from the observed drift rate

5 · The procedure, as a skill

Six things can change how an agent behaves. Four of them never go near change management. The skill counts those four first.

Then it tracks the drift across a quarter and splits the rise in two:

  • The part that lines up with the model upgrade.
  • The part that does not.

The second part is the interesting one, because nothing in your change log explains it.

▶Real time execution as skill

The skill — skills/detection/behavioural-drift-monitor/SKILL.md

name: behavioural-drift-monitor
description: >-
  Track an agent's drift from its signed-off baseline across a quarter and count
  how many of the surfaces that change its behaviour bypass change management.
  Use when an agent behaves differently than it was approved to, with no code
  change to point at.
allowed-tools: Read, Grep, Glob

Four of six things that change an agent are not code changes

The model version, the prompt, the tool manifest and the approval settings all change what an agent does, and none of them generates a change record. So drift is the only signal that the approved system and the running system have diverged, and it has to be measured rather than inferred from a changelog.

When to use this

Continuously, for any agent under governance — and specifically after a provider announces a model update.

Procedure

1 — Enumerate the change surfaces. Code, model version, system prompt, tool manifest, approval settings, retrieval corpus. For each, record whether a change produces a record anybody reviews.

2 — Count the ones that bypass change management. Four of six is typical. That count is the argument for measuring drift at all.

3 — Fix a baseline at sign-off. Tools, resources, rate, refusal rate — and the model version and prompt hash alongside, so a later drift can be attributed.

4 — Compute drift per period and attribute each rise. A jump that coincides with a model upgrade is a different conversation from a jump with no corresponding event, and the second is the one to escalate.

5 — Set a tolerance and a consequence. Beyond tolerance: re-attest, or revert. A drift figure with no consequence is a chart.

Example

Input — the fixture committed at the top of scripts/behavioural_drift_monitor.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:

    when  event                       drift  new tools
------------------------------------------------------------------
    90d  control signed off          0.000  []
    60d  prompt edited               0.100  []
    30d  tool added (no PR)          0.330  ['run_shell']
     5d  model upgraded by vendor    0.550  ['run_shell']
observed drift rate  0.00647 TVD/day
tolerance            0.25

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

{
  "surfaces": [{"name": "str", "produces_change_record": false}],
  "bypass_count": 0,
  "baseline": {"at": "str", "tools": ["str"], "model_version": "str", "prompt_hash": "str"},
  "timeline": [{"period": "str", "drift": 0.0, "new": ["str"], "attributed_to": "str|null"}],
  "tolerance": 0.0,
  "consequence": "str"
}

Failure modes

  • Trusting the changelog. Most of what changes an agent is not in it.
  • Drift with no attribution. A number nobody can act on.
  • No consequence at the tolerance. The line stops being a line.

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 E1.2

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

Then pick e1-2-drift-monitoring:

agentinstall just for this agentstart it
Claude Codepython3 scripts/install_skills.py --tool claude --lessons E1.2type /e1-2-drift-monitoring
GitHub Copilot (VS Code)python3 scripts/install_skills.py --tool copilot --lessons E1.2type /e1-2-drift-monitoring in Chat
Cursorpython3 scripts/install_skills.py --tool cursor --lessons E1.2type / in Agent chat and search for it
Codexpython3 scripts/install_skills.py --tool agents --lessons E1.2type $e1-2-drift-monitoring, 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 E1.2

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 E1.2 --out work/cybertravels
python3 scripts/checkpoint.py --at E1.2 --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

Drift rises across the quarter from 0.0 at sign-off to roughly 0.35 after the model upgrade, with run_shell appearing as a new tool. Four of six change surfaces bypass change management. The observed drift rate yields a freshness window, and the 90-day-old control test is reported STALE rather than passing.

✎Your turn

Compute the drift rate for one production agent from three months of telemetry, and set its control freshness window from that number rather than from the audit calendar.

Tools used

promptfooGLM-4.6Claude Haiku 4.5

Skill source: skills/detection/behavioural-drift-monitor

← PreviousE1.1 · The sensor estate — EDR, DLP, CSPM and CNAPP against an agent