-- Chat-side pin of the agent's latest pushed context snapshot -- (workspace_agent_context_snapshots). Written by hydration (chat -- create and agent push) and the dirty fan-out, and re-pinned by the -- refresh endpoint. These columns are dark plumbing: they do not feed -- prompt building and the per-turn context pull is unchanged. They are -- read by drift detection and the refresh endpoint only. ALTER TABLE chats ADD COLUMN context_aggregate_hash bytea, ADD COLUMN context_dirty_since timestamptz, ADD COLUMN context_dirty_resources jsonb, ADD COLUMN context_error text NOT NULL DEFAULT ''; COMMENT ON COLUMN chats.context_aggregate_hash IS 'Aggregate hash of the agent context snapshot this chat is pinned to. NULL until first hydrated; compared against the agent''s latest snapshot hash to detect drift.'; COMMENT ON COLUMN chats.context_dirty_since IS 'Set when an agent push changes the pinned hash; cleared on refresh. NULL means clean.'; COMMENT ON COLUMN chats.context_dirty_resources IS 'Deterministic prefix of resources that changed since the pinned hash. Reserved for the dirty diff; left NULL until the UI phase populates it.'; COMMENT ON COLUMN chats.context_error IS 'Snapshot-level error copied from the pinned snapshot (count cap exceeded, watcher degraded, etc.). Empty when healthy.'; -- Refresh chats_expanded to include the new chat columns. The gentest -- TestViewSubsetChat requires every chats column to appear in the view. -- Drop and recreate because a view cannot have columns inserted in the -- middle of its column list. DROP VIEW IF EXISTS chats_expanded; CREATE VIEW chats_expanded AS SELECT c.id, c.owner_id, c.workspace_id, c.title, c.status, c.worker_id, c.started_at, c.heartbeat_at, c.created_at, c.updated_at, c.parent_chat_id, c.root_chat_id, c.last_model_config_id, c.archived, c.last_error, c.mode, c.mcp_server_ids, c.labels, c.build_id, c.agent_id, c.pin_order, c.last_read_message_id, c.last_injected_context, c.dynamic_tools, c.organization_id, c.plan_mode, c.client_type, c.last_turn_summary, c.snapshot_version, c.history_version, c.queue_version, c.generation_attempt, c.retry_state, c.retry_state_version, c.runner_id, c.requires_action_deadline_at, COALESCE(root.user_acl, c.user_acl) AS user_acl, COALESCE(root.group_acl, c.group_acl) AS group_acl, owner.username AS owner_username, owner.name AS owner_name, c.context_aggregate_hash, c.context_dirty_since, c.context_dirty_resources, c.context_error FROM ((chats c LEFT JOIN chats root ON ((root.id = COALESCE(c.root_chat_id, c.parent_chat_id)))) JOIN visible_users owner ON ((owner.id = c.owner_id)));