Propostas Rejeitadas do OpenSpec: Uma Convenção de Memória de Decisão
Sem estado de rejeição. Veja a solução alternativa.
Um agente que propôs e implementou “mover a persistência para uma biblioteca compartilhada” há seis meses propô-lo-á novamente no próximo trimestre, a menos que algo durável informe que a ideia já foi investigada e rejeitada — e o OpenSpec não possui estado embutido para isso atualmente.
/opsx:archive foi projetado para um único resultado: uma mudança que foi implementada. Ele sincroniza os deltas de especificação para openspec/specs/ e move a pasta para openspec/changes/archive/YYYY-MM-DD-<name>/ como registro do que mudou e por quê. Não há um /opsx:reject ou /opsx:abandon correspondente, e nada no formato de arquivamento informa a uma proposta futura que “essa ideia exata foi investigada e recusada”. Essa lacuna é mais crítica exatamente nos codebases onde o OpenSpec seria um bom ajuste: sistemas brownfield com um número pequeno de contribuidores e agentes que periodicamente reexploram as mesmas perguntas arquitetônicas — mesclar estes dois serviços, compartilhar esta camada de persistência, substituir esta fronteira HTTP por uma importação direta.

Isso não é uma lacuna hipotética. Foi levantado diretamente com os próprios mantenedores do OpenSpec como uma solicitação de funcionalidade, e a forma como aquela conversa se desenrolou vale a pena conhecer antes de improvisar sua própria correção: o que o projeto concluiu na verdade molda qual convenção vale a pena adotar. Este guia passa por o que acontece se você depender apenas do /opsx:archive, a discussão real que já aconteceu no rastreador de problemas do OpenSpec e um padrão leve de decision.md que você pode adotar hoje sem esperar — ou precisar — de suporte no núcleo.
Por que Arquivar Sozinho Não Registra uma Decisão Rejeitada
Arquivar uma mudança que você decidiu não construir tecnicamente funciona — a pasta sai da sua lista ativa de qualquer forma. O problema é o que essa pasta arquivada falha em comunicar quando está ao lado de dezenas de mudanças implementadas:
- Nenhum campo de status. Uma mudança arquivada parece idêntica, seja ela implementada ou abandonada três mensagens dentro de
/opsx:propose. Um colega de equipe ou um agente varrendoopenspec/changes/archive/não pode distinguir a diferença sem abrir cada pasta de proposta e ler os artefatos dentro dela. - Nenhum sinal para verificar primeiro. Nada no fluxo de trabalho padrão instrui um agente a pesquisar o arquivo antes de rascunhar uma nova proposta.
/opsx:proposerascunha a partir da sua solicitação atual e do estado do codebase, ponto final — ele não faz referência cruzada a mudanças rejeitadas anteriores, a menos que você o instrua a fazê-lo. - Deltas de especificação que você não deseja sincronizar. Se uma mudança rejeitada já tem deltas de especificação rascunhados e você a arquiva da maneira comum,
/opsx:archiveoferecerá para sincronizar esses deltas paraopenspec/specs/primeiro. Aceitar essa oferta ensina às suas especificações canônicas a descrever um comportamento que você decidiu não construir, o que corrompe silenciosamente o registro do “o que o sistema faz atualmente” que toda outra proposta lê antes de planejar qualquer coisa.
Nada disso é um bug. /opsx:archive está fazendo exatamente o que a documentação diz que faz: completar uma mudança que foi implementada. O caso de rejeição fica fora desse escopo documentado propositalmente, e o próprio guia de fluxo de trabalho em equipe do OpenSpec é explícito que a maior parte do que recomenda — convenções de branch, ordem de revisão de PR, quando arquivar — é convenção empilhada sobre a ferramenta, não algo que o OpenSpec força por você. Lidar com uma rejeição é mais uma convenção que você pode definir por si mesmo, e o CLI já lhe dá a bandeira que você precisa para fazê-lo de forma limpa: passe --skip-specs quando arquivar uma mudança que não está sendo implementada, para que openspec archive investigate-shared-persistence --skip-specs arquivue a pasta sem tocar em openspec/specs/ de todo.
O que os Mantenedores do OpenSpec Decidiram Realmente sobre Suporte a ADR
Antes de inventar uma convenção interna, vale a pena ler como essa exata pergunta se desenrolou publicamente, porque a resolução é mais específica — e mais interessante — do que “não”. GitHub issue #557 abriu em janeiro de 2026 com uma solicitação de suporte de primeira classe para Architecture Decision Record: registros duráveis que persistem independentemente do ciclo de vida de qualquer mudança única, para que uma decisão rejeitada ou substituída permaneça visível para toda proposta futura. Um contribuidor até abriu uma pull request implementando isso.
O que se seguiu foram sete meses de ida e vinda genuinamente substanciais envolvendo o mantenedor principal Tabish Bidiwale (@TabishB) e vários membros da comunidade profundamente envolvidos, cobrindo registros imutáveis versus mutáveis, se um ADR pertence à fase de pesquisa ou à fase de design, propriedade entre mudanças quando uma decisão se desdobra em uma dúzia de mudanças posteriores, e como os ADRs se relacionam com as especificações como a descrição “autoritativa” do sistema. O enquadramento inicial de Tabish Bidiwale estabeleceu a direção em que a thread finalmente se assentou: o OpenSpec deve permanecer leve por padrão e tornar fluxos de trabalho especializados como ADRs configuráveis através do seu sistema de esquema em vez de incorporá-los ao núcleo. Um membro da comunidade resumiu posteriormente onde a discussão se assentou:
Fluxos de trabalho de ADR são valiosos, mas o OpenSpec não possui atualmente suporte de primeira classe/nativo para ADRs… a direção discutida aqui é manter o fluxo de trabalho padrão leve e tornar fluxos de trabalho especializados configuráveis.
O mantenedor Clay Good (@clay-good) fechou a issue nessa base em agosto de 2026 e moveu-a para GitHub Discussion #1553 para que a conversa pudesse continuar evoluindo sem permanecer aberta como um bug não resolvido. Essa é uma chamada razoável para uma ferramenta cuja única proposta é evitar a cerimônia estilo Spec Kit por padrão. Isso também significa que a correção vive um nível acima, em um de dois lugares:
- Um esquema da comunidade. O esquema
spec-driven-with-adr, construído pelo conselheiro técnico do OpenSpec Hari Krishnan (@harikrishnan83) e documentado em intent-driven.dev, adiciona um quinto artefato ao pipeline padrão de quatro artefatos do OpenSpec. Ele existe porque o esquema padrão perde o raciocínio dodesign.mdno momento em que uma mudança é arquivada — apenas os deltas de especificação são sincronizados para frente, para que o “porquê” por trás de uma decisão desapareça com a mudança, a menos que algo a preserve. - Uma convenção ao nível do repositório. Um pequeno arquivo
decision.mdfeito à mão mais uma regra de nomenclatura, que custa nada para adotar e não requer instalar um esquema personalizado.
O resto deste guia cobre a opção dois em profundidade, já que é o ponto de partida de menor atrito para a maioria das equipes — e, como a seção sobre o esquema da comunidade abaixo mostra, é compatível com a troca para aquela ferramenta mais pesada mais tarde, se seu log de rejeições crescer o suficiente para merecê-lo.
A Convenção de decision.md para Registrar uma Mudança Rejeitada
Estruture uma investigação rejeitada da mesma forma que você faria com uma implementada, mas pare antes de sincronizar qualquer delta, e adicione um arquivo que declara o resultado claramente:
openspec/
changes/
archive/
2026-09-16-rejected-shared-persistence-layer/
proposal.md
decision.md
decision.md responde às mesmas quatro perguntas que um apropriado Architecture Decision Record faz — o que foi decidido, por quê, quais alternativas existiram e o que mudaria a resposta:
# Decisão
Status: Rejeitada
## Decisão
Não substituir a fronteira HTTP serviço-a-serviço por uma importação
de pacote direta entre os dois serviços Go.
## Razões
- Aumenta o acoplamento em tempo de compilação entre serviços implantados independentemente.
- Torna a camada de persistência um contrato implícito e não documentado.
- O benefício medido (latência, duplicação de código) era menor do que
o custo de acoplamento neste codebase.
## Alternativas consideradas
- Módulo interno Go compartilhado — rejeitado pela mesma razão de acoplamento.
- gRPC em vez de HTTP — adiado, não rejeitado; reavaliar se a sobrecarga
HTTP se tornar uma garrafa de gargalo medida.
## Reconsiderar apenas se
- Os dois serviços forem intencionalmente mesclados em uma única implantável, ou
- Medições de latência mostrarem que o salto HTTP é uma garrafa de gargalo comprovada.
## Relacionados
- Regra arquitetural: serviços comunicam via HTTP, não pacotes compartilhados.
A única regra dura que faz toda essa convenção funcionar: não execute a etapa de sincronização para uma mudança rejeitada. Se /opsx:propose já rascunhou deltas de especificação antes de você decidir contra a mudança, use a bandeira que o CLI já lhe dá para exatamente essa situação:
openspec archive investigate-shared-persistence --skip-specs
--skip-specs informa openspec archive para arquivar a mudança sem tocar em openspec/specs/ de todo, o que é o padrão mais seguro para qualquer coisa que você está arquivando sem implementar. Aceitar o prompt de sincronização comum em vez disso mesclaria os deltas de especificação da ideia rejeitada nas suas especificações canônicas, e as especificações canônicas openspec/specs/ devem descrever o que o sistema faz atualmente, não cada ideia que foi rascunhada e recusada. Se uma mudança permanentemente não produz mudanças de especificação por uma razão estrutural — uma pasta pura de investigação, digamos — o OpenSpec também suporta declarar skip_specs: true no .openspec.yaml dessa mudança para que ela arquivue limpo sem a bandeira toda vez.
Nomeando Mudanças Rejeitadas para Humanos e Agentes Podem Varrer o Arquivo
Um arquivo decision.md só ajuda se alguém abrir a pasta. Prefixe o nome da pasta com o resultado para que tanto um humano vasculhando ls openspec/changes/archive/ quanto um agente listando mudanças possam ver o status sem abrir um único arquivo:
2026-09-16-rejected-shared-persistence-layer/
2026-09-20-abandoned-react-router-migration/
2026-10-01-superseded-old-auth-design/
2026-10-10-add-project-filtering/ # implementada, nenhum prefixo necessário
Isso espelha o vocabulário de status já recomendado para registros de decisão autônomos — proposto, aceito, substituído, deprecado — aplicado ao próprio arquivo do OpenSpec em vez de uma pasta separada docs/decisions/. Mantenha o vocabulário pequeno. Três ou quatro prefixes consistentes superam uma linha de status em texto livre que cada proposta escreve ligeiramente diferente.
Como Fazer Seu Agente Verificar o Arquivo Antes de Propor Novamente
Nomear e um arquivo decision.md resolvem a descoberta para um humano vasculhando a pasta. Eles não fazem nada por si só para fazer um agente pesquisar o arquivo antes de rascunhar uma nova proposta — isso tem que ser uma instrução explícita, porque /opsx:propose não faz isso por padrão, e nenhuma quantidade de nomenclatura de arquivo organizada muda isso por si só.
Dois lugares para colocar essa instrução, correspondendo a como o OpenSpec já espera que orientações específicas do projeto sejam injetadas:
Em openspec/config.yaml, sob o campo context: que é injetado em cada solicitação de planejamento (cuidado com o limite de 50KB coberto no Quickstart do OpenSpec):
context: |
Antes de propor uma mudança, pesquise openspec/changes/archive por pastas
prefixadas com "rejected-" ou "abandoned-" que descrevem uma ideia
materialmente semelhante. Se uma existir, resuma seu decision.md e declare o que
mudou antes de propor a ideia novamente. Não reabrir uma decisão
rejeitada sem novas evidências.
Em AGENTS.md ou nas instruções do próprio agente do seu projeto, como uma regra permanente em vez de um blob de contexto por solicitação:
## Mudanças do OpenSpec rejeitadas
Quando uma proposta é investigada e rejeitada:
1. Não sincronize nem aplique seus deltas de especificação.
2. Adicione `decision.md` com Status, Decisão, Razões, Alternativas
consideradas, e Reconsiderar apenas se.
3. Prefixe o nome da pasta arquivada: `rejected-<name>` ou `abandoned-<name>`.
4. Antes de propor uma mudança materialmente semelhante, pesquise
`openspec/changes/archive/` e refira a decisão anterior.
5. Não reabra uma decisão rejeitada a menos que suas condições
documentadas de reconsideração tenham realmente mudado.
Nenhuma instrução garante conformidade — um agente ainda pode pular a etapa de pesquisa, da mesma forma que pode pular a leitura de qualquer outro contexto que você injeta. Mas é a diferença entre “a informação existe em algum lugar no repositório” e “o agente é informado, toda vez, para ir procurá-la”, e apenas a segunda realmente reduz investigações repetidas na prática.
Um Exemplo Prático: Rejeitando uma Proposta, Depois Reconsiderando-a Corretamente
Junte as peças em um caso concreto. Digamos que um colega de equipe peça a um agente para olhar para substituir uma chamada HTTP serviço-a-serviço por uma importação direta de pacote Go, para reduzir a latência de rede.
- Explorar, depois propor.
/opsx:explorelê ambos os serviços, e/opsx:propose replace-http-with-direct-importrascunha uma proposta, um documento de design ponderando o ganho de latência contra o custo de acoplamento, e uma especificação de delta rascunhada. - Investigar e rejeitar. Após revisar o documento de design, a equipe decide que o custo de acoplamento — dois serviços implantados independentemente agora compartilhando uma dependência de tempo de compilação — supera um ganho de latência que ninguém mediu na verdade como um problema. Nada é construído.
- Arquivar sem sincronizar. Em vez de excluir a pasta, execute
openspec archive replace-http-with-direct-import --skip-specs, depois adicionedecision.mdà pasta arquivada comStatus: Rejected, as razões acima e uma cláusulaReconsider only ifnomeando a condição que mudaria a resposta — por exemplo, “medições de latência mostram que o salto HTTP é uma garrafa de gargalo comprovada”. Renomeie a pasta com um prefixorejected-para que leia comoopenspec/changes/archive/2026-09-16-rejected-replace-http-with-direct-import/. - Meses depois, alguém levanta novamente. Um contribuidor diferente, ou o mesmo agente em uma sessão nova, é pedido para “acelerar a chamada do checkout para o inventário” e começa a rascunhar uma proposta que se parece muito com a mesma ideia. Porque
openspec/config.yamlinstrui o agente a pesquisar o arquivo primeiro, ele encontra a pasta rejeitada, lêdecision.mde reporta de volta: “Uma mudança materialmente semelhante foi proposta e rejeitada em 16/09/2026 por razões de acoplamento. A condição de reconsideração era ‘medições de latência mostram que o salto HTTP é uma garrafa de gargalo comprovada.’ Você tem novas medições, ou este é um problema diferente?” - A equipe fornece novas evidências. Se o profiling agora mostra que o salto HTTP genuinamente domina a latência do checkout, essa é exatamente a circunstância alterada que o
decision.mdoriginal pediu. O agente prossegue com/opsx:propose, e odecision.mdda nova proposta — uma vez que esta também for arquivada, aceita ou rejeitada — refere a anterior sobRelated, para que o arquivo leia como um histórico de decisão contínuo em vez de duas pastas desconexas que acontecem de descrever a mesma ideia.
Esse quinto passo é o ponto inteiro da convenção. Sem isso, o passo 4 ou não acontece de todo — o agente apenas reinvestiga do zero — ou acontece por sorte, porque um humano se lembrou da conversa anterior. O arquivo decision.md e a instrução de pesquisa do arquivo transformam “alguém pode se lembrar” em algo que o fluxo de trabalho realmente verifica.
O Arquivo do OpenSpec vs. um Log de ADR Dedicado: Quem Posso o quê
Uma vez que você está mantendo arquivos decision.md dentro do arquivo, vale a pena ser explícito sobre qual artefato responde qual pergunta, para que a convenção não se torne silenciosamente documentação duplicada:
| Artefato | Responde |
|---|---|
openspec/specs/ |
O que o sistema faz atualmente? |
openspec/changes/<name>/ (ativo) |
O que estamos propondo mudar, agora mesmo? |
openspec/changes/archive/<name>/ |
O que mudou (ou foi rejeitado) no passado, e por quê? |
docs/adr/ (autônomo, neutro de ferramenta) |
Qual regra arquitetural durável aprendemos, independente de qualquer mudança única? |
Para uma decisão estreita o suficiente para pertencer a uma investigação — “olhamos para compartilhar esta camada de persistência e dissemos não” — a convenção de decision.md-dentro-do-arquivo acima é suficiente. Para uma decisão que deve sobreviver e restringir muitas mudanças futuras — “serviços comunicam via HTTP, nunca pacotes compartilhados” — promova-a para um Architecture Decision Record autônomo em docs/adr/, e faça o decision.md da mudança rejeitada referenciá-lo sob Related. Essa separação mantém o arquivo do OpenSpec focado em investigações individuais, enquanto o log de ADRs segura o pequeno número de regras que devem sobreviver ao ciclo de vida de qualquer ferramenta única — incluindo uma futura migração do OpenSpec por completo.
Quando Adotar o Esquema spec-driven-with-adr em Vez
A convenção feita à mão acima custa nada e cabe em quinze minutos de configuração, o que a torna o padrão certo. Mas vale a pena entender o que a alternativa mais estruturada realmente faz antes de decidir que você superou um prefixo de nomenclatura.
spec-driven-with-adr insere um quinto artefato, adr, entre design e tasks no pipeline do OpenSpec. Em vez de escrever conteúdo de ADR diretamente na pasta da mudança, a etapa adr produz um manifesto de revisão local da mudança adr.md curto e, quando a mudança introduz um compromisso arquitetural genuinamente durável, um registro numerado na raiz do repositório — /adr/0042-use-postgres-for-catalog.md, irmão de openspec/, não aninhado dentro dele. Cada ADR que o esquema cria é imutável uma vez aceito: as próprias instruções do esquema chamam isso de “regra de ferro” — você nunca edita o status, corpo ou data de um registro aceito. Para mudar uma decisão anterior, você escreve um novo ADR cujo campo Supersedes: nomeia o antigo, e designs futuros percorrem essa cadeia de substituição para saber quais decisões ainda estão em vigor. Essa é uma versão mais rigorosa de exatamente a ideia de “reconsiderar apenas se” na convenção de decision.md acima, forçada pelo esquema em vez de deixada para um humano se lembrar de anotar.
Vale a pena ser preciso sobre o que esse esquema faz e não faz. Ele é construído para decisões que são aceitas e precisam sobreviver ao arquivamento — Postgres sobre DynamoDB, JWT sobre cookies de sessão — não para propostas que foram investigadas e rejeitadas sem implementar nada. Uma investigação rejeitada ainda não tem um lugar óbvio para viver sob este esquema também; você empilharia a mesma convenção de decision.md-e-nomenclatura deste guia sobre ela, apenas referenciando registros /adr/ em vez de uma pasta autônoma docs/adr/.
Recorra a ele uma vez que você perceba qualquer destes:
- Seu contagem de decisões rejeitadas é grande o suficiente que grepping
openspec/changes/archive/por prefixes para de ser rápido. - Você deseja decisões arquiteturais duráveis validadas e referenciadas cruzadamente contra cada novo design automaticamente, em vez de por convenção e
grep. - Vários contribuidores continuam inventando formatos ligeiramente diferentes de
decision.md, e você deseja um esquema para forçar um formato numerado imutável único.
Instalar um esquema personalizado é um compromisso maior do que uma convenção de nomenclatura — ele muda o que /opsx:propose gera para cada mudança futura, não apenas as rejeitadas — então trate isso como um passo para cima uma vez que a versão leve estiver visivelmente sob pressão, não um movimento inicial padrão.
Conclusão
O arquivo do OpenSpec foi projetado ao redor de um único resultado — uma mudança que foi implementada — e seus próprios mantenedores foram explícitos, após uma discussão pública de sete meses, que suporte de rejeição ou ADR de primeira classe não está chegando ao fluxo de trabalho principal em breve. Isso deixa a correção onde o OpenSpec já coloca a maioria de suas convenções de equipe: no seu repositório, não na ferramenta. Um arquivo decision.md, a bandeira --skip-specs no arquivamento, um prefixo de nomenclatura rejected-/abandoned- e uma instrução explícita informando ao agente para pesquisar o arquivo antes de propor são suficientes para parar a maioria das investigações repetidas. Recorra ao esquema spec-driven-with-adr apenas uma vez que essa convenção leve estiver genuinamente sob pressão pelo número de decisões que você está rastreando — e mesmo assim, mantenha a distinção clara: ele gerencia decisões que você aceitou e deseja que sobrevivam ao arquivamento, não as que você recusou.
Links Úteis
- Quickstart do OpenSpec: Instalação, Fluxo de Trabalho e Armadilhas Comuns — instalação, o loop explorar-propor-aplicar-arquivar, e armadilhas do dia a dia
- Fluxo de Trabalho de Desenvolvimento Dirigido por Especificações de Requisitos para Código — o processo neutro de ferramenta de cinco fases no qual essa convenção preenche uma lacuna
- Registros de Decisão para Desenvolvimento de Software Dirigido por IA — o formato geral de ADR/PDR/DDR, ciclo de vida de status e instruções de leitura por IA que esta convenção empresta
- GitHub issue #557: suporte a architecture decision records — a discussão completa de sete meses sobre por que ADRs não são centrais no OpenSpec
- GitHub Discussion #1553 — onde aquela conversa continua depois que a issue foi fechada
- Esquema spec-driven-with-adr — o esquema da comunidade que mantém ADRs vivos fora do ciclo de vida da mudança, por Hari Krishnan, conselheiro do OpenSpec
- Documentação de fluxo de trabalho em equipe do OpenSpec — como arquivamento, branches e revisão de PR devem se encaixar
- GitHub Spec Kit vs Kiro vs Claude Code Fluxos de Trabalho SDD — como o OpenSpec se compara a ferramentas SDD mais pesadas em geral