Estudo de caso arquitetural · projeto open source

Da decisão arquitetural à verificação contínua

Um ADR pode explicar por que Domain não deve depender de Infrastructure. O desafio seguinte é detectar, com evidência verificável, quando a implementação deixa de respeitar essa decisão.

Este é um cenário reproduzível do repositório, não uma alegação de adoção em produção ou de certificação completa da arquitetura.

Problema

Documentar preserva o raciocínio; não preserva sozinho a dependência.

À medida que o software evolui, uma referência adicionada por conveniência pode inverter uma fronteira planejada. O ADR continua aceito e legível, enquanto o grafo real do código conta outra história.

As consequências aparecem depois: regras de domínio passam a conhecer persistência, testes exigem infraestrutura e uma mudança técnica atravessa camadas que deveriam evoluir separadamente. O problema não é a falta de documentação, mas a distância entre decisão, evidência e feedback.

Restrições e atributos de qualidade

A verificação precisa ser útil sem afirmar mais do que a evidência permite.

01

Rastreabilidade

Cada regra aponta para um ADR por identidade estável e caminho relativo, preservando a origem da restrição.

02

Determinismo

A mesma entrada deve produzir ordenação, fingerprint, resultado e relatório estáveis.

03

Falha segura

Evidência ausente, dinâmica ou ambígua resulta em unknown, nunca em aprovação implícita.

04

Compatibilidade

Drift, impacto e validação têm contratos próprios sem alterar os formatos já publicados.

AuditabilidadeSegurançaReprodutibilidadeOperabilidadeEvolutibilidadeCompatibilidade
Fluxo do ADR aceito para regra de fitness, evidência limitada, avaliação com quatro resultados e política advisory ou enforce.
A política é aplicada depois da avaliação; os quatro resultados não são reduzidos a um booleano.

Decisões arquiteturais

Quatro responsabilidades, quatro perguntas diferentes.

Validação estrutural de ADRs

adr-guard check verifica metadados, seções, referências, ciclo de vida e outros contratos documentais. Um ADR válido ainda não prova que o código o cumpre.

Referência da CLI ↗

Análise de impacto

adr-guard impact correlaciona arquivos alterados a mapeamentos locais explícitos. O resultado indica decisões possivelmente afetadas para revisão; não declara conformidade ou violação.

ADR 0006 ↗

Verificação de drift

adr-guard drift avalia regras opt-in associadas a ADRs efetivos. A v1 prova apenas referências estáticas exatas de projetos e consome testes externos reportados.

ADR 0007 ↗

Core compartilhado, interno

AdrGuard.Core concentra parsing, validação, inventário Git, impacto e drift para CLI e MCP. Ele não é pacote público independente; UI e transporte permanecem nos executáveis.

ADR 0008 ↗

O vocabulário de resultado preserva a incerteza

pass

Evidência determinística completa prova a condição declarada.

violation

Evidência determinística completa prova que a condição é falsa.

unknown

A evidência é insuficiente, ausente, dinâmica, condicional, inválida ou contraditória.

not-applicable

O ADR referenciado não está efetivo pela política de ciclo de vida configurada.

Componentes e contratos

Uma regra compartilhada, superfícies diferentes.

  1. CLIComandos, exit codes, texto, JSON/SARIF e escrita explícita.
  2. AdrGuard.CoreRegras determinísticas internas e limites de entrada.
  3. GitHub ActionExecuta a CLI e publica relatórios dentro do contrato da Action.
  4. VS CodeExploração, edição, diagnósticos e execução da CLI como processo.
  5. MCP ServerSete ferramentas read-only, transporte stdio e fronteira de workspace.
  6. HumanoAprova ADRs, seleciona regras e revisa mudanças de baseline.

O MCP não aprova decisões; revisão por IA é opcional e advisory. A Action composta existente não ganhou implicitamente um modo de drift: o guia instala a ferramenta e chama o comando em uma etapa explícita.

Implementação reproduzível

Domain sem referência para Infrastructure — até a mudança que introduz o drift.

1. Registrar a decisão

O ADR aceito declara: “The Domain project must not reference the Infrastructure project.” A consequência reconhece que referências condicionais ou expandidas dinamicamente exigem revisão humana.

2. Configurar a regra

