-- Teleo Agent Graph 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.

CREATE TABLE IF NOT EXISTS graph_schema_version (
    version TEXT PRIMARY KEY,
    source TEXT NOT NULL,
    applied_at TEXT DEFAULT CURRENT_TIMESTAMP
);

INSERT OR IGNORE INTO graph_schema_version (version, source)
VALUES ('teleo-agent-graph-v1', 'teleo-agent-architecture-excalidraw');

CREATE TABLE IF NOT EXISTS agents (
    slug TEXT PRIMARY KEY,
    display_name TEXT NOT NULL,
    archetype TEXT,
    status TEXT NOT NULL DEFAULT 'active'
        CHECK(status IN ('active', 'inactive', 'deprecated')),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS agent_persona_revisions (
    id TEXT PRIMARY KEY,
    agent_slug TEXT NOT NULL REFERENCES agents(slug),
    revision INTEGER NOT NULL,
    identity TEXT NOT NULL,
    voice TEXT NOT NULL,
    role TEXT NOT NULL,
    authored_by TEXT,
    stable INTEGER NOT NULL DEFAULT 1 CHECK(stable IN (0, 1)),
    loads_every_turn INTEGER NOT NULL DEFAULT 1 CHECK(loads_every_turn IN (0, 1)),
    active INTEGER NOT NULL DEFAULT 1 CHECK(active IN (0, 1)),
    notes TEXT,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(agent_slug, revision)
);

CREATE TABLE IF NOT EXISTS agent_strategy_revisions (
    id TEXT PRIMARY KEY,
    agent_slug TEXT NOT NULL REFERENCES agents(slug),
    persona_revision_id TEXT REFERENCES agent_persona_revisions(id),
    revision INTEGER NOT NULL,
    diagnosis TEXT NOT NULL,
    guiding_policy TEXT NOT NULL,
    proximate_objectives_json TEXT NOT NULL DEFAULT '[]',
    derivation_notes TEXT,
    active INTEGER NOT NULL DEFAULT 1 CHECK(active IN (0, 1)),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(agent_slug, revision)
);

CREATE TABLE IF NOT EXISTS agent_positions (
    id TEXT PRIMARY KEY,
    agent_slug TEXT NOT NULL REFERENCES agents(slug),
    title TEXT NOT NULL,
    statement TEXT NOT NULL,
    falsification_criteria TEXT,
    public_commitment INTEGER NOT NULL DEFAULT 1 CHECK(public_commitment IN (0, 1)),
    confidence TEXT NOT NULL DEFAULT 'experimental'
        CHECK(confidence IN ('proven', 'likely', 'experimental', 'speculative')),
    status TEXT NOT NULL DEFAULT 'active'
        CHECK(status IN ('draft', 'active', 'flagged', 'retired')),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    last_reviewed TEXT
);

CREATE TABLE IF NOT EXISTS agent_beliefs (
    id TEXT PRIMARY KEY,
    agent_slug TEXT NOT NULL REFERENCES agents(slug),
    belief_code TEXT NOT NULL,
    title TEXT NOT NULL,
    statement TEXT NOT NULL,
    falsification_criteria TEXT,
    is_keystone INTEGER NOT NULL DEFAULT 0 CHECK(is_keystone IN (0, 1)),
    min_claims INTEGER NOT NULL DEFAULT 3,
    confidence TEXT NOT NULL DEFAULT 'experimental'
        CHECK(confidence IN ('proven', 'likely', 'experimental', 'speculative')),
    status TEXT NOT NULL DEFAULT 'active'
        CHECK(status IN ('draft', 'active', 'load_bearing', 'flagged', 'retired')),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    last_evaluated TEXT,
    UNIQUE(agent_slug, belief_code)
);

CREATE TABLE IF NOT EXISTS evidence (
    id TEXT PRIMARY KEY,
    evidence_type TEXT NOT NULL
        CHECK(evidence_type IN ('study', 'data', 'event', 'formal_result', 'legal', 'market', 'historical', 'other')),
    title TEXT NOT NULL,
    source_uri TEXT,
    citation TEXT,
    summary TEXT NOT NULL,
    verification_status TEXT NOT NULL DEFAULT 'unverified'
        CHECK(verification_status IN ('unverified', 'sourced', 'verified', 'disputed', 'retracted')),
    observed_at TEXT,
    attribution_json TEXT NOT NULL DEFAULT '{}',
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS claims (
    id TEXT PRIMARY KEY,
    slug TEXT NOT NULL UNIQUE,
    domain TEXT NOT NULL,
    description TEXT NOT NULL,
    confidence TEXT NOT NULL DEFAULT 'experimental'
        CHECK(confidence IN ('proven', 'likely', 'experimental', 'speculative')),
    source_summary TEXT,
    proposed_by TEXT,
    primary_evidence_id TEXT REFERENCES evidence(id),
    importance REAL NOT NULL DEFAULT 0 CHECK(importance >= 0 AND importance <= 1),
    status TEXT NOT NULL DEFAULT 'draft'
        CHECK(status IN ('draft', 'active', 'accepted', 'challenged', 'quarantined', 'retired')),
    attribution_json TEXT NOT NULL DEFAULT '{}',
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    last_evaluated TEXT
);

CREATE TABLE IF NOT EXISTS position_belief_edges (
    id TEXT PRIMARY KEY,
    position_id TEXT NOT NULL REFERENCES agent_positions(id),
    belief_id TEXT NOT NULL REFERENCES agent_beliefs(id),
    relation TEXT NOT NULL DEFAULT 'depends_on'
        CHECK(relation IN ('depends_on', 'supports', 'challenged_by', 'related')),
    weight REAL NOT NULL DEFAULT 1 CHECK(weight >= 0 AND weight <= 1),
    rationale TEXT NOT NULL,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(position_id, belief_id, relation)
);

CREATE TABLE IF NOT EXISTS belief_claim_edges (
    id TEXT PRIMARY KEY,
    belief_id TEXT NOT NULL REFERENCES agent_beliefs(id),
    claim_id TEXT NOT NULL REFERENCES claims(id),
    relation TEXT NOT NULL DEFAULT 'cites'
        CHECK(relation IN ('cites', 'depends_on', 'supports', 'challenged_by', 'related')),
    weight REAL NOT NULL DEFAULT 1 CHECK(weight >= 0 AND weight <= 1),
    rationale TEXT NOT NULL,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(belief_id, claim_id, relation)
);

CREATE TABLE IF NOT EXISTS claim_edges (
    id TEXT PRIMARY KEY,
    from_claim_id TEXT NOT NULL REFERENCES claims(id),
    to_claim_id TEXT NOT NULL REFERENCES claims(id),
    relation TEXT NOT NULL
        CHECK(relation IN ('depends_on', 'supports', 'challenged_by', 'cited_by', 'related')),
    weight REAL NOT NULL DEFAULT 1 CHECK(weight >= 0 AND weight <= 1),
    rationale TEXT NOT NULL,
    authored_by TEXT,
    computed INTEGER NOT NULL DEFAULT 0 CHECK(computed IN (0, 1)),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    CHECK(from_claim_id <> to_claim_id),
    UNIQUE(from_claim_id, to_claim_id, relation)
);

CREATE TABLE IF NOT EXISTS claim_evidence_edges (
    id TEXT PRIMARY KEY,
    claim_id TEXT NOT NULL REFERENCES claims(id),
    evidence_id TEXT NOT NULL REFERENCES evidence(id),
    relation TEXT NOT NULL DEFAULT 'supports'
        CHECK(relation IN ('primary', 'supports', 'challenges', 'context', 'weakens')),
    weight REAL NOT NULL DEFAULT 1 CHECK(weight >= 0 AND weight <= 1),
    rationale TEXT NOT NULL,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(claim_id, evidence_id, relation)
);

CREATE TABLE IF NOT EXISTS graph_evaluation_runs (
    id TEXT PRIMARY KEY,
    target_layer TEXT NOT NULL
        CHECK(target_layer IN ('persona', 'strategy', 'position', 'belief', 'claim', 'evidence', 'edge')),
    target_id TEXT NOT NULL,
    trigger_type TEXT NOT NULL
        CHECK(trigger_type IN ('scheduled', 'history_replay', 'evidence_changed', 'claim_changed', 'manual', 'red_team')),
    trigger_id TEXT,
    evaluator TEXT NOT NULL,
    model TEXT,
    verdict TEXT NOT NULL
        CHECK(verdict IN ('approve', 'request_changes', 'reject', 'flag', 'quarantine', 'no_op')),
    confidence REAL CHECK(confidence IS NULL OR (confidence >= 0 AND confidence <= 1)),
    notes TEXT,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS cascade_events (
    id TEXT PRIMARY KEY,
    changed_layer TEXT NOT NULL
        CHECK(changed_layer IN ('evidence', 'claim', 'belief', 'position', 'strategy', 'persona')),
    changed_id TEXT NOT NULL,
    affected_layer TEXT NOT NULL
        CHECK(affected_layer IN ('claim', 'belief', 'position', 'strategy', 'persona')),
    affected_id TEXT NOT NULL,
    direction TEXT NOT NULL DEFAULT 'up'
        CHECK(direction IN ('up', 'down', 'lateral')),
    status TEXT NOT NULL DEFAULT 'queued'
        CHECK(status IN ('queued', 'reviewing', 'resolved', 'ignored')),
    reason TEXT NOT NULL,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP,
    resolved_at TEXT
);

CREATE TABLE IF NOT EXISTS graph_history_events (
    id TEXT PRIMARY KEY,
    provider TEXT NOT NULL CHECK(provider IN ('github', 'forgejo', 'local_git', 'web', 'x', 'telegram', 'manual')),
    repo TEXT,
    provider_event_id TEXT,
    event_type TEXT NOT NULL,
    actor TEXT,
    occurred_at TEXT,
    payload_json TEXT NOT NULL DEFAULT '{}',
    redacted INTEGER NOT NULL DEFAULT 1 CHECK(redacted IN (0, 1)),
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS graph_node_history_links (
    history_event_id TEXT NOT NULL REFERENCES graph_history_events(id),
    node_layer TEXT NOT NULL
        CHECK(node_layer IN ('persona', 'strategy', 'position', 'belief', 'claim', 'evidence', 'edge')),
    node_id TEXT NOT NULL,
    role TEXT NOT NULL
        CHECK(role IN ('created', 'updated', 'evaluated', 'merged', 'challenged', 'cited', 'sourced')),
    PRIMARY KEY (history_event_id, node_layer, node_id, role)
);

CREATE INDEX IF NOT EXISTS idx_persona_revisions_agent_active
    ON agent_persona_revisions(agent_slug, active);
CREATE INDEX IF NOT EXISTS idx_strategy_revisions_agent_active
    ON agent_strategy_revisions(agent_slug, active);
CREATE INDEX IF NOT EXISTS idx_positions_agent_status
    ON agent_positions(agent_slug, status);
CREATE INDEX IF NOT EXISTS idx_beliefs_agent_status
    ON agent_beliefs(agent_slug, status);
CREATE INDEX IF NOT EXISTS idx_claims_domain_status
    ON claims(domain, status);
CREATE INDEX IF NOT EXISTS idx_claims_importance
    ON claims(importance);
CREATE INDEX IF NOT EXISTS idx_evidence_status
    ON evidence(verification_status);
CREATE INDEX IF NOT EXISTS idx_belief_claim_edges_claim
    ON belief_claim_edges(claim_id, relation);
CREATE INDEX IF NOT EXISTS idx_claim_edges_to
    ON claim_edges(to_claim_id, relation);
CREATE INDEX IF NOT EXISTS idx_claim_evidence_edges_evidence
    ON claim_evidence_edges(evidence_id, relation);
CREATE INDEX IF NOT EXISTS idx_cascade_status
    ON cascade_events(status, affected_layer);
CREATE INDEX IF NOT EXISTS idx_history_provider_repo
    ON graph_history_events(provider, repo, event_type);
