Skip to content

feat(investigations): Add orchestration persistence - #122972

Draft
arslnb wants to merge 1 commit into
masterfrom
sentry/investigations-orchestration-persistence
Draft

feat(investigations): Add orchestration persistence#122972
arslnb wants to merge 1 commit into
masterfrom
sentry/investigations-orchestration-persistence

Conversation

@arslnb

@arslnb arslnb commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Adds the durable Sentry-side persistence boundary for agent-orchestrated investigations: one control-plane run per investigation, idempotent inbound event and outbound command envelopes, and revision-fenced report provenance on generated investigation blocks. Shared factories and fixtures make these records available to the service-layer PRs that will consume them.

The migration is additive and requires no backfill. Existing investigations do not receive orchestration runs, all new block fields are nullable, and the partial uniqueness constraint ignores existing/manual blocks. This PR intentionally adds no APIs, workers, Seer calls, or UI behavior; duplicating an investigation also continues to create an independent notebook without orchestration state or generated-report provenance.

@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Aug 28, 2026
@arslnb
arslnb requested a review from wedamija August 28, 2026 07:18
@github-actions

Copy link
Copy Markdown
Contributor

This PR has a migration; here is the generated SQL for src/sentry/investigations/migrations/0006_add_investigation_orchestration.py

for 0006_add_investigation_orchestration in investigations

