# Solicitações pendentes em um cofre bloqueado devem esperar?

Uma solicitação de agente que chega a um cofre bloqueado deve falhar naquele momento. Ela não deve se transformar em um comando adormecido que volta à vida quando alguém desbloqueia o cofre uma hora depois.

Isso parece rigoroso até você pensar no que um desbloqueio realmente prova. Ele prova que uma pessoa autorizou o acesso a um repositório de segredos neste momento. Não prova que um processo antigo do agente ainda tem a mesma tarefa, que uma implantação continua sendo desejável, que uma pull request não mudou ou que o antigo corpo HTTP e o comando SSH ainda fazem sentido.

Essa é uma daquelas decisões que acabam disfarçadas de recurso de conveniência. Alguém vê uma execução bloqueada e propõe uma fila: guardar a solicitação, mostrar uma notificação e liberar o trabalho depois do Touch ID. A fila parece útil porque a solicitação já está pronta. É justamente por isso que ela é perigosa. Uma solicitação pronta já passou da linha que separa um plano de uma ação aguardando autorização.

A regra mais segura é simples: enquanto o cofre estiver bloqueado, negue as ações e descarte sua forma pronta para envio. Depois do desbloqueio, o agente pode verificar seu estado atual e enviar uma nova solicitação. Essa segunda solicitação pode receber autorização de sessão ou aprovação por chamada, de acordo com o contexto atual.

## Um cofre bloqueado deve rejeitar a ação imediatamente

O bloqueio do cofre é um limite de acesso, não uma interrupção temporária de rede. Tratá-lo como uma indisponibilidade incentiva tentativas automáticas, exatamente o que você não quer quando há uma intenção antiga de um agente envolvida.

Quando um agente solicita uma chamada de API ou uma conexão SSH, o gateway já tem informação suficiente para decidir se a solicitação pode prosseguir. Se o cofre estiver bloqueado, não é necessário inspecionar um corpo, resolver um host, iniciar uma conexão ou esperar pelo usuário. O gateway deve retornar a negação antes de tocar no mundo externo.

O resultado precisa informar ao agente o que aconteceu sem convidá-lo a repetir a chamada às cegas. Um formato útil seria:

```json
{
  "ok": false,
  "error": {
    "code": "VAULT_LOCKED",
    "message": "The credential vault is locked. This action was not queued or sent.",
    "request_id": "req_7d4c1f",
    "retryable": false
  }
}
```

`retryable: false` pode parecer contraintuitivo. O agente pode fazer uma nova solicitação mais tarde, mas a solicitação que falhou não é segura para repetição. Essa distinção impede que autores de clientes criem um loop genérico de espera que transforme um desbloqueio em uma sequência não revisada de tarefas antigas.

Não substitua isso por `503 Service Unavailable`, um timeout ou um erro de transporte genérico. Essas respostas dizem a um cliente bem-intencionado para repetir exatamente a mesma ação. O gateway precisa de um resultado semântico que diga: «Uma condição de segurança controlada por uma pessoa bloqueou esta chamada, e esta chamada específica terminou».

A regra vale tanto para leituras quanto para gravações. As equipes costumam reservar a cautela para gravações porque uma gravação obsoleta pode apagar ou implantar algo. Uma leitura obsoleta também pode expor informações de clientes, revelar uma configuração de produção ou levar um agente a tomar uma decisão posterior com base em dados que o usuário já não pretendia consultar.

## Desbloquear não aprova uma intenção anterior

Um evento de desbloqueio e uma resposta de aprovação de ação respondem a perguntas diferentes. O desbloqueio pergunta se o cofre pode usar seus segredos. A aprovação pergunta se esse processo pode fazer esse tipo específico de chamada externa durante a tarefa atual.

Combinar essas decisões cria um erro sutil de autorização. Imagine que um agente prepare um comando SSH para reiniciar um serviço. O desenvolvedor fecha o laptop, o cofre é bloqueado e o agente envia a chamada mesmo assim. Quarenta minutos depois, o desenvolvedor volta e desbloqueia o Mac para investigar outro problema. O serviço é reiniciado porque o gateway manteve o comando antigo. A pessoa não aprovou um reinício naquele momento. Ela aprovou o acesso ao cofre para si mesma.

