distributable, please
Some checks failed
CI / Rustfmt (push) Successful in 22s
CI / Cargo Audit & Deny (push) Successful in 36s
CI / Security Blocking Checks (push) Successful in 6s
CI / Web Blocking Checks (push) Successful in 53s
CI / Web Advisory Checks (push) Successful in 34s
Publish Images / Resolve Publish Metadata (push) Successful in 1s
CI / Security Advisory Checks (push) Successful in 38s
CI / Clippy (push) Successful in 2m7s
Publish Images / Publish Docker Dist Bundle (push) Failing after 19s
Publish Images / Publish web (amd64) (push) Successful in 49s
Publish Images / Publish web (arm64) (push) Successful in 3m31s
CI / Tests (push) Successful in 8m48s
Publish Images / Build Rust Bundles (amd64) (push) Successful in 12m42s
Publish Images / Build Rust Bundles (arm64) (push) Successful in 12m19s
Publish Images / Publish agent (amd64) (push) Successful in 26s
Publish Images / Publish api (amd64) (push) Successful in 38s
Publish Images / Publish notifier (amd64) (push) Successful in 42s
Publish Images / Publish executor (amd64) (push) Successful in 46s
Publish Images / Publish agent (arm64) (push) Successful in 56s
Publish Images / Publish api (arm64) (push) Successful in 1m52s
Publish Images / Publish executor (arm64) (push) Successful in 2m2s
Publish Images / Publish notifier (arm64) (push) Successful in 2m3s
Publish Images / Publish manifest attune/agent (push) Successful in 6s
Publish Images / Publish manifest attune/api (push) Successful in 11s
Publish Images / Publish manifest attune/executor (push) Successful in 10s
Publish Images / Publish manifest attune/notifier (push) Successful in 8s
Publish Images / Publish manifest attune/web (push) Successful in 8s

This commit is contained in:
2026-03-26 12:26:23 -05:00
parent da8055cb79
commit 938c271ff5
72 changed files with 14798 additions and 6 deletions

View File