--
-- Add field producing_seer_run_id to investigationblock
--
ALTER TABLE "investigations_investigationblock" ADD COLUMN "producing_seer_run_id" bigint NULL;
--
-- Add field report_revision to investigationblock
--
ALTER TABLE "investigations_investigationblock" ADD COLUMN "report_revision" integer NULL CHECK ("report_revision" >= 0);
--
-- Add field stable_agent_key to investigationblock
--
ALTER TABLE "investigations_investigationblock" ADD COLUMN "stable_agent_key" varchar(128) NULL;
--
-- Create model InvestigationOrchestrationRun
--
CREATE TABLE "investigations_investigationorchestrationrun" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "date_updated" timestamp with time zone NOT NULL, "date_added" timestamp with time zone NOT NULL, "seer_run_id" bigint NULL UNIQUE, "schema_version" integer DEFAULT 1 NOT NULL CHECK ("schema_version" >= 0), "workflow_version" integer DEFAULT 1 NOT NULL CHECK ("workflow_version" >= 0), "generation" integer DEFAULT 1 NOT NULL CHECK ("generation" >= 0), "phase" varchar(32) DEFAULT 'intake' NOT NULL, "status" varchar(32) DEFAULT 'pending' NOT NULL, "source" jsonb DEFAULT '{}'::jsonb NOT NULL, "projection" jsonb DEFAULT '{}'::jsonb NOT NULL, "notebook_revision" integer DEFAULT 0 NOT NULL CHECK ("notebook_revision" >= 0), "last_event_sequence" integer DEFAULT 0 NOT NULL CHECK ("last_event_sequence" >= 0), "heartbeat_at" timestamp with time zone NULL, "error" jsonb NULL, "investigation_id" bigint NOT NULL UNIQUE);
--
-- Create model InvestigationOrchestrationEvent
--
CREATE TABLE "investigations_investigationorchestrationevent" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "date_updated" timestamp with time zone NOT NULL, "date_added" timestamp with time zone NOT NULL, "event_id" uuid NOT NULL, "sequence" integer NOT NULL CHECK ("sequence" >= 0), "type" varchar(64) NOT NULL, "payload" jsonb DEFAULT '{}'::jsonb NOT NULL, "application_status" varchar(32) DEFAULT 'pending' NOT NULL, "error" jsonb NULL, "applied_at" timestamp with time zone NULL, "orchestration_run_id" bigint NOT NULL);
--
-- Create model InvestigationOrchestrationCommand
--
CREATE TABLE "investigations_investigationorchestrationcommand" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "date_updated" timestamp with time zone NOT NULL, "date_added" timestamp with time zone NOT NULL, "request_id" uuid NOT NULL, "actor_id" bigint NULL, "expected_workflow_version" integer NOT NULL CHECK ("expected_workflow_version" >= 0), "resulting_workflow_version" integer NULL CHECK ("resulting_workflow_version" >= 0), "type" varchar(64) NOT NULL, "payload" jsonb DEFAULT '{}'::jsonb NOT NULL, "status" varchar(32) DEFAULT 'accepted' NOT NULL, "error" jsonb NULL, "orchestration_run_id" bigint NOT NULL);
--
-- Create constraint invest_unique_report_block_key on model investigationblock
--
CREATE UNIQUE INDEX CONCURRENTLY "invest_unique_report_block_key" ON "investigations_investigationblock" ("investigation_id", "report_revision", "stable_agent_key") WHERE "stable_agent_key" IS NOT NULL;
--
-- Create index investigati_status_9ed759_idx on field(s) status, heartbeat_at of model investigationorchestrationrun
--
CREATE INDEX CONCURRENTLY "investigati_status_9ed759_idx" ON "investigations_investigationorchestrationrun" ("status", "heartbeat_at");
--
-- Create index investigati_phase_8930ff_idx on field(s) phase, -date_updated of model investigationorchestrationrun
--
CREATE INDEX CONCURRENTLY "investigati_phase_8930ff_idx" ON "investigations_investigationorchestrationrun" ("phase", "date_updated" DESC);
--
-- Create index investigati_orchest_c79498_idx on field(s) orchestration_run, application_status, sequence of model investigationorchestrationevent
--
CREATE INDEX CONCURRENTLY "investigati_orchest_c79498_idx" ON "investigations_investigationorchestrationevent" ("orchestration_run_id", "application_status", "sequence");
--
-- Create constraint invest_orch_unique_event_id on model investigationorchestrationevent
--
CREATE UNIQUE INDEX CONCURRENTLY "invest_orch_unique_event_id" ON "investigations_investigationorchestrationevent" ("orchestration_run_id", "event_id");
ALTER TABLE "investigations_investigationorchestrationevent" ADD CONSTRAINT "invest_orch_unique_event_id" UNIQUE USING INDEX "invest_orch_unique_event_id";
--
-- Create constraint invest_orch_unique_event_sequence on model investigationorchestrationevent
--
CREATE UNIQUE INDEX CONCURRENTLY "invest_orch_unique_event_sequence" ON "investigations_investigationorchestrationevent" ("orchestration_run_id", "sequence");
ALTER TABLE "investigations_investigationorchestrationevent" ADD CONSTRAINT "invest_orch_unique_event_sequence" UNIQUE USING INDEX "invest_orch_unique_event_sequence";
--
-- Create index investigati_orchest_64e689_idx on field(s) orchestration_run, status, date_added of model investigationorchestrationcommand
--
CREATE INDEX CONCURRENTLY "investigati_orchest_64e689_idx" ON "investigations_investigationorchestrationcommand" ("orchestration_run_id", "status", "date_added");
--
-- Create constraint invest_orch_unique_command_request on model investigationorchestrationcommand
--
CREATE UNIQUE INDEX CONCURRENTLY "invest_orch_unique_command_request" ON "investigations_investigationorchestrationcommand" ("orchestration_run_id", "request_id");
ALTER TABLE "investigations_investigationorchestrationcommand" ADD CONSTRAINT "invest_orch_unique_command_request" UNIQUE USING INDEX "invest_orch_unique_command_request";
ALTER TABLE "investigations_investigationorchestrationrun" ADD CONSTRAINT "investigations_inves_investigation_id_27bb2b36_fk_investiga" FOREIGN KEY ("investigation_id") REFERENCES "investigations_investigation" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "investigations_investigationorchestrationrun" VALIDATE CONSTRAINT "investigations_inves_investigation_id_27bb2b36_fk_investiga";
ALTER TABLE "investigations_investigationorchestrationevent" ADD CONSTRAINT "investigations_inves_orchestration_run_id_a646a18e_fk_investiga" FOREIGN KEY ("orchestration_run_id") REFERENCES "investigations_investigationorchestrationrun" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "investigations_investigationorchestrationevent" VALIDATE CONSTRAINT "investigations_inves_orchestration_run_id_a646a18e_fk_investiga";
CREATE INDEX CONCURRENTLY "investigations_investigati_orchestration_run_id_a646a18e" ON "investigations_investigationorchestrationevent" ("orchestration_run_id");
ALTER TABLE "investigations_investigationorchestrationcommand" ADD CONSTRAINT "investigations_inves_orchestration_run_id_9613235b_fk_investiga" FOREIGN KEY ("orchestration_run_id") REFERENCES "investigations_investigationorchestrationrun" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "investigations_investigationorchestrationcommand" VALIDATE CONSTRAINT "investigations_inves_orchestration_run_id_9613235b_fk_investiga";
CREATE INDEX CONCURRENTLY "investigations_investigati_actor_id_7438bdc7" ON "investigations_investigationorchestrationcommand" ("actor_id");
CREATE INDEX CONCURRENTLY "investigations_investigati_orchestration_run_id_9613235b" ON "investigations_investigationorchestrationcommand" ("orchestration_run_id");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant