-- Teleo Agent Research Eval Schema v1
-- Common SQL subset intended for ephemeral SQLite tests and Postgres/Supabase
-- staging. IDs are app-generated text IDs so this can run across engines.
--
-- Apply after teleo-agent-graph-v1.sql.
--
-- Secret policy: store hashes, redacted excerpts, and proof references only.
-- Raw prompts, bearer tokens, API keys, wallet secrets, and private receipts do
-- not belong in these tables.

INSERT OR IGNORE INTO graph_schema_version (version, source)
VALUES ('teleo-agent-research-eval-v1', 'leo-x402-research-routing-benchmark');

CREATE TABLE IF NOT EXISTS agent_research_runs (
    id TEXT PRIMARY KEY,
    agent_slug TEXT NOT NULL REFERENCES agents(slug),
    source_surface TEXT NOT NULL
        CHECK(source_surface IN ('telegram', 'api', 'checkout', 'web', 'cli', 'test', 'other')),
    source_ref TEXT,
    request_kind TEXT NOT NULL DEFAULT 'free'
        CHECK(request_kind IN ('free', 'paid_quote', 'paid_work_order', 'benchmark', 'system')),
    sponsored_work_order_id TEXT,
    payment_receipt_id TEXT,
    prompt_sha256 TEXT NOT NULL,
    prompt_excerpt TEXT,
    selected_provider TEXT,
    selected_route TEXT NOT NULL DEFAULT 'unknown'
        CHECK(selected_route IN (
            'none',
            'web_search',
            'social_trends',
            'structured_market_data',
            'local_context',
            'mixed',
            'unknown'
        )),
    status TEXT NOT NULL DEFAULT 'running'
        CHECK(status IN (
            'quoted',
            'payment_pending',
            'running',
            'answered',
            'abstained',
            'blocked',
            'failed',
            'cancelled'
        )),
    answer_sha256 TEXT,
    answer_excerpt TEXT,
    proof_ref TEXT,
    cost_amount REAL NOT NULL DEFAULT 0 CHECK(cost_amount >= 0),
    currency TEXT NOT NULL DEFAULT 'USDC',
    latency_ms INTEGER CHECK(latency_ms IS NULL OR latency_ms >= 0),
    source_count INTEGER NOT NULL DEFAULT 0 CHECK(source_count >= 0),
    secret_values_included INTEGER NOT NULL DEFAULT 0 CHECK(secret_values_included = 0),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    completed_at TEXT,
    CHECK(prompt_excerpt IS NULL OR length(prompt_excerpt) <= 1000),
    CHECK(answer_excerpt IS NULL OR length(answer_excerpt) <= 2000)
);

CREATE INDEX IF NOT EXISTS idx_agent_research_runs_agent_created
    ON agent_research_runs(agent_slug, created_at);
CREATE INDEX IF NOT EXISTS idx_agent_research_runs_work_order
    ON agent_research_runs(sponsored_work_order_id);
CREATE INDEX IF NOT EXISTS idx_agent_research_runs_status_route
    ON agent_research_runs(status, selected_route);

CREATE TABLE IF NOT EXISTS agent_tool_invocations (
    id TEXT PRIMARY KEY,
    research_run_id TEXT NOT NULL REFERENCES agent_research_runs(id) ON DELETE CASCADE,
    sequence INTEGER NOT NULL DEFAULT 0 CHECK(sequence >= 0),
    provider TEXT NOT NULL,
    tool_name TEXT NOT NULL,
    tool_category TEXT NOT NULL
        CHECK(tool_category IN (
            'web_search',
            'social_trends',
            'market_data',
            'page_read',
            'x402_checkout',
            'agentcash',
            'faremeter',
            'database',
            'local_context',
            'other'
        )),
    endpoint_host TEXT,
    endpoint_hash TEXT,
    decision TEXT NOT NULL
        CHECK(decision IN ('candidate', 'selected', 'executed', 'skipped', 'rejected', 'fallback', 'failed')),
    decision_reason TEXT NOT NULL,
    paid INTEGER NOT NULL DEFAULT 0 CHECK(paid IN (0, 1)),
    rail TEXT CHECK(rail IS NULL OR rail IN ('x402', 'agentcash', 'manual', 'free', 'other')),
    network TEXT,
    amount REAL CHECK(amount IS NULL OR amount >= 0),
    currency TEXT NOT NULL DEFAULT 'USDC',
    payment_receipt_id TEXT,
    input_sha256 TEXT,
    output_sha256 TEXT,
    source_count INTEGER NOT NULL DEFAULT 0 CHECK(source_count >= 0),
    latency_ms INTEGER CHECK(latency_ms IS NULL OR latency_ms >= 0),
    error_class TEXT,
    secret_values_included INTEGER NOT NULL DEFAULT 0 CHECK(secret_values_included = 0),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(research_run_id, sequence)
);

