Caderno operacional — bytes, contratos e perdas
Este laboratório faz o leitor observar texto como bytes, executar um round trip JSON, validar um contrato mínimo e detectar adulteração por checksum. Uma ordem de manutenção sintética passa por UTF-8, serialização, validação e restauração; casos inválidos expõem campo ausente, tipo incorreto, custo negativo e versão incompatível. O roteiro também demonstra por que neutralizar fórmulas em CSV e como registrar uma evolução de schema sem quebrar consumidores. Cada resultado é guardado em um relatório reproduzível, com comandos e decisões, para provar não apenas que o arquivo abre, mas que significado, precisão, integridade e política de segurança foram preservados.
Caderno operacional — bytes, contratos e perdas
Situação concreta
Você precisa entregar ordens de manutenção a outro sistema por arquivo JSON. A equipe garante que “é só texto”, mas ninguém testou acentos, custo negativo, campos ausentes ou alteração durante a cópia. Neste laboratório, você criará um produtor e um validador pequenos, usando somente a biblioteca padrão do Python e dados fictícios.
Pré-requisitos, objetivos e artefatos
Leia Do bit ao significado. Tenha Python 3 e um editor. Crie laboratorio-dados e produza contrato.py, ordem.json, ordens.csv e relatorio.md.
O objetivo é provar quatro propriedades: texto usa UTF-8; a estrutura restaurada equivale à original; entradas inválidas são recusadas pelo motivo esperado; alteração de bytes muda o checksum.
Vocabulário operacional
- Payload é a representação de dados carregada numa mensagem ou arquivo.
- Round trip é o caminho valor → representação → valor equivalente.
- Hash transforma bytes em um resumo de tamanho fixo.
- SHA-256 é uma função hash padronizada; aqui será usada para detectar diferença, não para provar autoria.
- Injeção de fórmula CSV ocorre quando uma planilha interpreta conteúdo não confiável como fórmula.
Modelo mental e limite
Ler o fluxo em texto
- 1. Criar valor do domínio
- 2. Validar contrato
- 3. Serializar em JSON UTF-8
- 4. Calcular checksum
- 5. Ler e desserializar
- 6. Comparar significado
- 7. Registrar evidência
O experimento valida um contrato manual reduzido. Em produção, use uma implementação de JSON Schema avaliada, restrições no armazenamento e testes de integração. Um hash igual mostra bytes iguais; não mostra que a coleta era verdadeira ou autorizada.
Antes e agora
Antes, integrações aceitavam amostras felizes e problemas apareciam na importação mensal. Hoje, contratos versionados e casos negativos podem rodar a cada mudança. IA pode gerar amostras, mas o responsável pelo domínio define o significado e revisa casos perigosos; dados reais não devem ser enviados a ferramentas sem autorização.
Passo 1 — escreva a validação
Crie contrato.py com imports e regra:
import csv
import hashlib
import json
from pathlib import Path
def validar(ordem: dict) -> list[str]:
erros = []
obrigatorios = {"schemaVersion", "ordemId", "custoCentavos", "status"}
ausentes = obrigatorios - ordem.keys()
if ausentes:
erros.append("ausentes:" + ",".join(sorted(ausentes)))
if ordem.get("schemaVersion") != 1:
erros.append("versao_incompativel")
if not isinstance(ordem.get("ordemId"), str) or not ordem.get("ordemId"):
erros.append("ordemId_invalido")
custo = ordem.get("custoCentavos")
if not isinstance(custo, int) or isinstance(custo, bool) or custo < 0:
erros.append("custo_invalido")
if ordem.get("status") not in {"aberta", "concluida"}:
erros.append("status_invalido")
return errosO conjunto declara obrigatoriedade. As verificações seguintes produzem códigos estáveis. Em Python, bool é subtipo de int, então a condição o exclui explicitamente. Isso demonstra por que “tipo número” pode precisar de precisão adicional.
Passo 2 — serialize, restaure e compare
Acrescente:
ordem = {
"schemaVersion": 1,
"ordemId": "OS-SÃO-JOSÉ-01",
"custoCentavos": 1050,
"status": "aberta",
"observacao": None,
}
assert validar(ordem) == []
destino = Path("ordem.json")
destino.write_text(
json.dumps(ordem, ensure_ascii=False, indent=2),
encoding="utf-8",
)
bytes_gravados = destino.read_bytes()
restaurada = json.loads(bytes_gravados.decode("utf-8"))
assert restaurada == ordem
print("caracteres:", len(destino.read_text(encoding="utf-8")))
print("bytes:", len(bytes_gravados))
print("sha256:", hashlib.sha256(bytes_gravados).hexdigest())ensure_ascii=False mantém caracteres legíveis; UTF-8 define os bytes. A igualdade confirma o round trip dos tipos suportados. Uma data transformada em string exigiria reconstrução do tipo do domínio.
Passo 3 — execute casos negativos
Acrescente uma tabela de casos:
casos_invalidos = [
({"schemaVersion": 1}, "ausentes:"),
({**ordem, "schemaVersion": 2}, "versao_incompativel"),
({**ordem, "ordemId": 1842}, "ordemId_invalido"),
({**ordem, "custoCentavos": -1}, "custo_invalido"),
({**ordem, "status": "?"}, "status_invalido"),
]
for numero, (caso, esperado) in enumerate(casos_invalidos, start=1):
observados = validar(caso)
assert any(erro.startswith(esperado) for erro in observados)
print("caso", numero, "recusado:", observados)Execute python contrato.py. Os cinco casos precisam falhar pelo motivo esperado. Recusar por acidente, com exceção não prevista, não satisfaz o teste.
Passo 4 — demonstre checksum e bytes
No relatório, copie o checksum. Acrescente um espaço ao final de ordem.json e calcule novamente em um terminal Python:
python -c "import hashlib; print(hashlib.sha256(open('ordem.json','rb').read()).hexdigest())"O JSON ainda pode ser válido, mas o hash muda porque bytes mudaram. Não conclua que houve ataque ou identifique autor; SHA-256 aqui detecta diferença.
Como interpretar a evidência
Não resuma o resultado como “todos os testes passaram”. Relacione cada observação à propriedade demonstrada. A comparação restaurada == ordem sustenta equivalência dos valores que o JSON consegue representar neste exemplo; não prova que uma data voltará como objeto de data. A recusa do custo negativo sustenta uma regra do domínio; não prova que todo custo positivo está correto. O checksum sustenta igualdade de bytes entre duas medições; não sustenta autenticidade.
No relatório, use quatro colunas: propriedade, experimento, resultado e limite. Essa separação evita que uma evidência estreita seja usada para uma afirmação ampla. Se um caso falhar, preserve a entrada e o código da regra. Alterar simultaneamente schema, dado e programa impede saber qual mudança corrigiu o problema.
Passo 5 — exporte CSV com segurança
Acrescente ao programa:
def neutralizar_planilha(valor: str) -> str:
return "'" + valor if valor.startswith(("=", "+", "-", "@")) else valor
with open("ordens.csv", "w", encoding="utf-8", newline="") as arquivo:
escritor = csv.writer(arquivo)
escritor.writerow(["ordemId", "observacao"])
escritor.writerow([ordem["ordemId"], neutralizar_planilha("=1+1")])Não monte CSV concatenando vírgulas. csv.writer trata aspas e delimitadores; a função neutraliza um valor destinado a planilha. Essa regra depende do consumidor e deve ser testada nele.
Falha e diagnóstico
Provoque três falhas separadamente:
- leia UTF-8 como
latin-1e observe texto corrompido; - troque custo para
10.50e observe recusa de tipo; - remova
statuse confirme o código de ausência.
Para cada uma, registre bytes, esperado, observado, fronteira da divergência e correção mínima. Não substitua caracteres corrompidos antes de preservar a amostra.
Aplicação em manutenção/ERP
Antes de integrar, obtenha contrato oficial do ERP: nomes, tamanhos, codificação, unidades, datas e política de erro. Use ambiente de homologação. Reconcilie quantidade de ordens, identificadores e totais; “importação concluída” não prova equivalência. Para versão 2, publique leitor que aceite v1/v2 antes do produtor novo e mantenha rollback.
Uma migração precisa de contagens antes e depois. Registre quantos itens foram lidos, convertidos, recusados e reconciliados. Mantenha o lote original imutável até a conferência. Se dez registros forem recusados, a decisão não é apagá-los para fazer o indicador ficar verde: coloque-os em quarentena, atribua responsável e preserve a causa. Uma restauração só está comprovada quando quantidade, checksums aplicáveis e invariantes do domínio são verificados.
Segurança e privacidade
Use dados sintéticos. Limite tamanho antes de carregar JSON inteiro, não registre payload completo e não aceite caminho fornecido pelo usuário sem confinamento. Neutralização CSV reduz um risco específico, mas não torna o conteúdo confiável. Hash sem autenticação pode ser substituído junto com o arquivo; assinatura exige chaves e fica fora deste laboratório.
Exercício guiado
Acrescente abertaEm como string com offset e valide pelo menos presença de T e deslocamento. Crie um caso sem fuso e registre a limitação da validação manual. Depois acrescente moeda: "BRL" sem remover custoCentavos; explique por que isso é uma expansão compatível.
Faça também um teste de transferência: substitua ordem por leitura de medidor, mantendo a disciplina de contrato. Identificador continua textual, mas custo vira valor e unidade. Escreva antes do código o que significa leitura ausente, zero e inválida. Se você reutilizar null para os três, o consumidor não poderá decidir se deve repetir coleta, ignorar ou alertar.
Desafio e evidência
Entregue os quatro artefatos e peça que outra pessoa execute somente com seu relatório. Ela deve reproduzir cinco recusas, round trip e mudança de checksum.
Critérios de aceite:
- prosa registra Python, sistema, comando e horário;
- UTF-8, tipos e unidades estão explícitos;
- cinco casos negativos falham pelo motivo previsto;
- nenhum dado real aparece;
- checksum é descrito como detecção, não autoria;
- plano v2 contém expansão, migração, reconciliação e contração.
Conclusão e transição
Você observou a cadeia valor, schema, JSON, UTF-8, bytes e restauração. Também viu que arquivo válido pode conter significado errado e que hash responde uma pergunta limitada. No próximo livro, esses bytes atravessarão DNS, transporte, TLS e HTTP até outro processo.
Fontes oficiais
- Python —
json: serialização usada no laboratório. - Python —
hashlib: funções hash e disponibilidade de SHA-256. - Python —
csv: leitura e escrita tabular. - RFC 8259 — JSON: sintaxe e interoperabilidade do formato.
Comprove o que você aprendeu
Responda todas as questões. O gabarito comentado só aparece depois do envio.