Arquivar Especificação
Arquive uma especificação concluída escrevendo <slug>.md na raiz de arquivamento resolvida e removendo <resolved-spec-root>/<slug>/, que permanece no Git na source_revision do registro. A origem é a Raiz de Especificação configurada; o destino é sua raiz de arquivamento resolvida — docs/history/specs/ para a raiz docs/specs embutida, ou <spec-root>/_archived/ para uma raiz externa ou não padrão, correspondendo ao destino roundfix archive. Um arquivamento normal significa implementado, verificado e autocontido — toda tarefa concluída, QA aprovado quando o Grafo de Tarefas cria uma porta de QA, e toda referência indexada de propriedade da Especificação. Um Override de Arquivamento de QA registra a exceção explícita sem afirmar verificação. Após qualquer disposição, um ls <spec-root>/ separa o trabalho ativo do histórico, e o arquivamento permanece pesquisável como o registro do que foi construído e por quê.
O gatilho é a conclusão da especificação, não a publicação: execute isso automaticamente ao final de uma Roundfix Spec Run assim que a porta de QA for aprovada, ou sempre que o usuário pedir. Mesclagem e lançamento são etapas separadas, orientadas pelo usuário — o commit de arquivamento simplesmente viaja com o branch e é enviado dentro do PR da própria funcionalidade.
Relink de Arquivamento
Antes de escrever o Registro de Arquivamento, o arquivamento realiza um Relink de Arquivamento. Ele promove automaticamente cada arquivo não principal citado que um Documento Vivo referencia da Especificação proprietária para docs/references/<basename>, então reescreve as citações de cada Documento Vivo para a cópia promovida; citações da pasta da Especificação ou de um artefato principal apontam para o Registro de Arquivamento. O registro lista arquivos reescritos sob relinked quando existem. A fonte mantém um proprietário, então uma Especificação secundária não precisa de cópia (ADR-0260, ADR-0083).
A pasta da Especificação se aposenta por exclusão. No resultado copiado e em cada cópia promovida, um destino dentro da pasta removida nomeia uma cópia promovida ou se torna um Localizador Git, `<path>@<commit>`; ele nunca aponta para o próprio registro. O commit contém o caminho e é acessível a partir do branch padrão ou de uma tag. Quando nenhum commit existe, o localizador nomeia o caminho e o pull request do registro. Outros destinos retêm seu alvo de repositório (ADR-0278).
O arquivamento se recusa a escrever quando um destino de promoção já existe, quando duas promoções compartilham um basename, ou quando um Documento Vivo a ser reescrito tem alterações não commitadas em HEAD. Citações em arquivos que não são Documentos Vivos, ou citações que permanecem após a reescrita, são avisos nomeando o arquivo, linha e alvo; o arquivamento deixa esses arquivos inalterados.
Mesclagens squash
Uma mesclagem squash mantém source_revision apenas na ref head do pull request; o registro nomeia esse pull request em pull_request.
Declaração de recusa de QA
Um Grafo de Tarefas que declara qa: declined com um qa_reason não vazio arquiva uma vez que toda Tarefa está concluída, sem um Relatório de QA e sem um override, e seu Registro de Arquivamento tem a disposição no-qa.
--qa-override é recusado para tal Especificação. Toda outra pré-condição de arquivamento ainda se aplica.
Liquidação de QA
O mesmo resultado liquida a tarefa qa autorada e determina o que o arquivamento deixa:
| Resultado | Liquida | Arquiva |
|---|---|---|
pass | Liquida a Tarefa de QA como completed e torna a Especificação elegível para arquivamento quando o relatório não tem linhas bloqueadas proibidas. | O Registro de Arquivamento, que nomeia o Relatório de QA e veredito; a Especificação, seu relatório de QA e evidências permanecem no Git na source_revision do registro. |
partial declarado qualificado | Liquida a Tarefa de QA como completed quando nenhuma linha falhou, foi pulada ou está bloqueada por descoberta, toda linha bloqueada declarada é coberta por uma declaração ## Unreachable Acceptance correspondente, e toda linha bloqueada por ambiente é a linha de Pull Request pré-PR, registrada como blocked (environment: no open Pull Request) com a linha de Pull Request nomeada em sua proveniência, ou uma linha de evidência externa que o sandbox da Run não pôde alcançar, registrada como blocked (environment: network denied: <host>) com a linha de evidência externa nomeada em sua proveniência. Nenhuma linha precisa de uma declaração Unreachable Acceptance, e um partial cujas únicas linhas não atendidas são tais linhas se qualifica. | O Registro de Arquivamento, que nomeia o Relatório de QA e veredito e carrega o registro satisfied-by das declarações como unproven; a Especificação, seu relatório de QA e evidências permanecem no Git na source_revision do registro. |
environment-blocked | Deixa a linha bloqueada; o relatório ainda pode liquidar como pass quando evidência equivalente satisfaz a política de ambiente. | Nada por si só; um relatório qualificado pode arquivar a Especificação. |
failed | Deixa a Tarefa de QA não resolvida e recusa o arquivamento a menos que um override autorizado se aplique. | Nada. |
missing | Deixa a Tarefa de QA não resolvida e recusa o arquivamento a menos que um override autorizado se aplique. | Nada. |
override | Não altera o status da Tarefa de QA ou veredito do relatório; liquida o arquivamento como explicitamente autorizado apesar de QA falho ou ausente. | O Registro de Arquivamento com qa_override, qa_override_approval, qa_override_reason, qa_override_qa_outcome, qa_override_qa_task_status quando a Tarefa de QA está incompleta, e qa_override_revision; a Tarefa de QA e Relatórios permanecem inalterados no Git na source_revision do registro. |
Linhas que a autorização da Especificação mantém offline
O partial declarado qualificado acima também aceita uma linha de evidência externa que a porta não consultou porque a autorização da própria Especificação proíbe essa consulta, registrada como blocked (environment: <subject> prohibited by Spec authorization) com a linha de evidência externa nomeada em sua proveniência. O subject nomeia o que a autorização proíbe, em suas palavras: network para uma consulta de rede, ou another repository; tem 1 a 80 caracteres e não contém parênteses. Como a linha negada pela rede, ela nunca decide um partial qualificado e não precisa de declaração Unreachable Acceptance, uma linha conta para no máximo um tipo isento, e a liquidação, roundfix qa-report accept e roundfix archive a leem através da mesma política (ADR-0276, ADR-0335).
Cancelando uma Especificação
Uma Especificação que não será entregue é cancelada com roundfix cancel <slug> --reason <text>, nunca excluída manualmente. O comando escreve um Registro de Arquivamento com disposição cancelled, retorna cada Entrada de Backlog adotada para docs/backlog/ com status: open e cada Descoberta adotada para docs/findings/ com status: pending, então remove a pasta da Especificação enquanto seus bytes permanecem no Git em source_revision. Um registro cancelado nunca atende a um pré-requisito, nunca substitui outra Especificação e é recusado pela Tentativa de Entrega.
Arquivos ignorados e uma remoção falha
O Comando de Arquivamento e o Comando de Cancelamento recusam enquanto o Git ignorar qualquer arquivo sob a pasta da Especificação. Cada comando lista cada arquivo ignorado e não escreve nada. O operador deve remover cada arquivo ou commitá-lo com git add -f, então tentar novamente.
Se a remoção final da pasta da Especificação falhar, ambos os comandos mantêm cada escrita, saem com 1 e imprimem o comando que conclui a remoção:
chmod -R u+w '<pasta>' && rm -rf '<pasta>'.
Pré-condições — verifique, não confie
Verifique todas as três com evidências de comando frescas antes de tocar em qualquer coisa:
-
Tarefas obrigatórias concluídas. Para um arquivamento normal, leia cada
task_NN.mdlistado em_tasks.md; todostatusdeve sercompleted. Para um Override de Arquivamento de QA, toda Tarefa não-QA deve estarcompleted; a Tarefa de QA pode permanecerpendingoufailed. Se a Tarefa de QA também estivercompleted, o relatório mais recente deve permanecer inelegível ou o override é desnecessário e recusado.Comando: execute
grep -n '^status:' <cada-arquivo-de-tarefa-listado-em-_tasks.md>e retenha sua saída. Qualquer valor diferente destatus: completedbloqueia um arquivamento normal. Durante um override, apenas uma Tarefa não-QA com outro status bloqueia o arquivamento; nomeie esse arquivo de Tarefa. -
QA aprovado. O relatório mais recente em
qa/deve passar pelo verificador de QA do repositório. Não substitua um grep de linha por validação estruturada. No Roundfix, use o mesmo contratointernal/spec.QAVerdictque o Comando de Arquivamento: selecione o relatório mais recente pelo contrato de nome de arquivoqa-report-YYYY-MM-DD[-NN].md, analise seu frontmatter YAML, exija umverdictsuportado, exija que ambos os campos de linha bloqueada sejam inteiros não negativos quando presentes, e rejeiteverdict: passquandorows_blocked_findingfor diferente de zero. Retenha o caminho do relatório do verificador e o resultado como evidência. Um diretórioqa/ausente, relatório mais recente malformado ou veredito não aprovado bloqueia o arquivamento normal. Proceda apenas sob um Override de Arquivamento de QA explícito realizado através deroundfix archive <slug> --qa-override --approval <source> --reason <text>. Nunca registre o override editando o Registro de Arquivamento. Um relatório mais recente qualificado não torna uma Tarefa de QA falha ou pendente concluída; o override é recusado apenas quando o relatório se qualifica e toda Tarefa está concluída. -
A Especificação é autocontida. Aplique esta pré-condição quando
docs/specs/<slug>/references/_index.mdexistir ou for um link simbólico; um link simbólico, incluindo um quebrado, é estado de índice inválido em vez de uma Especificação legada. Apenas uma Especificação onde esse caminho não existe nem é um link simbólico é anterior a este contrato e passa sem adaptar artefatos históricos. Para uma Especificação indexada, todopathindexado deve existir relativo a_index.md, todo caminhosourcenunca atualizado deve estar ausente, e nenhum destino de link Markdown dentro da Especificação pode apontar paradocs/_inbox/oudocs/findings/.Comandos: primeiro execute esta verificação de destino de link; sua sintaxe deliberadamente corresponde a links Markdown inline ou de estilo de referência, não prosa que meramente nomeia qualquer árvore:
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 "self-containment failed: rewrite each listed link at adoption step 8" exit 1 fi test "$link_status" -eq 1 || exit "$link_status"Em seguida, analise e valide cada linha de dados. O índice pertence à Especificação atual:
ownerdeve igualar seu prefixo de quatro dígitos,typedeve serinbox,findingoubacklog, e cadasourceepathdeve aparecer apenas uma vez. Umpathdeve ser um basename relativo a_index.md; rejeite caminhos absolutos,.,.., separadores de caminho e links simbólicos em vez de permitir travessia ou um link fora dereferences/. Execute o seguinte da raiz do repositório e retenha as linhas normalizadas mais qualquer diagnóstico como evidência: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 'self-containment failed: references/ must not be a symbolic link\n' >&2 exit 1 fi if test -L "$index" || test ! -f "$index"; then printf 'self-containment failed: references/_index.md must be a regular, non-symbolic-link file\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 "self-containment failed: " 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 must use the fixed source | type | owner | adopted date | path header") } else { header = 1 } next } !divider { if (NF != 7 || !separator($2) || !separator($3) || !separator($4) || !separator($5) || !separator($6)) { reject("_index.md has an invalid table separator") } 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("invalid index row at line " NR ": " $0) next } if (type != "inbox" && type != "finding" && type != "backlog") { reject("type must be `inbox`, `finding`, or `backlog` at line " NR ": " type) } if (owner != expected_owner) { reject("owner must be " expected_owner " at line " NR ": " owner) } if (seen_source[source]++) { reject("duplicate source at line " NR ": " source) } if (seen_path[path]++) { reject("duplicate path at line " NR ": " path) } if (adopted !~ /^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$/) { reject("adopted date must be YYYY-MM-DD at line " NR ": " adopted) } if ((type == "inbox" && source !~ /^docs\/_inbox\/[^\/]+\.md$/) || (type == "finding" && source !~ /^docs\/findings\/[^\/]+\.md$/) || (type == "backlog" && source !~ /^docs\/backlog\/[^\/]+\.md$/)) { reject("source does not match type at line " NR ": " source) } print source "|" type "|" owner "|" adopted "|" path } END { if (!header || !divider) { reject("_index.md is missing its fixed table header") } if (invalid) { exit 1 } } ' "$index" > "$parsed_index" || exit $? while IFS='|' read -r source type owner adopted path; do case "$path" in ""|.|..|/*|*/*|*\\*) printf 'self-containment failed: path must be one basename relative to `_index.md`: %s\n' "$path" >&2 exit 1 ;; esac source_basename=${source##*/} if test "$path" != "$source_basename"…[truncado para tradução]