-- Spore Agent Commons — Core Primitives -- Claims, Evidence, Attestations, Intents, Commitments -- ============================================================ -- Claims (knowledge claims in the commons) -- ============================================================ CREATE TABLE IF NOT EXISTS claims ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), rid TEXT UNIQUE NOT NULL, proposer_rid TEXT NOT NULL, content TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'proposed' CHECK (status IN ('proposed', 'supported', 'challenged', 'superseded')), confidence FLOAT DEFAULT 0.5, anchor_type TEXT DEFAULT 'assertion', embedding vector(1024), metadata JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_claims_proposer ON claims (proposer_rid); CREATE INDEX IF NOT EXISTS idx_claims_status ON claims (status); CREATE INDEX IF NOT EXISTS idx_claims_metadata ON claims USING GIN (metadata); -- ============================================================ -- Evidence (supports or challenges a claim) -- ============================================================ CREATE TABLE IF NOT EXISTS evidence ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), rid TEXT UNIQUE NOT NULL, claim_id UUID NOT NULL REFERENCES claims(id) ON DELETE CASCADE, relation TEXT NOT NULL CHECK (relation IN ('supports', 'challenges')), body TEXT NOT NULL, provenance JSONB NOT NULL DEFAULT '{}', embedding vector(1024), created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_evidence_claim ON evidence (claim_id); CREATE INDEX IF NOT EXISTS idx_evidence_relation ON evidence (relation); -- ============================================================ -- Attestations (endorse/dispute/abstain on a claim) -- ============================================================ CREATE TABLE IF NOT EXISTS attestations ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), rid TEXT UNIQUE NOT NULL, claim_id UUID NOT NULL REFERENCES claims(id) ON DELETE CASCADE, attester_rid TEXT NOT NULL, verdict TEXT NOT NULL CHECK (verdict IN ('endorse', 'dispute', 'abstain')), strength FLOAT NOT NULL DEFAULT 1.0, reasoning TEXT DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (claim_id, attester_rid) ); CREATE INDEX IF NOT EXISTS idx_attestations_claim ON attestations (claim_id); CREATE INDEX IF NOT EXISTS idx_attestations_attester ON attestations (attester_rid); -- ============================================================ -- Claim strength (materialized view) -- ============================================================ CREATE MATERIALIZED VIEW IF NOT EXISTS claim_strength AS SELECT c.id AS claim_id, c.rid AS claim_rid, c.status, c.confidence, COUNT(DISTINCT CASE WHEN a.verdict = 'endorse' THEN a.id END) AS endorse_count, COUNT(DISTINCT CASE WHEN a.verdict = 'dispute' THEN a.id END) AS dispute_count, COUNT(DISTINCT CASE WHEN a.verdict = 'abstain' THEN a.id END) AS abstain_count, COUNT(DISTINCT CASE WHEN e.relation = 'supports' THEN e.id END) AS supporting_evidence, COUNT(DISTINCT CASE WHEN e.relation = 'challenges' THEN e.id END) AS challenging_evidence, COALESCE( (COUNT(DISTINCT CASE WHEN a.verdict = 'endorse' THEN a.id END)::float - COUNT(DISTINCT CASE WHEN a.verdict = 'dispute' THEN a.id END)::float) / NULLIF(COUNT(DISTINCT a.id)::float, 0), 0 ) AS net_sentiment, GREATEST( MAX(a.created_at), MAX(e.created_at), c.created_at ) AS last_activity FROM claims c LEFT JOIN attestations a ON a.claim_id = c.id LEFT JOIN evidence e ON e.claim_id = c.id GROUP BY c.id, c.rid, c.status, c.confidence; CREATE UNIQUE INDEX IF NOT EXISTS idx_claim_strength_id ON claim_strength (claim_id); -- ============================================================ -- Intents (need/offer/possibility) -- ============================================================ CREATE TABLE IF NOT EXISTS intents ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), rid TEXT UNIQUE NOT NULL, publisher_rid TEXT NOT NULL, title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', intent_type TEXT NOT NULL CHECK (intent_type IN ('need', 'offer', 'possibility')), capacity JSONB NOT NULL DEFAULT '{}', timing JSONB NOT NULL DEFAULT '{}', governance_fit TEXT[] DEFAULT '{}', state TEXT NOT NULL DEFAULT 'open' CHECK (state IN ('open', 'matched', 'committed', 'expired', 'withdrawn')), embedding vector(1024), metadata JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_intents_publisher ON intents (publisher_rid); CREATE INDEX IF NOT EXISTS idx_intents_type ON intents (intent_type); CREATE INDEX IF NOT EXISTS idx_intents_state ON intents (state); -- ============================================================ -- Intent matches (computed similarity pairs) -- ============================================================ CREATE TABLE IF NOT EXISTS intent_matches ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), intent_a_id UUID NOT NULL REFERENCES intents(id) ON DELETE CASCADE, intent_b_id UUID NOT NULL REFERENCES intents(id) ON DELETE CASCADE, similarity FLOAT NOT NULL, match_details JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (intent_a_id, intent_b_id), CHECK (intent_a_id < intent_b_id) ); CREATE INDEX IF NOT EXISTS idx_intent_matches_a ON intent_matches (intent_a_id); CREATE INDEX IF NOT EXISTS idx_intent_matches_b ON intent_matches (intent_b_id); -- ============================================================ -- Commitments (lifecycle state machine) -- ============================================================ CREATE TABLE IF NOT EXISTS commitments ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), rid TEXT UNIQUE NOT NULL, title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', state TEXT NOT NULL DEFAULT 'proposed' CHECK (state IN ('proposed', 'verified', 'active', 'evidence_linked', 'redeemed', 'disputed', 'resolved', 'cancelled')), proposer_rid TEXT NOT NULL, acceptor_rid TEXT, settlement_type TEXT DEFAULT 'attestation', terms JSONB NOT NULL DEFAULT '{}', metadata JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_commitments_state ON commitments (state); CREATE INDEX IF NOT EXISTS idx_commitments_proposer ON commitments (proposer_rid); CREATE INDEX IF NOT EXISTS idx_commitments_acceptor ON commitments (acceptor_rid); -- ============================================================ -- Commitment-Evidence links -- ============================================================ CREATE TABLE IF NOT EXISTS commitment_evidence ( commitment_id UUID NOT NULL REFERENCES commitments(id) ON DELETE CASCADE, evidence_id UUID NOT NULL REFERENCES evidence(id) ON DELETE CASCADE, linked_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (commitment_id, evidence_id) );