fix(gate-b): fresh-db install path - conditional guards on plugin-table migrations + dual-path convergence migrations
Check Cross-Plugin Imports / check (push) Has been cancelled

This commit is contained in:
Agent Zero
2026-08-23 21:36:56 +02:00
parent e3fb4728d7
commit ad7c763e59
24 changed files with 433 additions and 116 deletions
@@ -0,0 +1,10 @@
-- Dual-path convergence (Gate B): add compliance columns that Alembic
-- migration 0119 adds on the core path. Idempotent so both install paths
-- converge to the identical schema.
ALTER TABLE ai_providers ADD COLUMN IF NOT EXISTS region VARCHAR(20) NOT NULL DEFAULT 'unknown';
ALTER TABLE ai_providers ADD COLUMN IF NOT EXISTS hosting_type VARCHAR(30) NOT NULL DEFAULT 'cloud';
ALTER TABLE ai_providers ADD COLUMN IF NOT EXISTS dpa_status VARCHAR(20) NOT NULL DEFAULT 'none';
ALTER TABLE ai_providers ADD COLUMN IF NOT EXISTS retention_policy TEXT NOT NULL DEFAULT '';
ALTER TABLE ai_providers ADD COLUMN IF NOT EXISTS training_on_customer_data BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE ai_providers ADD COLUMN IF NOT EXISTS transfer_notice TEXT NOT NULL DEFAULT '';
ALTER TABLE ai_providers ADD COLUMN IF NOT EXISTS allowed_data_classes JSONB NOT NULL DEFAULT '[]'::jsonb;
+1 -1
View File
@@ -42,7 +42,7 @@ class AIAssistantPlugin(BasePlugin):
),
],
events=[],
migrations=["0001_initial.sql", "0002_folders_attachments.sql"],
migrations=["0001_initial.sql", "0002_folders_attachments.sql", "0003_sort_order.sql", "0004_compliance_fields.sql"],
permissions=[
"ai:read",
"ai:write",
@@ -0,0 +1,31 @@
-- Dual-path convergence (Gate B): create the ReAct step-tracking table
-- that Alembic migration 0121 creates on the core path, add the Phase-F
-- columns from 0122, and apply the RLS policy from 0129/0136. Idempotent
-- so both install paths converge to the identical schema.
CREATE TABLE IF NOT EXISTS automation_agent_run_steps (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
agent_run_id UUID NOT NULL REFERENCES automation_agent_runs(id) ON DELETE CASCADE,
step_number INTEGER NOT NULL,
thought TEXT,
action VARCHAR(255),
action_input JSONB,
observation TEXT,
cost_usd FLOAT NOT NULL DEFAULT 0.0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_agent_run_steps_run ON automation_agent_run_steps(tenant_id, agent_run_id);
ALTER TABLE automation_agent_definitions ADD COLUMN IF NOT EXISTS temperature FLOAT NOT NULL DEFAULT 0.3;
ALTER TABLE automation_agent_definitions ADD COLUMN IF NOT EXISTS max_tokens INTEGER NOT NULL DEFAULT 1000;
ALTER TABLE automation_agent_definitions ADD COLUMN IF NOT EXISTS max_steps INTEGER NOT NULL DEFAULT 20;
ALTER TABLE automation_agent_definitions ADD COLUMN IF NOT EXISTS trace_mode VARCHAR(20) NOT NULL DEFAULT 'standard';
ALTER TABLE automation_agent_definitions ADD COLUMN IF NOT EXISTS skill_ids JSONB NOT NULL DEFAULT '[]'::jsonb;
ALTER TABLE automation_agent_definitions ADD COLUMN IF NOT EXISTS trigger_config JSONB NOT NULL DEFAULT '{}'::jsonb;
ALTER TABLE automation_agent_definitions ADD COLUMN IF NOT EXISTS ai_use_case_metadata JSONB NOT NULL DEFAULT '{}'::jsonb;
-- RLS matching migrations 0129 + 0136 (current_tenant_id variant)
ALTER TABLE automation_agent_run_steps ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS tenant_isolation ON automation_agent_run_steps;
CREATE POLICY tenant_isolation ON automation_agent_run_steps
USING (tenant_id::text = current_setting('app.current_tenant_id', true));
+1 -1
View File
@@ -62,7 +62,7 @@ class AutomationPlugin(BasePlugin):
"mail.received",
"workflow.timeout",
],
migrations=["0001_initial.sql", "0002_agent_subtasks.sql", "0003_skill_definitions.sql"],
migrations=["0001_initial.sql", "0002_agent_subtasks.sql", "0003_skill_definitions.sql", "0004_run_steps_phase_f.sql"],
permissions=[
"automation:read",
"automation:write",
+7 -3
View File
@@ -25,7 +25,7 @@ class KnowledgePlugin(BasePlugin):
"""Register event-driven extraction hooks on activation."""
await super().on_activate(db, service_container, event_bus)
try:
from app.core.hooks import register_action
from app.core.hooks import get_hook_registry
from app.plugins.builtins.knowledge.services import extract_knowledge
async def on_wiki_create(*args, **kwargs):
article_id = kwargs.get("article_id") or kwargs.get("entity_id")
@@ -41,7 +41,9 @@ class KnowledgePlugin(BasePlugin):
source_type="wiki_article", source_id=uuid.UUID(str(article_id)),
source_title=title, source_text=content,
)
register_action("wiki.article.created", on_wiki_create, priority=20, owner_tag="knowledge")
get_hook_registry().register_action(
"wiki.article.created", on_wiki_create, priority=20, owner_tag="knowledge"
)
# H-DATA-LIFE: Re-extract when wiki article is updated
async def on_wiki_update(*args, **kwargs):
article_id = kwargs.get("article_id") or kwargs.get("entity_id")
@@ -57,7 +59,9 @@ class KnowledgePlugin(BasePlugin):
source_type="wiki_article", source_id=uuid.UUID(str(article_id)),
source_title=title, source_text=content,
)
register_action("wiki.article.updated", on_wiki_update, priority=20, owner_tag="knowledge")
get_hook_registry().register_action(
"wiki.article.updated", on_wiki_update, priority=20, owner_tag="knowledge"
)
logger.info("Registered knowledge extraction hooks")
except Exception:
logger.exception("Failed to register knowledge hooks")
@@ -0,0 +1,7 @@
-- Dual-path convergence (Gate B): add columns that Alembic migrations
-- 0120 (is_system) and 0140 (folder_id) add on the core path. Idempotent
-- so both install paths converge to the identical schema.
ALTER TABLE comm_conversations ADD COLUMN IF NOT EXISTS is_system BOOLEAN NOT NULL DEFAULT FALSE;
CREATE INDEX IF NOT EXISTS ix_comm_conversations_tenant_system ON comm_conversations(tenant_id, is_system);
ALTER TABLE comm_conversations ADD COLUMN IF NOT EXISTS folder_id UUID;
CREATE INDEX IF NOT EXISTS ix_comm_conversations_folder ON comm_conversations(folder_id);
+1 -1
View File
@@ -39,7 +39,7 @@ class KommunikationPlugin(BasePlugin):
"participant.left",
"reaction.added",
],
migrations=["0001_initial.sql"],
migrations=["0001_initial.sql", "0002_system_channel_folders.sql"],
permissions=[
"comm:read",
"comm:write",
@@ -0,0 +1,5 @@
-- Dual-path convergence (Gate B): add the folder_id column that Alembic
-- migration 0139 adds on the core path. Idempotent so both install paths
-- converge to the identical schema.
ALTER TABLE report_templates ADD COLUMN IF NOT EXISTS folder_id UUID;
CREATE INDEX IF NOT EXISTS ix_report_templates_folder ON report_templates(folder_id);
@@ -24,7 +24,7 @@ class ReportGeneratorPlugin(BasePlugin):
),
],
events=["report.requested", "report.generated"],
migrations=["0001_initial.sql"],
migrations=["0001_initial.sql", "0002_reports_folder_id.sql"],
permissions=["reports:read", "reports:generate", "reports:manage_templates"],
menu_items=[
FrontendMenuItem(label_key='nav.reports', label='Berichte', path='/reports', icon='BarChart3', order=70),
@@ -0,0 +1,18 @@
-- Dual-path convergence (Gate B): apply the tag tree structure that
-- Alembic migration 0138 adds on the core path. Idempotent so both install
-- paths converge to the identical schema.
ALTER TABLE tags ADD COLUMN IF NOT EXISTS parent_id UUID;
CREATE INDEX IF NOT EXISTS ix_tags_parent ON tags(parent_id);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'fk_tags_parent_id'
) THEN
ALTER TABLE tags ADD CONSTRAINT fk_tags_parent_id
FOREIGN KEY (parent_id) REFERENCES tags(id) ON DELETE SET NULL;
END IF;
END $$;
ALTER TABLE tags ADD COLUMN IF NOT EXISTS applicable_to JSONB;
ALTER TABLE tags ADD COLUMN IF NOT EXISTS icon VARCHAR(50);
+1 -1
View File
@@ -23,7 +23,7 @@ class TagsPlugin(BasePlugin):
),
],
events=[],
migrations=["0001_initial.sql", "0002_add_deleted_at.sql"],
migrations=["0001_initial.sql", "0002_add_deleted_at.sql", "0003_tree_structure.sql"],
permissions=[
"tags:read",
"tags:write",
@@ -0,0 +1,31 @@
-- Dual-path convergence (Gate B): apply the unified task system that
-- Alembic migrations 0124 (columns/indexes/FK) and 0127 (drop legacy FK)
-- create on the core path. Idempotent so both install paths converge to
-- the identical schema. The end state has NO foreign key on contact_id.
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS assignee_type VARCHAR(20) NOT NULL DEFAULT 'user';
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS assignee_id UUID;
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS entity_type VARCHAR(80);
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS entity_id UUID;
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS creator_type VARCHAR(20) NOT NULL DEFAULT 'user';
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS creator_id UUID;
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS parent_task_id UUID;
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS depends_on JSONB NOT NULL DEFAULT '[]'::jsonb;
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS task_type VARCHAR(30) NOT NULL DEFAULT 'todo';
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS success_criteria JSONB;
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS target_date TIMESTAMPTZ;
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS progress INTEGER NOT NULL DEFAULT 0;
CREATE INDEX IF NOT EXISTS ix_tasks_tenant_entity ON tasks(tenant_id, entity_type, entity_id);
CREATE INDEX IF NOT EXISTS ix_tasks_tenant_assignee ON tasks(tenant_id, assignee_type, assignee_id);
CREATE INDEX IF NOT EXISTS ix_tasks_tenant_parent ON tasks(tenant_id, parent_task_id);
CREATE INDEX IF NOT EXISTS ix_tasks_tenant_type ON tasks(tenant_id, task_type);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'fk_tasks_parent_task_id'
) THEN
ALTER TABLE tasks ADD CONSTRAINT fk_tasks_parent_task_id
FOREIGN KEY (parent_task_id) REFERENCES tasks(id) ON DELETE CASCADE;
END IF;
END $$;
+1 -1
View File
@@ -29,7 +29,7 @@ class TasksPlugin(BasePlugin):
),
],
events=[],
migrations=["0001_initial.sql"],
migrations=["0001_initial.sql", "0002_unified_task_system.sql"],
permissions=[
"tasks:read",
"tasks:write",