CREATE INDEX IF NOT EXISTS idx_agent_tool_invocations_run_decision
    ON agent_tool_invocations(research_run_id, decision);
CREATE INDEX IF NOT EXISTS idx_agent_tool_invocations_provider_category
    ON agent_tool_invocations(provider, tool_category);
CREATE INDEX IF NOT EXISTS idx_agent_tool_invocations_receipt
    ON agent_tool_invocations(payment_receipt_id);

CREATE TABLE IF NOT EXISTS agent_research_sources (
    id TEXT PRIMARY KEY,
    research_run_id TEXT NOT NULL REFERENCES agent_research_runs(id) ON DELETE CASCADE,
    tool_invocation_id TEXT REFERENCES agent_tool_invocations(id) ON DELETE SET NULL,
    source_type TEXT NOT NULL
        CHECK(source_type IN ('web', 'social', 'market', 'db', 'document', 'other')),
    source_uri TEXT,
    source_uri_sha256 TEXT,
    title TEXT,
    cited INTEGER NOT NULL DEFAULT 0 CHECK(cited IN (0, 1)),
    retrieval_rank INTEGER CHECK(retrieval_rank IS NULL OR retrieval_rank >= 0),
    observed_at TEXT,
    support_status TEXT NOT NULL DEFAULT 'unknown'
        CHECK(support_status IN ('supports', 'context', 'conflicts', 'stale', 'unknown')),
    secret_values_included INTEGER NOT NULL DEFAULT 0 CHECK(secret_values_included = 0),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_agent_research_sources_run
    ON agent_research_sources(research_run_id, cited);
CREATE INDEX IF NOT EXISTS idx_agent_research_sources_tool
    ON agent_research_sources(tool_invocation_id);

CREATE TABLE IF NOT EXISTS agent_eval_cases (
    id TEXT PRIMARY KEY,
    suite_id TEXT NOT NULL,
    case_slug TEXT NOT NULL,
    case_version INTEGER NOT NULL DEFAULT 1 CHECK(case_version >= 1),
    prompt_sha256 TEXT NOT NULL,
    prompt_excerpt TEXT NOT NULL CHECK(length(prompt_excerpt) <= 1000),
    fixture_context_sha256 TEXT,
    fixture_context_excerpt TEXT CHECK(fixture_context_excerpt IS NULL OR length(fixture_context_excerpt) <= 2000),
    expected_route TEXT NOT NULL
        CHECK(expected_route IN (
            'none',
            'web_search',
            'social_trends',
            'structured_market_data',
            'local_context',
            'mixed',
            'unknown'
        )),
    expected_provider TEXT,
    must_use_tools_json TEXT NOT NULL DEFAULT '[]',
    must_not_use_tools_json TEXT NOT NULL DEFAULT '[]',
    tags_json TEXT NOT NULL DEFAULT '[]',
    rubric_json TEXT NOT NULL DEFAULT '{}',
    stale_after TEXT,
    active INTEGER NOT NULL DEFAULT 1 CHECK(active IN (0, 1)),
    secret_values_included INTEGER NOT NULL DEFAULT 0 CHECK(secret_values_included = 0),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(suite_id, case_slug, case_version)
);

CREATE INDEX IF NOT EXISTS idx_agent_eval_cases_suite_active
    ON agent_eval_cases(suite_id, active);
CREATE INDEX IF NOT EXISTS idx_agent_eval_cases_route
    ON agent_eval_cases(expected_route);

CREATE TABLE IF NOT EXISTS agent_eval_results (
    id TEXT PRIMARY KEY,
    eval_case_id TEXT NOT NULL REFERENCES agent_eval_cases(id) ON DELETE CASCADE,
    research_run_id TEXT NOT NULL REFERENCES agent_research_runs(id) ON DELETE CASCADE,
    graph_evaluation_run_id TEXT REFERENCES graph_evaluation_runs(id) ON DELETE SET NULL,
    status TEXT NOT NULL
        CHECK(status IN ('passed', 'failed', 'warning', 'blocked', 'skipped')),
    score REAL CHECK(score IS NULL OR (score >= 0 AND score <= 1)),
    routing_correct INTEGER CHECK(routing_correct IS NULL OR routing_correct IN (0, 1)),
    tool_choice_score REAL CHECK(tool_choice_score IS NULL OR (tool_choice_score >= 0 AND tool_choice_score <= 1)),
    source_quality_score REAL CHECK(source_quality_score IS NULL OR (source_quality_score >= 0 AND source_quality_score <= 1)),
    groundedness_score REAL CHECK(groundedness_score IS NULL OR (groundedness_score >= 0 AND groundedness_score <= 1)),
    freshness_score REAL CHECK(freshness_score IS NULL OR (freshness_score >= 0 AND freshness_score <= 1)),
    cost_efficiency_score REAL CHECK(cost_efficiency_score IS NULL OR (cost_efficiency_score >= 0 AND cost_efficiency_score <= 1)),
    safety_payment_score REAL CHECK(safety_payment_score IS NULL OR (safety_payment_score >= 0 AND safety_payment_score <= 1)),
    failure_reason TEXT,
    judge TEXT,
    proof_ref TEXT,
    secret_values_included INTEGER NOT NULL DEFAULT 0 CHECK(secret_values_included = 0),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(eval_case_id, research_run_id)
);

CREATE INDEX IF NOT EXISTS idx_agent_eval_results_case_status
    ON agent_eval_results(eval_case_id, status);
CREATE INDEX IF NOT EXISTS idx_agent_eval_results_run
    ON agent_eval_results(research_run_id);
CREATE INDEX IF NOT EXISTS idx_agent_eval_results_graph_eval
    ON agent_eval_results(graph_evaluation_run_id);

CREATE TABLE IF NOT EXISTS work_order_graph_links (
    id TEXT PRIMARY KEY,
    sponsored_work_order_id TEXT NOT NULL,
    role TEXT NOT NULL
        CHECK(role IN (
            'input_context',
            'evaluation_target',
            'created_evidence',
            'created_claim',
            'created_eval_run',
            'research_run',
            'tool_trace',
            'history_trace',
            'outcome_trace'
        )),
    graph_layer TEXT NOT NULL
        CHECK(graph_layer IN (
            'persona',
            'strategy',
            'position',
            'belief',
            'claim',
            'evidence',
            'edge',
            'graph_evaluation_run',
            'cascade_event',
            'graph_history_event',
            'agent_research_run',
            'agent_tool_invocation',
            'agent_eval_result',
            'outcome_observation'
        )),
    graph_id TEXT NOT NULL,
    rationale TEXT,
    secret_values_included INTEGER NOT NULL DEFAULT 0 CHECK(secret_values_included = 0),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(sponsored_work_order_id, role, graph_layer, graph_id)
);

CREATE INDEX IF NOT EXISTS idx_work_order_graph_links_work_order
    ON work_order_graph_links(sponsored_work_order_id);
CREATE INDEX IF NOT EXISTS idx_work_order_graph_links_graph
    ON work_order_graph_links(graph_layer, graph_id);
