-- 018_tasks.up.sql -- Elevate a chat session into a "task": a goal-structured unit of work with a -- lifecycle status, an outcome, and a one-line summary — the first-class object -- the task board and the live context panel render. See -- plans/2026-07-11-goal-oriented-chat-control-panel.md. -- -- entity_id links the session to its OWN entity (type 'task', registered in -- seeds/ontology.yaml) so knowledge notes and involved-entity edges hang off -- the existing relationships graph unchanged — get_relations and -- get_entity_knowledge just work. Intentionally no hard FK (mirrors 017's -- decoupling): a race between task-entity creation and the session insert must -- not be able to break the session. ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS goal TEXT NOT NULL DEFAULT ''; ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS status TEXT NOT NULL DEFAULT 'active'; ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS outcome TEXT; ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS summary TEXT NOT NULL DEFAULT ''; ALTER TABLE agent_sessions ADD COLUMN IF NOT EXISTS entity_id UUID; -- Ordered plan steps. A step is a described unit of work that maps to a -- run/request_execution call (no fixed step enum, per general-gated-execution). -- execution_id is the gated action a step runs, if any; its terminal status -- auto-closes the step server-side. CREATE TABLE IF NOT EXISTS session_plan_steps ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), session_id UUID NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE, seq INT NOT NULL, title TEXT NOT NULL, detail TEXT NOT NULL DEFAULT '', status TEXT NOT NULL DEFAULT 'pending', -- pending | running | done | failed | skipped | blocked execution_id UUID, target_slug TEXT, started_at TIMESTAMPTZ, finished_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_plan_steps_session ON session_plan_steps(session_id, seq); -- Structured decisions the agent surfaces to the operator mid-task. context -- carries { entities:[], options:[], why:"" } for the pinned question card. CREATE TABLE IF NOT EXISTS session_questions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), session_id UUID NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE, prompt TEXT NOT NULL, context JSONB NOT NULL DEFAULT '{}', status TEXT NOT NULL DEFAULT 'open', -- open | answered | dismissed answer TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), answered_at TIMESTAMPTZ ); CREATE INDEX IF NOT EXISTS idx_questions_session_open ON session_questions(session_id) WHERE status = 'open';