Ctrl K
ComunidadGuías…

docs/data-protection.es.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
---
source_sha: "bf339c9ea7e0"
---

# Protección de datos { #data-protection }

Dónde residen los datos personales en un deployment, qué sale de él y bajo qué
configuración, qué controles existen en el código con una prueba detrás y cuáles
siguen siendo incidencias abiertas. Escrito para quien responde a una revisión
de protección de datos de un deployment — un delegado de protección de datos, un
responsable de seguridad, un operador — y honesto sobre la diferencia entre lo
que el software puede hacer y lo que un deployment ha decidido de verdad.

!!! warning "Una página no es cumplimiento"

    Nada de lo que hay aquí es prueba de que un deployment cumpla el RGPD. La
    base de código se puede desplegar dentro de un entorno conforme; que uno
    *lo sea* depende de los providers configurados, de la retención decidida, de
    los acuerdos firmados y del operador que lo lleva. Cada una de esas
    condiciones aparece abajo como algo que hay que obtener y verificar, nunca
    como algo que se da por supuesto.

El inventario de capabilities incluye también el coding agent local seleccionable por conversación, aunque el spec publicado no tenga ese binding o use un sandbox. Esa fila describe una ruta posible, no demuestra que se haya utilizado.

Las exportaciones de datos personales incluyen nombres de archivo y parches de tareas de programación de las conversaciones exportadas; su JSON cuenta para el límite de tamaño comprobado previamente. Al terminar la pertenencia a una organización se eliminan las conexiones personales de programación en la misma transacción. Volver a unirse requiere una conexión nueva y consentimiento nuevo; no reactiva el permiso anterior.

La exportación de datos personales también incluye tableros privados de tareas, valores de registros, historial conservado y esquemas de columnas, además de consentimientos permanentes para acciones de rutinas. Estos datos JSON cuentan para el límite previo de exportación. Las tablas compartidas de proyectos, grupos y organizaciones no se incluyen solo porque la persona haya creado una tarea en ellas.

## Qué sale por defecto { #nothing-leaves-by-default }

Un deployment recién instalado lo guarda todo en su propio PostgreSQL y en su
propio disco, o en el almacenamiento de objetos con el que esté configurado. No
envía ningún prompt, conversación ni documento a ninguna parte. Cada salto al
exterior es una fila o un ajuste que alguien añade después: un perfil de modelo
que nombra un provider, una colección que elige un parser o un provider de
embeddings remoto (que entonces recibe los chunks de los documentos), un método
de búsqueda en un spec, un token de Logfire, un servidor MCP, un
bot de canal. Quita la fila y el salto desaparece.

