Skip to content

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

  1. Crea scripts/manifest_diff.py (sin implementación previa — esto es greenfield).
  2. Crea dos manifiestos sintéticos bajo experiments/diff-demo/:
  3. monday.json (usa el ejemplo de theory/04-manifest-anatomy.md §1).
  4. tuesday.json (igual, pero con numpy 2.0.2).
  5. Confirma que uv run python scripts/manifest_diff.py experiments/diff-demo/monday.json experiments/diff-demo/tuesday.json corre.

§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.json imprime exactamente una línea VERSIONS y sale con código 1.
  • pytest tests/test_manifest_diff.py pasa (3/3).
  • mypy --strict scripts/manifest_diff.py pasa.
  • ruff check scripts/manifest_diff.py pasa.
  • Has escrito una entrada de diario en learners/borja/phase-00/notes/manifest-diff.md cubriendo: 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

  1. Aplana dicts anidados con un helper recursivo flatten(prefix, obj) -> dict[str, str]. Claves de salida tipo versions.numpy.
  2. Las "categorías" son solo prefijos regex sobre la clave aplanada. Un dict de { "CODE": ("git_sha", "git_dirty"), ... } basta.
  3. Usa argparse con dos argumentos posicionales; no necesitas opciones fancy. Añade --quiet para suprimir la línea "(no differences in ...)" solo si tienes tiempo.
  4. El "exit non-zero on CODE/VERSIONS drift" hace al script usable como manifest_diff.py prev.json next.json && echo OK || echo DRIFT en 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).