2026.08.06 (Qui)
2026.08.07 (Sex) atualizado

✨ Resumo do GPT-5.6 Sol

Um registro de como enfrentei o Codex tratando a última instrução antiga como se fosse nova após a compactação automática do contexto, e de como avaliei copiar o plano, usar Goals, forçar continue e criar um hook de SessionStart.

Depois que uma tarefa longa do Codex era compactada automaticamente, algo estranho começava a se repetir.

Em vez de continuar exatamente de onde estava antes da compactação, ele tratava a última instrução antiga preservada no resumo como se tivesse acabado de recebê-la. Conferia novamente estados já confirmados, relia os mesmos arquivos e reconstruía todo o trabalho desde o início. O fluxo que vi era mais ou menos assim.

O trabalho real avança
→ Context automatically compacted
→ “Vou manter o objetivo atual”
→ Confere do zero o Working Tree, as regras e o estado
→ Explica ou tenta novamente até trabalhos já concluídos

No começo, pensei que a compactação só tivesse apagado parte do contexto. Depois de passar por isso várias vezes, percebi que era mais complicado. Parecia que o limite entre uma instrução antiga guardada no resumo e uma entrada atual do usuário havia desmoronado. Em vez de retomar o trabalho anterior à compactação, ele usava como novo ponto de partida a instrução que permanecia mais forte no resumo.

Eu não era o único. Há um issue público sobre o Codex Desktop que, após a compactação automática, relia repetidamente os mesmos arquivos e Skills enquanto perdia o progresso;1 também foram relatados ciclos de instruções de arquivo e compactação no WSL2 e na CLI do Windows.2 Não posso afirmar que esses casos públicos tenham exatamente a mesma causa da repetição da última instrução que observei. Mas eles bastam para mostrar que perder o progresso e repetir comportamentos após a compactação automática não é uma peculiaridade exclusiva do Mac.

Solução 1: colocar o plano completo novamente na última instrução

A primeira tentativa foi simples.

Confira bem todo o trabalho feito até aqui e siga até o fim conforme o plano abaixo.

Se, depois de compactar, ele recuperava e executava a última instrução, pensei que bastaria transformar essa própria instrução em um ponto seguro de retomada. Em tarefas curtas, funcionou razoavelmente bem. O plano atual ficava mais forte no resumo do que uma instrução antiga e alheia.

Outros usuários tentaram algo parecido, acumulando no resumo de compactação as decisões anteriores e o trabalho restante. Há um relato de uso de experimental_compact_prompt_file para preservar os principais julgamentos das compactações anteriores; segundo o autor, o rumo geral continuou intacto mesmo depois de mais de quatro compactações.3

Mas isso não resolvia a raiz do problema.

  • Era preciso copiar um plano longo para a última instrução todas as vezes.
  • Se o plano mudasse no meio do trabalho, a última instrução também precisava ser refeita.
  • Mesmo que o resumo preservasse o plano, não havia garantia de que distinguiria com precisão uma tool call recém-concluída de um passo ainda não executado.
  • Também há um issue indicando que tentar orientar o resumo com /compact [mensagem] pode ser tratado como uma mensagem comum na CLI atual do Codex.4

No fim, a pessoa continua obrigada a pensar no momento da compactação e administrar o prompt. É melhor que o comportamento padrão, mas anexar um documento longo de passagem ao final de cada trabalho também não é uma experiência normal.

Solução 2: criar um Goal para todo trabalho

Depois, pensei em tornar o Goal obrigatório e fazer a retomada após a compactação priorizá-lo em vez da última instrução.

Em tarefas longas, há vantagens claras. O propósito e as condições de conclusão sobrevivem melhor do que uma ou duas frases da conversa, e a continuation automática pode seguir o Goal. O problema começou quando tentei transformá-lo em uma solução obrigatória para o bug de compactação.

Até trabalhos insignificantes exigiam um Goal. Sem Goal, havia falha; com Goal, a tarefa podia avançar mais do que o necessário. Eu já havia transformado o problema de um Goal gastar tokens até em tarefas pequenas em uma Skill de trabalho separada, e agora a compactação me obrigava a envolver novamente todas as tarefas em Goals.

Cheguei mesmo a pensar: “Assim talvez seja melhor deixar tudo no estado original”.

