Skip to content

Commit ccc6b1a

Browse files
committed
merge: adjunta datos verificados al release + narrativa de 1.22.0
2 parents 0c5b002 + dc9f532 commit ccc6b1a

4 files changed

Lines changed: 121 additions & 12 deletions

File tree

.github/workflows/pypi-release.yml

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,27 +55,74 @@ jobs:
5555
rm -rf data/normalized
5656
mkdir -p data/normalized
5757
58+
# Descarga el artefacto de un run de Pipeline Check y responde si es
59+
# publication-grade (perfil `publication` + require_live). Solo esos
60+
# pueden adjuntarse a un release: los demas no verificaron la fuente
61+
# en vivo.
62+
is_publication_grade() {
63+
local dir="$1"
64+
[[ -f "$dir/pipeline_artifact_provenance.json" ]] || return 1
65+
python - "$dir/pipeline_artifact_provenance.json" <<'PY' || return 1
66+
import json, sys
67+
p = json.load(open(sys.argv[1], encoding="utf-8"))
68+
sys.exit(
69+
0
70+
if p.get("verification_profile") == "publication" and p.get("require_live") is True
71+
else 1
72+
)
73+
PY
74+
}
75+
76+
try_download() {
77+
local candidate="$1"
78+
rm -rf data/normalized
79+
mkdir -p data/normalized
80+
gh run download "$candidate" --name "pipeline-output-$candidate" \
81+
--dir data/normalized 2>/dev/null || return 1
82+
is_publication_grade data/normalized
83+
}
84+
5885
if [[ "${{ github.event_name }}" == "workflow_run" ]]; then
5986
run_id="${{ github.event.workflow_run.id }}"
6087
else
61-
# Find the last successful run of Pipeline Check on main branch
6288
run_id=$(gh run list --workflow "Pipeline Check" --branch main --status success --limit 1 --json databaseId --jq '.[0].databaseId' || true)
6389
fi
6490
65-
if [[ -n "$run_id" ]]; then
66-
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"
67-
gh run download "$run_id" \
68-
--name "pipeline-output-$run_id" \
69-
--dir data/normalized
70-
else
91+
if [[ -z "$run_id" ]]; then
7192
echo "Error: No verified pipeline data assets found."
7293
exit 1
7394
fi
7495
75-
if [[ ! -f data/normalized/pipeline_artifact_provenance.json ]]; then
76-
echo "::notice::Pipeline artifact has no provenance manifest; release data assets will not be attached."
77-
echo "ready=false" >> "$GITHUB_OUTPUT"
78-
exit 0
96+
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"
97+
98+
if try_download "$run_id"; then
99+
echo "Artefacto publication-grade tomado del run disparador ($run_id)."
100+
else
101+
# El run que dispara el release casi siempre es `push`, y esos
102+
# construyen con perfil `readiness` (sin verificacion live). Los
103+
# artefactos publication-grade vienen de `schedule`/`workflow_dispatch`,
104+
# que rara vez coinciden con commits publicables — por eso NINGUN
105+
# release del proyecto llego a tener assets adjuntos. Se busca hacia
106+
# atras el ultimo artefacto publication-grade disponible.
107+
echo "::notice::El run disparador no es publication-grade; buscando el ultimo que lo sea."
108+
found=""
109+
for candidate in $(gh run list --workflow "Pipeline Check" --branch main \
110+
--status success --limit 30 --json databaseId,event \
111+
--jq '.[] | select(.event=="schedule" or .event=="workflow_dispatch") | .databaseId'); do
112+
if try_download "$candidate"; then
113+
found="$candidate"
114+
break
115+
fi
116+
done
117+
118+
if [[ -z "$found" ]]; then
119+
echo "::notice::No hay artefactos publication-grade disponibles (pueden haber expirado); no se adjuntan datos al release."
120+
echo "ready=false" >> "$GITHUB_OUTPUT"
121+
exit 0
122+
fi
123+
124+
echo "Artefacto publication-grade tomado del run $found."
125+
echo "assets_run_id=$found" >> "$GITHUB_OUTPUT"
79126
fi
80127
81128
set +e

CHANGELOG.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,47 @@ son la bitácora automática generada desde los Conventional Commits.
1414

1515
## 1.22.0 - 2026-07-29
1616

