marcioaltoe/archive-spec

Archiver une spécification terminée — vérifier que chaque tâche est accomplie, que l'assurance qualité est passée et que les références indexées sont autonomes, puis écrire <slug>.md dans la racine d'archive résolue (<racine-spec>/_archived/, ou docs/history/specs/ pour la racine intégrée docs/specs) et supprimer le dossier Spec, qui reste dans Git à la révision source de l'enregistrement. Fonctionne automatiquement à la fin d'un Roundfix Spec Run après une passe QA, ou à la demande de l'utilisateur.

Qu'est-ce que archive-spec ?

Cette compétence archive une spécification terminée en écrivant un enregistrement au format Markdown (<slug>.md) dans une racine d'archive résolue et en supprimant le dossier de spécification actif. Elle vérifie d'abord trois préconditions : toutes les tâches requises sont terminées, la QA est passée (en analysant le dernier rapport QA) et la spécification est autonome (toutes les références indexées existent, aucun lien vers _inbox/ ou findings/). L'archivage déplace les fichiers référencés non essentiels vers docs/references/<basename> et réécrit les citations avant de supprimer le dossier Spec. Elle prend en charge plusieurs dispositions : 'normal' pour une spécification entièrement vérifiée, 'qa_override' lorsque la QA est explicitement contournée par une autorisation, 'no-qa' si la QA a été déclinée par le graphe de tâches, et 'cancelled' pour les spécifications abandonnées (qui retournent les éléments aux backlogs et aux constats). L'outil refuse d'agir si des fichiers sont ignorés par Git dans le dossier Spec ou si les préconditions échouent. Elle est conçue pour s'intégrer à Roundfix et se déclenche automatiquement à la fin d'un Spec Run ou à la demande.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/marcioaltoe/roundfix/tree/HEAD/skills/archive-spec

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Archive Spec

Archiver une spécification terminée en écrivant <slug>.md dans la racine d'archive résolue et en supprimant <racine-spec-résolue>/<slug>/, qui reste dans Git à la source_revision de l'enregistrement. La source est la racine Spec configurée ; la destination est sa racine d'archive résolue — docs/history/specs/ pour la racine intégrée docs/specs, ou <racine-spec>/_archived/ pour une racine externe ou non par défaut, correspondant à la destination de roundfix archive. Un archivage normal signifie implémenté, vérifié et autonome — chaque tâche accomplie, QA passée lorsque le graphe de tâches rédige un portail QA, et chaque référence indexée appartenant à la spécification. Un remplacement QA Archive enregistre l'exception explicite sans revendiquer la vérification. Après l'une ou l'autre disposition, un ls <racine-spec>/ sépare le travail actif de l'historique, et l'archive reste consultable comme enregistrement de ce qui a été construit et pourquoi.

Le déclencheur est l'achèvement de la spécification, pas la publication : exécutez-la automatiquement à la fin d'un Roundfix Spec Run une fois que le portail QA est passé, ou à la demande de l'utilisateur. La fusion et la publication sont des étapes distinctes, pilotées par l'utilisateur — le commit d'archive voyage simplement avec la branche et est livré dans la propre PR de la fonctionnalité.

Reliure d'archive

Avant d'écrire l'enregistrement d'archive, l'archive effectue une reliure d'archive. Elle promeut automatiquement chaque fichier non essentiel cité qu'un document en direct référence depuis la spécification propriétaire vers docs/references/<basename>, puis réécrit les citations de chaque document en direct vers la copie promue ; les citations du dossier Spec ou d'un artefact essentiel pointent vers l'enregistrement d'archive. L'enregistrement liste les fichiers réécrits sous relinked lorsqu'ils existent. La source conserve un propriétaire, donc une spécification secondaire n'a pas besoin de copie (ADR-0260, ADR-0083).

Le dossier Spec est retiré par suppression. Dans le résultat copié et chaque copie promue, une destination dans le dossier supprimé nomme une copie promue ou devient un localisateur Git, `<path>@<commit>` ; il ne pointe jamais vers l'enregistrement lui-même. Le commit contient le chemin et est accessible depuis la branche par défaut ou un tag. Lorsqu'aucun commit de ce type n'existe, le localisateur nomme le chemin et la pull request de l'enregistrement. Les autres destinations conservent leur cible de dépôt (ADR-0278).

L'archive refuse d'écrire lorsqu'une destination de promotion existe déjà, lorsque deux promotions partagent un basename, ou lorsqu'un document en direct à réécrire a des modifications non commitées à HEAD. Les citations dans des fichiers qui ne sont pas des documents en direct, ou les citations qui subsistent après la réécriture, sont des avertissements nommant le fichier, la ligne et la cible ; l'archive laisse ces fichiers inchangés.

Fusions squash