O mesmo problema aparece de formas menos evidentes:

- Um agente preparou um comentário em uma pull request, mas o revisor já resolveu o problema.
- Um agente preparou uma chamada de API de nuvem usando um nome de branch que já não aponta para o mesmo commit.
- Um agente preparou uma consulta ao sistema de suporte, mas a solicitação do cliente que a justificava já terminou.
- Um agente preparou a publicação de um pacote, mas um teste falhou enquanto o acesso estava bloqueado.

O contra-argumento comum é que a solicitação já havia sido autorizada antes do bloqueio. Às vezes isso é verdade, mas ainda não justifica o envio adiado. A autorização pode continuar válida durante uma sessão enquanto o processo existir. A intenção não continua válida apenas porque uma sequência de bytes está em uma fila.

Por isso, um gateway deve separar claramente as decisões:

1. O bloqueio do cofre decide se uma ação que depende de segredos pode começar.
2. A autorização da sessão decide se esse processo de agente é reconhecido durante sua execução atual.
3. A aprovação por chamada decide se uma credencial marcada para confirmação individual pode ser usada agora.

Se a primeira decisão for negativa, pare. Não avalie as decisões seguintes e não preserve uma solicitação pronta para envio até que a resposta mude.

## Uma notificação não é uma fila de solicitações

É possível avisar uma pessoa de que o trabalho está bloqueado sem manter um trabalho que possa ser executado. São projetos diferentes, mas as equipes os confundem porque ambos são chamados de «solicitações pendentes».

Uma **notificação** é um fato não acionável. Ela pode informar que um processo tentou usar uma referência de credencial nomeada contra uma classe de destino em determinado momento. Isso ajuda a pessoa a decidir se deve desbloquear o cofre e voltar à tarefa. A notificação não pode reconstruir cabeçalhos, um corpo de solicitação, um comando SSH ou um token de aprovação.

Uma **fila de solicitações** retém material suficiente para fazer um envio posterior. Ela pode incluir um método HTTP, uma URL, um corpo, argumentos de comando, a seleção da credencial, uma decisão de autorização ou um token assinado para reprodução. Ao guardar esse material, você criou uma execução adiada.

A diferença importa na implementação. Isto é aceitável como aviso de trabalho bloqueado:

```json
{
  "event": "action_denied",
  "reason": "vault_locked",
  "session_id": "ses_31b8",
  "channel": "ssh",
  "credential_label": "production-deploy",
  "destination": "deploy host",
  "occurred_at": "2026-07-22T21:14:05Z"
}
```

Isto não é aceitável se o sistema puder recuperar mais tarde o comando completo, o endereço de destino, o corpo privado da solicitação ou uma autorização para usar a credencial a partir do evento. O registro deve apoiar a investigação, não a reprodução.

Tenha cuidado também com hashes. Um resumo criptográfico costuma ser seguro para correlação, mas apenas se o gateway não puder usá-lo para recuperar um payload retido. Um resumo acompanhado de um blob oculto ainda é uma fila. Um resumo que existe apenas em um registro de auditoria somente de acréscimo é diferente.

Existe aqui uma tentação de produto: uma lista de solicitações pendentes faz um painel parecer responsivo. Resista, a menos que cada item exija que o agente envie uma nova chamada depois que o usuário agir. Uma tela que oferece «executar tudo após o desbloqueio» transformou um alerta de segurança em um agendador de tarefas adiadas.

## Dê ao agente uma máquina de estados que não possa ser mal interpretada

Os agentes se comportam melhor quando o gateway expõe um modelo de estados pequeno e explícito. Erros ambíguos fazem os agentes inventarem planos de recuperação, e o plano inventado pode ser esperar, tentar novamente ou procurar outro caminho para a credencial.

Use uma máquina de estados na qual uma solicitação tenha um resultado terminal assim que o bloqueio do cofre a negar:

