feat: report agents new to an organization - #6061
Conversation
🦋 Changeset detectedLatest commit: 19cbe99 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Running ultrareview automatically — This PR adds an organization-wide 'first detected' check inside the AI detection upsert and emits growth signals; it changes a core telemetry function's contract and introduces subtle concurrency and correctness risks in the new existence query, so a deeper review is warranted.. I'll post findings when complete. |
41b8ce0 to
fb660ff
Compare
There was a problem hiding this comment.
Ultrareview completed in 11m 30s
Review completed against the latest diff
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
767c1d1 to
e6d2ce7
Compare
There was a problem hiding this comment.
Auto-approved: review:bypass label applied by @simplesagar. Required status checks still gate this merge.
1cd12de to
f4f5837
Compare
f4f5837 to
74e89fd
Compare
74e89fd to
bdd911b
Compare
Emits `agent_first_detected` when a device-agent scan reports a target the organization has no detection for yet. The existing read-merge-write is keyed by device serial and user email, because that is the storage key, which makes its notion of "existing" per-device: a harness already known on one laptop looks brand new on the next one. Firing on that would announce the same agent once per machine. A separate lookup keyed on nothing but the organization and the target answers the question actually being asked. No schema change. ReplacingMergeTree may hold unmerged duplicates, which does not matter here: the question is existence, and any surviving row answers it. Nobody performs this, so the activity carries no actor: a device agent scanned and reported what it found. Detections have no project dimension, so these never claim a project. Temporal actions/month: 0 (no background work added). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01761VcQZ1sW4TFb16AoozTA
A seed helper in the access tests still called UpsertAIDetections as a single-value expression. Caught by a whole-module vet rather than the per-package one, which had not covered this package. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01761VcQZ1sW4TFb16AoozTA
Two scans for the same organization and target can overlap: both pass the pre-insert lookup, both see the target as unseen, and both report. Making the claim atomic would cost a lock on a scan path that is otherwise append-only. Instead the report carries a key derived from what it asserts — this target was first seen in this organization — so PostHog collapses the duplicates however many scans raced. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01761VcQZ1sW4TFb16AoozTA
bdd911b to
19cbe99
Compare
Note
Stacked PR — merge bottom-up. Each PR targets the one above it, so its Files tab shows only its own diff.
Merging #6057 retargets #6058 to
mainautomatically, and so on down the stack.GRW-66
Last of a five-PR stack. Targets #6060, review that first.
Summary
Emits
agent_first_detectedwhen a device-agent scan reports a target the organization has no detection for yet.The interesting part is what "first" means. The existing read-merge-write in
ai_detectionsis keyed by device serial and user email, because that is the ClickHouse storage key. That makes its notion of "existing" per-device: a harness already known on one laptop looks brand new on the next one, so firing on that signal would announce the same agent once per machine as it spreads through a company.A separate lookup keyed on nothing but the organization and the target answers the question actually being asked. It runs before the insert, so it describes the organization as it was, and needs no schema change. ReplacingMergeTree may hold unmerged duplicates, which does not matter here: the question is existence, and any surviving row answers it.
Two shape decisions:
The catalog supplies the display name, with the raw target id kept alongside it so a renamed catalog entry stays traceable.
Motivation
Agents were in scope on the ticket but had no natural signal: they are derived from telemetry rather than stored as detection events, so there was no insert to hook. This uses the read-merge-write the write path already performs, which is what makes it a query rather than a migration.
Temporal actions/month: 0, scales with fixed. No background work is added.
Summary by cubic
Emits
agent_first_detectedwhen a device-agent scan reports a target the organization has no detection for yet, completing the agent piece of the GRW-66 PostHog Slack notifications revamp.$insert_idderived from the organization and target so PostHog collapses the duplicates.Written for commit 19cbe99. Summary will update on new commits.