OpenSpec Propuestas Rechazadas: Una Convención de Memoria de Decisiones
Sin estado de rechazo. Este es el workaround.
Un agente que propuso e implementó «mover la persistencia a una biblioteca compartida» hace seis meses estará encantado de proponerlo de nuevo el próximo trimestre, a menos que algo duradero le indique que la idea ya fue investigada y rechazada; y OpenSpec no tiene un estado integrado para eso hoy en día.
/opsx:archive está diseñado para un único resultado: un cambio que se implementó. Sincroniza las especificaciones diferenciales (delta specs) en openspec/specs/ y mueve la carpeta a openspec/changes/archive/YYYY-MM-DD-<name>/ como registro de qué cambió y por qué. No existe un par equivalente de /opsx:reject o /opsx:abandon, y nada en el formato de archivo indica a una propuesta futura que «esta idea exacta fue investigada y rechazada». Esta brecha es más relevante precisamente en las bases de código donde OpenSpec encaja de lo contrario: sistemas brownfield con un número reducido de contribuyentes y agentes que reexaminan periódicamente las mismas preguntas arquitectónicas —fusión de estos dos servicios, compartición de esta capa de persistencia, reemplazo de esta frontera HTTP con una importación directa.

Esta no es una brecha hipotética. Se planteó directamente a los propios mantenedores de OpenSpec como solicitud de funcionalidad, y el modo en que se desarrolló esa conversación merece ser conocido antes de improvisar su propia solución: lo que el proyecto concluyó realmente determina qué convención merece la pena adoptar. Esta guía detalla qué sucede si se confía solo en /opsx:archive, la discusión real que ya tuvo lugar en el rastreador de problemas de OpenSpec, y un patrón ligero de decision.md que puede adoptarse hoy sin esperar —ni necesitar— soporte del núcleo.
Por qué archivar solo no registra una decisión rechazada
Archivar un cambio que se decidió no construir técnicamente funciona: la carpeta se mueve fuera de la lista activa de una u otra manera. El problema es lo que esa carpeta archivada deja de comunicar cuando se encuentra junto a decenas de cambios implementados:
- Sin campo de estado. Un cambio archivado se ve idéntico si se implementó o si se abandonó tres mensajes dentro de
/opsx:propose. Un compañero o un agente que examineopenspec/changes/archive/no puede distinguir la diferencia sin abrir cada carpeta de propuesta y leer los artefactos dentro. - Sin señal para verificar primero. Nada en el flujo de trabajo por defecto instruye a un agente a buscar en el archivo antes de redactar una nueva propuesta.
/opsx:proposeredacta basándose en la solicitud actual y el estado de la base de código, y nada más: no hace referencia cruzada a cambios rechazados anteriormente a menos que se lo indique. - Especificaciones diferenciales que no desea sincronizar. Si un cambio rechazado ya tiene especificaciones diferenciales de borrador y se archiva de la manera ordinaria,
/opsx:archiveofrecerá sincronizar esas diferencias enopenspec/specs/primero. Aceptar esa oferta enseña a sus especificaciones canónicas a describir un comportamiento que se decidió no construir, lo cual corrompe silenciosamente el registro de «qué hace actualmente el sistema» que cada otra propuesta lee antes de planificar algo.
Nada de esto es un error. /opsx:archive está haciendo exactamente lo que su documentación dice que hace: completar un cambio que se implementó. El caso de rechazo se encuentra fuera de ese alcance documentado a propósito, y la guía de flujo de trabajo de equipo de OpenSpec es explícita en que la mayor parte de lo que recomienda —convenciones de ramas, orden de revisión de PR, cuándo archivar— es convención superpuesta sobre la herramienta, no algo que OpenSpec imponga por usted. Manejar un rechazo es una convención más que puede definir usted mismo, y la CLI ya le da la bandera que necesita para hacerlo limpiamente: pase --skip-specs cuando archive un cambio que no está implementando, para que openspec archive investigate-shared-persistence --skip-specs archive la carpeta sin tocar openspec/specs/ en absoluto.
Qué decidieron realmente los mantenedores de OpenSpec sobre el soporte ADR
Antes de inventar una convención propia, vale la pena leer cómo se desarrolló esta misma pregunta en público, porque la resolución es más específica —y más interesante— que un simple «no». El problema de GitHub #557 se abrió en enero de 2026 con una solicitud de soporte de primer nivel para Registros de Decisiones Arquitectónicas (ADR): registros duraderos que persistan independientemente del ciclo de vida de un solo cambio, para que una decisión rechazada o superada permanezca visible para cada propuesta futura. Un colaborador incluso abrió una solicitud de extracción (pull request) implementándolo.
Lo que siguió fueron siete meses de intercambios genuinamente sustanciales que involucraron al mantenedor principal Tabish Bidiwale (@TabishB) y varios miembros de la comunidad profundamente involucrados, cubriendo registros inmutables versus mutables, si un ADR pertenece a la fase de investigación o a la fase de diseño, la propiedad entre cambios cuando una decisión se ramifica en una docena de cambios posteriores, y cómo se relacionan los ADR con las especificaciones como la descripción «autoritativa» del sistema. El marco inicial de Tabish Bidiwale estableció la dirección en la que el hilo terminó finalmente: OpenSpec debe mantenerse ligero por defecto y hacer flujos de trabajo especializados como los ADR configurables a través de su sistema de esquemas, en lugar de incorporarlos al núcleo. Un miembro de la comunidad resumió después dónde llegó la discusión:
Los flujos de trabajo ADR son valiosos, pero OpenSpec actualmente no tiene soporte ADR de primer nivel/nativo… la dirección discutida aquí es mantener el flujo de trabajo por defecto ligero y hacer los flujos de trabajo especializados configurables.
El mantenedor Clay Good (@clay-good) cerró el problema con esa base en agosto de 2026 y lo movió a la Discusión de GitHub #1553 para que la conversación pudiera seguir evolucionando sin permanecer abierta como un error sin resolver. Es una decisión razonable para una herramienta cuyo entire argumento es evitar la ceremonia al estilo Spec Kit por defecto. También significa que la corrección vive un nivel más arriba, en uno de dos lugares:
- Un esquema comunitario. El esquema
spec-driven-with-adr, construido por el asesor técnico de OpenSpec Hari Krishnan (@harikrishnan83) y documentado en intent-driven.dev, agrega un quinto artefacto a la línea de producción de cuatro artefactos por defecto de OpenSpec. Existe porque el esquema por defecto pierde el razonamiento dedesign.mden el momento en que un cambio se archiva: solo las diferencias de especificación se sincronizan hacia adelante, por lo que el «por qué» detrás de una decisión desaparece con el cambio a menos que algo más lo preserve. - Una convención a nivel de repositorio. Un pequeño archivo
decision.mdhecho a mano más una regla de nombramiento, que no cuesta nada adoptar y no requiere instalar un esquema personalizado.
El resto de esta guía cubre en profundidad la opción dos, ya que es el punto de partida con menor fricción para la mayoría de los equipos —y, como la sección sobre el esquema comunitario a continuación muestra, es compatible con cambiar a esa herramienta más pesada más adelante si su registro de rechazos crece lo suficiente para merecerlo.
La convención de decision.md para registrar un cambio rechazado
Estructure una investigación rechazada de la misma manera que haría una implementada, pero deténgase antes de sincronizar cualquier diferencia, y agregue un archivo que declare el resultado claramente:
openspec/
changes/
archive/
2026-09-16-rejected-shared-persistence-layer/
proposal.md
decision.md
decision.md responde a las mismas cuatro preguntas que un Registro de Decisiones Arquitectónicas apropiado responde: qué se decidió, por qué, qué alternativas existían y qué cambiaría la respuesta:
# Decisión
Estado: Rechazada
## Decisión
No reemplazar la frontera HTTP entre servicios con una importación
directa de paquetes entre los dos servicios Go.
## Razones
- Aumenta el acoplamiento en tiempo de compilación entre servicios desplegados de forma independiente.
- Hace de la capa de persistencia un contrato implícito y no documentado.
- El beneficio medido (latencia, duplicación de código) fue menor que
el costo de acoplamiento en esta base de código.
## Alternativas consideradas
- Módulo Go interno compartido — rechazado por la misma razón de acoplamiento.
- gRPC en lugar de HTTP — diferido, no rechazado; reconsiderar si el
sobrecargo de HTTP se convierte en un cuello de botella medido.
## Reconsiderar solo si
- Los dos servicios se fusionan intencionalmente en un solo despliegue, o
- Las mediciones de latencia muestran que el salto HTTP es un cuello de botella probado.
## Relacionado
- Regla de arquitectura: los servicios se comunican a través de HTTP, no paquetes compartidos.
La única regla estricta que hace que toda esta convención funcione: no ejecute el paso de sincronización para un cambio rechazado. Si /opsx:propose ya redactó especificaciones diferenciales antes de que usted decidiera contra el cambio, use la bandera que la CLI ya le da para exactamente esta situación:
openspec archive investigate-shared-persistence --skip-specs
--skip-specs le indica a openspec archive que archive el cambio sin tocar openspec/specs/ en absoluto, lo cual es el valor por defecto más seguro para cualquier cosa que esté archivando sin implementar. Aceptar la invitación de sincronización ordinaria en su lugar fusionaría las especificaciones diferenciales de la idea rechazada en sus especificaciones canónicas, y las openspec/specs/ canónicas deben describir lo que el sistema hace actualmente, no cada idea que fue redactada y rechazada. Si un cambio no produce cambios de especificación por una razón estructural —una carpeta de investigación pura, por ejemplo—, OpenSpec también soporta declarar skip_specs: true en el .openspec.yaml de ese cambio para que se archive limpiamente sin la bandera cada vez.
Nombrar cambios rechazados para que humanos y agentes puedan examinar el archivo
Un archivo decision.md solo ayuda si alguien abre la carpeta. Prefije el nombre de la carpeta con el resultado para que tanto un humano que examine ls openspec/changes/archive/ como un agente que liste cambios puedan distinguir el estado sin abrir un solo archivo:
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/ # implementado, no necesita prefijo
Esto refleja el vocabulario de estado ya recomendado para registros de decisiones independientes —propuesto, aceptado, superado, descontinuado— aplicado al propio archivo de OpenSpec en lugar de una carpeta separada docs/decisions/. Mantenga el vocabulario pequeño. Tres o cuatro prefijos consistentes superan a una línea de estado de texto libre que cada propuesta escribe de manera ligeramente diferente.
Cómo hacer que su agente examine el archivo antes de proponer de nuevo
El nombramiento y un archivo decision.md resuelven la descubribilidad para un humano que examina la carpeta. No hacen nada por sí solos para hacer que un agente busque en el archivo antes de redactar una nueva propuesta —eso debe ser una instrucción explícita, porque /opsx:propose no lo hace por defecto, y ninguna cantidad de nombramiento ordenado de archivos lo cambia por sí solo.
Dos lugares para poner esa instrucción, coincidiendo con cómo OpenSpec ya espera que se inyecte la guía específica del proyecto:
En openspec/config.yaml, bajo el campo context: que se inyecta en cada solicitud de planificación (tenga en cuenta el límite de 50KB cubierto en la guía rápida de OpenSpec):
context: |
Antes de proponer un cambio, busque en openspec/changes/archive carpetas
con prefijo "rejected-" o "abandoned-" que describan una idea
materialmente similar. Si existe una, resuma su decision.md y declare
qué ha cambiado antes de proponer la idea de nuevo. No reintente
una decisión rechazada sin nueva evidencia.
En AGENTS.md o en las instrucciones de agente propias de su proyecto, como una regla permanente en lugar de un bloque de contexto por solicitud:
## Cambios rechazados de OpenSpec
Cuando una propuesta se investiga y se rechaza:
1. No sincronice ni aplique sus especificaciones diferenciales.
2. Añada `decision.md` con Estado, Decisión, Razones, Alternativas
consideradas, y Solo reconsiderar si.
3. Prefija el nombre de la carpeta archivada: `rejected-<name>` o `abandoned-<name>`.
4. Antes de proponer un cambio materialmente similar, busque
en `openspec/changes/archive/` y haga referencia a la decisión anterior.
5. No reabra una decisión rechazada a menos que sus condiciones
documentadas de reconsideración hayan cambiado realmente.
Ninguna instrucción garantiza el cumplimiento —un agente aún puede omitir el paso de búsqueda, de la misma manera que puede omitir la lectura de cualquier otro contexto que usted inyecte. Pero es la diferencia entre «la información existe en algún lugar del repositorio» y «al agente se le dice, cada vez, que vaya a buscarla», y solo la segunda reduce realmente las investigaciones repetidas en la práctica.
Un ejemplo práctico: rechazar una propuesta y luego reconsiderarla correctamente
Junte las piezas en un caso concreto. Suponga que un compañero pide a un agente que examine el reemplazo de una llamada HTTP entre servicios con una importación directa de paquetes Go, para reducir la latencia de red.
- Explorar y luego proponer.
/opsx:explorelee ambos servicios, y/opsx:propose replace-http-with-direct-importredacta una propuesta, un documento de diseño que pesa la ganancia de latencia contra el costo de acoplamiento, y una especificación diferencial de borrador. - Investigar y rechazar. Después de revisar el documento de diseño, el equipo decide que el costo de acoplamiento —dos servicios desplegados de forma independiente ahora compartiendo una dependencia en tiempo de compilación— supera una ganancia de latencia que nadie ha medido realmente como problema. Nada se construye.
- Archivar sin sincronizar. En lugar de eliminar la carpeta, ejecute
openspec archive replace-http-with-direct-import --skip-specs, luego añadadecision.mda la carpeta archivada conStatus: Rejected, las razones anteriores, y una cláusula deReconsiderar solo sique nombre la condición que cambiaría la respuesta —por ejemplo, «las mediciones de latencia muestran que el salto HTTP es un cuello de botella probado». Renombrar la carpeta con un prefijorejected-para que lea comoopenspec/changes/archive/2026-09-16-rejected-replace-http-with-direct-import/. - Meses después, alguien lo plantea de nuevo. Un contribuidor diferente, o el mismo agente en una sesión nueva, se le pide «acelerar la llamada de checkout a inventario» y comienza a redactar una propuesta que se parece mucho a la misma idea. Porque
openspec/config.yamlinstruye al agente a buscar en el archivo primero, encuentra la carpeta rechazada, leedecision.md, y responde: «Un cambio materialmente similar fue propuesto y rechazado el 16/09/2026 por razones de acoplamiento. La condición de reconsideración fue “las mediciones de latencia muestran que el salto HTTP es un cuello de botella probado”. ¿Tiene nuevas mediciones, o es este un problema diferente?» - El equipo suminueva evidencia. Si el perfilado ahora muestra que el salto HTTP domina genuinamente la latencia del checkout, esa es exactamente la circunstancia cambiada que la
decision.mdoriginal solicitó. El agente procede con/opsx:propose, y ladecision.mdde la nueva propuesta —una vez que esta también se archive, aceptada o rechazada— hace referencia a la anterior bajoRelated, para que el archivo lea como una historia continua de decisiones en lugar de dos carpetas desconectadas que describen accidentalmente la misma idea.
Ese quinto paso es todo el punto de la convención. Sin él, el paso 4 o no sucede en absoluto —el agente simplemente re-investiga desde cero— o sucede por azar, porque un humano se acordó de la conversación anterior. El archivo decision.md y la instrucción de búsqueda en el archivo convierten «alguien podría acordarse» en algo que el flujo de trabajo realmente verifica.
El archivo de OpenSpec vs. un registro ADR dedicado: ¿Quién posee qué?
Una vez que esté manteniendo archivos decision.md dentro del archivo, vale la pena ser explícito sobre qué artefacto responde a qué pregunta, para que la convención no se convierta silenciosamente en documentación duplicada:
| Artefacto | Responde |
|---|---|
openspec/specs/ |
¿Qué hace actualmente el sistema? |
openspec/changes/<name>/ (activo) |
¿Qué estamos proponiendo cambiar, ahora mismo? |
openspec/changes/archive/<name>/ |
¿Qué cambió (o fue rechazado) en el pasado, y por qué? |
docs/adr/ (independiente, neutral en herramientas) |
¿Qué regla arquitectónica duradera aprendimos, independiente de cualquier cambio individual? |
Para una decisión suficientemente estrecha como para pertenecer a una investigación —«miramos compartir esta capa de persistencia y dijimos que no»—, la convención de decision.md dentro del archivo anterior es suficiente. Para una decisión que debería sobrevivir y restringir muchos cambios futuros —«los servicios se comunican a través de HTTP, nunca paquetes compartidos»—, promóvela a un Registro de Decisiones Arquitectónicas independiente en docs/adr/, y haga que la decision.md del cambio rechazado lo haga referencia bajo Related. Esa división mantiene el archivo de OpenSpec enfocado en investigaciones individuales, mientras que el registro ADR contiene el pequeño número de reglas que deberían sobrevivir al ciclo de vida de cualquier herramienta individual —incluyendo una futura migración fuera de OpenSpec por completo.
Cuándo adoptar el esquema spec-driven-with-adr en su lugar
La convención hecha a mano anterior no cuesta nada y cabe dentro de quince minutos de configuración, lo que la hace el valor por defecto correcto. Pero vale la pena entender qué hace realmente la alternativa más estructurada antes de decidir que ha superado un prefijo de nombramiento.
spec-driven-with-adr inserta un quinto artefacto, adr, entre design y tasks en la línea de producción de OpenSpec. En lugar de escribir el contenido del ADR directamente en la carpeta de cambio, el paso adr produce un manifiesto de revisión local de cambio adr.md corto y, cuando el cambio introduce un compromiso arquitectónico genuinamente duradero, un registro numerado en la raíz del repositorio —/adr/0042-use-postgres-for-catalog.md, hermano de openspec/, no anidado dentro de él. Cada ADR que el esquema crea es inmutable una vez aceptado: las propias instrucciones del esquema lo señalan como una «regla de hierro» —nunca edite el estado, el cuerpo o la fecha de un registro aceptado. Para cambiar una decisión anterior, escribe un ADR nuevo cuyo campo Supersedes: nombre al antiguo, y los diseños futuros recorren esa cadena de superación para saber qué decisiones siguen vigentes. Es una versión más rigurosa de exactamente la idea de «solo reconsiderar si» en la convención de decision.md anterior, aplicada por el esquema en lugar de dejada a un humano recordando escribirla.
Vale la pena ser preciso sobre lo que este esquema hace y no hace. Está construido para decisiones que se aceptan y necesitan sobrevivir al archivado —Postgres sobre DynamoDB, JWT sobre cookies de sesión—, no para propuestas que fueron investigadas y rechazadas sin implementar nada. Una investigación rechazada aún no tiene un lugar obvio para vivir bajo este esquema; usted superpondría la misma convención de decision.md y nombramiento de esta guía encima de él, solo haciendo referencia a registros de /adr/ en lugar de una carpeta independiente docs/adr/.
Recúrrala una vez que note cualquiera de estas cosas:
- Su cuenta de decisiones rechazadas es lo suficientemente grande que buscar con
grepenopenspec/changes/archive/por prefijos deja de ser rápido. - Desea decisiones arquitectónicas duraderas validadas y con referencia cruzada contra cada nuevo diseño automáticamente, en lugar de por convención y
grep. - Múltiples contribuyentes siguen inventando formas ligeramente diferentes de
decision.md, y desea un esquema que imponga un formato inmutable y numerado único.
Instalar un esquema personalizado es un compromiso mayor que una convención de nombramiento —cambia lo que /opsx:propose genera para cada cambio futuro, no solo los rechazados—, por lo que trátela como un paso hacia arriba una vez que la versión ligera esté visiblemente tensándose, no como un movimiento inicial por defecto.
Conclusión
El archivo de OpenSpec fue diseñado alrededor de un único resultado —un cambio que se implementó— y sus propios mantenedores han sido explícitos, después de una discusión pública de siete meses, de que el soporte de rechazo o ADR de primer nivel no llegará pronto al flujo de trabajo del núcleo. Esto deja la corrección donde OpenSpec ya pone la mayor parte de sus convenciones de equipo: en su repositorio, no en la herramienta. Un archivo decision.md, la bandera --skip-specs al archivar, un prefijo de nombramiento rejected-/abandoned-, y una instrucción explícita diciendo al agente que busque en el archivo antes de proponer son suficientes para detener la mayoría de las investigaciones repetidas. Recurre al esquema spec-driven-with-adr solo una vez que esa convención ligera esté genuinamente tensándose bajo el número de decisiones que está rastreando —y aun así, mantenga clara la distinción: gestiona decisiones que aceptó y quiere que sobrevivan al archivado, no las que rechazó.
Enlaces útiles
- Guía rápida de OpenSpec: Instalación, Flujo de trabajo y Errores comunes — instalación, el bucle de explorar-proponer-aplicar-archivar, y errores cotidianos
- Flujo de Trabajo de Desarrollo Guiado por Especificaciones de Requisitos a Código — el proceso neutral en herramientas de cinco fases en el que esta convención rellena una brecha
- Registros de Decisiones para el Desarrollo de Software Guiado por IA — el formato general ADR/PDR/DDR, ciclo de vida de estado, e instrucciones de lectura por IA de las que esta convención se inspira
- Problema de GitHub #557: soporte para registros de decisiones arquitectónicas — la discusión completa de siete meses de por qué los ADR no son núcleo de OpenSpec
- Discusión de GitHub #1553 — donde esa conversación continúa después de que el problema fue cerrado
- Esquema spec-driven-with-adr — el esquema comunitario que mantiene los ADR vivos fuera del ciclo de vida del cambio, por el asesor de OpenSpec Hari Krishnan
- Documentación de flujo de trabajo de equipo de OpenSpec — cómo el archivado, las ramas y la revisión de PR están destinadas a encajar juntas
- GitHub Spec Kit vs Kiro vs Claude Code SDD Workflows — cómo OpenSpec se compara con herramientas SDD más pesadas en general