{
  "schemaVersion": "1.0",
  "rules": [{
    "id": "domain-no-infrastructure",
    "decision": {
      "stableId": "ADR-1",
      "path": "docs/adr/0001-protect-domain-boundary.md"
    },
    "scope": { "projects": [
      "src/Domain/Domain.csproj",
      "src/Infrastructure/Infrastructure.csproj"
    ]},
    "check": {
      "type": "forbid-project-reference",
      "from": "src/Domain/Domain.csproj",
      "to": "src/Infrastructure/Infrastructure.csproj"
    },
    "evidence": { "source": "dotnet-project-reference" },
    "failure": { "severity": "error", "onInconclusive": "unknown" },
    "gate": true
  }]
}

3. Verificar a implementação inicialmente conforme

adr-guard drift . --rules .adrguard-fitness.json --format json
# Resultado documentado pelo fixture: pass

O Domain.csproj versionado contém apenas o SDK e o target framework. O conjunto estático completo não possui a dependência proibida.

4. Introduzir a referência proibida

<ItemGroup>
  <ProjectReference Include="../Infrastructure/Infrastructure.csproj" />
</ItemGroup>

Ao substituir o projeto pelo fixture de violação e repetir o comando, o relatório identifica a referência e a linha como violation.

5. Aplicar política sem apagar nuances

ExecuçãoComportamento documentadoO que não significa
--policy advisoryPolítica padrão; registra a violação sem usar a regra como bloqueio de enforcement.Não transforma a violação em sucesso.
--policy enforceUma violação nova, gate: true, local e determinística retorna exit 4.Não bloqueia toda falha externa nem toda violação já registrada no baseline.
Resultado unknownRetorna exit 3 nas duas políticas e não pode aparecer como check verde.Não é convertido em violation.
Evidência externaMantém a proveniência como observação reportada.Não é atestação e nunca autoriza bloqueio automático.

6. Corrigir e validar novamente

adr-guard drift . --rules .adrguard-fitness.json \
  --baseline drift-baseline.json
# Violação anterior: resolved
# Regra atual: pass

O baseline só é criado ou substituído por comando explícito e deve ser revisado como código. Remover a referência proibida restaura o pass; comparado a um baseline que continha o finding, o histórico aparece como resolved.

Alternativas e trade-offs

O desenho escolhe prova estreita em vez de inferência ampla.

Revisão manual

É indispensável para interpretar decisões e exceções, mas pode não perceber drift repetitivo em todo pull request.

Quando usar: regras sem representação determinística ou decisões contextuais.

Testes arquiteturais específicos

Podem analisar código com maior profundidade, mas precisam de implementação e manutenção por stack. O ADR Guard pode consumir o resultado apenas como evidência externa reportada.

Quando usar: invariantes além do contrato estático v1.

Avaliar MSBuild

Resolveria mais referências condicionais, porém executaria uma superfície complexa e potencialmente não confiável. A v1 deliberadamente não invoca MSBuild.

Escolha: condições e propriedades permanecem unknown.

Baseline automático

Reduziria atrito imediato, mas poderia normalizar uma regressão. A criação e atualização são ações explícitas do responsável.

Escolha: histórico auditável em vez de aceitação silenciosa.

Limitações e riscos

O relatório verifica uma regra declarada, não a arquitetura inteira.

A v1 inspeciona apenas ProjectReference estático e exato em arquivos .csproj incluídos explicitamente no escopo. Imports, wildcards, propriedades, condições, arquivos ausentes, XML inseguro e limites excedidos são inconclusivos. Não há descoberta de rede nem execução arbitrária.

Uma regra mal formulada pode ser determinística e ainda representar mal o ADR. Cobertura parcial, exceções legítimas e mudanças de ciclo de vida continuam exigindo governança humana. pass significa que aquela condição foi provada sob aquele contrato — não que a solução recebeu uma certificação ampla.

Aprendizados e evolução

Tornar decisões executáveis começa por tornar limites explícitos.

A separação entre check, impact e drift evita que “documento válido”, “mudança relacionada” e “restrição violada” sejam tratados como sinônimos. O vocabulário de quatro estados impede que falta de evidência vire conformidade.

A extração do Core reduz divergência entre CLI e MCP sem criar uma nova API pública. A evolução pode adicionar novos checks versionados, desde que preserve proveniência, incerteza, compatibilidade e a autoridade humana sobre decisão e baseline.