Skip to content

English · Español

Lab 01 — Extender el Justfile

Pre-requisito: lee ../theory/02-engineering-hygiene.md y ../theory/03-dev-environment.md. Objetivo: interiorizar just añadiendo una nueva receta que usarás en fases posteriores. No mires solutions/01-justfile-ref.md hasta haberlo hecho funcionar.

§1 Contexto

just es un task runner — las recetas son como targets de make pero sin el footgun de la indentación con tab de make, sin el dolor del make recursivo, sin semántica implícita de rebuild. Las recetas son explícitas, parametrizadas y componibles.

Recetas actuales en /Justfile:

  • default — lista todas las recetas
  • setupuv sync --all-extras + uv run pre-commit install
  • lintruff check + ruff format --check + mypy src
  • fmtruff check --fix + ruff format
  • testuv run pytest
  • nbstrip — elimina outputs de cualquier notebook commiteado
  • clean — limpia artefactos de build/cache
  • phase00 — encadena setup → lint → test

§2 Tu tarea

Añade una receta nueva llamada manifest que:

  1. Tome un argumento posicional: topic (p.ej., just manifest softmax-stability).
  2. Genere un directorio experiments/$(date +%F)-{topic}/.
  3. Escriba un archivo experiments/$(date +%F)-{topic}/manifest.json que contenga como mínimo:
  4. id: "$(date +%F)-{topic}"
  5. git_sha: salida de git rev-parse HEAD
  6. git_dirty: true si git status --porcelain no está vacío, false en otro caso
  7. seed: 42 (placeholder — los scripts reales lo pasan)
  8. versions: salida de uv run python -c "from utils.seeding import log_versions; import json; print(json.dumps(log_versions()))"
  9. hardware: { "cpu": "$(uname -p)", "kernel": "$(uname -r)", "os": "$(. /etc/os-release; echo $PRETTY_NAME)" }
  10. started_at: ISO-8601 UTC $(date -u +%FT%TZ)
  11. Imprima la ruta al manifiesto al final.

§3 Restricciones

  • Sin dependencias externas. Usa solo lo que ya está en el lockfile (python, git, coreutils, jq del OS).
  • Idempotente: correr la receta dos veces el mismo día con el mismo topic sobrescribe el manifiesto limpiamente (tú decides: rotar por HH:MM:SS, o sobrescribir — defiende tu elección en el diario).
  • Cross-shell: las recetas corren bajo sh por defecto, no fish. Si necesitas algo cargado de bashism, pon set shell := ["bash", "-cu"] al inicio del Justfile y explica por qué en un comentario.
  • Quotea {topic} con seguridad — topic podría ser softmax stability o phase-12-something o peor. Nada de command injection por topic.

§4 Tests

Añade un test a tests/test_justfile.py (puede que tengas que crearlo) que:

  1. Llame a just manifest test-topic vía subprocess.
  2. Verifique que el archivo de manifiesto existe.
  3. Verifique que parsea como JSON.
  4. Verifique que el campo versions.python empieza con 3.11.
  5. Verifique que el campo git_sha es una cadena hex de 40 caracteres.

Usa tmp_path para el directorio de test si puedes; si no, documenta por qué el test corre in-tree.

§5 Condiciones de parada

Estás listo cuando:

  • just manifest <some-topic> produce un manifiesto JSON válido en experiments/.
  • Reejecutar just manifest <same-topic> funciona (sin errores, sin escritura parcial).
  • pytest tests/test_justfile.py pasa.
  • just lint sigue en verde (sin warnings de shell, sin nuevos errores de lint).
  • Commit: lab: phase-00 add manifest recipe.

§6 Qué habrás aprendido

Al final: - Recetas parametrizadas de just + quoting. - Composición de shell ($(...), códigos de retorno condicionales). - Por qué importan los manifiestos de determinismo (escribirás uno a mano aquí; fases posteriores consumen record_manifest() de src/utils/). - Cómo interactúan las recetas con pre-commit y el lockfile.

§7 Pistas (úsalas con moderación)

  1. just --evaluate muestra la expansión de la receta sin correr nada — útil para depurar el quoting.
  2. git rev-parse HEAD devuelve el sha completo; no necesitas git log -1 --pretty=%H.
  3. Para detectar "dirty", git diff-index --quiet HEAD -- es más limpio que parsear git status --porcelain.

Si recurres a solutions/01-justfile-ref.md antes de completar esto, marca dod.lab_attempted_before_solutions: false en learners/borja/phase-00/checkpoint.json. La honestidad importa aquí — el phase-gatekeeper lo comprueba.