Ir para o conteúdo

Modelo de execução

O que cada etapa lê, o que escreve e o que deliberadamente não faz.

As quatro coisas envolvidas

Tudo no modelo de execução é uma relação entre quatro coisas distintas. Mantê-las separadas é o que torna o resto previsível.

  • Estrutura esperada — os diretórios declarados na sua especificação. O contrato.
  • Estado do workspace — o que está de fato em disco sob o diretório raiz agora.
  • Plano — a diferença entre os dois, calculada e impressa sem alterar nada.
  • Fingerprint registrado — o SHA-256 da especificação a partir da qual o workspace foi construído pela última vez, guardado em .orv.lock.

Ordem das etapas

especificação (.orvienm.yaml)
        ↓
   parse            YAML inválido → saída 4
        ↓
   validate         estrutura inválida → saída 1
        ↓
   plan             diff somente leitura
        ↓
   apply            desvio → saída 3; caso contrário, create
        ↓
   verify / status / doctor

O parse e a validação rodam no início de todo comando, não apenas quando você os invoca diretamente. Uma especificação que falha na validação não chega ao plan nem ao apply.

O que o apply governa

O apply cria o diretório raiz nomeado por structure.name e todos os diretórios declarados dentro dele. Se a raiz já existe, ele cria os diretórios declarados que estão faltando e deixa o resto em paz. Essa é toda a sua superfície de escrita.

Ele não apaga, move nem renomeia nada, e não toca no conteúdo de arquivos. Um diretório que existe mas não foi declarado fica exatamente como está — o Orvienm não trata “ausente da especificação” como “não deveria existir”, porque um workspace raramente pertence a uma única ferramenta.

O apply é idempotente em efeito: rodá-lo contra um workspace que já corresponde reporta a estrutura como conforme e não escreve nada. Ele não é atômico — se a criação de diretórios falhar no meio, os diretórios já criados permanecem.

Como ler um plano

O plan imprime uma linha por diretório e um resumo. Os três marcadores são:

  • + create — declarado, ausente em disco. O apply vai criá-lo.
  • = keep — declarado e já presente. O apply vai deixá-lo em paz.
  • ? undeclared — presente em disco, não declarado. O apply não o cria nem o remove.

O resumo conta cada categoria. Nenhum comando da CLI atual executa exclusão, e o plano não nomeia nenhuma operação que o engine não vá executar.

Desvio

Desvio no Orvienm significa que a especificação mudou, não o sistema de arquivos. No primeiro apply bem-sucedido, o fingerprint da especificação é escrito em .orv.lock. Nas execuções seguintes, o apply recalcula esse fingerprint e compara.

Se forem diferentes, o apply se recusa a rodar e sai com 3. Remover .orv.lock aceita a nova especificação. Passar --dry-run contorna o bloqueio sem escrever nada.

Um diretório apagado à mão não gera desvio. Use verify para conferir se os diretórios declarados ainda existem, ou doctor para o quadro completo.

Convergência

Um workspace convergiu quando o doctor reporta HEALTHY: a raiz existe, nenhum diretório declarado está faltando, nenhum diretório não declarado está presente, e o fingerprint corresponde ao lock.

O verify é uma checagem mais estreita — os diretórios declarados existem, nada além disso — e o status fica entre os dois ao acrescentar o lock e o fingerprint. O verify sai com 0 quando a estrutura está completa e com 2 quando não está, sem precisar de flag: ele é o portão estrutural. O doctor reporta seu diagnóstico e sai com 0 por padrão; doctor --strict é a invocação que quebra um pipeline diante de qualquer coisa diferente de HEALTHY.

Um diretório declarado só é satisfeito por um diretório. Um arquivo comum parado em um caminho declarado não conta como esse diretório: verify, status e doctor reportam o workspace como incompleto, e o apply recusa a colisão em vez de resolvê-la — ele nomeia o caminho, não cria nada, sai com 2 e deixa o arquivo exatamente como estava.

O que é determinístico

Duas propriedades valem de forma precisa, e vale enunciá-las em vez de generalizar.

  • O fingerprint é calculado a partir de um manifesto canônico contendo apenas version, style, structure.name e a lista de diretórios ordenada. Reordenar diretórios, reformatar o arquivo ou acrescentar comentários não o altera. Mudar style altera.
  • Dada a mesma especificação e o mesmo estado do workspace, o apply produz os mesmos diretórios.

As duas valem também para entradas aninhadas: um caminho declarado se expande nos diretórios que implica, e plan, verify e doctor raciocinam sobre esse mesmo conjunto expandido.

Evoluir uma especificação

O apply cria os diretórios declarados que faltam, exista a raiz ou não, então um workspace pode crescer. O que fica entre você e esse crescimento é o bloqueio por desvio, não o apply: editar uma especificação muda o fingerprint dela, e o apply então se recusa a rodar e sai com 3 sem tocar em nada.

Para aceitar uma mudança que você pretendia, remova o lock e aplique de novo:

$ orvienm apply .orvienm.yaml
! Drift detected
Current YAML fingerprint differs from .orv.lock.
Update YAML or remove .orv.lock to proceed.     # exit 3

$ rm .orv.lock
$ orvienm apply .orvienm.yaml
Structure already exists. Added missing directories:
  + data/
.orv.lock generated successfully.               # exit 0

$ orvienm plan .orvienm.yaml                    # Create: 0

O apply cria o que a nova especificação acrescentou, mantém tudo o que já estava lá e registra o novo fingerprint. O plan então reporta Create: 0 e o workspace convergiu.

Remover o lock é hoje a única forma de aceitar uma mudança de especificação, e é um instrumento grosseiro: descarta o fingerprint registrado em vez de reconhecer a passagem de um para o outro, e aceita todas as edições do arquivo de uma vez — inclusive uma raiz renomeada ou entradas que você removeu. Revise a especificação antes de remover o lock. Uma etapa dedicada de reconhecimento é uma questão de design em aberto, não um recurso entregue.

Limitações atuais

O apply também não é atômico: se a criação de diretórios falhar no meio, os diretórios já criados permanecem.

Para os argumentos exatos e os códigos de saída de cada comando, veja a Referência da CLI; para o que uma falha específica significa, veja a Solução de problemas.