```text
received
  |
  +-- vault locked --> denied_locked (terminal)
  |
  +-- vault unlocked --> session check
                           |
                           +-- not approved --> denied_session (terminal)
                           |
                           +-- approved --> per-call check
                                             |
                                             +-- approval declined --> denied_call (terminal)
                                             |
                                             +-- approved --> dispatched --> completed
```

A parte importante não é o diagrama. É o fato de que `denied_locked` não tem uma seta de volta para `dispatched`. Uma solicitação posterior pode entrar em `received`, mas a antiga não pode voltar a entrar em nenhum ponto.

Esse projeto também facilita o raciocínio sobre idempotência. Se uma chamada falhar porque o cofre estava bloqueado, não reserve um token de idempotência como se o servidor tivesse aceitado a ação. O agente deve criar outra solicitação depois, com um novo ID de solicitação. Se a API externa aceitar chaves de idempotência, a nova solicitação poderá usar uma chave no nível da aplicação que represente a operação de negócio pretendida, mas a negação do gateway não deve criar um registro de ação pela metade.

Para operações de gravação, faça o agente incluir sua própria pré-condição atual sempre que o destino aceitar uma. Pode ser um ID de revisão, a versão de uma entidade, a cabeça esperada de uma branch ou uma ETag. Quando o cofre abrir, o agente deve consultar o contexto atual outra vez e montar uma chamada que o reflita. Uma solicitação obsoleta não passa por uma boa pré-condição, e uma solicitação nova traz evidências de que o agente consultou o estado novamente.

Não tente inferir atualidade apenas pelo tempo transcorrido. Cinco segundos podem ser demais para uma implantação que muda rapidamente, enquanto uma hora pode não fazer diferença em uma consulta estática. A atualidade vem de reler o estado da tarefa e reconstruir a ação, não de um cronômetro.

## A aprovação deve estar vinculada à chamada real

Mesmo uma solicitação nova depois do desbloqueio ainda precisa de um modelo de aprovação restrito. Caso contrário, você remove a reprodução adiada apenas para substituí-la por uma permissão vaga que permite ao agente mudar de ideia depois que o usuário clica.

Um cartão de aprovação deve estar vinculado ao material que altera o significado de segurança da ação. Para HTTP, isso normalmente inclui o método, o destino normalizado, a referência da credencial e um resumo criptográfico do corpo da solicitação. Para SSH, inclui a identidade do host, a conta, o comando ou seu resumo criptográfico e a referência da credencial. Também deve estar vinculado ao processo do agente e expirar rapidamente.

Evite um cartão que diga apenas: «Permitir acesso do agente à produção». Essa frase faz a pessoa aprovar uma categoria enquanto o agente controla os detalhes. Alguém pode aceitar que um processo leia um endpoint, mas não que invoque um endpoint administrativo no mesmo hostname.

Um registro de aprovação prático pode ter esta aparência:

```json
{
  "approval_id": "apr_8c62",
  "session_id": "ses_31b8",
  "process_identity": "signed-authority-and-process-instance",
  "channel": "http",
  "credential_label": "billing-api",
  "method": "POST",
  "destination": "api.example.internal/v1/invoices",
  "payload_digest": "sha256:...",
  "expires_at": "2026-07-22T21:16:00Z",
  "used": false
}
```

O gateway não precisa mostrar cada byte de um payload grande para ser honesto sobre o que aprova. Mas precisa vincular a aprovação aos bytes que enviará. Um resumo conciso para a pessoa pode aparecer ao lado de um digest, enquanto o digest protege a solicitação exata contra substituições.

Use registros de aprovação de uso único para credenciais que exigem aprovação por chamada. Marque a aprovação como usada antes do início do envio, não depois que uma resposta retornar. Se a conexão cair depois do envio, o agente talvez precise consultar o destino para saber se a ação teve efeito. Reutilizar a aprovação facilitaria gravações duplicadas.

## O caso de falha a testar é desbloquear no momento errado

O teste mais revelador não é «a chamada falha enquanto o cofre está bloqueado?». É «o que acontece quando o mundo muda antes de o usuário desbloquear?».

