Bump Dependency
Workflow complet pour livrer un bump de dépendance dans Megatron Bridge. Optimisé pour le cas où TE, MCore, ou une autre épingle GPU-lourde progresse — ce qui révèle souvent des flakes qu'il faut mettre en quarantaine avant que la PR ne puisse fusionner.
Le pipeline est toujours : edit → relock → push → /ok to test → watchdog → quarantine on red → re-trigger → repeat until green.
Quand utiliser cette skill
- Bumper une épingle git-source dans
pyproject.tomloverride-dependencies(ex.transformer-engine @ git+...@<ref>). - Bumper le submodule
3rdparty/Megatron-LM. - Tout changement qui touche
uv.locket a besoin de la matrice complète L0 + L1 pour valider avant la fusion.
Pour les ajouts/suppressions pures de dépendances sans boucle CI, la
skill build-and-dependency suffit.
Contexte requis
Lisez d'abord, puis suivez les étapes ci-dessous :
- @CONTRIBUTING.md — politique titre PR/label, signature DCO
- @skills/build-and-dependency/SKILL.md — mécanique
uv lock, choix du conteneur - @skills/cicd/SKILL.md — comment
copy-pr-botet/ok to testfonctionnent - @skills/testing/SKILL.md — layout
active/vsflaky/, recette quarantainegit mv
Étape 1 — Worktree et édition
Créez un worktree à partir de main per @CLAUDE.md. Puis, avant tout uv lock :
git submodule update --init 3rdparty/Megatron-LM
Le submodule doit être initialisé dans le worktree sinon uv lock errore
avec « not a Python project » sur le chemin MCore.
Éditez l'épingle. Pour TE, le levier canonique est la ligne override dans
pyproject.toml :
override-dependencies = [
...
"transformer-engine @ git+https://github.com/NVIDIA/TransformerEngine.git@<new-ref>",
...
]
Utilisez un nom de branche (release_v2.15) seulement si vous voulez suivre
un tip mouvant ; utilisez un SHA complet pour la reproductibilité. Les branches TE utilisent
release_vX.Y (tiret bas), pas release/vX.Y. Vérifiez avec
git ls-remote https://github.com/NVIDIA/TransformerEngine.git.
Étape 2 — Régénérer le fichier lock
Exécutez uv lock dans le conteneur du projet per
@skills/build-and-dependency/SKILL.md « Regenerating uv.lock ». Puis
confirmez que seuls les packages attendus ont bougé :
git diff --stat pyproject.toml uv.lock
Si le diff porte des changements que vous n'aviez pas demandés (mouvements
transitifs inexplicables), arrêtez et enquêtez avant de pusher. Notez que
override-dependencies porte des planchers CVE qui flottent — des packages
non-liés bumper par une version patch est attendu ; acceptez-les, ne les revertez pas.
Étape 3 — Commit et push
Sign-off + signed-commit + format titre PR per @CONTRIBUTING.md et @skills/cicd/SKILL.md « Commit and PR Workflow ». Pour un bump :
git add pyproject.toml uv.lock
git commit -S -s -m "[build] chore: bump <package> to <ref>"
git push -u origin <branch-name>
Un signed commit (-S) laisse copy-pr-bot déclencher la CI sans /ok to test
manuel au premier push — mais vous posterez quand même /ok to test
sur chaque SHA suivant dans cette boucle (Étape 5).
Étape 4 — Ouvrir la PR
Titre et labels per @CONTRIBUTING.md. Deux exigences spécifiques au bump :
- Appliquez
needs-more-tests— obligatoire pour un bump ; élargit la matrice de L0 à L0+L1. - Pour un bump à rayon de blast élevé (TE, submodule MCore, tout ce qui
touche les kernels CUDA), appliquez aussi
full-test-suitepour tirer L2 dans la run PR. L2 couvre les modèles VL, conversion de checkpoint, et quantization lourde qui sinon ne s'exécutent que sur horaire.
Le template du corps PR — c'est l'enregistrement durable du bump :
<details><summary>Claude summary</summary>
## What
- Bump <package> to <ref>.
- Regenerate `uv.lock`.
## Lockfile delta
Updated <package> <old> -> <new>
## Test plan
- [ ] L0 CI green
- [ ] L1 CI green (label `needs-more-tests` applied)
## Quarantined tests (this bump)
_None yet — will be appended as flakes are identified during CI iteration._
</details>
Pour mettre à jour le titre ou le corps PR plus tard, utilisez gh api -X PATCH "repos/NVIDIA-NeMo/Megatron-Bridge/pulls/<N>" -F "body=@/tmp/pr-body.md"
— jamais gh pr edit.
Étape 5 — Déclencher la CI sur le SHA exact
La mécanique de déclenchement vit dans @skills/cicd/SKILL.md « How CI Is Triggered ».
Pour cette boucle, la règle est simple : à chaque nouveau SHA que vous pushes, postez
/ok to test $(git rev-parse HEAD) comme commentaire PR, même si vos
commits sont signés. Cela garantit que la run cible le SHA que vous voulez
réellement exercer et re-déclenche tout ce qui a été annulé ou mis en cache.
Étape 6 — Attachez le watchdog (toujours ; jamais un cronjob)
Pour une PR de bump, vous voulez un seul processus actif qui émet les changements d'état
par job pour le workflow CICD NeMo uniquement. Les autres workflows (docs,
wheel, copyright, install-test) sont du bruit ici — la barrière qui décide
green-or-red pour un bump est CICD NeMo.
Attachez toujours un watchdog avec l'outil Monitor. Ne programmez jamais de réveils ou de cronjobs pour cette boucle. Un watchdog vous donne :
- Temps de réaction sub-minute à chaque transition de job.
- Un seul processus actif — pas d'état scattered scheduled-wakeup à raisonner.
- Terminaison naturelle précoce via
TaskStopune fois que la run est verte.
Script du watchdog
Sauvegardez dans /tmp/watchdog-<PR>.sh et chmod +x :
#!/usr/bin/env bash
# Watchdog: monitor "CICD NeMo" runs on pull-request/<PR> and emit
# per-job state changes. Stays alive across re-runs (new commits).
set -u
PR=<PR>
REPO=NVIDIA-NeMo/Megatron-Bridge
BRANCH="pull-request/$PR"
prev_run_id=""
declare -A prev_state
emit() { echo "[$(date -u +%H:%M:%SZ)] $*"; }
while true; do
run_json=$(gh run list --repo "$REPO" --workflow "CICD NeMo" \
--branch "$BRANCH" --limit 1 \
--json databaseId,status,conclusion,headSha 2>/dev/null || echo "[]")
run_id=$(echo "$run_json" | jq -r '.[0].databaseId // empty')
run_status=$(echo "$run_json" | jq -r '.[0].status // empty')
run_conclusion=$(echo "$run_json" | jq -r '.[0].conclusion // empty')
run_sha=$(echo "$run_json" | jq -r '.[0].headSha // empty')
if [[ -z "$run_id" ]]; then
sleep 30; continue
fi
if [[ "$run_id" != "$prev_run_id" ]]; then
emit "RUN ${run_id} STARTED sha=${run_sha:0:8} status=${run_status}"
prev_run_id="$run_id"
unset prev_state
declare -A prev_state
fi
jobs_json=$(gh run view "$run_id" --repo "$REPO" --json jobs 2>/dev/null || echo "{}")
while IFS=$'\t' read -r name status conclusion; do
[[ -z "$name" ]] && continue
cur="${status}/${conclusion}"
if [[ "${prev_state[$name]:-}" != "$cur" ]]; then
case "$status" in
completed)
emit "JOB ${name} -> ${conclusion}" ;;
in_progress)
if [[ -z "${prev_state[$name]:-}" || "${prev_state[$name]}" == "queued/" ]]; then
emit "JOB ${name} -> in_progress"
fi ;;
esac
prev_state[$name]="$cur"
fi
done < <(echo "$jobs_json" | jq -r '.jobs[]? | [.name, .status, (.conclusion // "")] | @tsv')
if [[ "$run_status" == "completed" ]]; then
emit "RUN ${run_id} COMPLETED conclusion=${run_conclusion}"
fi
sleep 60
done
Armer le watchdog
Monitor(
description="CICD NeMo run state changes on PR <N>",
command="bash /tmp/watchdog-<N>.sh",
persistent=true,
timeout_ms=3600000
)
persistent: true le garde actif à travers les re-runs (vous pusherez plus
de commits lors de la quarantaine de flakes). Arrêtez-le avec TaskStop(<task-id>)
une fois que la run est verte.
Pourquoi jamais un cronjob / wakeup programmé
- Les cronjobs tournent à l'aveugle — ils se déclenchent sur une horloge, pas sur un événement. Vous aurez soit du sur-polling (cache miss à chaque wakeup) soit des stalls manqués.
- Les wakeups ne peuvent pas facilement fan out vers « dites-moi quand un job transitionne » — ils reprennent juste l'agent à un intervalle fixe.
- Un Monitor persistent surface chaque transition de job en temps réel et sort proprement quand le travail est fait.
Étape 7 — Quarantaine sur rouge, puis itérez
Quand un événement JOB <name> -> failure se déclenche :
-
Triez la défaillance — est-ce le bump ou une flake ? Survolez les logs :
RUN_ID=<from "RUN ... STARTED" event> gh run view "$RUN_ID" --repo NVIDIA-NeMo/Megatron-Bridge --log-failed > /tmp/run.log wc -l /tmp/run.log tail -200 /tmp/run.logC'est le jugement spécifique au bump : ne mettez en quarantaine que si la défaillance se reproduit sur
mainou est clairement liée à l'infrastructure. Si la défaillance est causée par le bump (vrai regression), arrêtez la quarantaine — corrigez le problème sous-jacent ou revertez le bump. Mettre en quarantaine une vraie regression cache précisément le signal que la PR de bump existe pour surfacer. -
Déplacez le script de lancement vers
flaky/per @skills/testing/SKILL.md « Moving a Test to Flaky ». Mappez un nom de job CI à son script de lancement via :- préfixe
gb200_→gb200/active/, sinonh100/active/ - le reste est le basename du script sans
.sh
- préfixe
-
Appendez à la section Quarantined tests du corps PR avec une raison une ligne et un lien de suivi si vous en avez un. C'est l'enregistrement durable de ce que ce bump a différé — la section existe précisément pour qu'un reviewer voir d'un coup d'œil quelles flakes ont été contournées pour atterrir le bump.
-
Commit, push, re-trigger :
git commit -S -s -m "[ci] chore: quarantine flaky <test> for <package> bump" git push gh pr comment <N> --repo NVIDIA-NeMo/Megatron-Bridge \ --body "/ok to test $(git rev-parse HEAD)" -
Mettez à jour le corps PR via
gh api PATCHpour que la liste de quarantaine reste actuelle.
Le watchdog est persistant — il reprend la nouvelle run automatiquement et
émet RUN <id> STARTED pour la nouvelle tentative. Bouclez vers l'étape 1.
Étape 8 — Arrêtez quand c'est vert
RUN <id> COMPLETED conclusion=success est la condition de sortie. Puis :
gh pr checks <N> --repo NVIDIA-NeMo/Megatron-Bridge | awk '{print $2}' | sort | uniq -c
TaskStop(<watchdog-task-id>)
gh api -X PATCH "repos/NVIDIA-NeMo/Megatron-Bridge/pulls/<N>" -F "body=@/tmp/pr-body.md"
Pièges courants
| Symptôme | Cause | Correction |
|---|---|---|
Mauvaise ref de branche TE (release/v2.15) ne se résout silencieusement à rien |
TE utilise release_vX.Y avec un tiret bas |
Vérifiez avec git ls-remote avant de locker |
| Le diff du lockfile inclut des packages non-liés épinglés par CVE | override-dependencies porte des planchers qui flottent |
Re-run lock et acceptez ; n'essayez pas de revertir ceux-là |
| Le premier push signé déclenche la CI mais les pushes suivants ne le font pas | copy-pr-bot re-trust à chaque nouveau SHA uniquement via /ok to test une fois au-delà du premier signed commit dans cette boucle |
Toujours re-postez /ok to test $(git rev-parse HEAD) per Étape 5 |
| Le watchdog se tait pendant 30+ min | gh rate-limited ou auth expiré |
Bumpez l'intervalle de poll ; gh auth status ; redémarrez Monitor |
Le nom du job ne mappe à aucun script dans active/ |
Le préfixe gb200_ est l'indicateur matériel, pas partie du nom de fichier |
Stripez gb200_ et cherchez dans gb200/active/ |
Anti-patterns
- Cron / wakeups programmés pour cette boucle. Toujours Monitor.
- Polling tous les workflows. Filtrez à
CICD NeMo— le reste est du bruit pour un bump. - Mettre en quarantaine une vraie regression pour « rendre CI verte ». Ça defeat
le but de la PR de bump. Ne mettez en quarantaine que si la défaillance se reproduit
sur
mainou est clairement liée à l'infrastructure. gh pr editpour titre/corps. Utilisezgh api PATCH.- HEREDOC dans
gh pr create --body. Toujours passer par un tmpfile +--body-file. - Bundler des changements non-liés (feature work, refactors) dans une PR de bump. Les bumps doivent rester chirurgicaux pour que les défaillances CI s'attribuent proprement.