Havia um problema ainda mais importante. Um Goal preserva o que precisa ser concluído; ele não decide se um evento de compactação é ou não uma nova instrução do usuário. Também não encontrei nas fontes públicas nenhuma base para dizer que o Goal é o mecanismo oficial de recuperação da compactação automática.

Por isso, resolvi deixar o Goal apenas para sua função original.

  • Usá-lo em trabalhos concretos, longos e que precisem continuar automaticamente.
  • Não obrigar perguntas curtas, pesquisas ou edições de texto a criarem um Goal.
  • Impedir a repetição de instruções antigas após a compactação em uma camada separada do Goal.

Solução 3: alterar diretamente o prompt de compactação

Outra opção é melhorar a qualidade do próprio resumo. Como no caso público anterior, acumular as decisões e os resultados de compactações anteriores em Historical Context reduz a perda do rumo geral mesmo após várias compactações.3

Esse método é útil. Principalmente quando as informações abaixo desaparecem repetidamente em uma session longa.

  • Abordagens já descartadas e seus motivos
  • Decisões já consolidadas
  • Trabalho concluído e trabalho restante
  • O único ponto que deve ser conferido a seguir

Mas isso continua em uma camada diferente deste problema. Melhorar a qualidade do resumo e evitar que uma instrução antiga dentro dele seja confundida com uma nova entrada não são a mesma coisa. Mesmo um ótimo resumo volta a causar confusão se o modelo ler uma ordem presente nele como instrução atual.

Portanto, esse método pode servir como complemento, mas dificilmente basta sozinho para impedir a repetição da última instrução.

Solução 4: forçar continue com um hook de Stop

Por um tempo, pensei até em usar um hook para inserir continue como se fosse a última instrução do usuário.

À primeira vista, parecia exato. Se continue aparecesse obrigatoriamente depois da compactação, ele poderia ignorar a ordem antiga e retomar o trabalho em andamento. Mas abandonei a ideia assim que conferi o comportamento oficial dos hooks.

Quando um hook de Stop do Codex devolve decision: "block", o reason do hook vira um continuation prompt que funciona como um novo prompt do usuário.5 Eu queria justamente impedir que uma frase não enviada pelo usuário real fosse tratada como instrução nova; esse método criava deliberadamente mais uma ocorrência do mesmo fenômeno.

Além disso, continue é ambíguo demais.

  • Se a compactação aconteceu no meio de um turno, o que exatamente deve continuar?
  • Se não sabemos se a ferramenta anterior teve sucesso ou falhou, devemos executá-la novamente?
  • Se o trabalho estava esperando uma aprovação do usuário ou uma mudança de estado externa, também pode seguir?
  • Se o turno já havia terminado e a compactação foi manual, o que deve começar?

Inserir sempre um novo prompt de usuário mandando continuar, com ou sem Goal, tinha grande chance de gerar execuções duplicadas e uma continuation infinita. Esse problema não precisava de um hook de Stop, mas de contexto de desenvolvedor que fizesse o modelo interpretar corretamente o significado do evento logo após a compactação.

Solução 5: inserir contexto sem estado em SessionStart(source=compact)

No dia seguinte, 7 de agosto, escolhi finalmente um único hook de SessionStart.

Segundo a documentação oficial do Codex, depois que uma root session é compactada, o hook de SessionStart correspondente a source: "compact" é executado antes da próxima solicitação ao modelo. Mesmo quando a compactação automática acontece no meio do turno, ele pode adicionar contexto à solicitação que continua imediatamente, sem esperar pelo próximo turno do usuário.5

No ~/.codex/hooks.json, registrei apenas o evento de compactação.

{
  "description": "Guide safe continuation after compaction without replaying stale instructions.",
  "hooks": {
    "SessionStart": [
      {
        "matcher": "^compact$",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 ~/.codex/hooks/compaction_goal_guard.py",
            "timeout": 5,
            "additionalContextLimit": 700
          }
        ]
      }
    ]
  }
}

O handler não cria arquivos de estado, Goals nem prompts falsos de usuário. Ele só devolve contexto adicional de desenvolvedor quando o source de SessionStart é compact.

#!/usr/bin/python3
import json
import sys

