Bucle de Aprobación del Operador
Un agente que se comunica con contrapartes externas nunca debe enviar basándose en su propio juicio y debe mantener al operador informado internamente. Este skill define el contrato: cada borrador saliente se archiva como una obligación, un operador decide el texto exacto y un libro de contabilidad de entregas prueba qué salió.
Cuándo Usarlo
- Un agente redacta respuestas a clientes, proveedores, inversores o socios en un canal compartido, correo electrónico o chat, y un humano debe aprobar antes de enviar.
- Necesita un rastro de auditoría que vincule cada mensaje enviado con el texto exacto del borrador, el operador que lo aprobó y la hora de la decisión.
- Ha visto una aprobación desactualizada liberar un borrador reescrito, o dos trabajadores entregar el mismo mensaje aprobado dos veces.
- Los borradores siguen preguntando a las contrapartes información que el libro de contabilidad ya contiene.
Cómo Funciona
Objetos
| Objeto | Significado |
|---|---|
| Obligación | Algo que debemos a una contraparte. El estado avanza redactado, luego aprobado o rechazado, luego enviado. Lleva dirección, contraparte, canal y una época actualizado_en. |
| Borrador | Fila adjunta que contiene el texto exacto del borrador, un sha256 de ese texto, coordenadas de origen (plataforma, canal, hilo, usuario) y prioridad (P0 a P3). Uno por obligación, reemplazado al volver a archivar. |
| Decisión | Aprobación o rechazo de un operador, registrada con el identificador del operador, un nonce y la época del borrador contra la que se tomó. |
| Instantánea de aprobación | Texto inmutable, hash, época y destino registrados por el escritor de decisiones ya autorizado. Las instantáneas faltantes no pueden conceder el despacho. |
| Reclamación | Reserva duradera con un token aleatorio y estado; como máximo una reclamación activa por obligación. |
| Entrega | Fila del libro de contabilidad que prueba un envío o notificación para un par (obligación, decisión). |
El esquema de referencia está en references/approval-ledger.sql.
Archivar un borrador
- Limpiar entradas. Eliminar caracteres de control, colapsar espacios en blanco en campos de una sola línea y aplicar límites de longitud (borrador, resumen, contexto, contraparte). Los campos vacíos o demasiado grandes son rechazados, no truncados silenciosamente.
- Ejecutar la compuerta de línea base (abajo). Puede rechazar el archivo.
- Generar el hash del texto del borrador con sha256. El prefijo del hash va en el resumen para que el panel de aprobación muestre qué texto está aprobando.
- Actualizar o insertar. Si ya existe una obligación redactada abierta para la misma (contraparte, canal), reemplazar el borrador adjunto y adelantar el
actualizado_ende la obligación. Ese adelanto es la rotación de época: cualquier decisión basada en la época anterior ya no puede liberar el nuevo texto. De lo contrario, insertar una nueva obligación con estadoredactado. - Enrutar el recibo de archivo solo a un destino de operaciones internas configurado y verificado. Si el origen es ese destino interno, acusar recibo allí. Nunca silencioso significa informes internos, no una respuesta externa automática. Mantener hashes de borradores, estado de aprobación, identidad del operador y metadatos del flujo de trabajo fuera de los canales visibles para la contraparte. Los orígenes desconocidos o no clasificados permanecen en silencio; un mensaje directo no es automáticamente interno.
Si un destino interno verificado no está disponible, retener el resultado del archivo en el resultado de la herramienta interna o en la superficie del operador. Nunca recurrir a un origen externo o desconocido. Un resultado de herramienta expuesto a externos no es una superficie interna.
Archivar un borrador no autoriza una respuesta externa. Cualquier pregunta aclaratoria o respuesta neutral permitida por la política es una decisión de salida separada, sujeta a las restricciones existentes de mención, canal, solo borrador, congelado y nunca en la disciplina de canal de contraparte. No debe revelar metadatos de aprobación internos.
Compuerta de línea base
Antes de archivar cualquier borrador, consultar la línea base actual para la contraparte (un libro de contabilidad temporal, almacén de contratos o CRM):
- Contrato firmado o entregado registrado: rechazar el archivo con la evidencia y una recomendación. Preguntar a una contraparte sobre especificaciones después de firmar es exactamente el fallo que esta compuerta existe para evitar.
- Anulación del operador:
forzar_a_pesar_de_contrato_firmadopermite el archivo y estampa[ANULACIÓN_LÍNEA_BASE_CONTRATO_FIRMADO]en el contexto del borrador. - Servicio de compuerta inalcanzable: el archivo procede y el contexto se estampa con
[VERIFICACIÓN_LÍNEA_BASE_NO_DISPONIBLE]. El panel ve que la guardia estaba desactivada. Los fallos nunca desactivan silenciosamente la compuerta. - Cuando los hechos están disponibles, adjuntar los más recientes al contexto como un resumen
[HECHOS DE LÍNEA BASE: ...]para que el borrador aterrice con la verdad actual.
Decidir
El panel de aprobación lista las obligaciones con estado redactado y dirección nosotros_les_debemos. Aprobar o rechazar escribe una fila de decisión que lleva la época del borrador (marca_de_tiempo_actualización_borrador) y cambia el estado de la obligación en la misma transacción. Una decisión cuya época no coincida con el actualizado_en actual está obsoleta y no debe liberar nada.
Para una decisión de aprobación ya autorizada, la misma transacción inserta una fila inmutable de instantáneas_de_aprobación_de_obligación: IDs de decisión y obligación, época actual del borrador, texto exacto y SHA-256, plataforma/canal/hilo, y tipo borrador_enviado. El escritor de decisiones debe establecer la autorización antes de escribir; la referencia nunca autentica a un operador ni fabrica una decisión. La política de aprobación automática no está habilitada ni ampliada por la referencia. Las decisiones heredadas sin instantáneas requieren una conciliación explícita o una nueva aprobación; nunca retroceder el permiso del borrador mutable actual.
Entregar
La referencia SQLite está en references/approval_claims.py. Concede permiso de despacho pero nunca llama al transporte. Usar una base de datos de referencia local existente inicializada desde el fixture SQL; el módulo no aplica esquema ni migraciones de producción. Solo un escritor de decisiones de confianza puede poblar registros de aprobación. Todos los escritores deben habilitar claves foráneas y disparadores recursivos y respetar las salvaguardas del esquema; la manipulación administrativa de la base de datos está fuera de este modelo.
- Descubrir borradores aprobados vinculados. El descubrimiento no es permiso.
claim()abre su propia transacciónBEGIN IMMEDIATE, valida la época aprobada actual, el texto exacto, el SHA-256 calculado y el destino completo contra la instantánea, e inserta una reclamación única antes de devolver su token. Un conflicto detiene al trabajador antes del transporte. Los recibos completados no pueden reclamarse de nuevo. begin_dispatch()revalida el vínculo y cambia atómicamentereclamadoadespachandousando el token. Solo su llamante ganador recibe eltexto_borradorexacto y el destino después de la confirmación. Nunca regenerar texto, releer un adjunto mutable para el transporte ni reutilizar la carga para otro intento. Se rechaza una transacción de llamante anidada; el permiso no puede depender de una confirmación posterior del llamante. No queda ninguna transacción de base de datos abierta durante el transporte.- Un resultado exitoso confirmado va a
complete(), que registra atómicamente la coordenada de entrega, marca la reclamación como entregada y cambia la obligación aenviado. Una finalización idéntica es una no operación; las coordenadas conflictivas fallan. La clave ÚNICA del recibo deduplica registros, no efectos externos previos. - Excepciones, tiempos de espera, muerte del trabajador después de begin_dispatch o fallo en la persistencia del recibo dejan un intento bloqueado.
mark_unknown()registra incertidumbre. Las reclamaciones desconocidas nunca caducan, se reabren, se reintentan automáticamente ni permiten que otra decisión para esa obligación las omita. Un llamante de confianza puede usarreconcile()con coordenada y evidencia confirmadas exitosas; el módulo no verifica esa evidencia. La ausencia de un recibo no es prueba de no entrega.
La garantía es un intento de despacho automático por decisión aprobada, no una entrega externa exactamente una vez. Un bloqueo después de begin_dispatch pero antes del transporte puede dejar cero envíos y una reclamación retenida. Liberar un resultado desconocido para un nuevo intento requeriría cercar al ejecutor original y verificar la semántica del proveedor; esta referencia deliberadamente no proporciona tal operación de reintento.
| Estado de reclamación | Siguientes estados permitidos |
|---|---|
| reclamado | despachando o cancelado antes del despacho |
| despachando | entregado o desconocido |
| desconocido | entregado solo mediante conciliación de confianza |
| entregado, cancelado | terminal; la clave de decisión no puede reutilizarse |
Mientras una reclamación está activa, los guardias de la base de datos congelan las escrituras de obligación, borrador y decisión, incluyendo reemplazos. Las instantáneas y reclamaciones no pueden eliminarse. Cancelar una operación reclamada con su token antes de volver a archivar; el token obsoleto entonces no concede nada. Después de que comience el despacho, mantener nuevas ediciones o revocaciones para conciliación. Esto serializa los cambios en lugar de fingir que se recupera una operación en vuelo.
Las decisiones rechazadas y las filas heredadas sin borradores/instantáneas nunca entran en esta ruta de envío de borradores externos. Reportarlas en la superficie del operador interno para manejo manual. Los pies de recibo internos permanecen internos:
aprobado por <operador> · recibo <id_decisión> · borrador sha256 <prefijo>.
Nunca alterar texto externo ya aprobado para agregar metadatos de flujo de trabajo.
La validación local enfocada utiliza bases de datos temporales, conexiones separadas y un contador de intentos simulado, no un proveedor o mensaje real:
python3 -m unittest discover -s tests/skills -p 'test_approval_delivery_claims.py'.
Las pruebas requieren Python 3.11+ con soporte de serialización de SQLite; la referencia usa solo la biblioteca estándar. Las comprobaciones de contrato de patrón de escritorio existentes siguen siendo una verificación de compatibilidad separada.
Aprobación automática con límite de tiempo (opcional)
Un borrador puede llevar auto_enviar_después (segundos de época). Una barrida aprueba los borradores cuyo plazo haya vencido sin decisión, registrando el operador auto-ttl, luego la entrega procede por la ruta normal. Las acciones del operador siempre ganan: una decisión cambia el estado antes de que la barrida lo vea, y un rearchivo rota la época y mueve o elimina el plazo. La barrida vuelve a verificar el estado y la época dentro de la transacción de escritura para que una carrera se resuelva como una no operación. Los borradores sin plazo permanecen con compuerta dura para siempre.
Vinculación de señal
Un borrador puede nombrar la obligación entrante a la que responde (id_obligación_señal). Este es el único vínculo veraz para la medición de latencia (señal entrante a respuesta redactada) y permite que el escaneo de SLA trate ese elemento entrante como respondido. Rechazar el archivo si la fila referenciada no existe.
Ejemplos
Archivar un borrador
solicitud_archivo(
borrador="Gracias, podemos mantener el espacio hasta el viernes. ¿Qué fecha de inicio te funciona?",
contraparte="proveedor-acme",
contexto="respuesta a pregunta sobre ventana de entrega",
plataforma_origen="slack", canal_origen="#acme-compartido",
hilo_origen="1712345678.000100", prioridad="P1",
id_obligación_señal=412)
-> {id_obligación: 431, sha256_borrador: "9f2c...", rearchivado: false}
El destino de operaciones internas configurado y verificado ve:
Borrador archivado para aprobación (P1, sha 9f2c8a1b). Esperando operador.
El canal de origen visible para la contraparte no recibe ningún aviso de archivo. Si no hay un destino interno verificado disponible, el recibo permanece en el resultado de la herramienta interna o en la superficie del operador, sin recurrir a externos.
Re-archivar después de una redirección
El operador solicita un borrador más corto. Archivar de nuevo para la misma (contraparte, canal) devuelve rearchivado: true, el texto del adjunto y el hash cambian, y actualizado_en avanza. Un clic en aprobar en la fila antigua del panel lleva la época antigua y es ignorado.
Rechazo de compuerta
ErrorDeAprobaciónDeEscritorio: la compuerta de línea base rechazó este borrador: el libro de contabilidad muestra un
contrato firmado para 'proveedor-acme'. Evidencia: acuerdo maestro ejecutado
2026-08-14. Recomendación: no preguntar. Re-archivar con
forzar_a_pesar_de_contrato_firmado=true si esto es genuinamente un nuevo hilo.
Pie de entrega en un canal interno
Confirmado para el viernes, fecha de inicio 2026-09-08.
aprobado por operador-a · recibo 118 · borrador sha256 9f2c8a1b2d3e4f50
Invariantes a probar
- Los recibos de archivo van solo a operaciones internas configuradas y verificadas; el origen recibe uno solo cuando es ese destino interno verificado.
- Un origen desconocido permanece en silencio. Un destino interno no disponible utiliza el resultado de la herramienta interna o la superficie del operador, sin recurrir a externos.
- La misma (contraparte, canal) archivada dos veces produce una obligación, dos épocas.
- Una decisión con una época obsoleta nunca resulta en una fila de entrega.
- Dos reclamantes concurrentes producen un permiso de despacho; los perdedores nunca intentan el transporte.
- Los resultados desconocidos y la persistencia fallida del recibo nunca permiten un reintento automático.
- La finalización exitosa registra el recibo y el estado de enviado en una transacción.
- Una época, texto, hash o destino alterados no pueden adquirir ni iniciar una reclamación.
- Las reclamaciones activas bloquean el rearchivo; solo la cancelación previa al despacho puede liberar esa retención.
- La compuerta no disponible estampa el marcador; la compuerta con contrato firmado rechaza sin forzar.
- Auto-ttl nunca se activa contra texto que el operador ha rearchivado desde entonces.