Loop de Aprovação do Operador
Um agente que se comunica com contrapartes externas nunca deve enviar por conta própria e deve manter o operador informado internamente. Este skill define o contrato: todo rascunho de saída é arquivado como uma obrigação, um operador decide o texto exato e um livro-razão de entrega prova o que foi enviado.
Quando Usar
- Um agente redige respostas para clientes, fornecedores, investidores ou parceiros em um canal compartilhado, e-mail ou chat, e um humano deve aprovar antes do envio.
- Você precisa de uma trilha de auditoria que vincule cada mensagem enviada ao texto exato do rascunho, ao operador que a aprovou e ao momento da decisão.
- Você já viu uma aprovação desatualizada liberar um rascunho reescrito, ou dois trabalhadores entregarem a mesma mensagem aprovada duas vezes.
- Rascunhos continuam perguntando a contrapartes por fatos que o livro-razão já possui.
Como Funciona
Objetos
| Objeto | Significado |
|---|---|
| Obrigação | Uma coisa que devemos a uma contraparte. O status avança rascunho, depois aprovado ou rejeitado, depois enviado. Carrega direção, contraparte, canal e uma época atualizado_em. |
| Rascunho | Linha auxiliar contendo o texto exato do rascunho, um sha256 desse texto, coordenadas de origem (plataforma, canal, thread, usuário) e prioridade (P0 a P3). Um por obrigação, substituído no re-arquivamento. |
| Decisão | Aprovação ou rejeição de um operador, registrada com o ID do operador, um nonce e a época do rascunho contra a qual foi tomada. |
| Instantâneo de aprovação | Texto imutável, hash, época e destino registrados pelo escritor de decisão já autorizado. Instantâneos ausentes não podem conceder despacho. |
| Reivindicação | Reserva durável com um token aleatório e estado; no máximo uma reivindicação ativa por obrigação. |
| Entrega | Linha do livro-razão comprovando um envio ou notificação para um par (obrigação, decisão). |
O esquema de referência está em references/approval-ledger.sql.
Arquivando um rascunho
- Limpe as entradas. Remova caracteres de controle, colapse espaços em branco em campos de linha única e aplique limites de comprimento (rascunho, resumo, contexto, contraparte). Campos vazios ou muito grandes são recusados, não truncados silenciosamente.
- Execute a verificação de linha de base (abaixo). Ela pode recusar o arquivamento.
- Gere o hash do texto do rascunho com sha256. O prefixo do hash vai para o resumo para que o painel de aprovação mostre qual texto está aprovando.
- Atualize ou insira (upsert). Se já existir uma obrigação em rascunho aberta para a mesma (contraparte, canal), substitua o rascunho auxiliar e avance o
atualizado_emda obrigação. Esse avanço é a rotação de época: qualquer decisão baseada na época antiga não pode mais liberar o novo texto. Caso contrário, insira uma nova obrigação com statusrascunho. - Roteie o recibo de arquivamento apenas para um destino interno de operações configurado e verificado. Se a origem for esse destino interno, confirme lá. Nunca silencioso significa relatório interno, não uma resposta externa automática. Mantenha hashes de rascunho, status de aprovação, identidade do operador e metadados do fluxo de trabalho fora dos canais visíveis à contraparte. Origens desconhecidas ou não classificadas permanecem em silêncio; uma mensagem direta não é automaticamente interna.
Se um destino interno verificado não estiver disponível, retenha o resultado do arquivamento no resultado da ferramenta interna ou na superfície do operador. Nunca recorra a uma origem externa ou desconhecida. Um resultado de ferramenta exposto a terceiros não é uma superfície interna.
Arquivar um rascunho não autoriza uma resposta externa. Qualquer pergunta esclarecedora ou resposta neutra permitida pela política é uma decisão de saída separada, sujeita às restrições de menção, canal, apenas rascunho, congelado e nunca existentes em "disciplina de canal de contraparte". Ela não deve divulgar metadados internos de aprovação.
Verificação de linha de base
Antes de qualquer rascunho ser arquivado, consulte a linha de base atual para a contraparte (um livro-razão temporal, armazenamento de contrato ou CRM):
- Contrato assinado ou entregue registrado: recuse o arquivamento com a evidência e uma recomendação. Perguntar a uma contraparte sobre especificações após a assinatura é exatamente a falha que esta verificação existe para evitar.
- Substituição pelo operador:
forcar_apesar_contrato_assinadopermite o arquivamento e carimba[SUBSTITUICAO_LINHA_BASE_CONTRATO_ASSINADO]no contexto do rascunho. - Serviço de verificação inacessível: o arquivamento prossegue e o contexto é carimbado
[VERIFICACAO_LINHA_BASE_INDISPONIVEL]. O painel vê que a proteção estava desligada. Falhas nunca desabilitam silenciosamente a verificação. - Quando os fatos estão disponíveis, anexe os mais recentes ao contexto como um resumo
[FATOS DA LINHA BASE: ...]para que o rascunho chegue com a verdade atual.
Decidindo
O painel de aprovação lista obrigações com status rascunho e direção nos_devemos_eles. Aprovar ou rejeitar escreve uma linha de decisão carregando a época do rascunho (ts_atualizacao_rascunho) e altera o status da obrigação na mesma transação. Uma decisão cuja época não corresponde ao atualizado_em atual está obsoleta e não deve liberar nada.
Para uma decisão de aprovação já autorizada, a mesma transação insere uma linha imutável instantaneos_aprovacao_obrigacao: IDs da decisão e obrigação, época atual do rascunho, texto exato e SHA-256, plataforma/canal/thread e tipo rascunho_enviado. O escritor da decisão deve estabelecer autorização antes de escrever; a referência nunca autentica um operador ou fabrica uma decisão. A política de aprovação automática não é ativada ou expandida pela referência. Decisões legadas sem instantâneos exigem reconciliação explícita ou uma nova aprovação; nunca retroceda permissão a partir do rascunho mutável atual.
Entregando
A referência SQLite é references/approval_claims.py. Ela concede permissão de despacho, mas nunca chama o transporte. Use um banco de dados de referência local existente inicializado a partir do fixture SQL; o módulo não aplica esquema ou migrações de produção. Apenas um escritor de decisão confiável pode popular registros de aprovação. Todos os escritores devem habilitar chaves estrangeiras e gatilhos recursivos e honrar as proteções do esquema; adulteração administrativa do banco de dados está fora deste modelo.
- Descubra rascunhos aprovados vinculados. Descoberta não é permissão.
claim()abre sua própria transaçãoBEGIN IMMEDIATE, valida a época aprovada atual, texto exato, SHA-256 calculado e destino completo contra o instantâneo, e insere uma reivindicação única antes de retornar seu token. Um conflito interrompe o trabalhador antes do transporte. Recibos concluídos não podem ser reivindicados novamente. begin_dispatch()revalida a vinculação e altera atomicamentereivindicadoparadespachandousando o token. Apenas seu chamador vencedor recebe otexto_rascunhoexato e o destino após o commit. Nunca regere texto, releia um rascunho auxiliar mutável para transporte ou reutilize a carga para outra tentativa. Uma transação de chamador aninhada é recusada; a permissão não pode depender de um commit de chamador posterior. Nenhuma transação de banco de dados permanece aberta durante o transporte.- Um resultado bem-sucedido confirmado vai para
complete(), que registra atomicamente a coordenada de entrega, marca a reivindicação como entregue e altera a obrigação paraenviado. Conclusão idêntica é um no-op; coordenadas conflitantes falham. A chave UNIQUE do recibo desduplica registros, não efeitos externos anteriores. - Exceções, timeouts, morte do trabalhador após início do despacho ou falha de persistência do recibo deixam uma tentativa bloqueada.
mark_unknown()registra incerteza. Reivindicações desconhecidas nunca expiram, reabrem, repetem automaticamente ou permitem que outra decisão para aquela obrigação as ignore. Um chamador confiável pode usarreconcile()com coordenada e evidência de sucesso confirmadas; o módulo não verifica essa evidência. Um recibo ausente não é prova de não entrega.
A garantia é uma tentativa de despacho automática por decisão aprovada, não entrega externa exatamente uma vez. Uma falha após início do despacho, mas antes do transporte, pode resultar em zero envios e uma reivindicação retida. Liberar um resultado desconhecido para uma nova tentativa exigiria isolar o executor original e verificar a semântica do provedor; esta referência deliberadamente não fornece tal operação de repetição.
| Estado da reivindicação | Próximos estados permitidos |
|---|---|
| reivindicado | despachando ou cancelado antes do despacho |
| despachando | entregue ou desconhecido |
| desconhecido | entregue apenas através de reconciliação confiável |
| entregue, cancelado | terminal; chave da decisão não pode ser reutilizada |
Enquanto uma reivindicação estiver ativa, as proteções do banco de dados congelam gravações de obrigação, rascunho e decisão, incluindo substituições. Instantâneos e reivindicações não podem ser apagados. Cancele uma operação reivindicada com seu token antes de re-arquivar; o token obsoleto então não concede nada. Após o início do despacho, segure novas edições ou revogação para reconciliação. Isso serializa alterações em vez de fingir cancelar uma operação em andamento.
Decisões rejeitadas e linhas legadas sem rascunhos auxiliares/instantâneos nunca entram neste caminho de envio de rascunho externo. Relate-as na superfície interna do operador para tratamento manual. Os rodapés de recibos internos permanecem internos: aprovado por <operador> · recibo <id_decisao> · rascunho sha256 <prefixo>. Nunca altere o texto externo já aprovado para anexar metadados do fluxo de trabalho.
Validação local focada usa bancos de dados temporários, conexões separadas e um contador de tentativas simulado, não um provedor ou mensagem real:
python3 -m unittest discover -s tests/skills -p 'test_approval_delivery_claims.py'.
Os testes exigem Python 3.11+ com suporte a serialização SQLite; a referência usa apenas a biblioteca padrão. As verificações de contrato de padrão de mesa existentes permanecem uma verificação de compatibilidade separada.
Aprovação automática com prazo (opcional)
Um rascunho pode carregar enviar_automaticamente_apos (segundos de época). Uma varredura aprova rascunhos cujo prazo passou sem decisão, registrando operador auto-ttl, então a entrega prossegue pelo caminho normal. Ações do operador sempre vencem: uma decisão altera o status antes que a varredura o veja, e um re-arquivamento roda a época e move ou limpa o prazo. A varredura re-verifica status e época dentro da transação de escrita para que uma condição de corrida se resolva como um no-op. Rascunhos sem prazo permanecem permanentemente bloqueados.
Vinculação de sinal
Um rascunho pode nomear a obrigação de entrada à qual responde (id_obrigacao_sinal). Este é o único vínculo verdadeiro para medição de latência (sinal de entrada para resposta rascunhada) e permite que a varredura de SLA trate esse item de entrada como respondido. Rejeite o arquivamento se a linha referenciada não existir.
Exemplos
Arquivar um rascunho
solicitar_arquivamento(
rascunho="Obrigado, podemos segurar o horário até sexta. Qual data de início funciona?",
contraparte="fornecedor-acme",
contexto="resposta à pergunta sobre janela de entrega",
plataforma_origem="slack", canal_origem="#acme-compartilhado",
thread_origem="1712345678.000100", prioridade="P1",
id_obrigacao_sinal=412)
-> {id_obrigacao: 431, sha256_rascunho: "9f2c...", re-arquivado: false}
O destino interno de operações configurado e verificado vê:
Rascunho arquivado para aprovação (P1, sha 9f2c8a1b). Aguardando operador.
O canal de origem visível à contraparte não recebe nenhum aviso de arquivamento. Se nenhum destino interno verificado estiver disponível, o recibo permanece no resultado da ferramenta interna ou na superfície do operador, sem fallback externo.
Re-arquivamento após direcionamento
O operador pede um rascunho mais curto. Arquivar novamente para a mesma (contraparte, canal) retorna re-arquivado: true, o texto e o hash do rascunho auxiliar mudam e atualizado_em avança. Um clique de aprovação na linha antiga do painel carrega a época antiga e é ignorado.
Recusa da verificação
ErroAprovacaoMesa: a verificação de linha de base recusou este rascunho: o livro-razão mostra um
contrato assinado para 'fornecedor-acme'. Evidência: acordo principal executado
em 2026-08-14. Recomendação: não pergunte. Re-arquive com
forcar_apesar_contrato_assinado=true se for genuinamente uma nova thread.
Rodapé de entrega em um canal interno
Confirmado para sexta, data de início 2026-09-08.
aprovado por operador-a · recibo 118 · rascunho sha256 9f2c8a1b2d3e4f50
Invariantes a testar
- Recibos de arquivamento vão apenas para operações internas configuradas e verificadas; a origem recebe um apenas quando é esse destino interno verificado.
- Uma origem desconhecida permanece em silêncio. Um destino interno indisponível usa o resultado da ferramenta interna ou superfície do operador, sem fallback externo.
- Mesma (contraparte, canal) arquivada duas vezes resulta em uma obrigação, duas épocas.
- Uma decisão com época obsoleta nunca resulta em uma linha de entrega.
- Dois reivindicantes concorrentes resultam em uma permissão de despacho; perdedores nunca tentam transporte.
- Resultados desconhecidos e falha de persistência de recibo nunca habilitam uma repetição automática.
- Conclusão bem-sucedida registra o recibo e o status enviado em uma transação.
- Uma época, texto, hash ou destino alterados não podem adquirir ou iniciar uma reivindicação.
- Reivindicações ativas bloqueiam re-arquivamento; apenas cancelamento pré-despacho pode liberar essa retenção.
- Verificação indisponível carimba o marcador; verificação com contrato assinado recusa sem força.
- Auto-ttl nunca dispara contra texto que o operador re-arquivou desde então.