Propositions rejetées d'OpenSpec : une convention de mémoire décisionnelle
Aucun état de rejet. Voici le contournement.
Un agent qui a proposé et déployé « déplacer la persistance dans une bibliothèque partagée » il y a six mois le proposera sans problème le trimestre prochain, à moins qu’un élément durable ne lui signale que l’idée a déjà été étudiée et rejetée – et OpenSpec n’a aujourd’hui aucun état interne pour cela.
/opsx:archive est conçu pour un seul résultat : un changement qui a été déployé. Il synchronise les spécifications de delta dans openspec/specs/ et déplace le dossier vers openspec/changes/archive/AAAA-MM-JJ-<nom>/ comme trace de ce qui a changé et pourquoi. Il n’existe ni commande /opsx:reject ni /opsx:abandon, et rien dans le format d’archive n’indique à une future proposition « cette idée exacte a été étudiée et refusée ». Cette lacune est la plus importante précisément dans les bases de code où OpenSpec est autrement un bon choix : les systèmes existants avec un petit nombre de contributeurs et des agents qui réexplorent périodiquement les mêmes questions architecturales – fusionner ces deux services, partager cette couche de persistance, remplacer cette limite HTTP par un import direct.

Ce n’est pas une lacune hypothétique. Elle a été soulevée directement auprès des mainteneurs d’OpenSpec comme demande de fonctionnalité, et la manière dont cette conversation s’est déroulée mérite d’être connue avant d’improviser votre propre correctif : [ce que le projet a réellement conclu](#ce-que-les-mainteneurs-dopenspec-ont- réellement-decidé-sur-la-prestation-adr) détermine quelle convention vaut la peine d’être adoptée. Ce guide détaille ce qui se passe si vous reposez uniquement sur /opsx:archive, la vraie discussion qui a déjà eu lieu dans le suivi de problèmes d’OpenSpec, et un motif léger decision.md que vous pouvez adopter aujourd’hui sans attendre – ou nécessiter – un support intégré.
Pourquoi l’archivage seul n’enregistre pas une décision rejetée
Archiver un changement que vous avez décidé de ne pas construire fonctionne techniquement – le dossier sort de votre liste active dans tous les cas. Le problème, c’est ce que ce dossier archivé échoue à communiquer une fois qu’il est placé à côté de dizaines de changements déployés :
- Aucun champ de statut. Un changement archivé a exactement la même apparence qu’il ait été déployé ou abandonné trois messages après
/opsx:propose. Un collègue ou un agent qui parcourtopenspec/changes/archive/ne peut pas faire la différence sans ouvrir chaque dossier de proposition et lire les artefacts à l’intérieur. - Aucun signal pour vérifier en premier. Rien dans le flux de travail par défaut n’instruit un agent de rechercher dans l’archive avant de rédiger une nouvelle proposition.
/opsx:proposerédige à partir de votre demande actuelle et de l’état de la base de code, point final – il ne croise pas les changements rejetés précédents à moins que vous ne le lui disiez. - Des spécifications de delta que vous ne voulez pas synchroniser. Si un changement rejeté a déjà des spécifications de delta en brouillon et que vous l’archivez de manière ordinaire,
/opsx:archivevous proposera de synchroniser ces deltas dansopenspec/specs/d’abord. Accepter cette offre enseigne à vos spécifications canoniques de décrire un comportement que vous avez décidé de ne pas construire, ce qui corrompt silencieusement le registre « ce que le système fait actuellement » que chaque autre proposition lit avant de planifier quoi que ce soit.
Aucun de ces éléments n’est un bug. /opsx:archive fait exactement ce que sa documentation dit : compléter un changement qui a été déployé. Le cas de rejet se situe intentionnellement hors de ce périmètre documenté, et le guide de flux de travail d’équipe d’OpenSpec est explicite : la plupart de ce qu’il recommande – conventions de branches, ordre de revue de PR, quand archiver – est une convention ajoutée au-dessus de l’outil, et non quelque chose que OpenSpec applique pour vous. Gérer un rejet est une convention de plus que vous pouvez définir vous-même, et le CLI vous donne déjà le drapeau dont vous avez besoin pour le faire proprement : passez --skip-specs lors de l’archivage d’un changement que vous ne déployez pas, afin que openspec archive investigate-shared-persistence --skip-specs classe le dossier sans toucher openspec/specs/ du tout.
Ce que les mainteneurs d’OpenSpec ont réellement décidé au sujet de la prise en charge des ADR
Avant d’inventer une convention maison, il est utile de lire comment cette question exacte a évolué publiquement, car la résolution est plus spécifique – et plus intéressante – que « non ». La issue GitHub #557, ouverte en janvier 2026, demandait un support de premier niveau pour les enregistrements de décision architecturale (ADR) : des enregistrements durables qui persistent indépendamment du cycle de vie d’un changement unique, afin qu’une décision rejetée ou remplacée reste visible pour chaque proposition future. Un contributeur a même ouvert une pull request pour l’implémenter.
Il y a ensuite eu sept mois d’allers-retours substantiels impliquant le mainteneur principal Tabish Bidiwale (@TabishB) et plusieurs membres de la communauté très engagés, couvrant les enregistrements immuables vs mutables, si un ADR appartient à la phase de recherche ou à la phase de conception, la propriété inter-changements lorsqu’une décision se propage dans une douzaine de changements ultérieurs, et la relation entre les ADR et les spécifications en tant que description « authoritative » du système. Le cadrage initial de Tabish Bidiwale a fixé la direction sur laquelle le fil a finalement convergé : OpenSpec doit rester léger par défaut et rendre les flux de travail spécialisés comme les ADR configurables via son système de schéma, plutôt que de les intégrer au noyau. Un membre de la communauté a ensuite résumé où en était la discussion :
Les flux de travail ADR sont précieux, mais OpenSpec n’a actuellement pas de support ADR de premier niveau/natif… la direction discutée ici est de garder le flux de travail par défaut léger et de rendre les flux de travail spécialisés configurables.
Le mainteneur Clay Good (@clay-good) a fermé la issue sur cette base en août 2026 et l’a déplacée vers la Discussion GitHub #1553 afin que la conversation puisse continuer à évoluer sans rester ouverte comme un bug non résolu. C’est une décision raisonnable pour un outil dont toute la proposition est d’éviter la cérémonie de type Spec Kit par défaut. Cela signifie aussi que le correctif se situe un niveau au-dessus, dans l’une des deux options :
- Un schéma communautaire. Le schéma
spec-driven-with-adr, construit par le conseiller technique d’OpenSpec Hari Krishnan (@harikrishnan83) et documenté sur intent-driven.dev, ajoute un cinquième artefact au pipeline par défaut d’OpenSpec à quatre artefacts. Il existe parce que le schéma par défaut perd le raisonnement dedesign.mddès qu’un changement est archivé – seules les spécifications de delta sont synchronisées, donc le « pourquoi » d’une décision disparaît avec le changement à moins que quelque chose d’autre le préserve. - Une convention au niveau du dépôt. Un petit fichier
decision.mdfait main, plus une règle de nommage, qui ne coûte rien à adopter et ne nécessite pas d’installer un schéma personnalisé.
Le reste de ce guide couvre en détail l’option deux, car c’est le point de départ à plus faible friction pour la plupart des équipes – et, comme le montre la section sur le schéma communautaire ci-dessous, elle est compatible avec un passage ultérieur vers cet outillage plus lourd si votre journal de rejets grandit suffisamment pour le mériter.
La convention decision.md pour enregistrer un changement rejeté
Structurez une investigation rejetée de la même manière qu’un changement déployé, mais arrêtez-vous avant de synchroniser des deltas, et ajoutez un fichier qui énonce clairement le résultat :
openspec/
changes/
archive/
2026-09-16-rejected-shared-persistence-layer/
proposal.md
decision.md
decision.md répond aux quatre mêmes questions qu’un bon Enregistrement de Décision Architecturale – ce qui a été décidé, pourquoi, quelles alternatives existaient, et ce qui changerait la réponse :
# Décision
Statut : Rejetée
## Décision
Ne pas remplacer la limite HTTP entre services par un import direct de package entre les deux services Go.
## Raisons
- Augmente l'interdépendance au niveau de la compilation entre des services déployés de manière indépendante.
- Rend la couche de persistance un contrat implicite et non documenté.
- Le bénéfice mesuré (latence, duplication de code) était inférieur au coût de l'interdépendance dans cette base de code.
## Alternatives envisagées
- Module Go interne partagé – rejeté pour la même raison d'interdépendance.
- gRPC au lieu de HTTP – différé, non rejeté ; réévaluer si la surcharge HTTP devient un goulot d'étranglement mesuré.
## Réexaminer uniquement si
- Les deux services sont fusionnés intentionnellement en un seul déployable, ou
- Les mesures de latence montrent que la traversée HTTP est un goulot d'étranglement prouvé.
## Liés
- Règle architecturale : les services communiquent via HTTP, pas via des packages partagés.
La seule règle stricte qui fait fonctionner toute cette convention : ne pas exécuter l’étape de synchronisation pour un changement rejeté. Si /opsx:propose a déjà rédigé des spécifications de delta avant que vous ne décidiez contre le changement, utilisez le drapeau que le CLI vous donne déjà pour exactement cette situation :
openspec archive investigate-shared-persistence --skip-specs
--skip-specs indique à openspec archive de classer le changement sans toucher openspec/specs/ du tout, ce qui est le défaut le plus sûr pour tout ce que vous archivez sans déployer. Accepter la invite de synchronisation ordinaire à la place fusionnerait les spécifications de delta de l’idée rejetée dans vos spécifications canoniques, et les spécifications canoniques openspec/specs/ doivent décrire ce que le système fait actuellement, pas toutes les idées qui ont été rédigées et rejetées. Si un changement ne produit pas de modifications de spécifications pour une raison structurelle – un dossier de pure investigation, par exemple – OpenSpec prend également en charge la déclaration skip_specs: true dans .openspec.yaml de ce changement pour qu’il soit archivé proprement sans le drapeau à chaque fois.
Nommer les changements rejetés pour que les humains et les agents puissent parcourir l’archive
Un fichier decision.md n’est utile que si quelqu’un ouvre le dossier. Préfixez le nom du dossier avec le résultat pour qu’un humain qui parcourt ls openspec/changes/archive/ et un agent listant les changements puissent déterminer le statut sans ouvrir un seul fichier :
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/ # déployé, aucun préfixe nécessaire
Cela reproduit le vocabulaire de statut déjà recommandé pour les enregistrements de décision autonomes – proposé, accepté, remplacé, déprécié – appliqué à l’archive d’OpenSpec au lieu d’un dossier séparé docs/decisions/. Gardez le vocabulaire petit. Trois ou quatre préfixes cohérents valent mieux qu’une ligne de statut en texte libre que chaque proposition orthographie légèrement différemment.
Comment faire en sorte que votre agent vérifie l’archive avant de proposer à nouveau
Le nommage et un fichier decision.md résolvent la découvrabilité pour un humain parcourant le dossier. Ils ne font rien d’eux-mêmes pour faire en sorte qu’un agent recherche dans l’archive avant de rédiger une nouvelle proposition – cela doit être une instruction explicite, car /opsx:propose ne le fait pas par défaut, et aucune quantité de nommage de fichiers soigné ne change cela seul.
Deux endroits pour mettre cette instruction, correspondant à la façon dont OpenSpec s’attend déjà à ce que les guides spécifiques au projet soient injectés :
Dans openspec/config.yaml, sous le champ context: qui est injecté dans chaque demande de planification (attention à la limite de 50 Ko couverte dans le Guide de démarrage rapide OpenSpec) :
context: |
Avant de proposer un changement, recherchez dans openspec/changes/archive
des dossiers préfixés "rejected-" ou "abandoned-" qui décrivent une idée
matériellement similaire. Si un existe, résumez son decision.md et
indiquez ce qui a changé avant de proposer à nouveau l'idée. Ne
relancez pas une décision rejetée sans nouvelles preuves.
Dans AGENTS.md ou les instructions agent propres à votre projet, en tant que règle permanente plutôt qu’un bloc de contexte par demande :
## Changements OpenSpec rejetés
Lorsqu'une proposition est étudiée et rejetée :
1. Ne synchronisez ni n'appliquez ses spécifications de delta.
2. Ajoutez un `decision.md` avec Statut, Décision, Raisons,
Alternatives envisagées, et Réexaminer uniquement si.
3. Préfixez le nom du dossier archivé : `rejected-<nom>` ou `abandoned-<nom>`.
4. Avant de proposer un changement matériellement similaire, recherchez
dans `openspec/changes/archive/` et référencez la décision antérieure.
5. Ne rouvrez pas une décision rejetée à moins que ses conditions
documentées de réexamen aient réellement changé.
Aucune de ces instructions ne garantit la conformité – un agent peut toujours sauter l’étape de recherche, de la même manière qu’il peut sauter la lecture de tout autre contexte que vous injectez. Mais c’est la différence entre « l’information existe quelque part dans le dépôt » et « l’agent est instruit, à chaque fois, de chercher », et c’est seulement la seconde qui réduit réellement les investigations répétées en pratique.
Un exemple concret : Rejeter une proposition, puis la réexaminer correctement
Assemblez les éléments sur un cas concret. Disons qu’un collègue demande à un agent de regarder le remplacement d’un appel HTTP entre services par un import direct de package Go, pour réduire la latence réseau.
- Explorer, puis proposer.
/opsx:explorelit les deux services, et/opsx:propose replace-http-with-direct-importrédige une proposition, un document de conception pesant le gain de latence contre le coût d’interdépendance, et une spécification de delta en brouillon. - Investiguer et rejeter. Après avoir examiné le document de conception, l’équipe décide que le coût de l’interdépendance – deux services déployés de manière indépendante partageant maintenant une dépendance de compilation – l’emporte sur un gain de latence que personne n’a réellement mesuré comme un problème. Rien n’est construit.
- Archiver sans synchroniser. Plutôt que de supprimer le dossier, exécutez
openspec archive replace-http-with-direct-import --skip-specs, puis ajoutezdecision.mdau dossier archivé avecStatus: Rejected, les raisons ci-dessus, et une clauseReconsider only ifnommant la condition qui changerait la réponse – par exemple, « les mesures de latence montrent que la traversée HTTP est un goulot d’étranglement prouvé ». Renommez le dossier avec un préfixerejected-pour qu’il soit lu commeopenspec/changes/archive/2026-09-16-rejected-replace-http-with-direct-import/. - Des mois plus tard, quelqu’un le reprend. Un contributeur différent, ou le même agent dans une nouvelle session, est demandé de « accélérer l’appel checkout-vers-inventaire » et commence à rédiger une proposition qui ressemble beaucoup à la même idée. Parce que
openspec/config.yamlinstruit l’agent de rechercher d’abord dans l’archive, il trouve le dossier rejeté, litdecision.md, et répond : « Un changement matériellement similaire a été proposé et rejeté le 16/09/2026 pour des raisons d’interdépendance. La condition de réexamen était “les mesures de latence montrent que la traversée HTTP est un goulot d’étranglement prouvé”. Avez-vous de nouvelles mesures, ou est-ce un problème différent ? » - L’équipe fournit de nouvelles preuves. Si le profilage montre maintenant que la traversée HTTP domine réellement la latence de la commande, c’est exactement la circonstance modifiée demandée par le
decision.mdoriginal. L’agent procède avec/opsx:propose, et ledecision.mdde la nouvelle proposition – une fois celui-ci également archivé, accepté ou rejeté – référence le précédent sousRelated, de sorte que l’archive se lit comme une histoire de décision continue plutôt que comme deux dossiers non connectés qui se trouvent décrire la même idée.
Cinquième étape, c’est le but entier de la convention. Sans cela, l’étape 4 soit ne se produit pas du tout – l’agent réinvestit simplement depuis zéro – soit elle se produit par chance, parce qu’un humain se souvenait de la conversation antérieure. Le fichier decision.md et l’instruction de recherche d’archive transforment « quelqu’un pourrait se souvenir » en quelque chose que le flux de travail vérifie réellement.
Archive d’OpenSpec vs. Journal ADR dédié : Qui possède quoi
Une fois que vous maintenez des fichiers decision.md dans l’archive, il est utile d’être explicite sur quel artefact répond à quelle question, afin que la convention ne devienne pas silencieusement une documentation en double :
| Artefact | Répond à |
|---|---|
openspec/specs/ |
Que fait le système actuellement ? |
openspec/changes/<nom>/ (actif) |
Que proposons-nous de changer, maintenant ? |
openspec/changes/archive/<nom>/ |
Qu’est-ce qui a changé (ou été rejeté) dans le passé, et pourquoi ? |
docs/adr/ (autonome, neutre quant à l’outil) |
Quelle règle architecturale durable avons-nous apprise, indépendamment de tout changement unique ? |
Pour une décision assez étroite pour appartenir à une investigation unique – « nous avons regardé le partage de cette couche de persistance et avons dit non » – la convention decision.md-dans-l’archive ci-dessus suffit. Pour une décision qui doit survivre et contraindre de nombreux changements futurs – « les services communiquent via HTTP, jamais via des packages partagés » – promouvez-la vers un Enregistrement de Décision Architecturale autonome dans docs/adr/, et faites en sorte que le decision.md du changement rejeté le référence sous Related. Cette division garde l’archive d’OpenSpec concentrée sur les investigations individuelles, tandis que le journal ADR détient le petit nombre de règles qui doivent survivre au cycle de vie de tout outil unique – y compris une future migration loin d’OpenSpec.
Quand adopter le schéma spec-driven-with-adr à la place
La convention faite main ci-dessus ne coûte rien et s’insère dans quinze minutes de configuration, ce qui en fait le bon défaut. Mais il est utile de comprendre ce que l’alternative plus structurée fait réellement avant de décider que vous avez dépassé un préfixe de nommage.
spec-driven-with-adr insère un cinquième artefact, adr, entre design et tasks dans le pipeline d’OpenSpec. Plutôt que d’écrire le contenu ADR directement dans le dossier du changement, l’étape adr produit un court manifeste de revue adr.md local au changement et, lorsque le changement introduit un engagement architectural durablement réel, un enregistrement numéroté à la racine du dépôt – /adr/0042-use-postgres-for-catalog.md, jumeau de openspec/, pas imbriqué à l’intérieur. Chaque ADR créé par le schéma est immuable une fois accepté : les propres instructions du schéma en font une « règle de fer » – on ne modifie jamais le statut, le corps ou la date d’un enregistrement accepté. Pour modifier une décision précédente, on écrit un nouvel ADR dont le champ Supersedes: nomme l’ancien, et les conceptions futures suivent cette chaîne de remplacement pour savoir quelles décisions sont toujours en vigueur. C’est une version plus rigoureuse de l’idée de « réexaminer uniquement si » dans la convention decision.md ci-dessus, appliquée par le schéma plutôt que laissée à la mémoire humaine de le noter.
Il est utile d’être précis sur ce que ce schéma résout et ne résout pas. Il est conçu pour des décisions qui sont acceptées et doivent survivre à l’archivage – Postgres plutôt que DynamoDB, JWT plutôt que des cookies de session – et non pour des propositions qui ont été étudiées et rejetées sans rien déployer. Une investigation rejetée n’a toujours pas de place évidente sous ce schéma ; vous superposeriez la même convention decision.md-et-nommage de ce guide par-dessus, en référençant simplement des enregistrements /adr/ au lieu d’un dossier autonome docs/adr/.
Y recourir une fois que vous remarquez l’une de ces choses :
- Votre nombre de décisions rejetées est suffisant pour que le grep de
openspec/changes/archive/pour les préfixes cesse d’être rapide. - Vous voulez des décisions architecturales durables validées et croisées avec chaque nouvelle conception automatiquement, plutôt que par convention et
grep. - Plusieurs contributeurs inventent continuellement des formes de
decision.mdlégèrement différentes, et vous voulez un schéma pour imposer un format immuable et numéroté unique.
Installer un schéma personnalisé est un engagement plus important qu’une convention de nommage – cela change ce que /opsx:propose génère pour chaque changement futur, pas seulement les rejetés – donc considérez-le comme une montée en gamme une fois que la version légère montre visiblement ses limites, et non comme un premier mouvement par défaut.
Conclusion
L’archive d’OpenSpec a été conçue autour d’un seul résultat – un changement déployé – et ses propres mainteneurs ont été explicites, après une discussion publique de sept mois, que le support de premier niveau pour les rejets ou les ADR n’arrivera pas bientôt au flux de travail central. Cela laisse le correctif là où OpenSpec place déjà la plupart de ses conventions d’équipe : dans votre dépôt, pas dans l’outil. Un fichier decision.md, le drapeau --skip-specs à l’archivage, un préfixe de nommage rejected-/abandoned-, et une instruction explicite disant à l’agent de rechercher dans l’archive avant de proposer suffisent pour arrêter la plupart des investigations répétées. Recourez au schéma spec-driven-with-adr seulement une fois que cette convention légère est réellement sous pression du nombre de décisions que vous suivez – et même alors, gardez la distinction claire : il gère les décisions que vous avez acceptées et voulez voir survivre à l’archivage, pas celles que vous avez rejetées.
Liens utiles
- OpenSpec Guide de démarrage rapide : Installation, Flux de travail et pièges courants – installation, la boucle explorer-proposer-appliquer-archiver, et les pièges quotidiens
- Flux de travail de développement piloté par spécification : De la requête au code – le processus neutre à l’outil en cinq phases dans lequel cette convention comble une lacune
- Enregistrements de décisions pour le développement logiciel piloté par IA – le format général ADR/PDR/DDR, le cycle de vie des statuts, et les instructions de lecture par IA dont cette convention s’inspire
- Issue GitHub #557 : support des enregistrements de décision architecturale – la discussion complète de sept mois sur pourquoi les ADR ne sont pas centraux dans OpenSpec
- Discussion GitHub #1553 – où cette conversation continue après la fermeture de l’issue
- Schéma spec-driven-with-adr – le schéma communautaire qui garde les ADR vivants en dehors du cycle de vie du changement, par le conseiller OpenSpec Hari Krishnan
- Docs team-workflow OpenSpec – comment l’archivage, les branches et la revue de PR sont censées s’assembler
- GitHub Spec Kit vs Kiro vs Claude Code : Flux de travail SDD – comment OpenSpec se compare aux outillages SDD plus lourds en général