priv/repo/migrations/20260818150100_create_incidents.exs

main at 58e6347eeb72 · 1 KB

defmodule Sarah.Repo.Migrations.CreateIncidents do
  use Ecto.Migration

  # One durable, queryable home for every anomalous failure across surfaces —
  # turn, tool, voice, job, delegation, controller — so a failure is never again
  # captured "nowhere". Shaped like the receipts/work_jobs tables Sarah already
  # trusts. See docs/audits/2026-08-18-sarah-self-healing-and-error-observability-audit.md.
  def change do
    create table(:incidents, primary_key: false) do
      add :id, :binary_id, primary_key: true

      add :conversation_id,
          references(:conversations, type: :binary_id, on_delete: :nilify_all)

      add :owner_user_id, references(:users, type: :binary_id, on_delete: :nilify_all)
      add :owner_visitor_id, references(:visitors, type: :binary_id, on_delete: :nilify_all)

      # Where the failure happened and who reported it.
      add :surface, :string, null: false
      add :origin, :string, null: false
      # The durable record it points at: a turn_id / tool_step_id / job_id / request_id.
      add :correlation_ref, :string

      # The real machine-readable reason (transport:provider_task_exited, …).
      add :code, :string, null: false
      add :severity, :string, null: false, default: "anomalous"
      add :summary, :string
      # Bounded, secret-scrubbed structured context.
      add :context, :map, null: false, default: %{}

      add :status, :string, null: false, default: "open"
      add :fixer_job_id, references(:work_jobs, type: :binary_id, on_delete: :nilify_all)
      add :receipt_ref, :string

      timestamps(type: :utc_datetime_usec)
    end

    create index(:incidents, [:owner_user_id])
    create index(:incidents, [:conversation_id])
    create index(:incidents, [:code])
    create index(:incidents, [:severity])
    create index(:incidents, [:status])
    create index(:incidents, [:inserted_at])
  end
end