Un informe está activado por defecto y no lleva contenido: el
[diagnóstico del deployment](#deployment-diagnostics) envía a un colector el
estado de la instalación, recuentos de uso aproximados, recuentos de runs, jobs
e ingestas fallidos por categoría cerrada y una señal de actividad seudónima. Un
deployment que quiere **ningún contacto saliente** establece
`DIAGNOSTICS_ENABLED=false`.

Así que un deployment que no quiere **ninguna tercera parte en la cadena** se
configura así y el software coopera:

| Asunto | La respuesta local |
| --- | --- |
| El modelo de chat | Un perfil `ollama` o `litellm` — sin clave, apuntando a un endpoint que alojas tú. Cualquiera de los 28 providers con `base_url` admite también una pasarela tuya |
| Parseo de documentos | `pymupdf`, el valor por defecto, se ejecuta en el worker. El OCR de LiteParse también, o en un servidor de OCR que registres como servicio local. LlamaParse es una elección por colección que necesita una clave del vault; sin ella no se parsea nada fuera |
| Embeddings | Un Ollama que alojas tú, registrado como servicio local en Knowledge → Integrations y elegido por colección como provider `ollama`. Sin clave, y el único provider que puede usar una colección app-scoped |
| Trazas | Deja `LOGFIRE_TOKEN` sin definir y no vincules ningún token `observability` a un spec ni a un entorno. Los runs siguen registrando localmente un id de traza |
| Búsqueda, navegación, memoria, herramientas | No vincules ningún secreto `search`, ninguna capability `web_fetch` ni `browser_use`, ninguna conexión MCP. El navegador web puede quedarse si cada sitio que puede abrir está en `allowed_domains` y sus pasos van a un modelo que alojas tú |
| Correo | Tu propio relay SMTP |
| Voz, imágenes y vídeo | Para la voz a texto, ningún provider: deja el dictado en `off` o `browser` y los bots de canal desactivados, porque todavía no se puede nombrar un servidor propio de voz a texto (un paso previsto). Para la síntesis de voz y el vídeo, ninguna capability `text_to_speech` ni `video_generation`. Para las imágenes, perfiles en un provider que alojes tú, o ningún perfil de ese tipo |

Los embeddings incluidos: el catálogo nombra OpenRouter y OpenAI, a los que una
colección llega con una clave del vault, y `ollama`, al que una colección llega a
través de un servicio local — una fila que nombra un servidor que opera la
organización o el deployment. Una colección en `ollama` no envía sus chunks ni
sus consultas a ningún host que no sea ese, y no le paga a nadie. Un deployment
que deba mantener los documentos en su propio hardware crea allí todas sus
colecciones.

## Quién es responsable de qué { #who-is-responsible-for-what }

| Parte | Rol | Qué significa aquí |
| --- | --- | --- |
| La organización que lo despliega (una ciudad, una empresa) | **Responsable del tratamiento** | Decide finalidades, retención, a qué providers puede llegar un agent, y firma los acuerdos con ellos |
| Vstorm, como autor del software | **Ninguno de los dos**, en un deployment autoalojado | El código se ejecuta en tu infraestructura. Vstorm nunca ve tus prompts, conversaciones ni documentos. Mientras se use el colector por defecto, que opera Vstorm, este recibe el [diagnóstico del deployment](#deployment-diagnostics); con `DIAGNOSTICS_ENABLED=false` o con tu propio colector no recibe ninguno |
| Vstorm, si opera el deployment por ti | **Encargado del tratamiento** | Un contrato de encargo de tratamiento es un contrato entre nosotros, no un ajuste. Tiene que existir antes de publicar el primer agent |
| Un provider de modelos, embeddings, parseo, búsqueda u observabilidad | **Subencargado**, elegido por configuración | La plataforma registra _qué_ provider y _qué_ endpoint usa cada agent. Su ubicación, su retención y sus condiciones de entrenamiento son suyas, y se verifican en cada deployment |

La plataforma no entrena ni afina nada. Envía prompts, documentos y resultados
de herramientas a los providers que configura un deployment y guarda lo que
vuelve. Que un provider use el tráfico de la API para entrenar es una propiedad
de la cuenta y de las condiciones del provider, y la lista de comprobación del
final pide la declaración en lugar de darla por supuesta.

## Dónde residen los datos personales { #where-personal-data-lives }

Todo lo de abajo está en el PostgreSQL del propio deployment, en su propio disco
o en un servicio que el deployment eligió. Toda tabla que pertenece a una
organización lleva un `organization_id`; una fila hija — un mensaje, un adjunto,
una valoración — queda acotada a través de la conversación o el usuario del que
cuelga, y leerla pasa por la comprobación del padre.

### La base de datos { #the-database }

El límite total se comprueba en el savepoint de la modificación, bajo un bloqueo de la organización, antes del commit. Superarlo revierte el registro y todas sus copias, también en una fila de importación; las filas restantes se informan como rechazadas. Repetir un recibo, escribir sin cambios, leer y borrar siguen funcionando tras reducir el límite. La retención libera los bytes eliminados. Bytes JSONB almacenados en PostgreSQL por organización entre registros, historial, recibos y outbox; el espacio de tablas e índices se cuenta aparte.

| Almacén | Guarda | Datos personales que contiene | Finalidad |
| --- | --- | --- | --- |
| `users`, `sessions`, `organization_members` | Cuentas e inicios de sesión | Correo, nombre, avatar, contraseña con hash o el id de la cuenta de Google, hash del refresh token, dirección IP y user agent por sesión; lo que la persona dijo a los agents sobre sí misma - idioma de la consola, zona horaria, rol, en qué trabaja, horario laboral - y los primeros mensajes escritos para su chat vacío | Autenticación y autorización; lo que se le dice a cada agent sobre la persona |
| `browser_sign_ins` | Los inicios de sesión que una persona guardó en sitios, para el navegador web | El sitio, la organización, cuándo se usó por última vez y la propia sesión (cookies y el `localStorage` del sitio), sellada en el vault en el ámbito de la persona | Un recorrido posterior en su nombre empieza ya con la sesión iniciada. La exportación de datos personales lista los sitios, nunca la sesión |
| `coding_accounts` | Conexiones personales de Claude Code/Codex | Organización, propietario, nombre de cuenta, revisión de consentimiento y clave API o tokens ChatGPT sellados en el ámbito del usuario | Exportación de metadatos solo para el propietario; contenedor separado por tarea; desconectar elimina el permiso de la plataforma, no el del proveedor |
| `conversations`, `messages`, `tool_calls` | Todos los chats en todas las superficies | El texto que la gente escribió, las respuestas y el razonamiento del modelo, argumentos y resultados de herramientas, un resumen continuo de los hilos largos | La función central del producto; el historial al que vuelve la persona |
| `coding_task_changes` | Una tarea del agente de código con `edit` en una conversación | Los archivos que cambió la tarea y su parche, hasta 256 KiB: el código como era y como quedó | El diff de la tarea, mostrado en su panel; leído con el acceso de la conversación |
| `voice_calls` | Cada conexión de una [llamada de voz](voice.md) | El id de usuario de quien llama (ninguno para un visitante), el agent, el run, la conversación y el embed a los que perteneció, el provider y el modelo, el id de la llamada en el provider, el id de la clave del vault con la que se sostuvo, el worker que la mantiene, su heartbeat, sus horas de inicio, fin y colgado, su coste, sus segundos y su número de activaciones de guardrails. **Ni audio ni transcripción** - las palabras de la llamada son filas normales de `messages`, cada una marcada con un `turn_id` y, cuando quien llama habló por encima, `interrupted` | Colgar una llamada cuyo proceso murió, y contar los minutos de llamada mensuales de la organización |
| `chat_files` | Adjuntos de un mensaje | Nombre de archivo, tipo, tamaño, el texto extraído (`parsed_content`) y la ruta de los bytes en disco | Responder sobre un archivo |
| `generated_media` | Una fila por cada imagen, clip de voz o vídeo que generó un agent | La organización, la conversación en la que se hizo si el run tenía una, el nombre del archivo, su ruta de almacenamiento y su tamaño - **no su contenido**, que es un archivo bajo `MEDIA_DIR` | Contar los medios generados de cada organización contra su cuota, y borrarlos con su conversación o tras su periodo de retención |
| `context_files` | Conocimiento permanente que un builder escribió para los agents | Lo que el autor pusiera ahí — y llega al prompt literalmente. Consulta [Archivos de contexto](context.md) | Instrucciones y hechos que un agent debe saber siempre |
| `virtual_table_records`, `virtual_table_record_history`, `virtual_table_receipts`, `virtual_table_outbox` | Las filas de una [Virtual Table](virtual-tables.md) y el rastro de cada cambio en ellas | Lo que la organización puso en sus celdas, que puede ser dato personal. Los valores actuales (records); el registro completo en un create y un delete, y solo las celdas que cambiaron en un update (history); el registro completo tal como lo devolvió una escritura con clave (receipts); los ids y el external id de cada registro creado (outbox, sin valores). Borrar un registro elimina solo la fila actual: history y receipts conservan los valores hasta que el barrido diario de retención los elimina: los receipts a las 24 horas, las filas de outbox despachadas a los 3 días y el history a los 365 días, todo como ajustes del deployment. Borrar una cuenta elimina sus receipts y la borra como actor en history; borrar la organización elimina las cuatro | Registros tipados para agents y workflows, reintentos seguros de una escritura y el traspaso de un registro creado |
| `virtual_table_triggers`, `virtual_table_trigger_revisions`, `table_trigger_admissions` | Los [triggers](virtual-tables.md#triggers) de una tabla, cada configuración que han tenido y lo que cada uno decidió sobre un registro creado | El miembro con el que se ejecuta un trigger; los valores de sus filtros y las claves de su mapeo, que pueden contener datos personales si un builder los escribió (un filtro por una dirección de correo). Una decisión guarda un estado, un motivo general y el run que inició, nunca los valores del registro. Ninguna clase de retención los barre: se van con su tabla y su trigger, y borrar una cuenta la quita como miembro, tras lo cual el trigger no inicia nada | Ejecutar un workflow cuando se añade un registro |
| `artifacts`, `artifact_versions` y sus archivos | Páginas que los agents publicaron — informes, dashboards | Lo que muestre la página, que el run construyó con lo que podía leer — o, para una página vinculada a datos de tabla, sus page queries (tabla, filtros, orden, límite y columnas, cada una resuelta a ids), con los propios registros leídos en el momento de verla con el acceso del propietario de la página y nunca guardados en ella; por versión, quién la publicó y el consentimiento del propietario para compartir sus datos (una huella de las queries, la membresía del propietario y cuándo) y el consentimiento de datos públicos de la página (quién lo confirmó, la membresía del propietario, cuándo); la fila de la organización guarda el interruptor `public_live_data`; el propietario, el run que escribió cada versión y, cuando hay uno activo, la clave del enlace público, sus ajustes (una contraseña como hash bcrypt) y cuántas veces se abrió — un número y una hora, nada sobre el visitante. Consulta [Aplicaciones](artifacts.md) | Compartir un resultado bajo un enlace estable |
| `datasets`, `dataset_cases` | Casos de prueba para evals | Preguntas y respuestas copiadas de conversaciones cuando alguien eligió "Añadir al dataset", el comentario de una respuesta valorada negativamente como nota del caso, y lo que contenía un archivo importado. Las credenciales se ocultan antes de guardar un caso. Cada caso registra además de quién son las palabras que contiene - quién preguntó, quién escribió cada turno anterior, de quién es el comentario que es su nota -, algo que nunca se muestra ni se exporta y que sobrevive a la conversación. Borrar a la persona que preguntó anonimiza el caso en todas las versiones que lo contienen; borrar a cualquier otra persona cuyo turno o comentario conservó sustituye ese turno y la respuesta del agent a él, y vacía esa nota. Consulta [Datasets](datasets.md#personal-data) | Comprobar si un agent mejoró |
| `spec_proposal_hunks`, `skill_proposals`, `context_proposals`, `authoring_requests` | Los cambios que propone el asistente de autoría y sus informes | Citas, de hasta 600 caracteres cada una, de los runs que leyó: lo que preguntó la gente, lo que respondió el agent y los comentarios dejados con una valoración. Borrar a una persona elimina las citas de sus runs y las de sus comentarios en runs de otras personas. Consulta [Asistente de autoría](authoring.md#every-quote-is-checked) | Mostrar por qué el asistente propuso un cambio |
| `knowledge_searches`, `knowledge_gap_topics`, `knowledge_gap_members` | Cada búsqueda de conocimiento que un agent hizo en un run, y los fallos agrupados en temas | La consulta que el agent formuló a partir de la pregunta de alguien, las bases de conocimiento en las que buscó y lo cerca que estaba el fragmento más cercano. Una búsqueda, acierto o fallo, se guarda mientras dure su run, así que la alcanza la clase de runs de la [retención](governance.md#retention). Un tema no copia preguntas: guarda una media vectorial de sus preguntas y lee todo lo demás de las búsquedas. Su único texto es el borrador que un modelo o una persona escribió para él, que se revisa en busca de datos personales y de números repetidos de las preguntas antes de poder añadirse a la base de conocimiento, y el tema registra quién lo añadió y con qué documento. Un documento añadido desde un tema se queda en la base de conocimiento cuando se borra a una persona cuya pregunta le dio forma, porque una persona confirmó lo que dice. Consulta [Lagunas de conocimiento](knowledge-gaps.md#personal-data) | Mostrar qué preguntas no pudo responder la base de conocimiento |
| `knowledge_gap_classifications` | Cada respuesta que un modelo leyó en busca de lagunas de conocimiento, con su veredicto | Qué respuesta, para qué base de conocimiento, el veredicto, el motivo en una frase del clasificador y su run. Se va con la conversación de la respuesta; el motivo se borra cuando se borra a la persona que preguntó, salvo que el run de la respuesta ya no exista. Una pregunta leída de una respuesta como laguna es una fila de `knowledge_searches` con la pregunta de la persona. Consulta [Lagunas de conocimiento](knowledge-gaps.md#answers-and-comments) | No pagar dos veces por leer la misma respuesta |
| `case_scores` | Lo que la calificación determinó sobre la respuesta de un run a un caso | Una copia de la respuesta que calificó, hasta 8.000 caracteres; los motivos del juez y las citas que no encontró en la respuesta; la decisión de revisión y la nota de una persona, y quién la dio. Las decisiones que dio una persona, y las respuestas guardadas de sus runs, vuelven en su exportación (`GET /me/data/export`); borrar a la persona borra esas respuestas, con los motivos y las citas que pueden repetirlas. La respuesta a un visitante en una superficie que la persona publicó no es suya, y ni se le exporta ni se borra con ella. Las credenciales se ocultan antes de guardar una puntuación, y la respuesta solo la ve quien puede ver el agent que la dio. Consulta [Datasets](datasets.md#personal-data) | Decidir si la respuesta de un agent aprobó |
| `eval_runs`, `eval_run_arms`, `eval_run_cases` | Lo que un agent respondió a cada caso de un eval run | La respuesta y los argumentos de cada llamada que hizo: lo que preguntaba el caso y, en un caso respondido desde una grabación, lo que devolvió la conversación de la que se tomó; el spec del borrador que congeló el run. Se borra con su run, y un run con su agent o su dataset. Borrar a la persona de la que se tomó un caso, o cuyo turno contenía, borra las respuestas y llamadas registradas para él, recorta los manifiestos de los runs del agent y del juez a lo que decidió el spec y borra los argumentos de las llamadas que esos runs retuvieron; los runs se conservan. Consulta [Eval runs](evals.md#what-a-run-keeps) | Comparar las versiones de un agent |
| `case_generations`, `case_proposals` | Borradores del generador de casos que esperan una decisión | Paráfrasis de preguntas que la gente hizo a un agent, fragmentos de sus documentos y los enlaces a ellos. Las credenciales se ocultan antes de guardar un borrador. Una decisión borra el borrador. Consulta [Datasets](datasets.md#generating-cases) | Proponer casos de prueba que una persona acepta o descarta |
| `artifacts`, `artifact_versions` y sus archivos | Páginas que los agents publicaron — informes, dashboards | Lo que muestre la página, que el run construyó con lo que podía leer; el propietario, el run que escribió cada versión y, cuando hay uno activo, la clave del enlace público, sus ajustes (una contraseña como hash bcrypt) y cuántas veces se abrió — un número y una hora, nada sobre el visitante. Consulta [Aplicaciones](artifacts.md) | Compartir un resultado bajo un enlace estable |
| `agent_memory_files` | Notas que un agent escribió sobre una persona o un chat de grupo | Lo que el agent decidiera que valía la pena recordar, con clave `person:<user_id>` o una sala de chat | Continuidad entre conversaciones |
| `rag_documents`, `knowledge_bases` y una tabla vectorial por colección | Documentos subidos y sincronizados, sus chunks y sus embeddings | El texto del documento y sus vectores, la ruta original del archivo en el origen | Recuperación |
| `agent_runs`, `tool_approvals`, `run_manifests` | Lo que costó y lo que hizo cada run | El prompt de sistema y la última petición entregada al modelo, argumentos de herramientas a la espera de aprobación, la persona que decide y su nota. Junto a los argumentos, `tool_approvals.context` guarda los nombres que representan los ids de una llamada aparcada (el nombre de una vista y el de una tabla, nunca el contenido de un registro), resueltos como la persona del run cuando la llamada se aparcó. Se conserva con la fila de aprobación aunque la vista o la tabla cambien de nombre o desaparezcan, y lo lee quien pueda decidir aprobaciones, tenga o no acceso propio a esa tabla | Budgets, aprobaciones, historial de runs |
| `routine_deliveries` | [Entregas duraderas de rutinas reanudadas](governance.md#resumed-routine-answers) | Texto final, propietario, organización, ejecución y rutina de origen, destino y estado. Incluido en la exportación personal acotada; se elimina con el propietario o ejecución de origen y sigue su retención | Reintentar la entrega a consola sin otro modelo ni mensaje duplicado |
| `routine_device_waits` | Activaciones de rutinas locales pendientes | IDs del propietario, organización, rutina y dispositivo, huella de tarea, contexto de evento sin consumir, estado y contador limitado de fallos. Exportación acotada del propietario; contexto iniciado o cancelado eliminado de inmediato; filas terminadas sujetas a retención de ejecuciones; eliminación en cascada con usuario, organización o rutina | Esperar al ordenador concreto autorizado sin llamar al modelo ni repetir trabajo iniciado |
| `workflow_runs`, `node_runs`, `node_attempts`, `workflow_events`, `dispatch_outbox`, `resource_refs` | Cada run de un workflow, los intentos de cada nodo y el flujo de eventos del run | La cuenta en cuyo nombre actúa el run y, en un run iniciado desde la [acción de una página](artifacts.md#actions), la página y el número de su versión; el resultado de cada intento, que contiene lo que el nodo produjo con los datos que recibió; el código y el mensaje de un fallo; las referencias a archivos y tablas que vinculó un grafo. El historial y los archivos siguen `run_retention_days`. La limpieza conserva fuentes de reintentos activos, ejecuciones llamadas que un llamador activo necesita y productores de archivos usados por ejecuciones conservadas. Eliminar explícitamente un workflow puede borrar su historial. | Llevar un workflow hasta el final a través de reinicios, y mostrar su historial |
| `workflow_approvals` | Las solicitudes que plantearon los pasos [`human.approval`](reference/workflow-nodes.md#human-approval) de un workflow | El título y los detalles del paso, la propuesta vinculada y el texto final aprobado (contenido, en texto plano), los ids de quienes aprueban nombrados, la persona que decidió y su nota, y cuánto cambió quien aprobó la propuesta (`edit_ratio`, un número entre 0 y 1, nunca texto). Se borra con el run | Dejar que una persona apruebe, rechace o edite lo que un workflow está a punto de hacer |
| `workflow_files` | Los archivos que guardaron los pasos de un run de workflow - descargas, archivos escritos, páginas renderizadas, imágenes transformadas, la salida de un script, y los adjuntos de un mensaje de Gmail o de Outlook que inició el run | Lo que contenga el archivo, que puede ser dato personal, y su nombre. Los bytes están en `MEDIA_DIR` o en el almacén de objetos. El historial y los archivos siguen `run_retention_days`. La limpieza conserva fuentes de reintentos activos, ejecuciones llamadas que un llamador activo necesita y productores de archivos usados por ejecuciones conservadas. Eliminar explícitamente un workflow puede borrar su historial. | Pasar archivos de un paso al siguiente y descargarlos desde el run |
| `workflow_exposures`, `workflow_webhook_deliveries` | Los webhooks y programaciones de un workflow y cada entrega de webhook que admitió | El miembro como el que se ejecuta cada uno, la entrada de una programación, el signing secret de un webhook sellado en el vault y el id de cada entrega junto al run que inició. Se van con su workflow y su organización, y el miembro se borra al eliminar la cuenta | Ejecutar un workflow desde fuera de la consola exactamente una vez por entrega |
| `agent_triggers` | Runs programados y disparados por eventos | El prompt y la configuración y el filtro del origen de eventos | Ejecutar un agent sin una persona |
| `app_admin_audit_logs` | Quién cambió accesos o gastó dinero — el rastro de la organización y el del administrador del deployment comparten tabla | Actor, suplantador, dirección IP, la acción y un mapa `details`. El mapa nombra sobre todo campos, pero algunas entradas guardan valores: el correo de la cuenta suplantada, el correo de una cuenta que un administrador borró, una nota de publicación | Rendición de cuentas. Consulta [Gobernanza](governance.md#audit) |
| `notifications`, `notification_deliveries` | Cada notificación dirigida a alguien y su envío por correo. La fila se escribe incluso cuando el destinatario ha desactivado todos los canales para ese evento — es lo que impide escribir dos veces la misma ocurrencia — y simplemente no se muestra ni se envía nunca; solo la fila de envío es condicional | El destinatario, un resumen prerrenderizado (nunca un comentario en bruto ni un valor secreto) y las variables tipadas a partir de las cuales un correo se vuelve a renderizar; una fila de envío añade su canal, estado, intentos y un motivo de fallo depurado — nunca el texto de error del provider. Una aprobación pedida por una cuenta de chat sin enlazar conserva ese nombre visible o handle en el resumen y las variables, hasta que el barrido de retención de notificaciones elimina la fila; borrar la identidad no lo alcanza | Alertas que una persona lee una vez, sin supervisión. Consulta [Gobernanza](governance.md#alerts) |
| `notification_preferences`, `announcements` | Interruptores de canal por evento, y las difusiones propias del app admin | Un id de usuario por interruptor; el remitente de una difusión, su cuerpo y las organizaciones y el rol a los que iba dirigida — nunca la lista resuelta de destinatarios, que solo se puede reconstruir a partir de `notifications` hasta que esa fila caduca en [el barrido de retención de notificaciones](governance.md#alerts) — después de lo cual la entrada de audit detrás de ella conserva solo un recuento, nunca los destinatarios | Exclusión voluntaria, y el registro propio de quien la escribió |
| `notification_routes` | Tu chat privado elegido expresamente para una plataforma en una organización | Identificadores de persona, organización, sesión privada y generación de autorización; sin credenciales ni contenido de mensajes | Notificaciones con consentimiento. Sustituir revoca las rutas pendientes. Incluido en tu exportación; eliminar la persona, sesión u organización elimina la fila |
| `embed_visitors`, `channel_identities`, `channel_sessions` | Desconocidos en una página alojada y personas en Slack, Teams, Telegram o Mattermost | Una clave de visitante aleatoria; un id de usuario de la plataforma, nombre de usuario y nombre visible; el id del chat | Retomar el hilo correcto. Para quien pregunta sin cuenta enlazada, el nombre visible o el handle también se muestra en la cola de aprobaciones, su exportación CSV y el correo de aprobación, a las personas que deciden |
| `message_ratings` | Pulgares y comentarios sobre las respuestas | Quien valora y su comentario | Revisión de calidad |
| `suggestions` | Lo que el [trabajo por iniciativa propia](governance.md#proactive-work) propuso a una persona, y si lo aceptó | La persona, un título y una línea de detalle sacados de sus peticiones recientes, el prompt de rutina o el perfil que fijaría, y una clave que impide volver a proponer algo descartado | Propuestas sobre las que decide la persona |
| `watches` | Lo que una persona pidió al [trabajo por iniciativa propia](governance.md#proactive-work) vigilar en sus propias conexiones | La persona, cuál de sus conexiones, qué buscar y qué omitir con sus propias palabras, cada cuánto y cuándo revisó por última vez | Vigilancias que configura la persona |
| `ml_service_calls` | Cada llamada a los [servicios de ML](ml-services.md) y cada transcripción: dictado, un mensaje de voz de un canal, la API, el dictado de un visitante en una página alojada o un widget | La organización, quién pidió, qué servicio, recuentos de bytes y unidades, la duración y cómo terminó; en una transcripción también el proveedor y el modelo, el id de la clave del vault con la que se envió, por dónde llegó, el agent y el bot de canal para los que fue y la duración de la grabación. La fila de un mensaje de voz de un canal nombra a la persona con la que está vinculada la cuenta del remitente, y a nadie si el remitente no está vinculado. La fila de un visitante no nombra a nadie - ni al visitante, que no tiene cuenta, ni a quien publicó la página. Borrar a la persona, el agent, el bot o la clave quita el vínculo y conserva la fila - **nada de lo que se envió y nada de lo que volvió** | Informe de uso, y la vista de un operador sobre una integración que falla |
| `agent_workspaces`, `sandbox_operations` | Archivos sobre los que trabajó un agent y el registro de lo que ejecutó | Para el backend `state`, los propios archivos, en JSON; para un contenedor, el id de sesión y cada comando, destino y resumen del resultado | La sandbox. Consulta [La sandbox](sandbox.md#what-was-done-in-one-and-where-that-record-lives) |
| `organization_secrets`, `model_profiles`, `mcp_connections`, `channel_bots` | Credenciales y hacia dónde apuntan | Solo el cifrado sellado, con una pista; el provider, el modelo y la `base_url` en claro | Llegar a los providers. Consulta [Secretos](secrets.md) |

Al eliminar una conversación se eliminan también sus conjuntos de cambios de programación (`coding_task_changes`).

`workflow_node_spend` conserva los cargos directos de decisiones y embeddings tras borrar el historial: organización, UUID del intento, coste, indicador de coste parcial y fechas. No guarda prompts, resultados, archivos ni identidad del miembro. Los cargos de agentes permanecen en `agent_runs` y no se duplican. Los costes históricos nunca registrados no pueden reconstruirse.

El texto de un caso copiado de una conversación solo es visible para lectores con `runs:view` o acceso a la conversación original. Los demás ven metadatos y un marcador, tanto en versiones actuales e históricas como en exportaciones CSV/JSONL. Si falta la fuente, el texto sigue oculto. No se puede editar texto oculto ni revelarlo al cambiar metadatos. Las evaluaciones siguen ejecutando la revisión completa almacenada.

Las respuestas, notas de Review y pruebas de evaluación requieren `runs:view` y acceso al agente que respondió. Si falta alguno, se conservan el resultado y el estado, pero se eliminan el texto de respuesta, motivos, reglas y citas. Antes de copiar la conversación privada de otra persona, el diálogo identifica a su propietario y avisa de que los lectores del dataset que puedan leer runs verán su texto.

`messages.search_vector` es un índice de texto completo sobre el mismo
contenido, y `conversations.summary_messages` es una compresión de él escrita
por el modelo. Ambos son copias del chat y se van con él.

### Medios generados { #generated-media }

Una imagen, un clip de voz o un vídeo que genera un agent es un archivo bajo
`generated_<org>/` y una fila `generated_media` que lo nombra. La fila registra la
organización, la conversación si el run tenía una, y el tamaño, así que el total de
la organización queda acotado por `GENERATED_MEDIA_QUOTA_MB` (5120), comprobado
antes de cada llamada de generación de pago. Cuenta cada archivo, también uno
creado sin conversación: de una vista previa o una ejecución de prueba, de un
inciso `/btw` en un canal, de un run de la API que no nombra conversación, o un
archivo cuya conversación se borró por un camino que lo dejó atrás.

El archivo se borra con su conversación, con la cuenta a
la que pertenecía esa conversación, con la tarea diaria `sweep-generated-media`
cuando supera `GENERATED_MEDIA_RETENTION_DAYS` (90) aunque su conversación siga
ahí, y por prefijo con su organización. 0 desactiva cualquiera de los dos límites.
Un archivo sin conversación no es nada que un miembro pueda borrar para liberar
espacio, así que la misma tarea lo borra a los 7 días, sea cual sea
`GENERATED_MEDIA_RETENTION_DAYS`, 0 incluido. Un enlace a él - en una respuesta de
un canal o de la API - deja de funcionar entonces.

Borrar una conversación, una cuenta o una organización elimina las filas en su
propia transacción y encola la desvinculación de los bytes como tarea en segundo
plano en esa misma transacción, así que los bytes se van solo si se van las filas,
y un reinicio tras el commit no pierde la desvinculación.

Esa tarea reintenta un
prefijo que el almacenamiento no elimina entero - el de una organización - y un
archivo suelto de una conversación o una cuenta borradas que el almacenamiento
rechaza, porque nada más podría volver a encontrar esos bytes. Un archivo que el
almacenamiento sigue rechazando tras el último intento de la tarea se queda sin
fila bajo `generated_<org>/` hasta que se va su organización, y el informe de
abajo lo cuenta.

El barrido borra primero
el archivo y su fila solo cuando el archivo ya no está; un archivo que el
almacenamiento se niega a borrar conserva su fila, y el siguiente barrido lo
vuelve a intentar.

Los archivos generados antes de que existiera la tabla no tienen fila. Se siguen
sirviendo, pero no cuentan contra la cuota y el barrido no los ve: se van con su
organización, o a mano, y el informe de protección de datos los cuenta entre los
archivos sin fila.

### Fuera de la base de datos { #outside-the-database }

| Almacén | Guarda | Se borra cuando |
| --- | --- | --- |
| `MEDIA_DIR` en el host de la API (volumen `media_data`) | Adjuntos de chat bajo `<user_id>/`, avatares, logos de embeds, las imágenes, la voz y los vídeos que generaron los agents bajo `generated_<org>/` y una copia temporal de cada documento bajo `_rag_tmp` mientras se parsea | Se borra un documento desde el producto. Su copia de parseo bajo `_rag_tmp` se va cuando termina su job de ingesta - indexado, rechazado, su documento borrado o fallido en su último intento - y cuando se borra el documento; el job horario `sweep-rag-scratch` elimina una copia cuyo documento ya no existe o ya no se está procesando, y es el que limpia las copias que las versiones anteriores nunca eliminaron. Los bytes de un adjunto de chat se desvinculan tras el commit que borra su conversación o a su propietario. Un archivo generado se va con la conversación en la que se hizo, tras `GENERATED_MEDIA_RETENTION_DAYS` (90) sea cual sea la suerte de la conversación - a los 7 días si no tiene conversación -, y con su organización; consulta [Medios generados](#generated-media). Consulta [Qué alcanza el borrado](#what-deletion-reaches) |
| `SANDBOXD_WORKSPACE_ROOT` en el host de la sandbox | Los archivos de cada workspace respaldado por contenedor | Se borra la conversación, o `SANDBOXD_WORKSPACE_TTL` los barre; sin definir, se conservan indefinidamente. Consulta [Cuánto sobrevive cada cosa](sandbox.md#how-long-anything-survives) |
| Redis | Cubos de rate limit con clave en quien llama — en una superficie pública eso es la **dirección IP en claro**, dentro de la clave, durante el TTL de la ventana; claves de deduplicación de triggers y canales; estado del intercambio OAuth; invitaciones en espera; la vista en directo de una navegación — su última captura, sus pasos y lo que la persona que maneja el navegador pulsó y escribió hasta que la navegación lo lee; los pasos repetibles de una persona — las direcciones y etiquetas de lo que pulsaron sus navegaciones terminadas, nunca lo que escribió | Al expirar: una vista en directo una hora después del último fotograma de la navegación, los pasos repetibles dos semanas después de la última vez que se hizo la tarea, todo lo demás en minutos |
| `background_jobs` en PostgreSQL | El payload de cada job en segundo plano, su último error y la respuesta de un run asíncrono de la API | El barrido de retención elimina un job terminado tras `BACKGROUND_JOB_RETENTION_DAYS` (14). Los payloads son ids y rutas, con dos excepciones: el **`event_context` de un disparo por evento** — el remitente, el asunto y el cuerpo de un mensaje de Gmail o de Outlook con los ids del mensaje y del hilo, una incidencia de GitHub, un payload de webhook — y **el prompt y la respuesta de un run asíncrono de la API** se quedan en el job hasta entonces. Los logs del worker pasan por el mismo filtro de redacción que los de la API |
| Logfire, si está configurado | Trazas de cada run | La retención del provider. Hoy una traza lleva el prompt completo, la salida y los argumentos de las herramientas — consulta [Trazas](#traces) |
| Tu relay SMTP | Invitaciones, enlaces mágicos, peticiones de aprobación, alertas de budget, informes de uso, y el propio correo del [buzón de notificaciones](governance.md#alerts) - un run que termina o falla desatendido, la ingesta de un documento que se completa o falla, un evento de seguridad o un cambio de configuración, el propio anuncio de un admin - y el asunto y el texto de un paso [`email.send`](reference/workflow-nodes.md#email-send) de un workflow, a las direcciones que reciba | Lo que el relay conserve. El correo de aprobación nombra el agent, la herramienta y un enlace, no los argumentos de la herramienta; para una llamada pedida por una cuenta de chat sin enlazar, nombra también el nombre visible o el handle de esa cuenta y el bot |
| Copias de seguridad | Un `pg_dump` es la base de datos entera; el volumen de medios son los archivos | Tu caducidad de copias. El borrado nunca alcanza una copia ya tomada — consulta [Copias de seguridad](deploy.md#backups) |

## Qué sale del deployment { #what-leaves-the-deployment }

No sale nada mientras una fila o un ajuste no nombre un destino, con una
excepción: el [diagnóstico del deployment](#deployment-diagnostics) está activado
por defecto. Esta es la lista completa de destinos, con la configuración que
decide cada uno.

| Destino | Qué se envía | Lo decide | Ubicación y condiciones |
| --- | --- | --- | --- |
| El colector de diagnóstico | Estado de la instalación, recuentos de uso aproximados, recuentos de runs, jobs e ingestas fallidos por categoría cerrada, y una señal de actividad seudónima que envía cada navegador o app; ningún prompt, conversación, nombre de archivo, nombre de cuenta, correo electrónico ni clave de provider | `DIAGNOSTICS_ENABLED` (por defecto `true`) y `DIAGNOSTICS_COLLECTOR_URL` | `https://analytics-agenticos.testapp.ovh` por defecto; [qué se envía](configuration.md#diagnostics) |
| El modelo de chat | La conversación hasta ese punto, los adjuntos pegados o descritos, los chunks recuperados, los resultados de herramientas; una vez por noche, para el [trabajo por iniciativa propia](governance.md#proactive-work), las peticiones recientes de una persona (solo los prompts que pasaron el guardrail de entrada del agent; un prompt que redactó se lee sin redactar, [#2655](https://github.com/vstorm-co/agenticos/issues/2655)), su perfil y lo que su agent anotó sobre ella | Un [perfil de modelo](models.md#a-model-profile): `provider`, `model`, `base_url` y una clave sellada. Veintisiete providers; `ollama` y `litellm` no llevan clave y se alcanzan en un endpoint que alojas tú, y `openai`, `anthropic`, `google`, `huggingface` y otros aceptan una `base_url`, así que un endpoint en la UE o una pasarela es un campo, no una bifurcación. Un perfil `openai` o `azure` en la Responses API envía `store: false`, así que el provider no guarda una respuesta almacenada y recuperable salvo que el perfil fije `openai_store`; la retención de OpenAI para vigilar abusos sigue aplicándose salvo que la cuenta tenga zero data retention | La del provider. Verifícalo por perfil |
| El modelo del generador de casos | Las instrucciones, extractos de skills y descripciones de herramientas del agent probado; fragmentos de los documentos de su base de conocimiento; las preguntas que la gente le hizo, con el comentario dejado en una respuesta valorada negativamente. Las credenciales se ocultan de los fragmentos y las preguntas antes de enviarlos | El modelo de generación configurado en el dataset, solo cuando una persona con `datasets:edit` inicia la generación. Las fuentes de conversaciones también requieren `runs:view`. | La del provider. Verifícalo por perfil |
| El modelo de embeddings | Cada chunk de cada documento de una colección, cada consulta de recuperación y, de nuevo, las consultas que no encontraron nada, cuando las [lagunas de conocimiento](knowledge-gaps.md#topics) las agrupan | Por colección, y solo ahí: `embedding_provider` (`openrouter`, `openai` u `ollama`, del catálogo) y, para los dos primeros, la clave del vault `embedding_secret_id` que paga. No hay clave de embeddings a nivel de deployment; una colección con clave que no nombre ninguna rechaza indexar y buscar. `ollama` no lleva clave y se alcanza en el servicio local que nombra la colección (`embedding_endpoint_id`), un host que operas tú | La del provider, o tu propio host. [Una elección permanente](choosing-models.md#embeddings-are-a-separate-permanent-choice) |
| LlamaCloud | El documento entero | Una colección cuyo `pdf_parser` sea `llamaparse`; tiene que nombrar una clave del vault (`llamaparse_secret_id`), no hay clave de deployment. El `pymupdf` por defecto parsea en el worker | La de LlamaCloud, si se usa |
| Un servidor de OCR | Páginas renderizadas de un documento | Una colección cuyo `pdf_parser` sea `liteparse` **y** cuyo `ocr_endpoint_id` nombre un servicio local; sin él, el OCR se ejecuta en el worker | Tu propio host — un servicio local está por construcción en la red del deployment |
| Un modelo de descripción de imágenes | Las imágenes dentro de los documentos | El `image_description_model` de una colección | La de ese provider de modelos |
| Investigación web | La consulta de búsqueda que compuso el agent | `web_research.method` en el spec: `duckduckgo` (sin clave), `tavily`, `brave` o `exa` (un secreto `search` cada uno), o `native`, donde busca el provider del modelo de chat | La del proveedor de búsqueda, o la del provider del modelo |
| Web fetch y el navegador web | La URL; para el navegador, lo que escribe en los sitios que abre | La capability en el spec; el navegador necesita además un endpoint CDP en `BROWSER_CDP_ALLOWED_HOSTS`, vacía por defecto | El sitio consultado; el host del navegador y los sitios que abre |
| Proxy del navegador o navegador alojado de un agent | Todo lo que el navegador carga y envía, como lo haría el navegador del despliegue - páginas, contenido de formularios, cookies, inicios de sesión - más el registro propio del proxy o del servicio | `browser_use.connection` en el spec (#2130); `built_in` por defecto | El proxy o el servicio de navegador alojado (Browserbase, Steel u otro), bajo el contrato propio de la organización |
| Los pasos del navegador web | Cada paso de un recorrido va al propio modelo del agente: la URL de la página, su título, las etiquetas de los elementos visibles y hasta 4.000 caracteres de su texto visible, más una captura con `vision` activado — que puede ser el contenido de un sistema interno. Lo que contiene un campo no se repite: la tabla de elementos solo dice que el campo está relleno | La capability `browser_use` en el spec | El proveedor del modelo del agente, como en la conversación |
| Computer use | Cada captura del escritorio va al propio modelo del agente y puede mostrar cualquier cosa abierta en él; ninguna se guarda con el run. Las acciones, incluido el texto que escribe el modelo, van al escritorio | La capability `computer_use` en el spec, con una conexión de sandbox para un escritorio en la sandbox; un escritorio daemon necesita su host en `COMPUTER_DAEMON_ALLOWED_HOSTS`, vacía por defecto, y el token de la organización para él en el vault | El proveedor del modelo del agente; la conexión de sandbox del agente, o el host `computerd` que ejecuta el operador |
| Agentes de programación locales | La tarea y el código que Claude Code o Codex lee en el ordenador de la persona | `coding_agent.runs_on: this_computer`, acceso completo a una carpeta y confirmación nativa del inicio. El agente local decide su modelo, endpoint e inicio de sesión; el despliegue no los selecciona | Directamente desde ese ordenador al proveedor o gateway configurado en el agente local. El informe de protección de datos distingue esta ruta de la ejecución en sandbox |
| La sandbox, hacia fuera | **Cualquier cosa del workspace, a cualquier host** — la runtime `workbench` tiene red, shell y `curl` | La capability `sandbox` y una runtime con `needs_network`; la aprobación de comandos controla qué se ejecuta, no adónde se conecta | Adonde fuera el comando. El control de salida es el firewall del host de la sandbox, no un ajuste de aquí |
| Un servidor MCP | Argumentos y resultados de herramientas, de un agent o de un paso [`mcp.call`](reference/workflow-nodes.md#mcp-call) de un workflow | `mcp_connections.url`, por organización o por persona | La del operador del servidor |
| Google Workspace y Microsoft 365, mediante un servidor que ejecutas tú | Lo que pide el paso `mcp.call` de un agent o de un workflow: términos de búsqueda, ids de mensajes y de hilos, texto de la respuesta, detalles de eventos. Tu propio servidor lo reenvía a las APIs de Google o de Microsoft y guarda además los tokens de la cuenta conectada | Una conexión de la organización o personal, creada desde la entrada de catálogo `google-workspace` o `ms-365` | Tu servidor, y luego Google o Microsoft |
| Microsoft Work IQ | Lo que pide una llamada de herramienta, y la respuesta, en el servicio alojado de Microsoft; se factura en Copilot Credits | Una conexión creada desde la entrada de catálogo `work-iq` | De Microsoft |
| Un host de tu propia red | Todo lo que un paso HTTP de workflow, un conector, una llamada A2A o una conexión MCP envía allí | `OUTBOUND_PRIVATE_ALLOWLIST`, vacía por defecto; `MCP_ALLOWED_HOSTS` solo para MCP | El host que listes. Toda cuenta de toda organización alcanza cualquiera de sus puertos |
| El modelo del redactor de lagunas | Las preguntas más recientes de una laguna de conocimiento (hasta 20): qué preguntó cada persona, qué devolvió la búsqueda, qué respuesta recibió y los comentarios de los lectores, tras quitar las direcciones de correo electrónico, los números de teléfono, de tarjeta y de cuenta y los números parecidos a un número de pedido - los nombres no; y los archivos de contexto de los agents del tema que puede leer la persona que redacta | Solo mediante petición explícita de una persona con acceso a la base de conocimiento, modelo disponible y budget. | El proveedor de ese modelo |
| El modelo del clasificador de lagunas | Las respuestas recientes de una base de conocimiento (hasta 100 por revisión), o las malas respuestas de una sesión de mejora: qué preguntó cada persona, qué respuesta recibió y los comentarios de las valoraciones negativas, con las instrucciones y los archivos de contexto del agent que respondió que puede leer la persona que revisa | Solo mediante petición explícita de una persona con acceso a la base de conocimiento, modelo disponible y budget. | El proveedor de ese modelo |
| Los servicios de un terminal virtual | Los comandos que el agent ejecuta sobre cada carpeta montada, y lo que escribe en ella; lo que lee vuelve al modelo del agent | Las carpetas de la capability `mirage` en el spec: un servicio, sus opciones y un secreto del vault o una [cuenta conectada](secrets.md#connected-accounts). Un host escrito tiene que estar en `MIRAGE_ALLOWED_HOSTS` | Las de cada servicio montado: Google, GitHub, Notion, tu propia base de datos o servidor |
| Logfire | Spans de cada petición y cada run | `LOGFIRE_TOKEN` a nivel de deployment; un token `observability` en un spec, o `logfire_token_secret_id` en un entorno, redirige esos runs a otro proyecto. `LOGFIRE_BASE_URL` elige el deployment de EE. UU. o el de la UE. Sin definir en ninguna parte, no se envía nada | La de Pydantic, EE. UU. o UE |
| Voz a texto, generación de imágenes | Una nota de voz de un canal, una grabación dictada en `/chat`, o la grabación de un visitante anónimo en una página alojada o un widget; el prompt | El provider al que se resuelve una grabación - el par propio del bot, la anulación del agent o el predeterminado de la organización, que un bot hereda salvo que esté desactivado - enviado con la clave del vault nombrada junto a ese par - una clave de API de `groq`, `mistral` u `openai`, visible para la organización en la organización y en un bot; para el dictado en `/chat`, además, el motor de la organización en `server`, y para una página o un widget su propio `dictation: server`. Un perfil para `google` u `openai` para las imágenes. El audio de un dictado no se guarda aquí. Con `browser` en una página o un widget, el navegador del visitante envía el audio a su fabricante y nada de él pasa por este despliegue | La del provider, o tu propio host para las imágenes; con `browser`, la del fabricante del navegador |
| Un provider de voz realtime | Durante una [llamada de voz](voice.md): el audio de quien llama, las instrucciones del agent y las definiciones de herramientas, los resultados de las herramientas, y los turnos anteriores de la conversación como texto cuando una llamada empieza o se reconecta | La sección Voice del agent: `provider`, `model` (o un deployment de Azure) y la clave del vault `secret_id`, publicada; sin sección Voice el agent no atiende llamadas. Sobre WebRTC (OpenAI) el audio va directamente entre el navegador y el provider; sobre el relay (Azure, Gemini, xAI) pasa por este despliegue sin guardarse. Aquí no se conserva audio, y la sesión solo conserva transcripciones | La del provider |
| Texto a voz | El texto que se va a decir y cualquier indicación sobre cómo decirlo | El `provider` de la capability `text_to_speech`: `openai`, `elevenlabs` o `google`, con la clave del binding | La del provider |
| Generación de vídeo | El prompt y la imagen inicial, si la hay | El `provider` de la capability `video_generation`: `google`, `byteplus`, `xai` o `alibaba`, con la clave del binding. `google` guarda la interacción (`store: true`), porque Gemini solo entrega un clip por dirección desde una guardada; a los otros tres no se les pide | La del provider |
| Slack, Teams, Telegram, Mattermost | Las respuestas del agent; la dirección de correo de un miembro nuevo, para encontrarlo para una [bienvenida](channels.md#a-welcome-for-a-new-member) en Slack, Mattermost o Teams | Una fila `channel_bots` con su token en el vault | El proveedor de mensajería ya tiene el chat |
| Inicio de sesión con Google | Nada hacia fuera; Google devuelve el correo, el nombre, la foto y el id de la cuenta | `GOOGLE_CLIENT_ID` | La de Google |
| Tu relay SMTP | El correo de arriba y el texto de un paso [`email.send`](reference/workflow-nodes.md#email-send), a las direcciones que eligió su autor | `SMTP_HOST`, `SMTP_TLS` | La tuya, luego la de cada destinatario |

Los conectores de sincronización van al revés: un origen de Google Drive o S3
trae documentos **hacia dentro**, autenticado por un secreto `connector`, y a
partir de ahí los documentos son la copia del deployment y siguen las reglas de
arriba. Quién acaba pudiendo leer lo que un origen ha ingerido es
[una decisión que toma la fila del origen](file-processing.md#who-ends-up-able-to-read-what-a-source-ingested).

## Datos de tabla mostrados en una página { #table-data-on-a-page }

Una [página](artifacts.md#live-data) publicada puede mostrar registros de una tabla, y
esos registros pueden ser datos personales. Es **un flujo dentro del deployment, del
propietario de la página a todos los que pueden abrirla** — no un destino fuera de él —,
pero salta el control de acceso propio de la tabla, así que se lista aquí.

- **Qué fluye.** Solo las columnas que nombra una page query y las filas que seleccionan
  sus filtros, hasta 1.000 por binding. Un filtro puede usar una columna que la página no
  muestra, y se avisa al propietario de cuál. Las fórmulas, lookups, rollups y etiquetas de
  enlace llevan también datos de las tablas vinculadas, y el consentimiento nombra esas tablas.
- **Con qué autoridad.** La del propietario de la página. A cada lector se le sirven los
  mismos registros, sea cual sea su acceso a la tabla. Los datos salen de la tabla solo cuando
  el propietario los ha confirmado, tras leer las queries en palabras y quién puede abrir la
  página ahora y más adelante (los roles que abren todas las páginas, la visibilidad, personas
  y grupos). Los datos se leen de nuevo en cada carga y nunca se guardan en la página. Las lecturas
  para miembros no se almacenan en caché; las de una página pública sí, como se describe más abajo.
- **Qué se guarda al respecto.** Por versión de la página: quién la publicó, una huella de sus
  queries, si el propietario consintió, cuándo y con qué membresía. Las solicitudes de compartir
  guardan al solicitante, el tipo, una nota opcional, la decisión y quién la tomó. El registro de
  auditoría recoge el consentimiento, su retirada, el consentimiento automático, las concesiones
  `edit_data`, los cambios de propietario y las solicitudes, con el texto que una persona confirmó.
- **Qué no se registra nunca.** Los valores de los registros, los valores de los filtros y la
  dirección de contenido de una página servida con sus datos. Las entradas de auditoría y las
  notificaciones nombran la página y a las personas, nunca una fila.
- **Qué no llega.** El consentimiento de un miembro eliminado caduca con su membresía, y una
  página cuyo propietario se fue no sirve datos hasta que otro propietario la confirme.

### A personas sin cuenta { #table-data-on-a-public-page }

Este es el único flujo de aquí que **sale del círculo de personas que tienen una cuenta**. El
[enlace público y los embeds](artifacts.md#live-data-on-a-public-link) de una página pueden
escribir esos mismos registros en la página para cualquiera que abra la dirección, y para cada
sitio web que la incruste, sin iniciar sesión. Lo abren dos decisiones, y un deployment que no
quiera el flujo deja desactivada la primera.

- **Desactivado por defecto, para toda la organización.** `public_live_data` es un interruptor
  que solo cambia un Owner o Admin, como uno mismo. Desactivado, ninguna página muestra datos en
  un enlace ni en un embed, haya confirmado lo que haya confirmado su propietario.
- **Después, por página.** El propietario de la página, o un Owner o Admin en su nombre, lo
  confirma tras una pantalla que nombra las tablas y columnas y dice quién puede leerlas:
  cualquiera con el enlace, su contraseña y caducidad, y cada sitio web que la incrusta. El
  consentimiento queda ligado a las page queries y a esa audiencia. Añadir un sitio, quitar la
  contraseña, desactivar el enlace, archivar la página, un propietario nuevo y un consentimiento
  de miembro retirado lo borran.
- **Qué se guarda.** En la página: la huella de las queries a las que se dio, quién lo
  confirmó, la membresía del propietario y cuándo. La fila de la organización guarda el
  interruptor. El registro de auditoría recoge `organization.public_live_data_changed`,
  `artifact.public_data_consented`, `artifact.public_data_withdrawn` y
  `artifact.public_data_voided` con nombres de tablas y columnas, los sitios web que la
  incrustan, si hay una contraseña y el motivo; nunca una fila, un valor ni un visitante.
- **La caché.** Los registros de un binding se guardan 30 segundos en la memoria del proceso de
  la API, para que una página muy visitada no lea su tabla una vez por visitante. **Nunca se
  escriben en Redis**, en la base de datos ni en un archivo, la memoria está acotada en bytes
  (`ARTIFACT_PUBLIC_DATA_CACHE_BYTES`) y desaparece cuando el proceso se detiene. Todas las
  comprobaciones de acceso se ejecutan antes de leer la caché, así que desactivar el interruptor
  o rotar el enlace termina el flujo en la siguiente carga; lo que un visitante ya cargó
  permanece en su navegador.
- **Qué no se registra nunca.** Los valores de los registros, los valores de los filtros, la
  clave del enlace y la dirección de contenido de una página cargada con sus datos se mantienen
  fuera de los logs, las trazas y las entradas de auditoría. No se registra a ningún visitante: el
  enlace cuenta aperturas, no personas. Solo la clave del límite de peticiones guarda la IP del
  visitante, en Redis, durante minutos.
- **Nadie recibe el motivo.** Un visitante cuya carga no pasa una comprobación ve la página sin
  sus datos y sin motivo, de modo que la página no dice qué contiene una tabla ni por qué está
  oculta.
- **Qué ve un sitio web que incrusta la página.** El sitio web enmarca la página; la página se
  ejecuta en un origen opaco sin red, así que el sitio no puede leer los registros fuera del
  frame, pero quien abre el sitio sí los lee.

Los registros mostrados a cualquiera con un enlace puede copiarlos cualquiera que los vea.
Vincula una página pública solo a columnas que estén pensadas para ser públicas.

Un deployment que deba mantener las filas de una tabla fuera del alcance de algunos de sus
miembros no debería vincularle una página que esos miembros puedan abrir; la confirmación
indica quiénes son.

## Controles, y dónde se prueba cada uno { #controls-and-where-each-is-proved }

Cada fila nombra el mecanismo en el código y la prueba o la página que lo fija,
o la incidencia que lo hará. Una fila cuya última columna es una incidencia es
una laguna, y así queda dicho.

| Control | Mecanismo | Probado por |
| --- | --- | --- |
| Aislamiento entre tenants | `organization_id` en toda tabla que pertenece a una organización, resuelto desde `X-Organization-Id` a una membresía en cada petición; las filas hijas solo se alcanzan a través de la comprobación de su padre | `tests/integration/test_conversation_tenant_isolation.py` y sus hermanos; [Permisos](permissions.md) |
| Acceso a una fila | Tres capas: administrador del deployment, rol en la organización, grant por recurso a través de `resolve_access`. Un control que quien llama no puede usar no se renderiza | Pruebas de rechazo en `tests/api/`; [Permisos](permissions.md#how-the-layers-combine) |
| Leer el chat de otra persona | El propietario, una compartición explícita o el app admin del deployment — nunca un rol de la organización. El chat de un proyecto se lee solo a través del proyecto: quien puede ver el proyecto, incluida la persona que lo empezó, y nadie que ya no pueda. Las conversaciones tienen su propia comprobación, `ConversationService._may_read`, en vez de la fórmula de grants | `admin_conversations.py` exige `is_app_admin`; `tests/integration/test_conversation_tenant_isolation.py` |
| Credenciales en reposo | Cifrado de sobre por organización, claves maestras versionadas, rotación con ejecución en seco | [Secretos](secrets.md#what-never-happens), cuatro garantías fijadas por pruebas |
| Contenido en reposo | **La aplicación no lo cifra.** Los datos de Postgres, `media_data` y la raíz de workspaces del sandbox dependen del cifrado de disco o volumen que tú aportes. La excepción son los ficheros subidos y de chat con `FILE_STORAGE_BACKEND=s3` y `FILE_STORAGE_S3_ENCRYPTION` en `sse-s3` (el valor por defecto) o `sse-kms` bajo una clave que tú tienes: cada escritura pide entonces al almacén que los cifre. Su tercer modo, `none`, no envía cabecera de cifrado y existe para un almacén compatible con S3 sin KMS | Control del operador. [Configuración](configuration.md#uploaded-files-at-rest); `agenticos cmd doctor` indica en qué backend está un despliegue en marcha |
| En tránsito, entrante | HTTPS en tu proxy; `Strict-Transport-Security` cuando `ENVIRONMENT=production`; cookies de sesión `httpOnly`, y `secure` según el esquema de la petición al iniciar sesión y al refrescar. La ruta de cambio de contraseña pone `secure` solo en una build de producción | [Despliegue](deploy.md#choose-a-reverse-proxy); `frontend/src/app/api/auth/login/route.ts` |
| En tránsito, hacia los almacenes | `POSTGRES_SSLMODE` y `REDIS_SSL`; `agenticos cmd doctor` informa de si la conexión que estableció iba cifrada | [Conexiones cifradas](configuration.md#encrypted-connections-tls); `tests/integration/test_store_tls.py` |
| En tránsito, hacia los providers | HTTPS a todo endpoint catalogado. Una `base_url` propia se rechaza sin host o con credenciales dentro, pero **`http://` se acepta**, para un Ollama o una pasarela en la propia red del deployment; un perfil en HTTP plano que apunte fuera de esa red envía los prompts y la clave en claro. El punto 4 de la lista de comprobación enumera todos esos perfiles | `refused_field("base_url", ...)` en el servicio de perfiles de modelo; el esquema es control del operador |
| Secretos en respuestas, logs, auditoría, exportaciones | Ningún endpoint devuelve un texto en claro; `SecretStr` en todas partes; los specs referencian secretos por id | [Secretos](secrets.md#what-never-happens) |
| Datos personales en los logs | `app/core/logging.py` redacta direcciones de correo, JWT, claves de API, tokens bearer, tokens de interacción de Discord, consultas completas de las URL firmadas de adjuntos de Discord, pares `password=` y el segmento secreto de una dirección (la clave de enlace o el token de contenido de un artefacto, y el token de una conversación compartida, de un formulario de workflow, de una prueba de webhook, de un enlace de canal o de una invitación, o el token de reanudación de una ejecución de workflow) y el valor de un parámetro de consulta que hace de credencial (`visitor` y `token` en el socket del widget del agente, `code`, `state` e `invitation_handle` en un inicio de sesión, y el `token` de un enlace enviado por correo) de cada registro de log, tanto en la API como en el worker, incluidos el log de acceso de uvicorn y sus líneas de WebSocket. Los mismos segmentos y valores se redactan en los spans de Logfire y en los argumentos de endpoint que llevan, antes de que un span se copie o se imprima. Las configuraciones de Traefik y Nginx incluidas dejan la ruta, la query string y el `Referer` fuera del log de acceso del proxy Una llamada a Discord autenticada con un token de interacción, que viaja en su URL, no se traza | `tests/test_logging.py`, `tests/test_logfire_redaction.py`; el worker lo instala en `app/worker/__main__.py`, y cada proceso hijo de ingesta en `app/worker/child.py` (#440); [Despliegue](deploy.md#choose-a-reverse-proxy) |
| Datos personales que llegan al modelo | La capability `guardrails` redacta IBAN, números de tarjeta, números de seguridad social estadounidenses, números de teléfono y direcciones de correo de los prompts, las respuestas, los resultados y los argumentos de herramientas cuando está configurada | [Capabilities](reference/capabilities.md); sus pruebas bajo `tests/` |
| Datos personales en una columna de fallo | `rag_documents.error_message` y similares registran la etapa y la clase, nunca el texto del cliente | `app/services/rag/failures.py` (#423) |
| Rendición de cuentas | Las entradas de auditoría comparten la transacción que actúa y fallan en cerrado; la suplantación nombra a ambas personas; las exportaciones masivas quedan registradas | [Gobernanza](governance.md#audit) |
| Exportación de auditoría | `GET /audit/export`, CSV o JSONL sobre una ventana, con puerta en `audit:read` y registrada en el propio rastro | [Governance](governance.md#audit) (#1422) |
| Prueba de no manipulación del rastro | Cada entrada se une a una cadena de hashes por organización, y cada cadena lleva un checkpoint en su marca más alta, de modo que una entrada reescrita, una cola cortada y una cadena borrada son todas detectables. `agenticos cmd audit-verify` las recorre y termina con código distinto de cero ante una rotura | [Gobernanza](governance.md#audit) (#1622, #1648). Detección, no prevención: quien tenga las credenciales de la propia base de datos puede volver a forjar una cadena o quitar el trigger que protege el checkpoint |
| Trazas | `observability.content` por agent: `full` registra todo, `none` solo tiempo, tokens, coste y nombres de herramienta, y un especialista de ese agent hereda el modo | [Entornos](environments.md) (#1413); un término medio `redacted` se descartó, [#1616](https://github.com/vstorm-co/agenticos/issues/1616) |
| Retención programada | Por organización y por clase —conversaciones y sus archivos, runs y manifiestos, workspaces, memoria de agentes, documentos subidos y auditoría— dentro de un valor por defecto, un techo y un suelo de auditoría de todo el despliegue. Un barrido diario borra de verdad y registra recuentos, nunca contenido. Los receipts, las filas de outbox despachadas y el history de las Virtual Tables se barren en la misma ejecución, con plazos de todo el deployment y no por organización. Las copias de seguridad y todo lo ya enviado a un colector externo quedan fuera. `notifications` no es una de esas clases: se barre con su propio calendario fijo en su lugar, una fila _leída_ a los 90 días y cualquier fila al año sin importar el estado. Los propios `announcements` quedan excluidos, así que lo enviado sigue siendo consultable en el rastro de auditoría después de que sus entregas caduquen Los medios generados también tienen su propio plazo `GENERATED_MEDIA_RETENTION_DAYS`. | [Retención](governance.md#retention); `test_retention.py`, `tests/integration/test_retention_sweep.py`; el barrido de notificaciones es `tests/integration/test_notification_retention.py` (#1598, Decision 8); `test_generated_media.py`, `tests/integration/test_generated_media.py` |
| Supresión de una persona | El borrado de la cuenta concilia lo que lo bloquearía, desvincula los bytes de los adjuntos tras el commit y purga lo que ninguna cascada alcanza: las notas que los agents escribieron sobre ella, sus identidades de plataforma, sus workspaces. Borrar la memoria es también una llamada aparte | [Qué alcanza un borrado](#what-deletion-reaches) para lo que se conserva a propósito; `test_personal_data.py` |
| Acceso a los propios datos | Una persona lee en Ajustes → Memoria todo lo que cada agente de aquí ha escrito sobre ella, y puede suspender una nota, restaurarla o borrarla. Leer el almacén _de otra persona_ es solo de la administradora del despliegue —no de un rol de organización— y queda auditado con el actor, el tenant, el sujeto y un motivo, nunca el contenido | [Leerla, y borrarla](reference/capabilities.md#reading-it-and-erasing-it); `test_memory_self_service.py`. Todo lo demás que se guarda sobre ella vuelve de `GET /me/data/export`, acotado y auditado (#1421) |
| Identidad corporativa | Inicio de sesión con Google, contraseñas, OIDC genérico contra el proveedor que ya tienes — configurado solo por discovery desde `OIDC_ISSUER` — y tu propio directorio por LDAP o Kerberos. La dirección, el nombre visible y el identificador estable del directorio se guardan en la cuenta; sus grupos se leen en cada inicio de sesión y no se guardan, solo las membresías que los mapeos de las organizaciones hacen de ellos. Sin SAML ni SCIM | [Inicio de sesión con el directorio y grupos](directory.md); `OIDC_ISSUER`, `LDAP_URL` |
| La matriz de controles que lee una revisión de seguridad | [Seguridad](security.md#controls-matrix) asigna a cada control su mecanismo y el test que lo sostiene, en el marco de HIPAA §164.312 y SOC 2 CC6–CC8; esta página y [Ponerlo en marcha](rollout.md#what-your-security-review-will-ask) son el resto | [Seguridad](security.md) (#1412) |
| Superficies públicas | La clave de visitante de una página alojada es aleatoria, nunca derivada de la persona; la admisión y las subidas se limitan por dirección, y la dirección vive en una clave de Redis durante la ventana y en ningún otro sitio | [Canales](channels.md#a-hosted-page) |
| Avisos legales | Las URL de Términos y Privacidad propias del deployment sustituyen a las páginas incorporadas | [El deployment](deployment.md#identity) |

### Trazas { #traces }

`instrument_pydantic_ai()` se ejecuta con el valor por defecto de la biblioteca,
así que un span contiene el mensaje del usuario, la respuesta del modelo y cada
argumento y resultado de herramienta. Con `LOGFIRE_TOKEN` sin definir, sin token
`observability` en ningún spec y sin `logfire_token_secret_id` en ningún
entorno, no se envía nada y el id de la traza se sigue registrando localmente.
Un deployment que necesite trazas sin el contenido pone el
`observability.content` del agent en `none`: se registran tiempo, tokens, coste y
nombres de herramienta, y ningún texto de mensaje sale — y un especialista de ese
agent hereda el modo, escrito inline o inventado por el modelo del run.

No hay un tercer modo intermedio. Una exportación depurada por un filtro de PII
es una garantía que nadie puede auditar — un identificador que el filtro deje
pasar ya ha salido, y el operador cree que no —, así que la elección es a
propósito entre todo el contenido y nada de él
([#1616](https://github.com/vstorm-co/agenticos/issues/1616)).

### Qué alcanza el borrado { #what-deletion-reaches }

Borrar es lo que hace el producto hoy cuando alguien lo pide; la retención
programada es [#1420](https://github.com/vstorm-co/agenticos/issues/1420).

| Acción | Elimina | Deja |
| --- | --- | --- |
| `DELETE /conversations/{id}` (el propietario) | La conversación, sus mensajes, llamadas a herramientas, valoraciones, comparticiones, filas `chat_files` y las búsquedas de conocimiento hechas en ella, por cascada - entre ellos la transcripción de una llamada de voz, ya que sus turnos son mensajes; los bytes de los adjuntos bajo `MEDIA_DIR`, recogidos antes del borrado y desvinculados tras su commit; los objetos de medios descargados de ese hilo, por prefijo; un workspace de contenedor mediante `purge_for_conversation`; los borradores de dataset generados a partir de ella que aún esperan una decisión Las imágenes, la voz y los vídeos generados en estas conversaciones se eliminan con sus filas; un trabajo en la misma transacción elimina sus archivos. | Las filas de runs y los manifiestos que nombraron la conversación conservan su copia del prompt; una fila `voice_calls` conserva sus horas y su coste con el vínculo a la conversación vaciado. Los casos de datasets copiados de ella conservan su texto, y se borra todo vínculo con la conversación, su run y sus mensajes; el texto puede seguir conteniendo datos personales que alguien escribió, y se va cuando se borra a esa persona. Los resultados de eval runs ya producidos a partir de esos casos conservan las respuestas y llamadas que registraron. Las bifurcaciones hechas de ella conservan sus mensajes y llamadas a herramientas copiados, con el vínculo vaciado, y las imágenes generadas dejan de cargarse en ellas; el periodo de retención de una bifurcación cuenta desde que se creó |
| `DELETE /projects/{id}` (`projects:edit`) | El contenedor del proyecto y cada fichero que contiene; los chats cuyo iniciador borró su cuenta, a los que ya solo llegaba el proyecto, con lo que elimina borrar una conversación; los borradores de dataset generados a partir de esos chats que aún esperan una decisión | Sus demás chats, que se conservan como chats normales fuera de cualquier proyecto. Los casos de dataset copiados de un chat que eliminó conservan su texto, sin ningún vínculo con el chat, su run ni sus mensajes |
| `DELETE /memory/person/{user_id}` (la persona, o `members:manage`) | Cada fila de `agent_memory_files` con clave en la persona a lo largo de todos los agents de la organización, cada claim registrado en el ámbito de la persona y las copias compartidas a partir de ellos | Las notas con clave en un chat de grupo en el que la persona habló |
| `DELETE /users/{id}` | La cuenta, sus sesiones, su organización personal y sus colecciones personales con sus tablas vectoriales y ficheros, por teardown explícito; conversaciones fuera de un proyecto y ficheros de chat por cascada; sus bytes, desvinculados tras el commit; y lo que ninguna cascada alcanza: las notas que los agents escribieron sobre ella (`owner_key` es una cadena, no una clave foránea), sus identidades de plataforma, sus workspaces de usuario, las búsquedas de conocimiento de cada run que inició, también en un chat de proyecto, la copia de una respuesta que una puntuación de eval guardó de uno de sus runs, los borradores de dataset generados a partir de las preguntas que escribió, sus conversaciones o sus runs que aún esperan una decisión; el texto de los casos de datasets cuya pregunta hizo, en todas las versiones, encontrados incluso después de borrarse la conversación, con las respuestas y llamadas que los eval runs registraron para esos casos, los mensajes de los manifiestos de los runs del agent y del juez que los respondieron y los argumentos de las llamadas que esos runs retuvieron; sus turnos en el historial anterior de los casos de otras personas, con las respuestas del agent a ellos; sus comentarios guardados como nota de un caso; las citas que el asistente de autoría hizo de ella; y los borradores de los temas de lagunas de conocimiento que contienen sus búsquedas Las imágenes, la voz y los vídeos generados en estas conversaciones se eliminan con sus filas; un trabajo en la misma transacción elimina sus archivos. | Entradas de auditoría que nombran el id del actor y, en algunas acciones, el correo: se conservan a propósito, porque una entrada sin su actor es peor que una que nombra una cuenta borrada. Mensajes en conversaciones de otra persona, y los chats de proyecto que empezó, que se conservan para el equipo sin autor; sus mensajes ahí se muestran como de un antiguo miembro. Los casos de datasets copiados de sus conversaciones o runs, que se conservan marcados como anonimizados tras el borrado (**Anonymised after erasure**) y sin ningún vínculo con esa persona, para que su curador pueda reescribirlos o eliminarlos; hasta entonces un eval run los deja fuera. Un caso escrito antes de que los casos registraran quién preguntó, cuya conversación se borró antes de eso, conserva su texto. Un caso del run de otra persona que solo valoró conserva su pregunta y su respuesta Los medios generados sin conversación no están vinculados a la persona y caducan a los siete días. |
| Borrar un documento o una colección | Las filas, la tabla vectorial (o solo los chunks de la colección, mientras otra colección o chunks que no son de ninguna colección conserven la tabla) y el archivo almacenado, mediante un flow duradero tras el commit; la copia de parseo bajo `_rag_tmp`, cuando se borra el documento o cuando su job de ingesta vuelve a correr, y si no, mediante el sweep horario cuando la copia tiene una hora - en unas dos horas desde la subida. Una copia se conserva mientras su documento se sigue procesando | Nada, una vez que el flow ha corrido, salvo chunks antiguos sin colección registrada, que pueden quedarse hasta que se elimine la tabla mientras otra colección o contenido de un operador la conserve; los recuentos de `sync_logs` permanecen |
| Borrar una organización | Todo lo acotado a ella, con el mismo desmontaje diferido - sus medios generados por prefijo, incluidos los archivos escritos antes de que se registraran | Las colecciones personales que solo llevaban el id |

Los mensajes de canal guardan solo el texto del remitente. Las etiquetas del autor se resuelven desde las identidades de canal justo antes de enviar la solicitud al modelo, fuera de las instrucciones del sistema. La consola y las acciones de copiar, fijar y crear atajos reciben el texto original. Los historiales guardados y las ejecuciones pausadas conservan referencias opacas; los manifiestos omiten las partes de referencia del canal añadidas. Al eliminar la cuenta se borran sus identidades, por lo que las solicitudes futuras no pueden resolver sus etiquetas; se conservan los mensajes compartidos.

Ninguno de estos alcanza una copia de seguridad. Una restauración devuelve lo
que se había borrado, así que la caducidad de las copias forma parte de la
política de retención y se escribe junto a ella.

## Qué tiene que decidir y obtener un deployment { #what-a-deployment-has-to-decide-and-obtain }

El software no puede aportar ninguna de estas cosas. Cada una es una prueba que
pedirá la revisión, distinta de la capacidad técnica que la hace posible.

- **Un contrato de encargo con cada subencargado configurado** — cada provider
  que nombre una fila de `model_profiles` o de `organization_secrets`, el
  provider de embeddings, LlamaCloud si lo usa alguna colección, el proveedor de
  búsqueda que nombre el `method` de un agent, Logfire, el
  relay SMTP y Google si el inicio de sesión está habilitado.
- **Una declaración de ubicación de datos por provider**, cotejada con la
  `base_url` que cada perfil usa realmente. Un provider con endpoint en la UE
  solo está en la UE si el perfil lo dice.
- **Una exclusión de entrenamiento por provider**: el ajuste de cuenta o la
  cláusula contractual por la que los datos de la API no se usan para entrenar.
  La posición de la propia plataforma es una frase — no entrena nada — y el
  resto es cosa suya.
- **Un contrato de encargo con Vstorm**, solo si Vstorm opera el deployment.
- **Un calendario de retención** para conversaciones, archivos, memoria,
  documentos, runs y auditoría, y junto a él la caducidad de las copias de
  seguridad. Hasta que
  [#1420](https://github.com/vstorm-co/agenticos/issues/1420) imponga uno, la
  retención es un borrado manual.
- **Cifrado de disco o de volumen** en el host de la base de datos, el volumen
  de medios y el host de la sandbox, ya que la aplicación no cifra el contenido
  por sí misma — y una regla de salida en el host de la sandbox si los agents
  pueden ejecutar comandos.
- **Las páginas legales** a las que enlaza el deployment, y quién responde a una
  solicitud de acceso o supresión. Los mecanismos están aquí — `GET
/me/data/export` y el borrado de la cuenta — pero quién recibe la solicitud y en
  qué plazo es cosa del responsable.

## Verificar un deployment { #verifying-one-deployment }

Comprobaciones reproducibles, desde el host, contra el deployment en marcha. Cada
una imprime hechos que la revisión puede adjuntar; ninguna imprime una credencial
ni los datos de una persona. Ejecútalas desde `backend/`, o a través de
`docker compose exec api`.

```bash
# 1. ¿Arranca siquiera, y van cifradas las conexiones a los almacenes?
#    `postgres` informa del estado TLS de la conexión que el propio doctor
#    estableció.
uv run agenticos cmd doctor

# 2. Cada credencial sellada sigue abriéndose con las master keys configuradas.
uv run agenticos cmd vault-rotate --dry-run

# 3. Las cadenas de hashes del rastro de auditoría y sus checkpoints, recalculados.
#    Termina con código distinto de cero si alguna cadena ha sido alterada.
uv run agenticos cmd audit-verify

# 4. Todo lo que este deployment ha configurado realmente: los ajustes que
#    deciden qué sale, cada provider y endpoint que un agent puede alcanzar, las
#    credenciales guardadas por propósito, las colecciones y quién calcula sus
#    embeddings, los servidores de tu propia red, los servidores MCP, los
#    portales de trigger, las fuentes de sincronización y los bots de canal, las
#    capabilities que alcanzan una dirección propia, dónde se trazan los runs y
#    cuánto contenido lleva un span, cuánto de cada almacén alcanzaría un periodo
#    de retención, y los archivos bajo `MEDIA_DIR` a los que ya no apunta ninguna
#    fila.
uv run agenticos cmd data-protection-report --older-than 365
```

El punto 4 es el que hay que adjuntar. Imprime configuración y recuentos, nunca
contenido: ningún texto de mensaje, ningún documento, ningún valor de secreto ni
pista de uno, y un ajuste que guarda una credencial se informa como definido o no
definido en vez de imprimirse. `--older-than` es el periodo de retención que se
está considerando, en días, y la última columna de su tabla de retención es lo
que ese periodo ya habría eliminado.

Su última sección cuenta los bytes que ya no nombra ninguna fila. Borrar una
conversación o una cuenta desvincula ahora sus adjuntos tras el commit, así que
ese camino ya no suma; lo que todavía encuentra viene de antes de esos borrados,
o de una desvinculación que un barrido best-effort no completó.

El directorio
temporal de parseo queda excluido, ya que por diseño no tiene fila; el job horario
`sweep-rag-scratch` elimina una copia cuyo documento ya no existe o ya no se está
procesando.

Los medios
generados se cuentan desde que `generated_media` registra cada archivo, así que lo
que aparece bajo un directorio `generated_<org>` es sobre todo un archivo generado
antes de que existiera esa tabla, que solo se va con su organización. También
puede ser un archivo cuya desvinculación falló tras borrarse su fila, o uno que
aún se está guardando, antes de que se escriba su fila. Todo lo demás
que se cuenta ahí son bytes que el producto ya no encuentra y no puede borrar.

Informa de un directorio y un
recuento en vez de un nombre de archivo, porque una ruta almacenada conserva el
nombre con el que se subió el archivo.

Dos secciones se leen de lo que se ejecuta y no de una tabla. **Destinos de las
capabilities** enumera las capabilities vinculadas a un agent que alcanzan una
dirección propia - `web_research` busca a través de DuckDuckGo sin credencial
alguna y por tanto sin fila en ningún otro punto del informe - y **Tracing** se
lee de cada versión ejecutable: la predeterminada y la que fija cada
[entorno](environments.md) con nombre, porque un run a través de ese entorno usa
la observabilidad de esa versión y no la de la predeterminada.

Lo que ningún comando puede producir es la otra mitad de esta página: los
acuerdos, las ubicaciones y las exclusiones de entrenamiento de la sección
anterior. Adjúntalos junto a la salida.

## Condiciones abiertas para una primera puesta en marcha { #open-conditions-for-a-first-rollout }

Enunciadas para el deployment para el que se escribió esta página, y ciertas para
cualquier deployment hasta que cada una se cierre.

**En el código, y permanentes:**

- Las trazas llevan contenido completo salvo que un agent ponga
  `observability.content` en `none`. No hay término medio filtrado ni lo habrá:
  una exportación parcialmente depurada es una garantía que nadie puede auditar
  ([#1616](https://github.com/vstorm-co/agenticos/issues/1616)).
- **El contenido en reposo es del operador.** Los cuerpos de los mensajes, los
  documentos y sus vectores, y los workspaces del sandbox son columnas y ficheros
  en claro; el vault sella credenciales, no contenido. Los ficheros subidos pueden
  ir a un almacén compatible con S3 que los cifra en su lado, pero la base de
  datos y el volumen de medios los protege el cifrado de disco o de volumen, o
  nada.

**Cerradas, y respondidas arriba en vez de aquí:** la prueba de no manipulación
del rastro de auditoría (#1622, #1648), el modo de contenido de trazas por agent
y su herencia por los especialistas (#1413, #1699), el trazado en el proceso
que ejecuta un agent disparado (#1700), la matriz de controles de HIPAA y SOC 2 en
[Seguridad](security.md#controls-matrix) (#1412), el borrado y la exportación de
los datos de una persona (#1421), el backend S3 con cifrado en el servidor
(#1423) y el inicio de sesión OIDC genérico (#1419). Las trazas no tienen término
medio filtrado y no lo tendrán
([#1616](https://github.com/vstorm-co/agenticos/issues/1616)); para un deployment
que no pueda exportar contenido, la respuesta es `none`.

**En el deployment, decididas por su operador:** los acuerdos, las ubicaciones,
las exclusiones de entrenamiento, el calendario de retención, la caducidad de las
copias de seguridad, el cifrado de disco, la salida de red de la sandbox y las
páginas legales de la sección anterior. Cada una es la clase de prueba que
`data-protection-report` deliberadamente no puede producir.

Una revisión que encuentre cada fila de arriba cerrada o aceptada por escrito
tiene lo que esta página puede darle. El resto es del deployment.

## Diagnóstico del despliegue { #deployment-diagnostics }

El colector recibe estado de instalación, rangos de uso, recuentos agrupados de
fallos (un componente, un código de error cerrado y un recuento, nunca el texto
de una excepción) y presencia seudónima en primer plano, que cada navegador o app
con sesión iniciada le envía directamente. Los informes están activados por
defecto, incluso con un `.env` antiguo, y el colector por defecto es una
dirección remota, `https://analytics-agenticos.testapp.ovh`. La
[configuración de diagnóstico](configuration.md#diagnostics) detalla campos,
retención, cómo apuntarlo a tu propio colector y cómo desactivarlo con
`DIAGNOSTICS_ENABLED=false`.

## Datos del puente de iMessage { #imessage-bridge-data }

El canal opcional de iMessage transmite texto y archivos adjuntos explícitos mediante el Mac de BlueBubbles configurado por la organización y Mensajes de Apple. El Mac y su cuenta de Apple son otros lugares donde pueden conservarse copias. AgenticOS guarda direcciones vinculadas, conversaciones, ejecuciones y archivos según las reglas existentes de conservación y borrado de canales; borrar aquí no elimina las copias del Mac ni de Mensajes. Las notificaciones privadas requieren una ruta explícita; los grupos no heredan la memoria privada del perfil.

La contraseña del servidor y la credencial independiente del callback se cifran en la bóveda. El cliente HTTP oculta la contraseña en las direcciones visibles de las solicitudes; el puente sigue recibiendo su parámetro de autenticación obligatorio, por lo que su operador debe proteger sus propios registros y red.