feat(governance): Governance Engine MVP implementation
- Backend: - Migration 032: agent_gov_level, status, incidents, permissions tables - Domain types for governance layer - Permission Engine with all governance checks - Governance Service (promote/demote/roles) - Revocation Service (revoke/suspend/reinstate) - Audit Service (events filtering and stats) - Incidents Service (create/assign/escalate/resolve) - REST API routes for governance, audit, incidents - Frontend: - TypeScript types for governance - API clients for governance, audit, incidents - GovernanceLevelBadge component - CityGovernancePanel component - AuditDashboard component - IncidentsList component with detail modal Based on: Agent_Governance_Protocol_v1.md
This commit is contained in:
257
migrations/032_governance_engine.sql
Normal file
257
migrations/032_governance_engine.sql
Normal file
@@ -0,0 +1,257 @@
|
||||
-- Migration 032: Governance Engine
|
||||
-- Purpose: Implement Governance Layer for DAARION.city
|
||||
-- Based on: docs/foundation/Agent_Governance_Protocol_v1.md
|
||||
-- Date: 2025-11-29
|
||||
-- Status: MVP Feature
|
||||
|
||||
-- ============================================================================
|
||||
-- 0. ENUM TYPES
|
||||
-- ============================================================================
|
||||
|
||||
-- Agent governance level (0-7 hierarchy)
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'agent_gov_level') THEN
|
||||
CREATE TYPE agent_gov_level AS ENUM (
|
||||
'guest', -- Level 0
|
||||
'personal', -- Level 1
|
||||
'member', -- Level 2
|
||||
'worker', -- Level 3
|
||||
'core_team', -- Level 4
|
||||
'orchestrator', -- Level 5
|
||||
'district_lead', -- Level 6
|
||||
'city_governance' -- Level 7
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Agent status
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'agent_status') THEN
|
||||
CREATE TYPE agent_status AS ENUM ('active', 'suspended', 'revoked');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Revocation type
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'revocation_type') THEN
|
||||
CREATE TYPE revocation_type AS ENUM ('soft', 'hard', 'shadow');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Incident status
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'incident_status') THEN
|
||||
CREATE TYPE incident_status AS ENUM ('open', 'in_progress', 'resolved', 'closed');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Incident priority
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'incident_priority') THEN
|
||||
CREATE TYPE incident_priority AS ENUM ('low', 'medium', 'high', 'critical');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Incident escalation level
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'escalation_level') THEN
|
||||
CREATE TYPE escalation_level AS ENUM ('microdao', 'district', 'city');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Target scope type for incidents
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'target_scope_type') THEN
|
||||
CREATE TYPE target_scope_type AS ENUM ('city', 'district', 'microdao', 'room', 'node', 'agent');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Permission action
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'permission_action') THEN
|
||||
CREATE TYPE permission_action AS ENUM ('read', 'write', 'moderate', 'admin', 'superadmin');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ============================================================================
|
||||
-- 1. AGENTS TABLE UPDATE - Governance Fields
|
||||
-- ============================================================================
|
||||
|
||||
-- Add governance fields to agents
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS gov_level agent_gov_level DEFAULT 'personal';
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS status agent_status DEFAULT 'active';
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS revoked_at TIMESTAMPTZ;
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS revoked_by TEXT;
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS revocation_reason TEXT;
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS revocation_type revocation_type;
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_agents_gov_level ON agents(gov_level);
|
||||
CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_agents_revoked ON agents(revoked_at) WHERE revoked_at IS NOT NULL;
|
||||
|
||||
-- Migrate existing agent_role to gov_level
|
||||
UPDATE agents
|
||||
SET gov_level = 'orchestrator'::agent_gov_level
|
||||
WHERE agent_role = 'orchestrator' AND gov_level = 'personal';
|
||||
|
||||
-- Set city governance agents
|
||||
UPDATE agents
|
||||
SET gov_level = 'city_governance'::agent_gov_level
|
||||
WHERE id IN ('daarwizz', 'dario', 'daria');
|
||||
|
||||
-- ============================================================================
|
||||
-- 2. INCIDENTS TABLE
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS incidents (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
created_by_dais_id TEXT NOT NULL,
|
||||
target_scope_type target_scope_type NOT NULL,
|
||||
target_scope_id TEXT NOT NULL,
|
||||
status incident_status NOT NULL DEFAULT 'open',
|
||||
priority incident_priority NOT NULL DEFAULT 'medium',
|
||||
assigned_to_dais_id TEXT,
|
||||
escalation_level escalation_level NOT NULL DEFAULT 'microdao',
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
resolution TEXT,
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
resolved_at TIMESTAMPTZ,
|
||||
closed_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_incidents_status ON incidents(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_incidents_priority ON incidents(priority);
|
||||
CREATE INDEX IF NOT EXISTS idx_incidents_escalation ON incidents(escalation_level);
|
||||
CREATE INDEX IF NOT EXISTS idx_incidents_created_by ON incidents(created_by_dais_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_incidents_assigned ON incidents(assigned_to_dais_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_incidents_target ON incidents(target_scope_type, target_scope_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_incidents_open ON incidents(status, priority) WHERE status IN ('open', 'in_progress');
|
||||
|
||||
-- ============================================================================
|
||||
-- 3. INCIDENT HISTORY TABLE
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS incident_history (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
incident_id UUID NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
|
||||
action TEXT NOT NULL, -- created, assigned, escalated, resolved, closed, comment
|
||||
actor_dais_id TEXT NOT NULL,
|
||||
old_value JSONB,
|
||||
new_value JSONB,
|
||||
comment TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_incident_history_incident ON incident_history(incident_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_incident_history_actor ON incident_history(actor_dais_id);
|
||||
|
||||
-- ============================================================================
|
||||
-- 4. PERMISSIONS TABLE
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permissions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
dais_id TEXT NOT NULL,
|
||||
target_type TEXT NOT NULL, -- room, microdao, node, district, city
|
||||
target_id TEXT NOT NULL,
|
||||
action permission_action NOT NULL,
|
||||
granted_by TEXT NOT NULL,
|
||||
expires_at TIMESTAMPTZ,
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE(dais_id, target_type, target_id, action)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_permissions_dais ON permissions(dais_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_permissions_target ON permissions(target_type, target_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_permissions_valid ON permissions(dais_id)
|
||||
WHERE expires_at IS NULL OR expires_at > now();
|
||||
|
||||
-- ============================================================================
|
||||
-- 5. REVOCATIONS TABLE (Audit trail for revocations)
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agent_revocations (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
agent_id TEXT NOT NULL REFERENCES agents(id),
|
||||
dais_id TEXT,
|
||||
revoked_by TEXT NOT NULL,
|
||||
revocation_type revocation_type NOT NULL,
|
||||
reason TEXT NOT NULL,
|
||||
scope TEXT NOT NULL, -- city, district:<id>, microdao:<id>
|
||||
keys_invalidated BOOLEAN NOT NULL DEFAULT true,
|
||||
wallet_disabled BOOLEAN NOT NULL DEFAULT true,
|
||||
room_access_revoked BOOLEAN NOT NULL DEFAULT true,
|
||||
node_privileges_removed BOOLEAN NOT NULL DEFAULT true,
|
||||
assignments_terminated BOOLEAN NOT NULL DEFAULT true,
|
||||
reversible BOOLEAN NOT NULL DEFAULT true,
|
||||
reversed_at TIMESTAMPTZ,
|
||||
reversed_by TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_revocations_agent ON agent_revocations(agent_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_revocations_dais ON agent_revocations(dais_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_revocations_type ON agent_revocations(revocation_type);
|
||||
|
||||
-- ============================================================================
|
||||
-- 6. UPDATE EVENT_OUTBOX WITH NEW GOVERNANCE EVENTS
|
||||
-- ============================================================================
|
||||
|
||||
-- Add actor_id column to event_outbox for audit
|
||||
ALTER TABLE event_outbox ADD COLUMN IF NOT EXISTS actor_id TEXT;
|
||||
ALTER TABLE event_outbox ADD COLUMN IF NOT EXISTS target_id TEXT;
|
||||
ALTER TABLE event_outbox ADD COLUMN IF NOT EXISTS scope TEXT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_outbox_actor ON event_outbox(actor_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_outbox_target ON event_outbox(target_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_outbox_scope ON event_outbox(scope);
|
||||
|
||||
-- ============================================================================
|
||||
-- 7. DAIS KEYS - Add revoked flag
|
||||
-- ============================================================================
|
||||
|
||||
ALTER TABLE dais_keys ADD COLUMN IF NOT EXISTS revoked BOOLEAN DEFAULT false;
|
||||
ALTER TABLE dais_keys ADD COLUMN IF NOT EXISTS revoked_reason TEXT;
|
||||
ALTER TABLE dais_keys ADD COLUMN IF NOT EXISTS revoked_by TEXT;
|
||||
|
||||
-- Migrate existing revoked_at to revoked
|
||||
UPDATE dais_keys SET revoked = true WHERE revoked_at IS NOT NULL AND revoked = false;
|
||||
|
||||
-- ============================================================================
|
||||
-- 8. COMMENTS
|
||||
-- ============================================================================
|
||||
|
||||
COMMENT ON TABLE incidents IS 'Incident tracking for governance escalation';
|
||||
COMMENT ON TABLE incident_history IS 'Audit trail for incident changes';
|
||||
COMMENT ON TABLE permissions IS 'Explicit permissions for DAIS identities';
|
||||
COMMENT ON TABLE agent_revocations IS 'Audit trail for agent revocations';
|
||||
|
||||
COMMENT ON COLUMN agents.gov_level IS 'Governance level: 0=guest to 7=city_governance';
|
||||
COMMENT ON COLUMN agents.status IS 'Agent status: active, suspended, or revoked';
|
||||
COMMENT ON COLUMN agents.revoked_at IS 'Timestamp when agent was revoked';
|
||||
COMMENT ON COLUMN agents.revocation_type IS 'Type of revocation: soft, hard, or shadow';
|
||||
|
||||
COMMENT ON COLUMN incidents.escalation_level IS 'Current escalation: microdao → district → city';
|
||||
COMMENT ON COLUMN incidents.target_scope_type IS 'What the incident is about: city, district, microdao, room, node, agent';
|
||||
|
||||
-- ============================================================================
|
||||
-- 9. SEED DATA - City Governance Agents
|
||||
-- ============================================================================
|
||||
|
||||
-- Ensure city governance agents have correct level
|
||||
UPDATE agents
|
||||
SET gov_level = 'city_governance'::agent_gov_level,
|
||||
status = 'active'::agent_status
|
||||
WHERE id IN ('daarwizz', 'dario', 'daria');
|
||||
|
||||
-- ============================================================================
|
||||
-- DONE
|
||||
-- ============================================================================
|
||||
|
||||
SELECT 'Migration 032 completed: Governance Engine' as result;
|
||||
|
||||
Reference in New Issue
Block a user