Une fusion squash conserve source_revision uniquement dans la ref de tête de la pull request ; l'enregistrement nomme cette pull request dans pull_request.

Déclin QA déclaré

Un graphe de tâches qui déclare qa: declined avec un qa_reason non vide archive une fois que chaque tâche est terminée, sans rapport QA et sans remplacement, et son enregistrement d'archive a la disposition no-qa. --qa-override est refusé pour une telle spécification. Toute autre précondition d'archive s'applique toujours.

Règlement QA

Le même résultat règle la tâche qa rédigée et détermine ce que l'archive laisse :

RésultatRègleArchive
passRègle la tâche QA comme terminée et rend la spécification éligible à l'archivage lorsque le rapport n'a pas de lignes bloquées interdites.L'enregistrement d'archive, qui nomme le rapport QA et le verdict ; la spécification, son rapport QA et ses preuves restent dans Git à la source_revision de l'enregistrement.
partial déclaré qualifiantRègle la tâche QA comme terminée lorsqu'aucune ligne n'a échoué, n'a été ignorée ou n'est bloquée par une constatation, chaque ligne déclarée bloquée est couverte par une déclaration ## Acceptation inaccessible correspondante, et chaque ligne bloquée par l'environnement est la ligne de pull request pré-PR, enregistrée comme bloquée (environnement : aucune pull request ouverte) avec la ligne de pull request nommée dans sa provenance, ou une ligne de preuve externe que le bac à sable d'exécution n'a pas pu atteindre, enregistrée comme bloquée (environnement : réseau refusé : <hôte>) avec la ligne de preuve externe nommée dans sa provenance. Aucune de ces lignes n'a besoin d'une déclaration d'Acceptation inaccessible, et un partial dont les seules lignes non satisfaites sont de telles lignes est qualifiant.L'enregistrement d'archive, qui nomme le rapport QA et le verdict et porte l'enregistrement satisfait-par des déclarations comme non-prouvé ; la spécification, son rapport QA et ses preuves restent dans Git à la source_revision de l'enregistrement.
environment-blockedLaisse la ligne bloquée ; le rapport peut toujours régler comme pass lorsque des preuves équivalentes satisfont la politique d'environnement.Rien par lui-même ; un rapport qualifiant peut archiver la spécification.
failedLaisse la tâche QA non résolue et refuse l'archivage sauf si un remplacement autorisé s'applique.Rien.
missingLaisse la tâche QA non résolue et refuse l'archivage sauf si un remplacement autorisé s'applique.Rien.
overrideNe change pas le statut de la tâche QA ou le verdict du rapport ; règle l'archivage comme explicitement autorisé malgré une QA échouée ou manquante.L'enregistrement d'archive avec qa_override, qa_override_approval, qa_override_reason, qa_override_qa_outcome, qa_override_qa_task_status lorsque la tâche QA est incomplète, et qa_override_revision ; la tâche QA et les rapports restent inchangés dans Git à la source_revision de l'enregistrement.

Lignes que l'autorisation de la spécification maintient hors ligne

