English · Español
Lab 04 — Escribe un helper de manifest-diff¶
Pre-requisito: lee
../theory/04-manifest-anatomy.md. Objetivo: implementar una CLI de 30 líneas que tome dos rutas de manifiesto, imprima solo los campos que cambiaron y los ordene por probabilidad de causar drift. Solo CPU, < 5 minutos wall-clock.
§1 Setup¶
- Crea
scripts/manifest_diff.py(sin implementación previa — esto es greenfield). - Crea dos manifiestos sintéticos bajo
experiments/diff-demo/: monday.json(usa el ejemplo detheory/04-manifest-anatomy.md§1).tuesday.json(igual, pero connumpy 2.0.2).- Confirma que
uv run python scripts/manifest_diff.py experiments/diff-demo/monday.json experiments/diff-demo/tuesday.jsoncorre.
§2 Tu tarea¶
Implementa manifest_diff.py como CLI:
usage: manifest_diff.py [-h] A B
Prints fields that differ between manifests A and B, grouped by drift category.
Categories (in print order, highest-impact first):
CODE git_sha, git_dirty
VERSIONS versions.*
HARDWARE hardware.*
ENV env.*
TIME wall_seconds, started_at, finished_at
OTHER everything else
Formato de salida (un ejemplo):
$ uv run python scripts/manifest_diff.py monday.json tuesday.json
[VERSIONS] numpy: 2.0.1 -> 2.0.2
(no differences in CODE, HARDWARE, ENV, TIME, OTHER)
Restricciones:
- Debe usar solo stdlib (json, argparse, pathlib, sys).
- Debe manejar el caso en que una clave existe en un manifiesto pero no en el otro (<missing> en el lado ausente).
- Debe pasar mypy --strict. Debe pasar ruff check limpio.
- Debe salir con código distinto de cero si los manifiestos difieren en CODE o VERSIONS (así es usable como puerta de CI).
§3 Tests¶
Añade tests/test_manifest_diff.py:
- test_identical_manifests_have_zero_exit_code — ambos archivos iguales → exit 0.
- test_version_drift_exits_nonzero — versión de numpy difiere → exit code != 0.
- test_missing_key_is_reported — manifiesto A carece de env.OMP_NUM_THREADS; manifiesto B lo tiene → diff imprime <missing> -> 8.
Los tests deben correr en < 1 segundo en total.
§4 Condiciones de parada¶
-
uv run python scripts/manifest_diff.py experiments/diff-demo/monday.json experiments/diff-demo/tuesday.jsonimprime exactamente una línea VERSIONS y sale con código 1. -
pytest tests/test_manifest_diff.pypasa (3/3). -
mypy --strict scripts/manifest_diff.pypasa. -
ruff check scripts/manifest_diff.pypasa. - Has escrito una entrada de diario en
learners/borja/phase-00/notes/manifest-diff.mdcubriendo: qué clase de drift querrías una alarma más sonora (CI rompe build), y cuál es más bien un "FYI". - Commit:
lab: phase-00 add manifest-diff CLI for drift triage.
§5 Pistas¶
- Aplana dicts anidados con un helper recursivo
flatten(prefix, obj) -> dict[str, str]. Claves de salida tipoversions.numpy. - Las "categorías" son solo prefijos regex sobre la clave aplanada. Un dict de
{ "CODE": ("git_sha", "git_dirty"), ... }basta. - Usa
argparsecon dos argumentos posicionales; no necesitas opciones fancy. Añade--quietpara suprimir la línea "(no differences in ...)" solo si tienes tiempo. - El "exit non-zero on CODE/VERSIONS drift" hace al script usable como
manifest_diff.py prev.json next.json && echo OK || echo DRIFTen un paso de CI.
§6 Qué habrás aprendido¶
- Los manifiestos no son solo de escritura — se consultan.
- Un helper de diff de 30 líneas hace el 80% del trabajo de triaje de drift que necesita un research-engineer.
- "Severidad por categoría" es una idea de diseño útil (la usarás de nuevo en el logger de training-dynamics de la Fase 19).