Repository navigation
feat(alerts): show investigation results in a moved alert's history - #127913
Conversation
A moved insight alert's check history now carries the investigation agent's status, verdict, summary and notebook link, and whether the agent suppressed the notification, from InsightAlertInvestigation and the platform's delivery holds. Investigation rows are pruned after 90 days in the daily AlertCheck cleanup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ook link without a model import Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
😎 This pull request was merged. |
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 8f4d3e5: 2 Should fix.
This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.
See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.
🤖 CI report
|
| File | Comment lines | Added lines |
|---|---|---|
products/alerts/backend/investigation_release.py |
2 | 5 |
products/alerts/backend/models/investigation.py |
2 | 12 |
products/alerts/backend/platform_investigation_detail.py |
1 | 2 |
products/alerts/backend/presentation/views/alert.py |
1 | 9 |
products/alerts_platform/backend/facade/contracts.py |
1 | 2 |
This check does not block merging. It updates on every push and clears when the share drops.
⚠️ Django migration SQL — 1 new migration to review
We've detected new migrations on this PR. Review the SQL output for each migration:
products/alerts/backend/migrations/0016_insight_alert_investigation_age_index.py
/home/runner/work/tmp/tool_cache/Python/3.14.7/x64/lib/python3.14/site-packages/anyio/from_thread.py:119: SyntaxWarning: 'return' in a 'finally' block
return result
2026-11-04T00:47:06.565231Z [error ] Path must be a valid database or directory containing databases. [posthog.exceptions_capture] pid=5618 tid=140445337254784
Traceback (most recent call last):
File "/home/runner/work/posthog/posthog/posthog/geoip.py", line 15, in <module>
geoip: Optional[GeoIP2] = GeoIP2(cache=8)
~~~~~~^^^^^^^^^
File "/home/runner/work/tmp/tool_cache/Python/3.14.7/x64/lib/python3.14/site-packages/django/contrib/gis/geoip2.py", line 114, in __init__
raise GeoIP2Exception(
"Path must be a valid database or directory containing databases."
)
django.contrib.gis.geoip2.GeoIP2Exception: Path must be a valid database or directory containing databases.
/home/runner/work/tmp/tool_cache/Python/3.14.7/x64/lib/python3.14/site-packages/sshtunnel.py:1040: SyntaxWarning: 'return' in a 'finally' block
return (ssh_host,
System check identified some issues:
WARNINGS:
?: (axes.W001) You are using the django-axes cache handler for login attempt tracking. Your cache configuration is however invalid and will not work correctly with django-axes. This can leave security holes in your login systems as attempts are not tracked correctly. Reconfigure settings.AXES_CACHE and settings.CACHES per django-axes configuration documentation.
?: (staticfiles.W004) The directory '/home/runner/work/posthog/posthog/frontend/dist' in the STATICFILES_DIRS setting does not exist.
--
-- Concurrently create index insight_alert_inv_age_idx on field(s) created_at of model insightalertinvestigation
--
SET lock_timeout = 0;
SET statement_timeout = 0;
CREATE INDEX CONCURRENTLY "insight_alert_inv_age_idx" ON "alerts_insightalertinvestigation" ("created_at");Last updated: 2026-11-04 00:47 UTC (1366c62)
✅ Django migration risk — migration analysis complete
We've analyzed your migrations for potential risks.
Summary: 1 Safe | 0 Needs Review | 0 Blocked
✅ Safe
Brief or no lock, backwards compatible
alerts.0016_insight_alert_investigation_age_index
└─ #1 ✅ SafeAddIndexConcurrently
PostHog concurrent-index helper: idempotent (timeout disabling + invalid-leftover recovery)
model: insightalertinvestigation, index: insight_alert_inv_age_idx
Last updated: 2026-11-04 00:48 UTC (1366c62)
…rt id Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Risk: No findings This increment adds a platform "verdict change" follow-up: a new Sentinel reviewed |
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
The Migration risk check has not finished for this commit, so stamphog cannot tell a safe migration from a risky one yet. The review runs again on the next push, or you can re-request it once the check reports.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 167L, 11F substantive, 242L/14F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (242L, 14F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head 0432822 |
👀 Auto-assigned reviewersThese soft owners were skipped because they only have minor changes here. Nothing blocks merge, so self-assign if you'd like a look:
Soft owners come from each directory's |
The agent takes an investigation id instead of an alert check. It reads what the evaluation measured from the InsightAlertInvestigation row, records status, verdict, summary and notebook there, and releases the firing's held delivery by the verdict. The workflow starts the released delivery behind a patch. A verdict that contradicts the firing's previous one on a firing that already went out calls the platform's verdict-changed announcement, which is a stub until the platform has that kind. The signal contract accepts an investigation id and evaluation key in place of the alert check id, and Today keys an occurrence on either. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
The Migration risk check has not finished for this commit, so stamphog cannot tell a safe migration from a risky one yet. The review runs again on the next push, or you can re-request it once the check reports.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 170L, 13F substantive, 245L/16F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (245L, 16F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head 0100a47 |
…vity Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A firing of an alert the platform owns now follows the insight stack's investigation rules. The check decides whether the firing gets an investigation, holds a gated alert's delivery until the verdict, and mutes a firing past the budget whose last verdict suppresses it. Only an owned check decides, so a parallel run never pays for an agent run. After the record, a new claim activity writes the investigation row and the evaluate workflow starts the agent on the AI queue, behind a patch. A refused claim releases the held firing by the firing's last verdict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lerts A metrics alert the platform owns now gets the insight stack's metrics investigation on a transition into firing. The check marks the firing, and the claim after the record writes a metrics investigation row, sharing the agent's cooldown, and runs the metric queries. Its failure is recorded on the row. It holds no delivery, as the insight stack never gates on it. The claim's budget grows to cover the queries, and the insight binding's evaluation timeout grows from 20 to 22 minutes to hold it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its migrate round trip now passes migration 0016, whose concurrent index cannot run in a transaction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
The Migration risk check has not finished for this commit, so stamphog cannot tell a safe migration from a risky one yet. The review runs again on the next push, or you can re-request it once the check reports.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 170L, 13F substantive, 249L/17F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (249L, 17F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head 90679d2 |
…cade The agent imported products.alerts internals that tach does not expose to core, which failed Repo checks. It now imports facade.investigations, kept apart from facade.api to avoid an import cycle with the insight stack's task helpers. The two dataclasses it touched now state frozen= explicitly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ght-investigation-adapter
…-metrics-investigation
…tigation-agent-rows # Conflicts: # products/alerts/backend/facade/contracts.py
…ght-investigation-adapter
…-metrics-investigation
…stigation-ui-275c09 # Conflicts: # products/alerts_platform/backend/facade/api.py
There was a problem hiding this comment.
PostHog Review
Found 5 should fix.
This is review round 3 on this pull request. When findings keep coming back in the same code, the approach is usually the problem. Before the next fix, check whether a different design would remove the whole class of findings.
Findings on the changed lines
products/alerts/backend/platform_investigation.py:208
P2 · Record the carried-verdict suppression in source detail
When an episode exhausts its investigation budget after a false-positive verdict, this branch suppresses delivery without setting SUPPRESSED_BY_AGENT_KEY. No investigation or hold exists for that check, so moved_alert_check_page reports notification_suppressed_by_agent=False. Persist the suppression marker in the group's source_detail.
products/alerts_platform/backend/facade/api.py:108
P2 · Implement delivery of changed-verdict announcements
When a later investigation contradicts an earlier delivered verdict, _announce_verdict_change calls this facade, but it always returns None. The new workflow therefore sends no correction, unlike the legacy path; the added test mocks this function and misses the failure. Record a follow-up announcement and return its delivery request.
products/alerts/backend/temporal/platform_evaluate.py:822
P2 · Complete metrics investigations before starting their deliveries
For a metrics firing, _record_chunk starts delivery before claiming or running its investigation. A delivery that executes immediately finds no summary in firing_investigation, so its Slack notification loses the explanation that the legacy path computes before notifying. Complete the metrics investigation before starting that firing's delivery.
products/alerts/backend/investigation_release.py:141
P2 · Distinguish disabled-alert suppression from agent suppression
When an alert is disabled during an investigation that returns true_positive, this release suppresses its hold with released_by=VERDICT. source_suppressed_holds_by_legacy_id then marks it as agent-suppressed, and history claims the agent deemed it unworthy of notification. Preserve a distinct reason for suppression caused by disabling the alert.
products/alerts/backend/temporal/platform_evaluate.py:397
P2 · Enforce the metrics deadline during slot acquisition and queries
When ClickHouse slots are saturated, ClickHouseQuerySlot waits up to 45 seconds, exhausting this activity's entire timeout before queries start. The loop checks its deadline only before each run, and synchronous work continues after Temporal times out, occupying evaluation workers and ClickHouse slots. Propagate the remaining budget into slot acquisition and queries.
…'s suppress off the agent Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
The Migration risk check has not finished for this commit, so stamphog cannot tell a safe migration from a risky one yet. The review runs again on the next push, or you can re-request it once the check reports.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 187L, 15F substantive, 286L/20F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (286L, 20F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head 5d98720 |
… its deadline A metrics firing's delivery now waits for its investigation, as the insight stack sends its explanation with the firing. It still goes out when the claim grants no run or the run fails. The run's wait for a ClickHouse slot counts against the activity's deadline, so a full budget cannot use it all up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-investigation-ui-275c09
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
The Migration risk check has not finished for this commit, so stamphog cannot tell a safe migration from a risky one yet. The review runs again on the next push, or you can re-request it once the check reports.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 187L, 15F substantive, 286L/20F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (286L, 20F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head 2209262 |
A metrics firing's delivery is now a held delivery with a short deadline, released once its investigation ends or its claim is refused. The hold lets delivery drop the incident trigger of a firing that resolved while it waited, and the safety net sends it if the run never releases it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-investigation-ui-275c09 # Conflicts: # products/alerts/backend/test/test_platform_source_cycle.py
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
The Migration risk check has not finished for this commit, so stamphog cannot tell a safe migration from a risky one yet. The review runs again on the next push, or you can re-request it once the check reports.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 187L, 15F substantive, 286L/20F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (286L, 20F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head 8c531b2 |
…leased Only the agent's verdict rewords a firing. A metrics investigation explains the firing beside its threshold breaches, so a release after its run, or the safety net after it failed, keeps them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-investigation-ui-275c09
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
The Migration risk check has not finished for this commit, so stamphog cannot tell a safe migration from a risky one yet. The review runs again on the next push, or you can re-request it once the check reports.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 187L, 15F substantive, 286L/20F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (286L, 20F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head 019989a |
A finished metrics investigation's summary now follows the firing's own threshold breaches, which every channel reads, so email, PagerDuty and webhooks carry the explanation the firing waited for, not only Slack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-investigation-ui-275c09
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
The Migration risk check has not finished for this commit, so stamphog cannot tell a safe migration from a risky one yet. The review runs again on the next push, or you can re-request it once the check reports.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: migrations |
| size | ✓ | 187L, 15F substantive, 286L/20F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (286L, 20F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head a26fc01 |
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
Re-add the stamphog label to request another review once you have addressed this.
stamphog declined to auto-review this pull request because it failed the size gate. It has 1467 substantive lines in the global category, over the 1200-line ceiling. Including docs, generated files and snapshots, it touches 43 files and 2194 lines. The other gates (prerequisites, deny-list, tier) passed, but they don't override the size refusal.
To move forward, ask a human reviewer to take it. Alternatively, split it into smaller pull requests, for example the investigation workflow and EvaluatedCheck refactor, the delivery-hold facade read and release logic, and the moved-alert history join with the retention prune and migration 0016. Each piece would then need to come in under the size ceiling.
- DanielVisca reviewed the current head.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✗ | too large for auto-review (1467L substantive in global — ceiling is 1200L; 1467L, 29F total, 2194L/43F incl. docs/generated/snapshots) |
| tier | ✓ | T1-agent / T1d-complex (2194L, 43F, cross-cutting, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head a26fc01 |
…stigation-ui-275c09 # Conflicts: # products/alerts/backend/investigation_release.py # products/alerts/backend/platform_investigation.py # products/alerts/backend/platform_investigation_detail.py # products/alerts/backend/test/test_platform_source_cycle.py # products/alerts/backend/tests/test_platform_investigation.py # products/alerts_platform/backend/facade/api.py # products/alerts_platform/backend/logic/delivery_holds.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stigation-ui-275c09 # Conflicts: # products/alerts_platform/backend/facade/api.py
|
Stacked PR 127926 failed testing in the merge queue. Please investigate the failure and re-submit the stack. |
|
This pull request was merged into |
Problem
AlertCheck, which the platform never writes. This blocks cutting over alerts with the investigation agent on.Changes
moved_alert_check_pagejoinsInsightAlertInvestigationand released delivery holds onto the platform's history page by evaluation key.source_suppressed_holds_by_legacy_id, returns the evaluations whose hold the source released with a suppress. A safety-net suppress (an alert turned off) does not count.SUPPRESSED_BY_AGENT_KEY, on the firing it mutes, and the history reads it.cleanup_alert_checksactivity now also deletes investigation rows older than 90 days, the platform's history TTL.created_atfor that prune, built concurrently.Before (moved alert, platform history without the join) and after, rendered in Storybook with invented data:
How did you test this code?
AlertHistorySectionin a scratch Storybook story (not committed) against the old and new response shapes.Test rationale:
test_a_moved_alert_shows_each_checks_investigation_and_what_the_agent_suppressedcatches a dropped or mismatched join, and a safety-net suppress counted as the agent's. The nearest existing test covers detector output only.test_the_daily_prune_drops_only_investigations_past_retentioncatches a prune that deletes recent rows or never runs. No prune test existed for this table.Release status
Docs update
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Claude Opus 5.5 (
claude-opus-5-5)Skills:
/improving-drf-endpoints,/django-migrations,/writing-tests,/writing-pr-descriptions,/reviewing-with-coderabbit,/simplify,/code-reviewMore context for AI agents
alertsimports nonotebooksmodels.nosemgrep.products/alerts/backend/platform_alert_reads.pyandproducts/alerts_platform/backend/logic/delivery_holds.py.🤖 Generated with Claude Code