Le partial déclaré qualifiant ci-dessus accepte également une ligne de preuve externe que le portail n'a pas consultée parce que l'autorisation propre de la spécification interdit cette consultation, enregistrée comme bloquée (environnement : <sujet> interdit par l'autorisation de la spécification) avec la ligne de preuve externe nommée dans sa provenance. Le sujet nomme ce que l'autorisation interdit, dans ses mots : réseau pour une consultation réseau, ou un autre dépôt ; il fait 1 à 80 caractères et ne contient pas de parenthèses. Comme la ligne refusée par réseau, elle ne décide jamais d'un partial qualifiant et n'a pas besoin de déclaration d'Acceptation inaccessible, une ligne compte pour au plus un type exempté, et le règlement, roundfix qa-report accept et roundfix archive le lisent par la même politique (ADR-0276, ADR-0335).

Annulation d'une spécification

Une spécification qui ne sera pas livrée est annulée avec roundfix cancel <slug> --reason <texte>, jamais supprimée manuellement. La commande écrit un enregistrement d'archive avec la disposition cancelled, retourne chaque entrée de backlog adoptée à docs/backlog/ avec status: open et chaque constat adopté à docs/findings/ avec status: pending, puis supprime le dossier Spec tandis que ses octets restent dans Git à source_revision. Un enregistrement annulé ne répond jamais à un prérequis, ne remplace jamais une autre spécification et est refusé par la livraison différée.

Fichiers ignorés et suppression échouée

La commande Archiver et la commande Annuler refusent tant que Git ignore un fichier dans le dossier Spec. Chaque commande liste chaque fichier ignoré et n'écrit rien. L'opérateur doit supprimer chaque fichier ou le commiter avec git add -f, puis réessayer.

Si la suppression finale du dossier Spec échoue, les deux commandes conservent chaque écriture, se terminent avec 1 et affichent la commande qui termine la suppression : chmod -R u+w '<dossier>' && rm -rf '<dossier>'.

Préconditions — vérifier, ne pas faire confiance

Vérifiez les trois avec des preuves fraîches de commandes avant de toucher quoi que ce soit :

  1. Tâches requises terminées. Pour un archivage normal, lisez chaque task_NN.md listé dans _tasks.md ; chaque status doit être completed. Pour un remplacement d'archive QA, chaque tâche non-QA doit être terminée ; la tâche QA peut rester pending ou failed. Si la tâche QA est également terminée, le rapport le plus récent doit rester inéligible ou le remplacement est inutile et refusé.

    Commande : exécutez grep -n '^status:' <chaque-fichier-tâche-listé-dans-_tasks.md> et conservez sa sortie. Toute valeur autre que status: completed bloque un archivage normal. Pendant un remplacement, seule une tâche non-QA avec un autre statut bloque l'archivage ; nommez ce fichier de tâche.

  2. QA passée. Le rapport le plus récent dans qa/ doit passer le vérificateur QA du dépôt. Ne substituez pas une grep de ligne à une validation structurée. Dans Roundfix, utilisez le même contrat internal/spec.QAVerdict que la commande d'archive : sélectionnez le rapport le plus récent par le contrat de nom de fichier qa-report-YYYY-MM-DD[-NN].md, analysez son frontmatter YAML, exigez un verdict pris en charge, exigez que les deux champs de lignes bloquées soient des entiers non négatifs lorsqu'ils sont présents, et rejetez verdict : pass lorsque rows_blocked_finding est non nul. Conservez le chemin et le résultat du rapport du vérificateur comme preuve. Un répertoire qa/ manquant, un rapport le plus récent mal formé ou un verdict non passant bloque l'archivage normal. Procédez uniquement sous un remplacement explicite d'archive QA effectué via roundfix archive <slug> --qa-override --approval <source> --reason <texte>. N'enregistrez jamais le remplacement en éditant l'enregistrement d'archive. Un rapport le plus récent qualifiant ne rend pas une tâche QA échouée ou en attente terminée ; le remplacement est refusé uniquement lorsque le rapport est qualifiant et que chaque tâche est terminée.

  3. La spécification est autonome. Appliquez cette précondition lorsque docs/specs/<slug>/references/_index.md existe ou est un lien symbolique ; un lien symbolique, y compris un lien brisé, est un état d'index invalide plutôt qu'une spécification héritée. Seule une spécification où ce chemin n'existe ni n'est un lien symbolique est antérieure à ce contrat et passe sans rétrofitter les artefacts historiques. Pour une spécification indexée, chaque path indexé doit exister relatif à _index.md, chaque chemin source jamais mis à jour doit être absent, et aucune destination de lien Markdown à l'intérieur de la spécification ne peut pointer vers docs/_inbox/ ou docs/findings/.

    Commandes : exécutez d'abord cette vérification de destination de lien ; sa syntaxe correspond délibérément aux liens Markdown en ligne ou par référence, pas à une prose qui nomme simplement l'un ou l'autre répertoire :

    spec_dir=docs/specs/<slug>
    link_hits=$(grep --include='*.md' -RInE '(\](\([^)]*(docs/)?(_inbox|findings)/[^)]*\)|^[[:space:]]*\[[^]]+\]:[[:space:]]*<?[^[:space:]>]*(docs/)?(_inbox|findings)/)' "$spec_dir")
    link_status=$?
    if test "$link_status" -eq 0; then
      printf '%s\n' "$link_hits"
      echo "auto-contenance échouée : réécrivez chaque lien listé à l'étape d'adoption 8"
      exit 1
    fi
    test "$link_status" -eq 1 || exit "$link_status"
    

    Ensuite, analysez et validez chaque ligne de données. L'index appartient à la spécification actuelle : owner doit être égal à son préfixe à quatre chiffres, type doit être inbox, finding ou backlog, et chaque source et path ne doit apparaître qu'une seule fois. Un path doit être un basename relatif à _index.md ; rejetez les chemins absolus, ., .., les séparateurs de chemin et les liens symboliques au lieu d'autoriser la traversée ou un lien en dehors de references/. Exécutez les commandes suivantes depuis la racine du dépôt et conservez les lignes normalisées ainsi que tout diagnostic comme preuve :

    slug=<slug>
    index="docs/specs/$slug/references/_index.md"
    expected_owner=${slug%%-*}
    parsed_index=$(mktemp) || exit 1
    trap 'rm -f "$parsed_index"' EXIT HUP INT TERM
    
    if test -L "$(dirname "$index")"; then
      printf 'auto-contenance échouée : references/ ne doit pas être un lien symbolique\n' >&2
      exit 1
    fi
    
    if test -L "$index" || test ! -f "$index"; then
      printf 'auto-contenance échouée : references/_index.md doit être un fichier régulier, non un lien symbolique\n' >&2
      exit 1
    fi
    
    awk -F '|' -v expected_owner="$expected_owner" '
    function trim(value) {
      gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
      return value
    }
    function reject(message) {
      print "auto-contenance échouée : " message > "/dev/stderr"
      invalid = 1
    }
    function separator(value) {
      value = trim(value)
      return value ~ /^:?-{3,}:?$/
    }
    /^[[:space:]]*$/ || /^[[:space:]]*#/ { next }
    !header {
      if (NF != 7 || trim($2) != "source" || trim($3) != "type" ||
          trim($4) != "owner" || trim($5) != "adopted date" ||
          trim($6) != "path") {
        reject("_index.md doit utiliser l'en-tête fixe source | type | owner | adopted date | path")
      } else {
        header = 1
      }
      next
    }
    !divider {
      if (NF != 7 || !separator($2) || !separator($3) || !separator($4) ||
          !separator($5) || !separator($6)) {
        reject("_index.md a un séparateur de tableau invalide")
      } else {
        divider = 1
      }
      next
    }
    {
      source = trim($2)
      type = trim($3)
      owner = trim($4)
      adopted = trim($5)
      path = trim($6)
      if (NF != 7 || source == "" || type == "" || owner == "" ||
          adopted == "" || path == "") {
        reject("ligne d'index invalide à la ligne " NR ": " $0)
        next
      }
      if (type != "inbox" && type != "finding" && type != "backlog") {
        reject("type doit être `inbox`, `finding` ou `backlog` à la ligne " NR ": " type)
      }
      if (owner != expected_owner) {
        reject("owner doit être " expected_owner " à la ligne " NR ": " owner)
      }
      if (seen_source[source]++) {
        reject("source en double à la ligne " NR ": " source)
      }
      if (seen_path[path]++) {
        reject("path en double à la ligne " NR ": " path)
      }
      if (adopted !~ /^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$/) {
        reject("la date adoptée doit être AAAA-MM-JJ à la ligne " NR ": " adopted)
      }
      if ((type == "inbox" && source !~ /^docs\/_inbox\/[^\/]+\.md$/) ||
          (type == "finding" && source !~ /^docs\/findings\/[^\/]+\.md$/) ||
          (type == "backlog" && source !~ /^docs\/backlog\/[^\/]+\.md$/)) {
        reject("la source ne correspond pas au type à la ligne " NR ": " source)
      }
      print source "|" type "|" owner "|" adopted "|" path
    }
    END {
      if (!header || !divider) {
        reject("_index.md n'a pas son en-tête de tableau fixe")
      }
      if (invalid) {
        exit 1
      }
    }
    ' "$index" > "$parsed_index" || exit $?
    
    while IFS='|' read -r source type owner adopted path; do
      case "$path" in
        ""|.|..|/*|*/*|*\\*)
          printf 'auto-contenance échouée : path doit être un basename relatif à `_index.md` : %s\n' "$path" >&2
          exit 1
          ;;
      esac
      source_basename=${source##*/}
      if test "$path" != "$source_basename"
      ...
      # Suite du contenu tronqué
    done
    

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

marcioaltoe/roundfix

Use Roundfix to plan releases with the read-only Release Plan Command, clean CodeRabbit pull request feedback, diagnose runtime readiness with the Doctor Command, execute a Spec's Task Graph with the Implement Command, monitor Runs through the Supervisor Run Event Stream, reclaim Run storage with the GC Command, archive completed Specs, run its `--follow-up`, `--status` and `--unattended` Skill Modes, and, inside daemon-assigned Batch runs, follow the bounded Review Issue or Task resolution contract.

marcioaltoe/write-prd

Write a PRD as a durable local artifact at docs/specs/<slug>/_prd.md — research first, clarify with one multiple-choice question at a time, record decisions as ADRs, then write directly without draft-approval rounds.

marcioaltoe/write-tasks

Decompose a spec's PRD/TechSpec into a dependency-ordered task graph — vertical-slice task files plus a machine-parseable _tasks.md DAG manifest under docs/specs/<slug>/, including the authored QA gate decision, decided autonomously from the Spec and escalated only when authority, architecture, or blast radius is at stake.

marcioaltoe/write-techspec

Write the technical spec at docs/specs/<slug>/_techspec.md — explore the architecture, settle technical decisions one question at a time, record them as ADRs, and produce a build order that write-tasks can decompose. Entry point for feature work with an approved PRD, and also for refactors and bug fixes, where it mints the spec folder with a minimal _prd.md instead of requiring a product interview.

Skills associés