@@ -0,0 +1,428 @@
-- Migration: LISTEN/NOTIFY Triggers
-- Description: Consolidated PostgreSQL LISTEN/NOTIFY triggers for real-time event notifications
-- Version: 20250101000008
-- ============================================================================
-- EXECUTION CHANGE NOTIFICATION
-- ============================================================================
-- Function to notify on execution creation
CREATE OR REPLACE FUNCTION notify_execution_created()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
enforcement_rule_ref TEXT;
enforcement_trigger_ref TEXT;
BEGIN
-- Lookup enforcement details if this execution is linked to an enforcement
IF NEW.enforcement IS NOT NULL THEN
SELECT rule_ref, trigger_ref
INTO enforcement_rule_ref, enforcement_trigger_ref
FROM enforcement
WHERE id = NEW.enforcement;
END IF;
payload := json_build_object(
'entity_type', 'execution',
'entity_id', NEW.id,
'id', NEW.id,
'action_id', NEW.action,
'action_ref', NEW.action_ref,
'status', NEW.status,
'enforcement', NEW.enforcement,
'rule_ref', enforcement_rule_ref,
'trigger_ref', enforcement_trigger_ref,
'parent', NEW.parent,
'result', NEW.result,
'started_at', NEW.started_at,
'workflow_task', NEW.workflow_task,
'created', NEW.created,
'updated', NEW.updated
);
PERFORM pg_notify('execution_created', payload::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Function to notify on execution status changes
CREATE OR REPLACE FUNCTION notify_execution_status_changed()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
enforcement_rule_ref TEXT;
enforcement_trigger_ref TEXT;
BEGIN
-- Only notify on updates, not inserts
IF TG_OP = 'UPDATE' AND OLD.status IS DISTINCT FROM NEW.status THEN
-- Lookup enforcement details if this execution is linked to an enforcement
IF NEW.enforcement IS NOT NULL THEN
SELECT rule_ref, trigger_ref
INTO enforcement_rule_ref, enforcement_trigger_ref
FROM enforcement
WHERE id = NEW.enforcement;
END IF;
payload := json_build_object(
'entity_type', 'execution',
'entity_id', NEW.id,
'id', NEW.id,
'action_id', NEW.action,
'action_ref', NEW.action_ref,
'status', NEW.status,
'old_status', OLD.status,
'enforcement', NEW.enforcement,
'rule_ref', enforcement_rule_ref,
'trigger_ref', enforcement_trigger_ref,
'parent', NEW.parent,
'result', NEW.result,
'started_at', NEW.started_at,
'workflow_task', NEW.workflow_task,
'created', NEW.created,
'updated', NEW.updated
);
PERFORM pg_notify('execution_status_changed', payload::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on execution table for creation
CREATE TRIGGER execution_created_notify
AFTER INSERT ON execution
FOR EACH ROW
EXECUTE FUNCTION notify_execution_created();
-- Trigger on execution table for status changes
CREATE TRIGGER execution_status_changed_notify
AFTER UPDATE ON execution
FOR EACH ROW
EXECUTE FUNCTION notify_execution_status_changed();
COMMENT ON FUNCTION notify_execution_created() IS 'Sends execution creation notifications via PostgreSQL LISTEN/NOTIFY';
COMMENT ON FUNCTION notify_execution_status_changed() IS 'Sends execution status change notifications via PostgreSQL LISTEN/NOTIFY';
-- ============================================================================
-- EVENT CREATION NOTIFICATION
-- ============================================================================
-- Function to notify on event creation
CREATE OR REPLACE FUNCTION notify_event_created()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
payload := json_build_object(
'entity_type', 'event',
'entity_id', NEW.id,
'id', NEW.id,
'trigger', NEW.trigger,
'trigger_ref', NEW.trigger_ref,
'source', NEW.source,
'source_ref', NEW.source_ref,
'rule', NEW.rule,
'rule_ref', NEW.rule_ref,
'payload', NEW.payload,
'created', NEW.created
);
PERFORM pg_notify('event_created', payload::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on event table
CREATE TRIGGER event_created_notify
AFTER INSERT ON event
FOR EACH ROW
EXECUTE FUNCTION notify_event_created();
COMMENT ON FUNCTION notify_event_created() IS 'Sends event creation notifications via PostgreSQL LISTEN/NOTIFY';
-- ============================================================================
-- ENFORCEMENT CHANGE NOTIFICATION
-- ============================================================================
-- Function to notify on enforcement creation
CREATE OR REPLACE FUNCTION notify_enforcement_created()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
payload := json_build_object(
'entity_type', 'enforcement',
'entity_id', NEW.id,
'id', NEW.id,
'rule', NEW.rule,
'rule_ref', NEW.rule_ref,
'trigger_ref', NEW.trigger_ref,
'event', NEW.event,
'status', NEW.status,
'condition', NEW.condition,
'conditions', NEW.conditions,
'config', NEW.config,
'payload', NEW.payload,
'created', NEW.created,
'resolved_at', NEW.resolved_at
);
PERFORM pg_notify('enforcement_created', payload::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on enforcement table
CREATE TRIGGER enforcement_created_notify
AFTER INSERT ON enforcement
FOR EACH ROW
EXECUTE FUNCTION notify_enforcement_created();
COMMENT ON FUNCTION notify_enforcement_created() IS 'Sends enforcement creation notifications via PostgreSQL LISTEN/NOTIFY';
-- Function to notify on enforcement status changes
CREATE OR REPLACE FUNCTION notify_enforcement_status_changed()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
-- Only notify on updates when status actually changed
IF TG_OP = 'UPDATE' AND OLD.status IS DISTINCT FROM NEW.status THEN
payload := json_build_object(
'entity_type', 'enforcement',
'entity_id', NEW.id,
'id', NEW.id,
'rule', NEW.rule,
'rule_ref', NEW.rule_ref,
'trigger_ref', NEW.trigger_ref,
'event', NEW.event,
'status', NEW.status,
'old_status', OLD.status,
'condition', NEW.condition,
'conditions', NEW.conditions,
'config', NEW.config,
'payload', NEW.payload,
'created', NEW.created,
'resolved_at', NEW.resolved_at
);
PERFORM pg_notify('enforcement_status_changed', payload::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on enforcement table for status changes
CREATE TRIGGER enforcement_status_changed_notify
AFTER UPDATE ON enforcement
FOR EACH ROW
EXECUTE FUNCTION notify_enforcement_status_changed();
COMMENT ON FUNCTION notify_enforcement_status_changed() IS 'Sends enforcement status change notifications via PostgreSQL LISTEN/NOTIFY';
-- ============================================================================
-- INQUIRY NOTIFICATIONS
-- ============================================================================
-- Function to notify on inquiry creation
CREATE OR REPLACE FUNCTION notify_inquiry_created()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
payload := json_build_object(
'entity_type', 'inquiry',
'entity_id', NEW.id,
'id', NEW.id,
'execution', NEW.execution,
'status', NEW.status,
'ttl', NEW.ttl,
'created', NEW.created
);
PERFORM pg_notify('inquiry_created', payload::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Function to notify on inquiry response
CREATE OR REPLACE FUNCTION notify_inquiry_responded()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
-- Only notify when status changes to 'responded'
IF TG_OP = 'UPDATE' AND NEW.status = 'responded' AND OLD.status != 'responded' THEN
payload := json_build_object(
'entity_type', 'inquiry',
'entity_id', NEW.id,
'id', NEW.id,
'execution', NEW.execution,
'status', NEW.status,
'response', NEW.response,
'updated', NEW.updated
);
PERFORM pg_notify('inquiry_responded', payload::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on inquiry table for creation
CREATE TRIGGER inquiry_created_notify
AFTER INSERT ON inquiry
FOR EACH ROW
EXECUTE FUNCTION notify_inquiry_created();
-- Trigger on inquiry table for responses
CREATE TRIGGER inquiry_responded_notify
AFTER UPDATE ON inquiry
FOR EACH ROW
EXECUTE FUNCTION notify_inquiry_responded();
COMMENT ON FUNCTION notify_inquiry_created() IS 'Sends inquiry creation notifications via PostgreSQL LISTEN/NOTIFY';
COMMENT ON FUNCTION notify_inquiry_responded() IS 'Sends inquiry response notifications via PostgreSQL LISTEN/NOTIFY';
-- ============================================================================
-- WORKFLOW EXECUTION NOTIFICATIONS
-- ============================================================================
-- Function to notify on workflow execution status changes
CREATE OR REPLACE FUNCTION notify_workflow_execution_status_changed()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
-- Only notify for workflow executions when status changes
IF TG_OP = 'UPDATE' AND NEW.is_workflow = true AND OLD.status IS DISTINCT FROM NEW.status THEN
payload := json_build_object(
'entity_type', 'execution',
'entity_id', NEW.id,
'id', NEW.id,
'action_ref', NEW.action_ref,
'status', NEW.status,
'old_status', OLD.status,
'workflow_def', NEW.workflow_def,
'parent', NEW.parent,
'created', NEW.created,
'updated', NEW.updated
);
PERFORM pg_notify('workflow_execution_status_changed', payload::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on execution table for workflow status changes
CREATE TRIGGER workflow_execution_status_changed_notify
AFTER UPDATE ON execution
FOR EACH ROW
WHEN (NEW.is_workflow = true)
EXECUTE FUNCTION notify_workflow_execution_status_changed();
COMMENT ON FUNCTION notify_workflow_execution_status_changed() IS 'Sends workflow execution status change notifications via PostgreSQL LISTEN/NOTIFY';
-- ============================================================================
-- ARTIFACT NOTIFICATIONS
-- ============================================================================
-- Function to notify on artifact creation
CREATE OR REPLACE FUNCTION notify_artifact_created()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
BEGIN
payload := json_build_object(
'entity_type', 'artifact',
'entity_id', NEW.id,
'id', NEW.id,
'ref', NEW.ref,
'type', NEW.type,
'visibility', NEW.visibility,
'name', NEW.name,
'execution', NEW.execution,
'scope', NEW.scope,
'owner', NEW.owner,
'content_type', NEW.content_type,
'size_bytes', NEW.size_bytes,
'created', NEW.created
);
PERFORM pg_notify('artifact_created', payload::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on artifact table for creation
CREATE TRIGGER artifact_created_notify
AFTER INSERT ON artifact
FOR EACH ROW
EXECUTE FUNCTION notify_artifact_created();
COMMENT ON FUNCTION notify_artifact_created() IS 'Sends artifact creation notifications via PostgreSQL LISTEN/NOTIFY';
-- Function to notify on artifact updates (progress appends, data changes)
CREATE OR REPLACE FUNCTION notify_artifact_updated()
RETURNS TRIGGER AS $$
DECLARE
payload JSON;
latest_percent DOUBLE PRECISION;
latest_message TEXT;
entry_count INTEGER;
BEGIN
-- Only notify on actual changes
IF TG_OP = 'UPDATE' THEN
-- Extract progress summary from data array if this is a progress artifact
IF NEW.type = 'progress' AND NEW.data IS NOT NULL AND jsonb_typeof(NEW.data) = 'array' THEN
entry_count := jsonb_array_length(NEW.data);
IF entry_count > 0 THEN
latest_percent := (NEW.data -> (entry_count - 1) ->> 'percent')::DOUBLE PRECISION;
latest_message := NEW.data -> (entry_count - 1) ->> 'message';
END IF;
END IF;
payload := json_build_object(
'entity_type', 'artifact',
'entity_id', NEW.id,
'id', NEW.id,
'ref', NEW.ref,
'type', NEW.type,
'visibility', NEW.visibility,
'name', NEW.name,
'execution', NEW.execution,
'scope', NEW.scope,
'owner', NEW.owner,
'content_type', NEW.content_type,
'size_bytes', NEW.size_bytes,
'progress_percent', latest_percent,
'progress_message', latest_message,
'progress_entries', entry_count,
'created', NEW.created,
'updated', NEW.updated
);
PERFORM pg_notify('artifact_updated', payload::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger on artifact table for updates
CREATE TRIGGER artifact_updated_notify
AFTER UPDATE ON artifact
FOR EACH ROW
EXECUTE FUNCTION notify_artifact_updated();
COMMENT ON FUNCTION notify_artifact_updated() IS 'Sends artifact update notifications via PostgreSQL LISTEN/NOTIFY (includes progress summary for progress-type artifacts)';