17+
> 🎯 **Resumen:** El release más grande de la historia del proyecto, y no por
18+
> diseño: **la publicación estuvo bloqueada 19 días sin que nada lo señalara.**
19+
> El 2026-07-10 un `git push` no atómico dejó el tag `v1.22.0` publicado mientras
20+
> el commit de bump era rechazado por una carrera con otro bot. Desde entonces
21+
> `python-semantic-release` calculaba esa misma versión, veía su propio tag y
22+
> respondía *"already released"* — en verde, porque los pasos de build y publish
23+
> quedaban `skipped`. Resultado: 59 commits `feat`/`fix` acumulados en una sola
24+
> versión, en vez de las ~6 minor que habrían salido con cadencia normal. El tag
25+
> huérfano se eliminó y el push ahora usa `--atomic`, con un guardrail en
26+
> `tests/test_ci_config.py` porque este fallo no produce ninguna señal roja.
27+
>
28+
> **Nada se perdió**: estas notas cubren el rango completo desde `v1.21.1`, así
29+
> que los cambios que habrían aparecido en las versiones intermedias están todos
30+
> listados abajo. Lo que se perdió fue la *granularidad* — no el registro.
31+
>
32+
> Qué trae, agrupado por hilo de trabajo:
33+
>
34+
> - **Confianza en el dato.** Detección de anomalías temporales en series
35+
> numéricas con rechazo de publicación override-able (ADR-013); backfill
36+
> consciente de la edad, que impide que una serie muerta se esconda tras un
37+
> reuso del último artefacto publicado (ADR-016 — descubierto porque `ipc`
38+
> llevaba 240 días congelado y nadie lo veía); y separación de *drift esperado*
39+
> vs *drift real* (ADR-014), que bajó `drifted_count` de 8 a 3 sin relajar un
40+
> solo gate ni tocar un dato.
41+
> - **Salud legible.** Estado `retired` para fuentes muertas, derivado del
42+
> registry (ADR-015); historial append-only `hub_health_history.jsonl` con
43+
> sparkline en la landing; y contadores que por fin distinguen ruido
44+
> estructural de trabajo pendiente.
45+
> - **Distribución.** Catálogo DCAT `data.json`, publicación del bundle en
46+
> Hugging Face Hub, GeoParquet comunal publicado por CI y servido desde Pages
47+
> (carril `candidate`, fuera del bundle estable), y señal de adopción
48+
> PyPI + GitHub Releases.
49+
> - **API.** `resolve_comunas()` para mapear nombres a códigos CUT (ADR-009) y
50+
> `from_datapackage()` aceptando URLs (ADR-010).
51+
> - **Landing.** Explorador SQL con DuckDB-Wasm, overhaul tipográfico, ritmo
52+
> visual, skeletons de carga y unificación de idioma y tokens de color.
53+
> - **Anti-drift.** Campo `extractor` en las 22 entradas del catálogo, tabla de
54+
> extractores auto-generada, y cuatro fases de `doc-sync` que eliminan bloques
55+
> de documentación mantenidos a mano.
56+
57+
1758
### Corregido
1859

1960
- **api**: From_datapackage acepta URLs

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ chile-hub health # severidad, frescura, drift y cobertura
204204
### Respaldo adicional
205205

206206
<!-- START_TEST_COUNT -->
207-
- **804 tests** (`pytest --collect-only`) que validan extracción, contratos e integridad de datos.
207+
- **805 tests** (`pytest --collect-only`) que validan extracción, contratos e integridad de datos.
208208
<!-- END_TEST_COUNT -->
209209
<!-- START_ADR_COUNT -->
210210
- **16 ADRs** ([`docs/adr/`](docs/adr/)) que documentan cada decisión de arquitectura con su contexto, consecuencias y tradeoffs — no solo el "qué", sino el "por qué".

tests/test_ci_config.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,27 @@ def test_adoption_stats_completion_triggers_pages_deploy(self):
171171
)
172172
self.assertIn('"Adoption Stats (PyPI + GitHub Releases)"', content)
173173

174+
def test_release_falls_back_to_a_publication_grade_artifact(self):
175+
"""El release debe poder adjuntar datos verificados.
176+
177+
El run que dispara PyPI Release es casi siempre `push`, y esos
178+
construyen con perfil `readiness`; los artefactos publication-grade
179+
vienen de `schedule`/`workflow_dispatch`, que rara vez coinciden con
180+
commits publicables. Sin fallback, la condicion `ready == 'true'` nunca
181+
se cumple — de hecho ningun release del proyecto llego a tener assets
182+
adjuntos. El fallback nunca debe relajar el criterio: solo acepta
183+
`verification_profile == publication` con `require_live`.
184+
"""
185+
content = (ROOT_DIR / ".github" / "workflows" / "pypi-release.yml").read_text(
186+
encoding="utf-8"
187+
)
188+
self.assertIn("is_publication_grade", content)
189+
self.assertIn('select(.event=="schedule" or .event=="workflow_dispatch")', content)
190+
self.assertIn('p.get("verification_profile") == "publication"', content)
191+
self.assertIn('p.get("require_live") is True', content)
192+
# Degradacion segura: si no hay artefacto verificado, no se adjunta nada.
193+
self.assertIn('echo "ready=false" >> "$GITHUB_OUTPUT"', content)
194+
174195
def test_release_push_is_atomic(self):
175196
"""El push del commit de release y su tag debe ser atomico.
176197

0 commit comments

Comments
 (0)