// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: autopilot.sql package db import ( "context" "github.com/jackc/pgx/v5/pgtype" ) const advanceTriggerNextRun = `-- name: AdvanceTriggerNextRun :exec UPDATE autopilot_trigger SET next_run_at = $2, last_fired_at = now(), updated_at = now() WHERE id = $1 ` type AdvanceTriggerNextRunParams struct { ID pgtype.UUID `json:"id"` NextRunAt pgtype.Timestamptz `json:"next_run_at"` } func (q *Queries) AdvanceTriggerNextRun(ctx context.Context, arg AdvanceTriggerNextRunParams) error { _, err := q.db.Exec(ctx, advanceTriggerNextRun, arg.ID, arg.NextRunAt) return err } const claimDueScheduleTriggers = `-- name: ClaimDueScheduleTriggers :many UPDATE autopilot_trigger t SET next_run_at = NULL FROM autopilot a WHERE t.autopilot_id = a.id AND t.kind = 'schedule' AND t.enabled = true AND t.next_run_at IS NOT NULL AND t.next_run_at <= now() AND a.status = 'active' RETURNING t.id, t.autopilot_id, t.kind, t.enabled, t.cron_expression, t.timezone, t.next_run_at, t.webhook_token, t.label, t.last_fired_at, t.created_at, t.updated_at, t.provider, t.signing_secret, t.event_filters, a.workspace_id AS autopilot_workspace_id ` type ClaimDueScheduleTriggersRow struct { ID pgtype.UUID `json:"id"` AutopilotID pgtype.UUID `json:"autopilot_id"` Kind string `json:"kind"` Enabled bool `json:"enabled"` CronExpression pgtype.Text `json:"cron_expression"` Timezone pgtype.Text `json:"timezone"` NextRunAt pgtype.Timestamptz `json:"next_run_at"` WebhookToken pgtype.Text `json:"webhook_token"` Label pgtype.Text `json:"label"` LastFiredAt pgtype.Timestamptz `json:"last_fired_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` Provider string `json:"provider"` SigningSecret pgtype.Text `json:"signing_secret"` EventFilters []byte `json:"event_filters"` AutopilotWorkspaceID pgtype.UUID `json:"autopilot_workspace_id"` } // ===================== // Scheduler Queries // ===================== // Atomically claim all due schedule triggers to prevent concurrent execution. // Joins the autopilot table to ensure only active autopilots are fired. func (q *Queries) ClaimDueScheduleTriggers(ctx context.Context) ([]ClaimDueScheduleTriggersRow, error) { rows, err := q.db.Query(ctx, claimDueScheduleTriggers) if err != nil { return nil, err } defer rows.Close() items := []ClaimDueScheduleTriggersRow{} for rows.Next() { var i ClaimDueScheduleTriggersRow if err := rows.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, &i.AutopilotWorkspaceID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const createAutopilot = `-- name: CreateAutopilot :one INSERT INTO autopilot ( workspace_id, title, description, assignee_type, assignee_id, status, execution_mode, issue_title_template, project_id, created_by_type, created_by_id ) VALUES ( $1, $2, $9, $3, $4, $5, $6, $10, $11, $7, $8 ) RETURNING id, workspace_id, title, description, assignee_id, status, execution_mode, issue_title_template, created_by_type, created_by_id, last_run_at, created_at, updated_at, assignee_type, project_id ` type CreateAutopilotParams struct { WorkspaceID pgtype.UUID `json:"workspace_id"` Title string `json:"title"` AssigneeType string `json:"assignee_type"` AssigneeID pgtype.UUID `json:"assignee_id"` Status string `json:"status"` ExecutionMode string `json:"execution_mode"` CreatedByType string `json:"created_by_type"` CreatedByID pgtype.UUID `json:"created_by_id"` Description pgtype.Text `json:"description"` IssueTitleTemplate pgtype.Text `json:"issue_title_template"` ProjectID pgtype.UUID `json:"project_id"` } func (q *Queries) CreateAutopilot(ctx context.Context, arg CreateAutopilotParams) (Autopilot, error) { row := q.db.QueryRow(ctx, createAutopilot, arg.WorkspaceID, arg.Title, arg.AssigneeType, arg.AssigneeID, arg.Status, arg.ExecutionMode, arg.CreatedByType, arg.CreatedByID, arg.Description, arg.IssueTitleTemplate, arg.ProjectID, ) var i Autopilot err := row.Scan( &i.ID, &i.WorkspaceID, &i.Title, &i.Description, &i.AssigneeID, &i.Status, &i.ExecutionMode, &i.IssueTitleTemplate, &i.CreatedByType, &i.CreatedByID, &i.LastRunAt, &i.CreatedAt, &i.UpdatedAt, &i.AssigneeType, &i.ProjectID, ) return i, err } const createAutopilotRun = `-- name: CreateAutopilotRun :one INSERT INTO autopilot_run ( autopilot_id, trigger_id, source, status, trigger_payload, squad_id ) VALUES ( $1, $4, $2, $3, $5, $6 ) RETURNING id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id ` type CreateAutopilotRunParams struct { AutopilotID pgtype.UUID `json:"autopilot_id"` Source string `json:"source"` Status string `json:"status"` TriggerID pgtype.UUID `json:"trigger_id"` TriggerPayload []byte `json:"trigger_payload"` SquadID pgtype.UUID `json:"squad_id"` } // ===================== // Autopilot Run Management // ===================== // squad_id is an attribution hook: set to the assignee squad when the // parent autopilot has assignee_type='squad', NULL otherwise. The executing // agent_id on agent_task_queue still records who actually ran the work // (the squad leader); squad_id lets reports group by squad without a join. func (q *Queries) CreateAutopilotRun(ctx context.Context, arg CreateAutopilotRunParams) (AutopilotRun, error) { row := q.db.QueryRow(ctx, createAutopilotRun, arg.AutopilotID, arg.Source, arg.Status, arg.TriggerID, arg.TriggerPayload, arg.SquadID, ) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const createAutopilotTask = `-- name: CreateAutopilotTask :one INSERT INTO agent_task_queue (agent_id, runtime_id, issue_id, status, priority, autopilot_run_id, trigger_summary) VALUES ($1, $2, NULL, 'queued', $3, $4, $5) RETURNING id, agent_id, issue_id, status, priority, dispatched_at, started_at, completed_at, result, error, created_at, context, runtime_id, session_id, work_dir, trigger_comment_id, chat_session_id, autopilot_run_id, attempt, max_attempts, parent_task_id, failure_reason, trigger_summary, force_fresh_session, is_leader_task, wait_reason ` type CreateAutopilotTaskParams struct { AgentID pgtype.UUID `json:"agent_id"` RuntimeID pgtype.UUID `json:"runtime_id"` Priority int32 `json:"priority"` AutopilotRunID pgtype.UUID `json:"autopilot_run_id"` TriggerSummary pgtype.Text `json:"trigger_summary"` } // ===================== // Task Queue (run_only mode) // ===================== func (q *Queries) CreateAutopilotTask(ctx context.Context, arg CreateAutopilotTaskParams) (AgentTaskQueue, error) { row := q.db.QueryRow(ctx, createAutopilotTask, arg.AgentID, arg.RuntimeID, arg.Priority, arg.AutopilotRunID, arg.TriggerSummary, ) var i AgentTaskQueue err := row.Scan( &i.ID, &i.AgentID, &i.IssueID, &i.Status, &i.Priority, &i.DispatchedAt, &i.StartedAt, &i.CompletedAt, &i.Result, &i.Error, &i.CreatedAt, &i.Context, &i.RuntimeID, &i.SessionID, &i.WorkDir, &i.TriggerCommentID, &i.ChatSessionID, &i.AutopilotRunID, &i.Attempt, &i.MaxAttempts, &i.ParentTaskID, &i.FailureReason, &i.TriggerSummary, &i.ForceFreshSession, &i.IsLeaderTask, &i.WaitReason, ) return i, err } const createAutopilotTrigger = `-- name: CreateAutopilotTrigger :one INSERT INTO autopilot_trigger ( autopilot_id, kind, enabled, cron_expression, timezone, next_run_at, webhook_token, label, provider, event_filters ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, COALESCE($9::text, 'generic'), $10 ) RETURNING id, autopilot_id, kind, enabled, cron_expression, timezone, next_run_at, webhook_token, label, last_fired_at, created_at, updated_at, provider, signing_secret, event_filters ` type CreateAutopilotTriggerParams struct { AutopilotID pgtype.UUID `json:"autopilot_id"` Kind string `json:"kind"` Enabled bool `json:"enabled"` CronExpression pgtype.Text `json:"cron_expression"` Timezone pgtype.Text `json:"timezone"` NextRunAt pgtype.Timestamptz `json:"next_run_at"` WebhookToken pgtype.Text `json:"webhook_token"` Label pgtype.Text `json:"label"` Provider pgtype.Text `json:"provider"` EventFilters []byte `json:"event_filters"` } func (q *Queries) CreateAutopilotTrigger(ctx context.Context, arg CreateAutopilotTriggerParams) (AutopilotTrigger, error) { row := q.db.QueryRow(ctx, createAutopilotTrigger, arg.AutopilotID, arg.Kind, arg.Enabled, arg.CronExpression, arg.Timezone, arg.NextRunAt, arg.WebhookToken, arg.Label, arg.Provider, arg.EventFilters, ) var i AutopilotTrigger err := row.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, ) return i, err } const deleteAutopilot = `-- name: DeleteAutopilot :exec DELETE FROM autopilot WHERE id = $1 ` func (q *Queries) DeleteAutopilot(ctx context.Context, id pgtype.UUID) error { _, err := q.db.Exec(ctx, deleteAutopilot, id) return err } const deleteAutopilotTrigger = `-- name: DeleteAutopilotTrigger :exec DELETE FROM autopilot_trigger WHERE id = $1 ` func (q *Queries) DeleteAutopilotTrigger(ctx context.Context, id pgtype.UUID) error { _, err := q.db.Exec(ctx, deleteAutopilotTrigger, id) return err } const failAutopilotRunsByIssue = `-- name: FailAutopilotRunsByIssue :exec UPDATE autopilot_run SET status = 'failed', completed_at = now(), failure_reason = 'linked issue was deleted' WHERE issue_id = $1 AND status IN ('issue_created', 'running') ` // Fails active autopilot runs linked to a given issue. // Must be called BEFORE issue deletion (ON DELETE SET NULL clears issue_id). func (q *Queries) FailAutopilotRunsByIssue(ctx context.Context, issueID pgtype.UUID) error { _, err := q.db.Exec(ctx, failAutopilotRunsByIssue, issueID) return err } const getAutopilot = `-- name: GetAutopilot :one SELECT id, workspace_id, title, description, assignee_id, status, execution_mode, issue_title_template, created_by_type, created_by_id, last_run_at, created_at, updated_at, assignee_type, project_id FROM autopilot WHERE id = $1 ` func (q *Queries) GetAutopilot(ctx context.Context, id pgtype.UUID) (Autopilot, error) { row := q.db.QueryRow(ctx, getAutopilot, id) var i Autopilot err := row.Scan( &i.ID, &i.WorkspaceID, &i.Title, &i.Description, &i.AssigneeID, &i.Status, &i.ExecutionMode, &i.IssueTitleTemplate, &i.CreatedByType, &i.CreatedByID, &i.LastRunAt, &i.CreatedAt, &i.UpdatedAt, &i.AssigneeType, &i.ProjectID, ) return i, err } const getAutopilotInWorkspace = `-- name: GetAutopilotInWorkspace :one SELECT id, workspace_id, title, description, assignee_id, status, execution_mode, issue_title_template, created_by_type, created_by_id, last_run_at, created_at, updated_at, assignee_type, project_id FROM autopilot WHERE id = $1 AND workspace_id = $2 ` type GetAutopilotInWorkspaceParams struct { ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` } func (q *Queries) GetAutopilotInWorkspace(ctx context.Context, arg GetAutopilotInWorkspaceParams) (Autopilot, error) { row := q.db.QueryRow(ctx, getAutopilotInWorkspace, arg.ID, arg.WorkspaceID) var i Autopilot err := row.Scan( &i.ID, &i.WorkspaceID, &i.Title, &i.Description, &i.AssigneeID, &i.Status, &i.ExecutionMode, &i.IssueTitleTemplate, &i.CreatedByType, &i.CreatedByID, &i.LastRunAt, &i.CreatedAt, &i.UpdatedAt, &i.AssigneeType, &i.ProjectID, ) return i, err } const getAutopilotRun = `-- name: GetAutopilotRun :one SELECT id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id FROM autopilot_run WHERE id = $1 ` func (q *Queries) GetAutopilotRun(ctx context.Context, id pgtype.UUID) (AutopilotRun, error) { row := q.db.QueryRow(ctx, getAutopilotRun, id) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const getAutopilotRunByIssue = `-- name: GetAutopilotRunByIssue :one SELECT id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id FROM autopilot_run WHERE issue_id = $1 AND status IN ('issue_created', 'running') LIMIT 1 ` // ===================== // Run lookup by linked entities // ===================== func (q *Queries) GetAutopilotRunByIssue(ctx context.Context, issueID pgtype.UUID) (AutopilotRun, error) { row := q.db.QueryRow(ctx, getAutopilotRunByIssue, issueID) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const getAutopilotTrigger = `-- name: GetAutopilotTrigger :one SELECT id, autopilot_id, kind, enabled, cron_expression, timezone, next_run_at, webhook_token, label, last_fired_at, created_at, updated_at, provider, signing_secret, event_filters FROM autopilot_trigger WHERE id = $1 ` func (q *Queries) GetAutopilotTrigger(ctx context.Context, id pgtype.UUID) (AutopilotTrigger, error) { row := q.db.QueryRow(ctx, getAutopilotTrigger, id) var i AutopilotTrigger err := row.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, ) return i, err } const getWebhookTriggerByToken = `-- name: GetWebhookTriggerByToken :one SELECT t.id, t.autopilot_id, t.kind, t.enabled, t.cron_expression, t.timezone, t.next_run_at, t.webhook_token, t.label, t.last_fired_at, t.created_at, t.updated_at, t.provider, t.signing_secret, t.event_filters, a.workspace_id AS autopilot_workspace_id FROM autopilot_trigger t JOIN autopilot a ON a.id = t.autopilot_id WHERE t.kind = 'webhook' AND t.webhook_token = $1 ` type GetWebhookTriggerByTokenRow struct { ID pgtype.UUID `json:"id"` AutopilotID pgtype.UUID `json:"autopilot_id"` Kind string `json:"kind"` Enabled bool `json:"enabled"` CronExpression pgtype.Text `json:"cron_expression"` Timezone pgtype.Text `json:"timezone"` NextRunAt pgtype.Timestamptz `json:"next_run_at"` WebhookToken pgtype.Text `json:"webhook_token"` Label pgtype.Text `json:"label"` LastFiredAt pgtype.Timestamptz `json:"last_fired_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` Provider string `json:"provider"` SigningSecret pgtype.Text `json:"signing_secret"` EventFilters []byte `json:"event_filters"` AutopilotWorkspaceID pgtype.UUID `json:"autopilot_workspace_id"` } // Look up a webhook trigger by its public bearer token. Joined to autopilot // so the webhook handler can derive the workspace from the trigger's parent // without trusting any request header. The handler still re-loads the // Autopilot via GetAutopilot and cross-checks WorkspaceID matches the row's // autopilot_workspace_id. func (q *Queries) GetWebhookTriggerByToken(ctx context.Context, webhookToken pgtype.Text) (GetWebhookTriggerByTokenRow, error) { row := q.db.QueryRow(ctx, getWebhookTriggerByToken, webhookToken) var i GetWebhookTriggerByTokenRow err := row.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, &i.AutopilotWorkspaceID, ) return i, err } const listAutopilotRuns = `-- name: ListAutopilotRuns :many SELECT id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id FROM autopilot_run WHERE autopilot_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3 ` type ListAutopilotRunsParams struct { AutopilotID pgtype.UUID `json:"autopilot_id"` Limit int32 `json:"limit"` Offset int32 `json:"offset"` } func (q *Queries) ListAutopilotRuns(ctx context.Context, arg ListAutopilotRunsParams) ([]AutopilotRun, error) { rows, err := q.db.Query(ctx, listAutopilotRuns, arg.AutopilotID, arg.Limit, arg.Offset) if err != nil { return nil, err } defer rows.Close() items := []AutopilotRun{} for rows.Next() { var i AutopilotRun if err := rows.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listAutopilotTriggers = `-- name: ListAutopilotTriggers :many SELECT id, autopilot_id, kind, enabled, cron_expression, timezone, next_run_at, webhook_token, label, last_fired_at, created_at, updated_at, provider, signing_secret, event_filters FROM autopilot_trigger WHERE autopilot_id = $1 ORDER BY created_at ASC ` // ===================== // Autopilot Trigger CRUD // ===================== func (q *Queries) ListAutopilotTriggers(ctx context.Context, autopilotID pgtype.UUID) ([]AutopilotTrigger, error) { rows, err := q.db.Query(ctx, listAutopilotTriggers, autopilotID) if err != nil { return nil, err } defer rows.Close() items := []AutopilotTrigger{} for rows.Next() { var i AutopilotTrigger if err := rows.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listAutopilots = `-- name: ListAutopilots :many SELECT id, workspace_id, title, description, assignee_id, status, execution_mode, issue_title_template, created_by_type, created_by_id, last_run_at, created_at, updated_at, assignee_type, project_id FROM autopilot WHERE workspace_id = $1 AND ($2::text IS NULL OR status = $2) ORDER BY created_at DESC ` type ListAutopilotsParams struct { WorkspaceID pgtype.UUID `json:"workspace_id"` Status pgtype.Text `json:"status"` } // ===================== // Autopilot CRUD // ===================== func (q *Queries) ListAutopilots(ctx context.Context, arg ListAutopilotsParams) ([]Autopilot, error) { rows, err := q.db.Query(ctx, listAutopilots, arg.WorkspaceID, arg.Status) if err != nil { return nil, err } defer rows.Close() items := []Autopilot{} for rows.Next() { var i Autopilot if err := rows.Scan( &i.ID, &i.WorkspaceID, &i.Title, &i.Description, &i.AssigneeID, &i.Status, &i.ExecutionMode, &i.IssueTitleTemplate, &i.CreatedByType, &i.CreatedByID, &i.LastRunAt, &i.CreatedAt, &i.UpdatedAt, &i.AssigneeType, &i.ProjectID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const recoverLostTriggers = `-- name: RecoverLostTriggers :many SELECT t.id, t.autopilot_id, t.kind, t.enabled, t.cron_expression, t.timezone, t.next_run_at, t.webhook_token, t.label, t.last_fired_at, t.created_at, t.updated_at, t.provider, t.signing_secret, t.event_filters, a.workspace_id AS autopilot_workspace_id FROM autopilot_trigger t JOIN autopilot a ON t.autopilot_id = a.id WHERE t.kind = 'schedule' AND t.enabled = true AND t.next_run_at IS NULL AND t.cron_expression IS NOT NULL AND a.status = 'active' ` type RecoverLostTriggersRow struct { ID pgtype.UUID `json:"id"` AutopilotID pgtype.UUID `json:"autopilot_id"` Kind string `json:"kind"` Enabled bool `json:"enabled"` CronExpression pgtype.Text `json:"cron_expression"` Timezone pgtype.Text `json:"timezone"` NextRunAt pgtype.Timestamptz `json:"next_run_at"` WebhookToken pgtype.Text `json:"webhook_token"` Label pgtype.Text `json:"label"` LastFiredAt pgtype.Timestamptz `json:"last_fired_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` Provider string `json:"provider"` SigningSecret pgtype.Text `json:"signing_secret"` EventFilters []byte `json:"event_filters"` AutopilotWorkspaceID pgtype.UUID `json:"autopilot_workspace_id"` } // ===================== // Scheduler Recovery // ===================== // Finds schedule triggers that were claimed (next_run_at = NULL) but never // advanced — typically due to a scheduler crash. Returns them so the scheduler // can recompute next_run_at. func (q *Queries) RecoverLostTriggers(ctx context.Context) ([]RecoverLostTriggersRow, error) { rows, err := q.db.Query(ctx, recoverLostTriggers) if err != nil { return nil, err } defer rows.Close() items := []RecoverLostTriggersRow{} for rows.Next() { var i RecoverLostTriggersRow if err := rows.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, &i.AutopilotWorkspaceID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const rotateAutopilotTriggerWebhookToken = `-- name: RotateAutopilotTriggerWebhookToken :one UPDATE autopilot_trigger SET webhook_token = $2, updated_at = now() WHERE id = $1 AND kind = 'webhook' RETURNING id, autopilot_id, kind, enabled, cron_expression, timezone, next_run_at, webhook_token, label, last_fired_at, created_at, updated_at, provider, signing_secret, event_filters ` type RotateAutopilotTriggerWebhookTokenParams struct { ID pgtype.UUID `json:"id"` WebhookToken pgtype.Text `json:"webhook_token"` } // Rotates the bearer token for a webhook trigger. Restricted to kind='webhook' // so an accidental call against a schedule/api trigger is a no-op (returns no // rows) rather than corrupting unrelated state. func (q *Queries) RotateAutopilotTriggerWebhookToken(ctx context.Context, arg RotateAutopilotTriggerWebhookTokenParams) (AutopilotTrigger, error) { row := q.db.QueryRow(ctx, rotateAutopilotTriggerWebhookToken, arg.ID, arg.WebhookToken) var i AutopilotTrigger err := row.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, ) return i, err } const selectAutopilotsExceedingFailureThreshold = `-- name: SelectAutopilotsExceedingFailureThreshold :many WITH stats AS ( SELECT autopilot_id, count(*) FILTER (WHERE status IN ('completed', 'failed')) AS total, count(*) FILTER (WHERE status = 'failed') AS failed FROM autopilot_run WHERE created_at >= $3::timestamptz GROUP BY autopilot_id ) SELECT a.id, a.workspace_id, a.title, a.assignee_id, a.created_by_type, a.created_by_id, s.total::bigint AS total_runs, s.failed::bigint AS failed_runs FROM autopilot a JOIN stats s ON s.autopilot_id = a.id WHERE a.status = 'active' AND s.total >= $1::bigint AND s.failed::float8 / NULLIF(s.total, 0)::float8 >= $2::float8 ORDER BY s.failed DESC, a.id ASC ` type SelectAutopilotsExceedingFailureThresholdParams struct { MinRuns int64 `json:"min_runs"` FailRatioThreshold float64 `json:"fail_ratio_threshold"` Since pgtype.Timestamptz `json:"since"` } type SelectAutopilotsExceedingFailureThresholdRow struct { ID pgtype.UUID `json:"id"` WorkspaceID pgtype.UUID `json:"workspace_id"` Title string `json:"title"` AssigneeID pgtype.UUID `json:"assignee_id"` CreatedByType string `json:"created_by_type"` CreatedByID pgtype.UUID `json:"created_by_id"` TotalRuns int64 `json:"total_runs"` FailedRuns int64 `json:"failed_runs"` } // ===================== // Failure-rate auto-pause // ===================== // Find active autopilots whose recent run failure rate exceeds the threshold. // Counts only "real" terminal runs (completed | failed). 'skipped' is // excluded from BOTH numerator and denominator: an admission-skipped run // (e.g. assignee runtime offline at dispatch time, MUL-1899) is neither a // success nor a failure, so it must not dilute the failure ratio (which // would let a 100%-failing autopilot mask itself behind a wall of skips) // nor inflate it. issue_created/running are still excluded so in-flight // work isn't penalised. // Used by the failure monitor to auto-pause sustained-failure autopilots // (the canonical example from MUL-1336 was an autopilot scheduled every 5 min // that 100% failed for days, burning ~1.5k useless tasks per week). func (q *Queries) SelectAutopilotsExceedingFailureThreshold(ctx context.Context, arg SelectAutopilotsExceedingFailureThresholdParams) ([]SelectAutopilotsExceedingFailureThresholdRow, error) { rows, err := q.db.Query(ctx, selectAutopilotsExceedingFailureThreshold, arg.MinRuns, arg.FailRatioThreshold, arg.Since) if err != nil { return nil, err } defer rows.Close() items := []SelectAutopilotsExceedingFailureThresholdRow{} for rows.Next() { var i SelectAutopilotsExceedingFailureThresholdRow if err := rows.Scan( &i.ID, &i.WorkspaceID, &i.Title, &i.AssigneeID, &i.CreatedByType, &i.CreatedByID, &i.TotalRuns, &i.FailedRuns, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const setAutopilotTriggerSigningSecret = `-- name: SetAutopilotTriggerSigningSecret :one UPDATE autopilot_trigger SET signing_secret = $2, updated_at = now() WHERE id = $1 AND kind = 'webhook' RETURNING id, autopilot_id, kind, enabled, cron_expression, timezone, next_run_at, webhook_token, label, last_fired_at, created_at, updated_at, provider, signing_secret, event_filters ` type SetAutopilotTriggerSigningSecretParams struct { ID pgtype.UUID `json:"id"` SigningSecret pgtype.Text `json:"signing_secret"` } // Writes the signing secret for a webhook trigger. Kept as a dedicated query // (not a field on UpdateAutopilotTrigger) so the request body for the // write-only endpoint only ever carries the secret value, with no risk of an // accidental log line leaking it alongside other fields. Restricted to // webhook triggers to avoid corrupting unrelated state. func (q *Queries) SetAutopilotTriggerSigningSecret(ctx context.Context, arg SetAutopilotTriggerSigningSecretParams) (AutopilotTrigger, error) { row := q.db.QueryRow(ctx, setAutopilotTriggerSigningSecret, arg.ID, arg.SigningSecret) var i AutopilotTrigger err := row.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, ) return i, err } const setAutopilotTriggerWebhookToken = `-- name: SetAutopilotTriggerWebhookToken :one UPDATE autopilot_trigger SET webhook_token = $2, updated_at = now() WHERE id = $1 RETURNING id, autopilot_id, kind, enabled, cron_expression, timezone, next_run_at, webhook_token, label, last_fired_at, created_at, updated_at, provider, signing_secret, event_filters ` type SetAutopilotTriggerWebhookTokenParams struct { ID pgtype.UUID `json:"id"` WebhookToken pgtype.Text `json:"webhook_token"` } // Sets the webhook token at creation time. CreateAutopilotTrigger inserts the // row first (using its full 8-arg signature), then this query attaches the // token. Splitting the create + token-set keeps the existing CreateAutopilotTrigger // query usable by the schedule path without forcing every caller to think // about webhook_token. func (q *Queries) SetAutopilotTriggerWebhookToken(ctx context.Context, arg SetAutopilotTriggerWebhookTokenParams) (AutopilotTrigger, error) { row := q.db.QueryRow(ctx, setAutopilotTriggerWebhookToken, arg.ID, arg.WebhookToken) var i AutopilotTrigger err := row.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, ) return i, err } const systemPauseAutopilot = `-- name: SystemPauseAutopilot :one UPDATE autopilot SET status = 'paused', updated_at = now() WHERE id = $1 AND status = 'active' RETURNING id, workspace_id, title, description, assignee_id, status, execution_mode, issue_title_template, created_by_type, created_by_id, last_run_at, created_at, updated_at, assignee_type, project_id ` // Atomically pauses an autopilot only if it is currently active. Returns no // rows when the autopilot was already paused/archived (or another worker // raced first), letting the caller treat that as a benign no-op rather than // an error. func (q *Queries) SystemPauseAutopilot(ctx context.Context, id pgtype.UUID) (Autopilot, error) { row := q.db.QueryRow(ctx, systemPauseAutopilot, id) var i Autopilot err := row.Scan( &i.ID, &i.WorkspaceID, &i.Title, &i.Description, &i.AssigneeID, &i.Status, &i.ExecutionMode, &i.IssueTitleTemplate, &i.CreatedByType, &i.CreatedByID, &i.LastRunAt, &i.CreatedAt, &i.UpdatedAt, &i.AssigneeType, &i.ProjectID, ) return i, err } const touchAutopilotTriggerFiredAt = `-- name: TouchAutopilotTriggerFiredAt :exec UPDATE autopilot_trigger SET last_fired_at = now(), updated_at = now() WHERE id = $1 ` // Bumps last_fired_at after a webhook fires, regardless of whether the // dispatch succeeded, was admission-skipped, or even if Autopilot status // transitioned to paused/disabled at exactly the wrong moment. Disabled / // paused early-return paths in the handler never call this. func (q *Queries) TouchAutopilotTriggerFiredAt(ctx context.Context, id pgtype.UUID) error { _, err := q.db.Exec(ctx, touchAutopilotTriggerFiredAt, id) return err } const updateAutopilot = `-- name: UpdateAutopilot :one UPDATE autopilot SET title = COALESCE($2, title), description = COALESCE($3, description), assignee_type = COALESCE($4, assignee_type), assignee_id = COALESCE($5::uuid, assignee_id), status = COALESCE($6, status), execution_mode = COALESCE($7, execution_mode), issue_title_template = $8, project_id = $9, updated_at = now() WHERE id = $1 RETURNING id, workspace_id, title, description, assignee_id, status, execution_mode, issue_title_template, created_by_type, created_by_id, last_run_at, created_at, updated_at, assignee_type, project_id ` type UpdateAutopilotParams struct { ID pgtype.UUID `json:"id"` Title pgtype.Text `json:"title"` Description pgtype.Text `json:"description"` AssigneeType pgtype.Text `json:"assignee_type"` AssigneeID pgtype.UUID `json:"assignee_id"` Status pgtype.Text `json:"status"` ExecutionMode pgtype.Text `json:"execution_mode"` IssueTitleTemplate pgtype.Text `json:"issue_title_template"` ProjectID pgtype.UUID `json:"project_id"` } func (q *Queries) UpdateAutopilot(ctx context.Context, arg UpdateAutopilotParams) (Autopilot, error) { row := q.db.QueryRow(ctx, updateAutopilot, arg.ID, arg.Title, arg.Description, arg.AssigneeType, arg.AssigneeID, arg.Status, arg.ExecutionMode, arg.IssueTitleTemplate, arg.ProjectID, ) var i Autopilot err := row.Scan( &i.ID, &i.WorkspaceID, &i.Title, &i.Description, &i.AssigneeID, &i.Status, &i.ExecutionMode, &i.IssueTitleTemplate, &i.CreatedByType, &i.CreatedByID, &i.LastRunAt, &i.CreatedAt, &i.UpdatedAt, &i.AssigneeType, &i.ProjectID, ) return i, err } const updateAutopilotLastRunAt = `-- name: UpdateAutopilotLastRunAt :exec UPDATE autopilot SET last_run_at = now(), updated_at = now() WHERE id = $1 ` func (q *Queries) UpdateAutopilotLastRunAt(ctx context.Context, id pgtype.UUID) error { _, err := q.db.Exec(ctx, updateAutopilotLastRunAt, id) return err } const updateAutopilotRunCompleted = `-- name: UpdateAutopilotRunCompleted :one UPDATE autopilot_run SET status = 'completed', completed_at = now(), result = $2 WHERE id = $1 RETURNING id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id ` type UpdateAutopilotRunCompletedParams struct { ID pgtype.UUID `json:"id"` Result []byte `json:"result"` } func (q *Queries) UpdateAutopilotRunCompleted(ctx context.Context, arg UpdateAutopilotRunCompletedParams) (AutopilotRun, error) { row := q.db.QueryRow(ctx, updateAutopilotRunCompleted, arg.ID, arg.Result) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const updateAutopilotRunFailed = `-- name: UpdateAutopilotRunFailed :one UPDATE autopilot_run SET status = 'failed', completed_at = now(), failure_reason = $2 WHERE id = $1 RETURNING id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id ` type UpdateAutopilotRunFailedParams struct { ID pgtype.UUID `json:"id"` FailureReason pgtype.Text `json:"failure_reason"` } func (q *Queries) UpdateAutopilotRunFailed(ctx context.Context, arg UpdateAutopilotRunFailedParams) (AutopilotRun, error) { row := q.db.QueryRow(ctx, updateAutopilotRunFailed, arg.ID, arg.FailureReason) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const updateAutopilotRunIssueCreated = `-- name: UpdateAutopilotRunIssueCreated :one UPDATE autopilot_run SET status = 'issue_created', issue_id = $2 WHERE id = $1 RETURNING id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id ` type UpdateAutopilotRunIssueCreatedParams struct { ID pgtype.UUID `json:"id"` IssueID pgtype.UUID `json:"issue_id"` } func (q *Queries) UpdateAutopilotRunIssueCreated(ctx context.Context, arg UpdateAutopilotRunIssueCreatedParams) (AutopilotRun, error) { row := q.db.QueryRow(ctx, updateAutopilotRunIssueCreated, arg.ID, arg.IssueID) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const updateAutopilotRunRunning = `-- name: UpdateAutopilotRunRunning :one UPDATE autopilot_run SET status = 'running', task_id = $2 WHERE id = $1 RETURNING id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id ` type UpdateAutopilotRunRunningParams struct { ID pgtype.UUID `json:"id"` TaskID pgtype.UUID `json:"task_id"` } func (q *Queries) UpdateAutopilotRunRunning(ctx context.Context, arg UpdateAutopilotRunRunningParams) (AutopilotRun, error) { row := q.db.QueryRow(ctx, updateAutopilotRunRunning, arg.ID, arg.TaskID) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const updateAutopilotRunSkipped = `-- name: UpdateAutopilotRunSkipped :one UPDATE autopilot_run SET status = 'skipped', completed_at = now(), failure_reason = $2 WHERE id = $1 RETURNING id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id ` type UpdateAutopilotRunSkippedParams struct { ID pgtype.UUID `json:"id"` FailureReason pgtype.Text `json:"failure_reason"` } // Marks an autopilot_run as skipped without enqueueing any task. Used by the // pre-flight admission check when the assignee agent's runtime is offline: // creating an issue / task in that state would just pile a doomed job onto // agent_task_queue (the canonical "持续给离线 local agent 入队" symptom from // MUL-1899). Recording the skip + reason gives the UI / failure monitor / ops // a paper trail without polluting the failure ratio. func (q *Queries) UpdateAutopilotRunSkipped(ctx context.Context, arg UpdateAutopilotRunSkippedParams) (AutopilotRun, error) { row := q.db.QueryRow(ctx, updateAutopilotRunSkipped, arg.ID, arg.FailureReason) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const updateAutopilotRunSkippedWithResult = `-- name: UpdateAutopilotRunSkippedWithResult :one UPDATE autopilot_run SET status = 'skipped', completed_at = now(), failure_reason = $2, result = $3 WHERE id = $1 RETURNING id, autopilot_id, trigger_id, source, status, issue_id, task_id, triggered_at, completed_at, failure_reason, trigger_payload, result, created_at, squad_id ` type UpdateAutopilotRunSkippedWithResultParams struct { ID pgtype.UUID `json:"id"` FailureReason pgtype.Text `json:"failure_reason"` Result []byte `json:"result"` } func (q *Queries) UpdateAutopilotRunSkippedWithResult(ctx context.Context, arg UpdateAutopilotRunSkippedWithResultParams) (AutopilotRun, error) { row := q.db.QueryRow(ctx, updateAutopilotRunSkippedWithResult, arg.ID, arg.FailureReason, arg.Result) var i AutopilotRun err := row.Scan( &i.ID, &i.AutopilotID, &i.TriggerID, &i.Source, &i.Status, &i.IssueID, &i.TaskID, &i.TriggeredAt, &i.CompletedAt, &i.FailureReason, &i.TriggerPayload, &i.Result, &i.CreatedAt, &i.SquadID, ) return i, err } const updateAutopilotTrigger = `-- name: UpdateAutopilotTrigger :one UPDATE autopilot_trigger SET enabled = COALESCE($2::boolean, enabled), cron_expression = COALESCE($3, cron_expression), timezone = COALESCE($4, timezone), next_run_at = $5, label = COALESCE($6, label), event_filters = COALESCE($7, event_filters), updated_at = now() WHERE id = $1 RETURNING id, autopilot_id, kind, enabled, cron_expression, timezone, next_run_at, webhook_token, label, last_fired_at, created_at, updated_at, provider, signing_secret, event_filters ` type UpdateAutopilotTriggerParams struct { ID pgtype.UUID `json:"id"` Enabled pgtype.Bool `json:"enabled"` CronExpression pgtype.Text `json:"cron_expression"` Timezone pgtype.Text `json:"timezone"` NextRunAt pgtype.Timestamptz `json:"next_run_at"` Label pgtype.Text `json:"label"` EventFilters []byte `json:"event_filters"` } func (q *Queries) UpdateAutopilotTrigger(ctx context.Context, arg UpdateAutopilotTriggerParams) (AutopilotTrigger, error) { row := q.db.QueryRow(ctx, updateAutopilotTrigger, arg.ID, arg.Enabled, arg.CronExpression, arg.Timezone, arg.NextRunAt, arg.Label, arg.EventFilters, ) var i AutopilotTrigger err := row.Scan( &i.ID, &i.AutopilotID, &i.Kind, &i.Enabled, &i.CronExpression, &i.Timezone, &i.NextRunAt, &i.WebhookToken, &i.Label, &i.LastFiredAt, &i.CreatedAt, &i.UpdatedAt, &i.Provider, &i.SigningSecret, &i.EventFilters, ) return i, err }