Configure um serviço de teste inofensivo com um endpoint que registre um destino de implantação e outro que altere o destino permitido atual. Depois execute esta sequência:

1. Inicie uma tarefa de agente que planeje enviar `POST /deploy` com `{\"revision\":\"a1b2c3\"}`.
2. Bloqueie o cofre antes que o agente envie a chamada.
3. Confirme que o gateway retorna `VAULT_LOCKED` e que o serviço de teste não recebe nada.
4. Altere a revisão permitida para `d4e5f6` enquanto o cofre continua bloqueado.
5. Desbloqueie o cofre por um motivo não relacionado.
6. Espere sem tocar no agente.

O resultado correto é sem graça: o serviço de teste continua sem receber nada. Se ele receber uma implantação para `a1b2c3`, seu gateway tem um caminho de execução adiada.

Depois informe ao agente que a chamada foi negada, deixe-o consultar novamente a revisão permitida e faça-o enviar uma nova solicitação. A solicitação esperada agora é `d4e5f6`, e o gateway pode pedir a autorização de sessão ou por chamada aplicável. Isso prova que o caminho de recuperação preserva o contexto atual, em vez de tratar o tempo em que o cofre ficou bloqueado como um botão invisível de pausa.

Execute o mesmo teste para SSH. Use um comando que escreva um marcador inofensivo contendo a revisão pretendida. Não teste apenas o estabelecimento da conexão. A implementação insegura muitas vezes mantém um comando depois de selecionar uma chave e o envia quando o cofre fica disponível. Você precisa provar que o próprio texto do comando morre no limite do bloqueio.

## Não deixe os clientes esconderem a negação

Um gateway pode tomar a decisão certa e ainda produzir um comportamento ruim se seus clientes transformarem todo erro em «tente novamente mais tarde». O protocolo precisa ter estrutura suficiente para que frameworks de agentes e scripts de wrapper tratem um cofre bloqueado de forma deliberada.

Os agentes devem receber três instruções no contrato de resposta. Primeiro, a ação não saiu do gateway. Segundo, o gateway descartou a solicitação. Terceiro, o agente não deve repetir automaticamente a mesma solicitação.

O próprio loop de recuperação do agente deve se parecer mais com isto:

```text
if result.error.code == "VAULT_LOCKED":
    record_blocked_task()
    ask the user to unlock when appropriate
    stop this action

if user later resumes the task:
    reread relevant state
    decide whether the action is still needed
    create a new request
```

A linha `decide whether the action is still needed` é importante. Ela não deve ser substituída por `retry request`. Um agente que recebeu novas instruções, editou arquivos, trocou de branch ou descobriu que um teste falhou talvez precise agora de outra ação, ou de nenhuma ação.

Em execuções sem supervisão, devolva a negação ao orquestrador e encerre a execução em um estado bloqueado. Não faça o gateway esperar que alguém desbloqueie o cofre. Um processo de agente em espera mantém memória, retém contexto que pode se tornar sensível e cria pressão para tratar um desbloqueio posterior como autorização para continuar. Uma parada limpa dá à pessoa a chance de revisar a tarefa antes de retomá-la.

Se sua interface mostrar uma notificação, use uma mensagem precisa: «Uma ação do agente foi negada porque o cofre estava bloqueado». Evite botões com os rótulos «continuar» ou «aprovar pendente». Um botão pode abrir o cofre ou mostrar detalhes da sessão, mas não deve fazer uma ação antiga ser executada.

## Os registros devem provar que nada foi enviado

Uma negação merece um registro de auditoria porque responde a uma pergunta que os operadores acabarão fazendo: o agente apenas tentou realizar a ação ou realmente entrou em contato com o sistema externo?

Registre o canal tentado, a identidade da execução do agente, a referência da credencial, um destino normalizado, o resultado e os horários. Marque claramente o estado do envio. Os operadores devem conseguir distinguir `denied_before_dispatch` de `dispatch_started`, `remote_rejected` e `completed` sem interpretar strings de exceção.

