lib/openagents/memory/semantic_derivative_receipt.ex

58e6347eeb72 · 1 KB

defmodule OpenAgents.Memory.SemanticDerivativeReceipt do
  @moduledoc "Content-free append-only receipt for semantic invalidation, deletion, or rebuild."
  use Ecto.Schema
  import Ecto.Changeset

  @primary_key {:id, :binary_id, autogenerate: true}
  @timestamps_opts [type: :utc_datetime_usec, updated_at: false]

  schema "semantic_derivative_receipts" do
    field :message_id, :binary_id
    field :conversation_id, :binary_id
    field :content_digest, :string
    field :action, :string
    field :reason_code, :string
    field :generation, :integer
    field :deleted_embedding_count, :integer
    field :invalidated_job_count, :integer
    field :receipt_digest, :string
    timestamps()
  end

  def changeset(record, attributes) do
    record
    |> cast(
      attributes,
      ~w(message_id conversation_id content_digest action reason_code generation deleted_embedding_count invalidated_job_count receipt_digest)a
    )
    |> validate_required(
      ~w(message_id conversation_id content_digest action reason_code generation deleted_embedding_count invalidated_job_count receipt_digest)a
    )
    |> validate_inclusion(:action, ~w(invalidate delete rebuild))
    |> validate_number(:generation, greater_than: 0)
    |> validate_number(:deleted_embedding_count, greater_than_or_equal_to: 0)
    |> validate_number(:invalidated_job_count, greater_than_or_equal_to: 0)
    |> validate_format(:content_digest, ~r/\A[0-9a-f]{64}\z/)
    |> validate_format(:receipt_digest, ~r/\A[0-9a-f]{64}\z/)
    |> validate_length(:reason_code, min: 1, max: 64)
  end
end