Como impedi que o Claude Code partisse a minha arquitetura com 18 testes que correm em 0,4 segundos
Passei as últimas semanas a construir um boilerplate de produção para sistemas de AI Agent e IoT. FastAPI, asyncpg, LangGraph, MQTT, pgvector — uma stack complexa com fronteiras arquiteturais muito específicas que não podem ser violadas.
O problema: estava a usar Claude Code e Cursor para acelerar o desenvolvimento. E são brilhantes. Mas também são completamente agnósticos à arquitetura que tens na cabeça.
Deixa-me mostrar-te o tipo de coisa que acontece sem proteção.
O Problema
O meu sistema tem uma regra crítica: o IngestionService nunca pode importar SQLModel ou SQLAlchemy. É o hot path para ingestão de telemetria IoT — apenas SQL puro com asyncpg, zero overhead de ORM. Esta separação é intencional e está documentada em 20 páginas de ARCHITECTURE.md.
Numa sessão típica, pedi ao Claude Code para "refatorar o IngestionService para ser mais consistente com o resto do código base".
Resultado gerado:
# services/ingestion.py — gerado pelo Claude Code
from sqlmodel import Session # ← VIOLAÇÃO CRÍTICA
from core.database import get_session
class IngestionService:
async def ingest(self, payload, trace_id):
async with get_session() as session: # ← destrói o hot path
session.add(SensorReading(**payload.dict()))
await session.commit()
Tecnicamente correto. Arquiteturalmente catastrófico. A latência de escrita salta de 0,8ms para 4–6ms. A 5.000 mensagens por segundo, é a diferença entre um sistema que aguenta a carga e outro que colapsa.
O Claude Code não sabe disto. Não consegue saber. A arquitetura vive na minha cabeça e num documento de texto que pode ou não ter lido antes de gerar o código.
A Solução: Architecture Fitness Tests
A ideia não é nova — Martin Fowler escreve sobre "fitness functions" em Building Evolutionary Architectures. Mas a aplicação ao desenvolvimento assistido por IA é muito concreta: se o modelo vai ter permissão total de refactor, precisas de testes que falham imediatamente quando uma fronteira arquitetural é cruzada.
Não testes em runtime. Testes estruturais estáticos — análise AST do código Python, zero dependências externas, zero servidor a correr.
A suite completa corre em 0,4 segundos. Pre-commit, não post-deploy.
Um Exemplo Concreto
O teste mais importante no meu sistema:
# tests/test_architecture_fitness.py
def test_ingestion_service_never_imports_sqlmodel(self):
"""
O IngestionService é o Hot Path. SQLModel (SQLAlchemy) nunca
pode aparecer aqui. É a fronteira mais crítica do sistema.
"""
if not INGESTION_SERVICE.exists():
pytest.skip(f"IngestionService not yet created at {INGESTION_SERVICE}")
violations = []
forbidden = {"sqlmodel", "sqlalchemy", "SQLModel", "AsyncSession"}
for imp in _get_imports(INGESTION_SERVICE):
module = imp["module"]
names = imp["names"]
if any(module.startswith(f) for f in forbidden):
violations.append(imp)
if any(name in forbidden for name in names):
violations.append(imp)
assert not violations, _format_violation(
violations,
"IngestionService imported SQLModel/SQLAlchemy.\n"
" Fix: Use asyncpg raw SQL only in services/ingestion.py.\n"
" This is the Dual-Path contract. The hot path has zero ORM overhead."
)
A função _get_imports usa o módulo ast da stdlib do Python para parsear o ficheiro sem o executar:
def _get_imports(filepath: Path) -> list[dict]:
tree = ast.parse(filepath.read_text(encoding="utf-8"))
imports = []
for node in ast.walk(tree):
if isinstance(node, ast.ImportFrom):
module = node.module or ""
imports.append({
"module": module,
"names": [alias.name for alias in node.names],
"line": node.lineno,
"file": str(filepath),
})
return imports
Zero imports externos. Zero servidor. Zero base de dados. Apenas Python.
As 8 Fronteiras que Testo
O meu sistema tem um contrato arquitetural de 7 camadas. Os testes cobrem as violações mais comuns que a IA gera:
1. Isolamento de Camadas — Import Guards
- Workers MQTT nunca importam LangGraph
- IngestionService nunca importa SQLModel
- Agentes nunca escrevem diretamente via ORM
- Routers nunca chamam o IngestionService diretamente
2. Integridade do Hot Path
- IngestionService usa apenas strings SQL puras, nunca query builders
- Tabelas do hot path nunca são definidas como modelos SQLModel
3. Contratos de Eventos
- Publicações em Redis Stream usam o envelope canónico
DomainEvent - Workers MQTT validam com Pydantic antes de publicar
4. Async Enforcement
- Sem clientes HTTP síncronos (
requests) em routers - Sem
time.sleep()no IngestionService - Handlers de workers são
async def
5. Contrato de Trace ID
IngestionService.ingest()aceitatrace_idcomo parâmetro- Todos os eventos de domínio incluem
trace_id
6. Convenção do Keyspace do Redis
- Sem chaves Redis sem prefixo de namespace
checkpoint:{id},stream:{name},cache:{type}:{id}
7. Integridade de Migrations
- Zero instruções DDL em código aplicacional
8. Topologia de Dependências Completa
- Valida a matriz completa de imports proibidos numa única passagem
O Resultado em Produção
Quando dou ao Claude Code permissão total para refatorar qualquer ficheiro, o ciclo é:
Claude Code gera código
↓
pytest tests/test_architecture_fitness.py -v
↓ (0,4 segundos)
Vermelho → Claude Code corrige
↓
Verde → commit
O modelo nunca pode violar fronteiras arquiteturais sem que eu saiba imediatamente. Não porque seja adversarial — mas porque otimiza para consistência local, não para contratos globais.
Depois de adicionar estes testes, todas as violações arquiteturais desapareceram das code reviews. O Claude Code começou a gerar código compliant automaticamente porque o ficheiro de contexto CLAUDE.md descreve explicitamente o que os testes verificam.
CLAUDE.md — O Segundo Mecanismo
Os testes são enforcement. O CLAUDE.md é prevenção.
É um ficheiro na raiz do repositório que o Cursor e o Claude Code leem antes de gerar código. Contém os contratos em linguagem explícita com exemplos ✅ corretos vs ❌ errados:
## Hard Boundaries (Enforced by tests/test_architecture_fitness.py)
### 1. The Dual-Path Contract
services/ingestion.py → asyncpg ONLY
✅ await pool.acquire() → await conn.execute("INSERT INTO ...", ...)
❌ from sqlmodel import Session
❌ session.add() / session.commit()
❌ time.sleep() → use await asyncio.sleep()
A combinação de testes que falham + documentação explícita cria um ambiente onde a IA pode refatorar livremente com garantias estruturais.
Números Finais
Suite completa: 18 testes
Tempo de execução: 0,42 segundos
Dependências: 0 (Python stdlib + pytest)
Violações apanhadas
antes dos testes: 12+
Violações depois: 0
Conclusão
O desenvolvimento assistido por IA é genuinamente transformador para a produtividade. Mas cria uma nova categoria de risco: deriva arquitetural silenciosa. O modelo otimiza para o que vê, não para o que a arquitetura global exige.
Os Architecture Fitness Tests são a resposta. Não são difíceis de escrever — o módulo ast do Python faz todo o trabalho pesado. E o retorno é imediato: liberdade total para usar IA em tarefas de refactor sem ansiedade pelo que pode ter sido partido.
Se estás a construir um sistema distribuído com desenvolvimento assistido por IA, estes testes são a primeira coisa que devias escrever — não a última.
O boilerplate completo (FastAPI + asyncpg + LangGraph + MQTT + pgvector + Prometheus + Grafana) com os 18 testes, o CLAUDE.md e um ARCHITECTURE.md de 20 secções está disponível em murinelo.gumroad.com/l/pdmfvr