Por padrão, não registre segredos, cabeçalhos de autorização brutos, material de chave privada ou corpos completos. Para corpos sensíveis, registre um resumo criptográfico e um pequeno resumo aprovado, caso o sistema possa produzi-lo sem vazar conteúdo. O objetivo é estabelecer o que aconteceu, não criar uma segunda cópia dos dados que o cofre deveria proteger.

Uma consulta de auditoria deve conseguir responder a um relato de incidente como este:

```text
21:14:05  session ses_31b8 attempted SSH action using production-deploy
21:14:05  vault gate denied action before dispatch
21:15:41  vault unlocked by local user action
21:16:09  no action dispatched from ses_31b8
```

Essa última linha pode ser inferida pela ausência de registros de envio, mas estados terminais explícitos tornam as investigações mais rápidas e reduzem a ambiguidade. Se você usa um registro encadeado por hashes, verifique a cadeia durante a investigação de incidentes e também nas verificações rotineiras. A evidência contra adulteração tem pouco valor se ninguém a usa quando o registro é importante.

A separação do Sallyport entre um diário Sessions para execuções e um diário Activity para chamadas individuais se encaixa bem nesse problema, porque uma negação causada pelo cofre bloqueado pertence tanto ao histórico da execução quanto ao rastro da ação. A verificação offline `sp audit verify` também permite testar a integridade desse histórico sem abrir o cofre.

## Filas de conveniência criam um segundo sistema de autorização

Quando um gateway armazena solicitações para liberá-las depois, ele começa a acumular regras: por quanto tempo as solicitações vivem, quem pode liberá-las, se o processo original ainda precisa existir, se o conteúdo pode mudar, o que acontece depois de uma reinicialização e se um desbloqueio libera uma solicitação ou todas elas.

Essas regras são um mecanismo de políticas disfarçado. É difícil explicá-las aos usuários porque cada exceção muda o significado do desbloqueio. Um timeout curto da fila não resolve o problema de significado. Exigir que o processo original continue vivo também não, porque o processo pode estar comprometido ou simplesmente trabalhar com contexto obsoleto.

Mantenha o projeto menor. O bloqueio do cofre nega todas as ações enquanto ele estiver fechado. Uma nova sessão de processo pode exigir aprovação. Uma credencial marcada para aprovação por chamada exige uma confirmação explícita a cada uso. Todo o restante da conveniência deve ficar do lado do agente, como recuperação de tarefas, onde ele precisa reconstruir seu plano e a pessoa pode ver o que mudou.

Isso também cria um hábito confiável para os usuários: desbloquear restaura a capacidade de considerar novas ações. Nunca libera ações que eles esqueceram estar aguardando. As pessoas conseguem tomar boas decisões com esse modelo mental. Elas têm dificuldade quando uma tela de bloqueio também funciona como uma fila de trabalho oculta.

## Torne o caminho seguro menos incômodo que o inseguro

As equipes criam filas porque uma falha imediata pode parecer uma interrupção durante o desenvolvimento normal. Corrija o atrito sem reter solicitações executáveis.

Mantenha a autorização da sessão limitada à vida útil do processo do agente para que um desenvolvedor não precise aprovar cada chamada comum. Reserve a confirmação por chamada para credenciais que merecem uma fricção deliberada, como administração de produção ou publicação externa. Retorne uma negação clara que permita ao agente informar o trabalho bloqueado em linguagem simples. Ofereça à pessoa uma forma de desbloquear o cofre, inspecionar a sessão do agente e retomar a tarefa conscientemente.

Depois, torne explícitas as instruções do agente. Diga aos agentes que as credenciais permanecem fora de seu contexto, que um resultado de cofre bloqueado encerra a ação tentada e que uma ação posterior deve ser reconstruída depois de verificar o estado atual. Um prompt de agente não consegue impor a regra, mas reduz tentativas inúteis e facilita o trabalho com o comportamento do protocolo.

O teste desse projeto é simples. Se uma pessoa desbloquear o cofre distraída, cansada ou ocupada com uma tarefa não relacionada, nenhuma ação anterior do agente deve ocorrer. Se isso não for verdade, remova a fila antes que ela se transforme em um relatório de incidente.