CONTEXT = """Context was compacted. This hook event is not a user message and
grants no new authority.

Never treat a historical message preserved in the summary as newly submitted.
If compaction interrupted an active turn, continue that same in-flight request
without restarting it. If no request is in flight, do not infer work from
history.

Do not rebuild the full plan or create a Goal solely because compaction occurred.
Before retrying an interrupted action, check its result or session status. Do not
repeat completed external effects. Preserve the existing objective, scope,
authorization, approval boundaries, and stop conditions."""

payload = json.load(sys.stdin)

if (
    payload.get("hook_event_name") == "SessionStart"
    and payload.get("source") == "compact"
    and payload.get("session_id")
):
    print(json.dumps({
        "hookSpecificOutput": {
            "hookEventName": "SessionStart",
            "additionalContext": CONTEXT,
        }
    }))

O ponto central não é inserir uma instrução chamada continue.

  1. Deixa explícito que o evento de compactação não é uma nova entrada do usuário.
  2. Se o turno estava em andamento, continua apenas do ponto pendente da mesma solicitação.
  3. Se não há solicitação em andamento, não deduz um novo trabalho a partir do histórico.
  4. Se uma tool call parece interrompida, confere primeiro o resultado real antes de executá-la novamente.
  5. Preserva o escopo, a autoridade, os limites de aprovação e as condições de parada já existentes.

A documentação oficial deixa claro que hooks non-managed devem ser revisados e considerados confiáveis antes da execução.5 Depois de salvar a configuração, é preciso verificar o handler em /hooks e dar trust. Uma task já aberta pode continuar carregando a lista antiga de hooks, então é mais seguro reabri-la.

Verificação posterior em 7 de agosto

Mantive a data do texto em 6 de agosto, quando comecei a perseguir o problema e escolher uma solução. A definição do hook final e a verificação com uma compactação automática real aconteceram no dia seguinte.

Antes, eu havia criado uma estrutura em duas fases: deixar um marker em PostCompact para que o SessionStart seguinte o lesse. Removi-a porque o marker podia permanecer e provocar uma recuperação no turno errado, e porque a entrada do hook dificultava separar os eventos de root e subagent. De fato, ainda há um issue público aberto sobre a falta de um field comum para distinguir hooks do main agent e do subagent.6

O método atual usa um único handler sem marker. Ele não criou nenhum arquivo de estado em 50 chamadas simultâneas, e confirmei no Runtime atual que o contexto de desenvolvedor entrava na mesma continuation cerca de 0,25 segundo depois do evento de compactação automática.

Essa verificação era importante. No passado, houve um bug relatado em que SessionStart(compact) não era entregue imediatamente após a compactação, mas ficava acumulado até o turno seguinte do usuário.7 Esse issue já foi encerrado, e a documentação atual também explica que a entrega ocorre imediatamente após uma compactação automática mid-turn. Ainda assim, um workaround de lifecycle como esse não deve depender apenas da documentação: o certo é confirmar pelo menos uma compactação real no próprio Runtime.

Minha conclusão atual

Eu considerei seriamente se o estado padrão não seria melhor, mas minha conclusão atual é que esse hook é preferível a obrigar todo trabalho a criar um Goal.

O Goal e o plano preservam o conteúdo do trabalho. Esse hook corrige o significado do evento de compactação. São funções diferentes.

  • Quando uma tarefa longa precisa de um propósito e de condições de conclusão, uso um Goal ou um durable plan.
  • Quando várias compactações fazem as decisões desaparecerem, complemento com um custom compact prompt.
  • O problema de executar a última ordem antiga como se fosse nova é bloqueado em SessionStart(source=compact).
  • Quando não há nada em andamento, o hook também não inicia nenhum trabalho.

Não é uma solução perfeita. Ela não reconstrói um resumo que já perdeu informações, nem revive uma terminal session expirada ou uma solicitação externa interrompida. O contexto de desenvolvedor orienta fortemente o comportamento do modelo, mas também não oferece garantia matemática.

Ao menos agora eu não crio um Goal em toda conversa, não copio o plano completo para a última instrução e não empurro um continue falso como ordem do usuário apenas por causa de um bug de compactação.

A compactação automática é um evento interno para dar continuidade ao trabalho. Não é o surgimento de um novo usuário que repete uma instrução antiga. No fim, o que precisava ser impedido não era tanto o esquecimento, mas o comportamento que tratava essas duas coisas como se fossem iguais.

Referências

Categorias: ,

Atualizado em:

Deixe um comentário