RN-003 · Research note
Coordinated agent fleets share a config, not a clock.
We built a coordinated-fleet detector on two signals and it scored 0.97 precision in simulation. On real GitHub data it scored zero. The reason turned out to be more useful than the result we wanted.
Most work on agentic AI asks a binary question: is this actor a human or a machine? That question gets less useful every month. In a world where an enterprise runs hundreds of agents and shares an internet with adversarial ones, the operational question is not what an actor is — it is who is driving it, and how many others are being driven the same way. A single rogue agent is an incident. A hundred agents under one controller is a campaign.
So we built a detector for coordinated fleets and tried to break it on real data. This note is what happened, including the part where it failed.
The method, and why it needs two signals
A controlled fleet should leave two traces. Its members share a configuration, so they should be behavioural near-clones of one another. And a controller dispatches them together, so they should be co-active in time beyond what the ambient rhythm explains.
Neither signal is sufficient alone, and the failure modes are symmetric. Ten unrelated log-summarisers look alike, so fingerprint similarity alone flags independent agents doing the same job. Business hours synchronise everybody, so timing alone flags the whole working day. We therefore joined instances only when both held — and required the resulting group to be a dense clique rather than a chain, because transitivity will otherwise merge an entire population into one meaningless blob.
Instance
One login on one repository over the window. The unit an operator can actually act on — not an account firehose.
Two views
A behavioural fingerprint (what it does) and an activity histogram (when it does it). Nothing identifying, no content.
Pairwise gate
An edge joins two instances only if they are near-clones — and, in scheduled mode, co-active far beyond chance.
Structure guard
A fleet must be a dense clique, not a chain: k-core prune plus a density floor. Without it, transitivity merges the world.
On a simulated population containing both decoys — a look-alike group sharing a config but not a schedule, and a rush-hour group sharing a schedule but not a config — the AND gate does exactly what it was designed to do.
| Detector | Precision | Recall | F1 |
|---|---|---|---|
| Fingerprint only | 0.08 | 0.25 | 0.12 |
| Timing only | 0.43 | 1.00 | 0.60 |
| AND gate | 0.97 | 0.83 | 0.88 |
Precision 0.97 against 0.08 and 0.43 for the single signals. If we had stopped here, we would have shipped it.
Then we ran it on real data
Public GitHub gives an unusually honest ground truth. A coding-agent vendor — cursor[bot], Copilot, devin-ai-integration[bot] — operates hundreds of per-repository instances from one controller. That is a real controlled fleet, at scale, with a label we did not have to invent. Independent human accounts are the negatives.
We took two days of GH Archive, defined an instance as one login on one repository, and gave the detector nothing but behaviour and timing: 1,677 instances, 378 of them agent, a 22.5% base rate.
| Detector | Flagged | Precision | Recall | Lift |
|---|---|---|---|---|
| Fingerprint only | 16 | 0.438 | 0.019 | 1.9× |
| Timing only | 9 | 0.000 | 0.000 | 0.0× |
| AND gate | 12 | 0.000 | 0.000 | 0.0× |
Zero. The configuration that scored 0.97 in simulation detected not one agent fleet in the wild. The interesting part is that the two signals did not fail together.
Which signal actually carries “same controller”
Rather than tune thresholds until something passed, we measured each signal directly. For every pair of instances we know the truth — same login means same controller — so each signal can be scored as a classifier of that fact, split by whether the pair is agent or human.
The fingerprint works, modestly, for both populations. Temporal co-activity is at 0.496 for agent pairs — precisely chance — while reaching 0.736 for humans. The signal we built the gate around does not merely underperform on agent fleets. It carries no information about them at all, while carrying real information about people.
The obvious objection is that this is an artifact: per-repository sessions are short and bursty, so maybe we simply have not observed enough to see a schedule. That is testable. We recomputed both signals over progressively better-observed instances.
The fingerprint improves and plateaus around 0.74 once an instance has roughly sixteen events — a useful operating requirement, now stated rather than assumed. Co-activity stays flat at chance at every observation depth. The null is real, not a sparsity artifact.
Why: agents are demand-driven
The explanation is mundane and, in retrospect, obvious. A vendor coding agent does not run on the vendor’s clock. It runs when some developer, somewhere, asks it to. Thousands of independent humans pulling a lever produce no shared schedule at all — a fleet with one configuration and no clock.
A human, meanwhile, has a circadian rhythm and a working week, and carries it across every repository they touch. That is why co-activity scores 0.736 on human pairs. On GitHub, temporal coordination identifies people, not machines. Requiring it, as our AND gate did, filtered out exactly the fleets we were hunting.
This is the second time a “machine-like” prior has inverted on us on real GitHub data. The first was rhythm regularity: we expected agents to be clock-like and humans irregular, and found the opposite, because plenty of humans run cron jobs and agents wait to be asked. Priors about how machines behave are worth exactly as much as the data you have checked them against.
What we changed
The fix is not a better threshold. It is admitting that “coordinated fleet” names two different things with different observable signatures, and that requiring a signal which does not exist is worse than not having it.
The fleet is centrally dispatched — cron-driven swarms, scripted botnets, anything with a controller clock.
P 0.97 in simulation; the timing signal is what rejects look-alikes.
The fleet is triggered independently — vendor agent platforms, where a human asks and the agent acts.
The only mode that detects anything on real GitHub fleets.
Three further changes came out of the same exercise. Pearson correlation is degenerate on bursty telemetry — two instances firing in the same single time bin score 1.0 — so coordination is now measured as a chance-corrected co-activity surprise: observed shared bins against the number expected if the two were independent. Instances too sparse to judge are marked unjudgeable and given no coordination edge at all, rather than a fabricated one. And a density floorrejects chained pseudo-fleets — without it, real data produced a single 703-member “fleet” with 1% purity, which is not a finding, it is a bug with confidence.
Where this leaves the product
In demand mode on real GitHub fleets, the honest operating point is a high-precision tip generator rather than an enumerator: at a tight threshold it reaches 1.00 precision at 4.4× lift over base rate, with recall around 2%. It will tell you that a specific handful of instances are provably co-controlled. It will not hand you the whole fleet.
That is a real limit and worth stating plainly, along with the others. A fingerprint AUROC of 0.74 is a corroborating signal, not a verdict. Our ground truth is vendor bot logins, which are cooperative — they announce themselves and have no incentive to blend in. An adversary running a covert fleet can diversify configurations and jitter dispatch to defeat both signals. Coordination detection raises the cost of running one; it does not prove none is running.
We think the negative result is the more valuable half of this work. A detector that scores 0.97 on data you generated is telling you about your generator. The two-signal architecture survived — the AND gate is still right for centrally-dispatched fleets, and we can now say which fleets those are instead of assuming all of them. What did not survive was our assumption about how agents in the world are actually driven, and we would rather find that out on GH Archive than in a customer’s enclave.