Projeto do Engine
Os módulos que compõem o engine, o que cada um governa e como uma especificação passa por eles.
Formato do engine
O engine é um pacote Python com um único ponto de entrada de console. Ele tem duas dependências de runtime — um parser YAML e uma biblioteca de cores de terminal — e nenhum daemon, servidor ou banco de dados. Todo comando é um processo de vida curta que lê uma especificação, opcionalmente toca o sistema de arquivos e sai com um código.
Módulos
cli
Parse e despacho de argumentos. Carrega e valida a especificação uma vez, depois roteia para um comando. Governa o bloqueio por desvio no apply e o código de saída do processo.
parser
Leitura de YAML para dicionário. Sem validação e sem transformação — só falha diante de arquivo ausente, YAML malformado, arquivo vazio ou uma raiz que não seja um mapping.
validator
A única função validate(). Junta todos os problemas de esquema e de caminho e levanta um único ValidationError contendo todos eles.
engine
Tudo o que lê ou escreve no sistema de arquivos: plan, apply, verify, doctor e os scaffolds de projeto. É um único módulo, não componentes separados de planejamento e execução.
fingerprint
O manifesto canônico, seu SHA-256, o conteúdo de .orv.lock e a comparação de desvio.
policy
O comando policy: lê policy.forbid e reporta nomes proibidos encontrados dentro da raiz da estrutura declarada.
errors
Os seis códigos de saída, como constantes de módulo.
ui
Auxiliares de saída no terminal para linhas de sucesso, aviso e erro.
Caminho pelos módulos
cli lê os argumentos, resolve o arquivo ↓ parser YAML → dict (falha: saída 4) ↓ validator regras de esquema e de caminho (falha: saída 1) ↓ engine plan / apply / verify / doctor ↕ fingerprint hash canônico, .orv.lock, desvio
O parse e a validação acontecem uma vez, na CLI, antes de qualquer comando rodar. Os comandos, portanto, sempre recebem uma especificação que já está bem formada.
Fronteira com o sistema de arquivos
Só o módulo engine escreve. Ele cria o diretório raiz nomeado por structure.name e os diretórios declarados dentro dele, e não escreve mais nada. Não existe caminho de exclusão no código: diretórios não declarados são reportados por plan e doctor, nunca removidos.
Alguns diretórios são inteiramente ignorados ao varrer um workspace — .git, .vscode, __pycache__ .pytest_cache — em qualquer profundidade.
Persistência
O engine mantém um único arquivo: .orv.lock, escrito no diretório de trabalho no primeiro apply bem-sucedido. Ele registra a versão do engine, um timestamp, o fingerprint da especificação, o nome da estrutura, a versão do esquema e o style.
Não há diretório de estado, repositório de snapshots nem histórico de execuções. O lock é toda a memória do engine, e seu único papel funcional é a comparação de desvio que bloqueia o apply.
Comportamento em falhas
As falhas aparecem como códigos de saída, e não como exceções: 1 para validação, 2 para estrutura inválida, 3 para desvio, 4 para problemas de arquivo, 5 para qualquer coisa não tratada. Exceções não tratadas são capturadas no ponto de entrada e reportadas como erro interno.
O apply não é transacional. Ele cria a raiz e depois cria cada diretório declarado por vez; se um falhar, os já criados permanecem e o comando reporta um erro.