AkurAI Build
Menu

popagent

public

Latest change c5cc989445aeac1b3fd80068df03e23002a15a47 - Let evolution retain bounded durable facts by AkurAI Build

BEGIN;

DO $lock$
BEGIN
  PERFORM pg_advisory_xact_lock(hashtextextended('popagent-evolution-schema-v1', 0));
END
$lock$;

CREATE TABLE IF NOT EXISTS popagent_data_migrations (
  id TEXT PRIMARY KEY,
  applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS popagent_autonomy_settings (
  singleton BOOLEAN PRIMARY KEY CHECK (singleton),
  enabled BOOLEAN NOT NULL,
  reflection_interval_ms INTEGER NOT NULL CHECK (reflection_interval_ms BETWEEN 60000 AND 86400000),
  batch_size INTEGER NOT NULL CHECK (batch_size BETWEEN 1 AND 100),
  max_attempts INTEGER NOT NULL CHECK (max_attempts BETWEEN 1 AND 10),
  auto_apply_strategies BOOLEAN NOT NULL,
  auto_create_skills BOOLEAN NOT NULL,
  auto_retain_facts BOOLEAN NOT NULL DEFAULT FALSE,
  self_update_enabled BOOLEAN NOT NULL,
  self_update_cron TEXT NOT NULL CHECK (char_length(btrim(self_update_cron)) BETWEEN 1 AND 100),
  idle_improvement_enabled BOOLEAN NOT NULL DEFAULT FALSE,
  idle_deployment_enabled BOOLEAN NOT NULL DEFAULT FALSE,
  idle_workspace_ids JSONB NOT NULL DEFAULT '[]'::jsonb CHECK (jsonb_typeof(idle_workspace_ids) = 'array'),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS popagent_evolution_signals (
  id TEXT PRIMARY KEY,
  dedupe_key TEXT NOT NULL UNIQUE CHECK (char_length(dedupe_key) = 64),
  session_id TEXT,
  turn_id TEXT,
  trace_id TEXT,
  agent_id TEXT NOT NULL REFERENCES popagent_agents(id),
  workspace_id TEXT,
  kind TEXT NOT NULL CHECK (kind IN ('turn-success', 'turn-failure')),
  summary TEXT NOT NULL CHECK (char_length(summary) BETWEEN 1 AND 4000),
  status TEXT NOT NULL CHECK (status IN ('pending', 'processing', 'applied', 'ignored', 'dead-letter')),
  attempts INTEGER NOT NULL DEFAULT 0 CHECK (attempts BETWEEN 0 AND 10),
  next_attempt_at TIMESTAMPTZ,
  processed_at TIMESTAMPTZ,
  error TEXT CHECK (error IS NULL OR char_length(error) <= 2000),
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS popagent_evolution_signals_claim_idx
  ON popagent_evolution_signals (next_attempt_at, created_at, id)
  WHERE status = 'pending';
CREATE INDEX IF NOT EXISTS popagent_evolution_signals_recent_idx
  ON popagent_evolution_signals (created_at DESC, id DESC);

CREATE TABLE IF NOT EXISTS popagent_learned_overlays (
  agent_id TEXT PRIMARY KEY REFERENCES popagent_agents(id),
  content TEXT NOT NULL CHECK (char_length(btrim(content)) BETWEEN 1 AND 12000),
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

ALTER TABLE popagent_agent_skills
  ADD COLUMN IF NOT EXISTS evolution_managed BOOLEAN NOT NULL DEFAULT FALSE;

CREATE TABLE IF NOT EXISTS popagent_evolution_revisions (
  id TEXT PRIMARY KEY,
  agent_id TEXT NOT NULL REFERENCES popagent_agents(id),
  target_type TEXT NOT NULL CHECK (target_type IN ('overlay', 'skill', 'fact')),
  target_key TEXT NOT NULL CHECK (char_length(btrim(target_key)) BETWEEN 1 AND 100),
  before_content TEXT,
  after_content TEXT,
  rationale TEXT NOT NULL CHECK (char_length(btrim(rationale)) BETWEEN 1 AND 2000),
  evidence_ids JSONB NOT NULL CHECK (jsonb_typeof(evidence_ids) = 'array'),
  status TEXT NOT NULL CHECK (status IN ('applied', 'reverted')),
  reverts_revision_id TEXT REFERENCES popagent_evolution_revisions(id),
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CHECK (before_content IS NOT NULL OR after_content IS NOT NULL)
);

CREATE INDEX IF NOT EXISTS popagent_evolution_revisions_recent_idx
  ON popagent_evolution_revisions (created_at DESC, id DESC);
CREATE INDEX IF NOT EXISTS popagent_evolution_revisions_target_idx
  ON popagent_evolution_revisions (agent_id, target_type, target_key, created_at DESC);

CREATE OR REPLACE FUNCTION popagent_reject_evolution_revision_mutation()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $function$
BEGIN
  RAISE EXCEPTION 'popagent_evolution_revisions is append-only';
END
$function$;

DROP TRIGGER IF EXISTS popagent_evolution_revisions_append_only
  ON popagent_evolution_revisions;
CREATE TRIGGER popagent_evolution_revisions_append_only
  BEFORE UPDATE OR DELETE ON popagent_evolution_revisions
  FOR EACH ROW EXECUTE FUNCTION popagent_reject_evolution_revision_mutation();

DO $migration$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM popagent_data_migrations
    WHERE id = '2026-08-14-evolution-v1'
  ) THEN
    INSERT INTO popagent_autonomy_settings (
      singleton,
      enabled,
      reflection_interval_ms,
      batch_size,
      max_attempts,
      auto_apply_strategies,
      auto_create_skills,
      self_update_enabled,
      self_update_cron
    ) VALUES (
      TRUE,
      TRUE,
      3600000,
      20,
      3,
      TRUE,
      TRUE,
      TRUE,
      '0 3 * * *'
    )
    ON CONFLICT (singleton) DO NOTHING;

    INSERT INTO popagent_data_migrations (id)
    VALUES ('2026-08-14-evolution-v1')
    ON CONFLICT (id) DO NOTHING;
  END IF;
END
$migration$;

DO $revision_lineage$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM popagent_data_migrations
    WHERE id = '2026-08-14-evolution-revert-lineage-v2'
  ) THEN
    CREATE UNIQUE INDEX IF NOT EXISTS popagent_evolution_revisions_reverts_unique_idx
      ON popagent_evolution_revisions (reverts_revision_id)
      WHERE reverts_revision_id IS NOT NULL;

    INSERT INTO popagent_data_migrations (id)
    VALUES ('2026-08-14-evolution-revert-lineage-v2');
  END IF;
END
$revision_lineage$;

DO $idle_improvement$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM popagent_data_migrations
    WHERE id = '2026-08-15-idle-improvement-v1'
  ) THEN
    ALTER TABLE popagent_autonomy_settings
      ADD COLUMN IF NOT EXISTS idle_improvement_enabled BOOLEAN NOT NULL DEFAULT FALSE,
      ADD COLUMN IF NOT EXISTS idle_deployment_enabled BOOLEAN NOT NULL DEFAULT FALSE,
      ADD COLUMN IF NOT EXISTS idle_workspace_ids JSONB NOT NULL DEFAULT '[]'::jsonb
        CHECK (jsonb_typeof(idle_workspace_ids) = 'array');
    INSERT INTO popagent_data_migrations (id)
    VALUES ('2026-08-15-idle-improvement-v1');
  END IF;
END
$idle_improvement$;

DO $evolution_facts$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM popagent_data_migrations
    WHERE id = '2026-08-15-evolution-memory-facts-v3'
  ) THEN
    ALTER TABLE popagent_autonomy_settings
      ADD COLUMN IF NOT EXISTS auto_retain_facts BOOLEAN NOT NULL DEFAULT FALSE;
    ALTER TABLE popagent_evolution_revisions
      DROP CONSTRAINT IF EXISTS popagent_evolution_revisions_target_type_check;
    ALTER TABLE popagent_evolution_revisions
      ADD CONSTRAINT popagent_evolution_revisions_target_type_check
      CHECK (target_type IN ('overlay', 'skill', 'fact'));
    INSERT INTO popagent_data_migrations (id)
    VALUES ('2026-08-15-evolution-memory-facts-v3');
  END IF;
END
$evolution_facts$;

COMMIT;