Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
2afd45a
ci: add nightly sync workflow from main to dev
Phlip79 Apr 6, 2026
d5c2cc3
ci: add semantic conflict prevention to nightly sync
Phlip79 Apr 6, 2026
a99763b
ci: rewrite sync to take main's version for all shared files
Phlip79 Apr 7, 2026
db62dd7
ci: also restore main-only files deleted/renamed in dev
Phlip79 Apr 7, 2026
983029f
ci: rewrite nightly sync workflow with Claude Code Action
Phlip79 Apr 7, 2026
bdacf5f
ci: use claude-opus-4-6 model for nightly sync
Phlip79 Apr 7, 2026
67141ae
ci: rewrite nightly sync prompt for targeted merge strategy
Phlip79 Apr 7, 2026
d929db9
ci: make nightly sync manual-only for initial testing
Phlip79 Apr 7, 2026
9826d45
ci: improve nightly sync prompt with early failure detection and pyli…
Apr 8, 2026
93581f7
Update workflow
Phlip79 Apr 8, 2026
6fcd721
ci: add push trigger to register workflow for dispatch
ko3n1g Apr 9, 2026
d9d76e7
ci: address Deyu's review feedback on sync workflow
Phlip79 Apr 10, 2026
b29fd0d
Merge remote-tracking branch 'origin/main' into add-nightly-sync-work…
Phlip79 Apr 13, 2026
817d52b
ci: remove push trigger, keep workflow_dispatch only
Phlip79 Apr 13, 2026
144ab2c
fix: use 'prompt' instead of 'direct_prompt' for claude-code-action
Phlip79 Apr 13, 2026
d016d2f
ci: add --max-turns 200 so Claude can poll CI and iterate on failures
Phlip79 Apr 13, 2026
7338e1a
ci: explicitly instruct Claude not to exit until Phase 4 completes
Phlip79 Apr 13, 2026
83a9648
ci: add squash-merge chain detection — favor dev when it has follow-u…
Phlip79 Apr 13, 2026
360cc3d
ci: temp push trigger to register workflow
Phlip79 Apr 13, 2026
72a4724
ci: remove push trigger, keep workflow_dispatch only
Phlip79 Apr 13, 2026
e2a0491
ci: instruct Claude to act on failures immediately, not wait for full…
Phlip79 Apr 13, 2026
dbf994c
ci: increase max-turns to 1000
Phlip79 Apr 13, 2026
0cfa56e
Merge remote-tracking branch 'origin/main' into add-nightly-sync-work…
Phlip79 Apr 13, 2026
90ba46e
ci: temp push trigger to register workflow
Phlip79 Apr 13, 2026
e5fe06d
ci: remove push trigger, keep workflow_dispatch only
Phlip79 Apr 13, 2026
44ea75e
ci: use opus 1M context, max effort, and stronger do-not-exit instruc…
Phlip79 Apr 13, 2026
5ca0c69
ci: temp push trigger
Phlip79 Apr 13, 2026
73b2f1a
ci: remove push trigger
Phlip79 Apr 13, 2026
9fdf985
ci: reframe exit condition as concrete deliverable (gh pr ready)
Phlip79 Apr 13, 2026
bd8cbde
ci: temp push trigger
Phlip79 Apr 13, 2026
d71ec23
ci: remove push trigger
Phlip79 Apr 13, 2026
9ee4f1a
ci: add show_full_output to diagnose early exit
Phlip79 Apr 13, 2026
eca0b56
ci: temp push trigger
Phlip79 Apr 13, 2026
8bd8058
ci: remove push trigger
Phlip79 Apr 13, 2026
a843f19
ci: ban ScheduleWakeup, use synchronous Bash polling loop instead
Phlip79 Apr 14, 2026
392a41c
ci: temp push trigger
Phlip79 Apr 14, 2026
fa880e0
ci: remove push trigger
Phlip79 Apr 14, 2026
02238bb
ci: Phase 4 must wait for final CI run to complete before marking ready
Phlip79 Apr 14, 2026
df52f5f
ci: ban run_in_background and tail polling, require single foreground…
Phlip79 Apr 14, 2026
e52c53c
ci: require empirical verification of pre-existing failures against r…
Phlip79 Apr 14, 2026
42abd3e
ci: refactor sync prompt — move domain knowledge to skill file, keep …
Phlip79 Apr 14, 2026
5768a69
ci: add PR body format, deleted file heuristic, and direct-push rule …
Phlip79 Apr 14, 2026
bf360c1
ci: temp push trigger
Phlip79 Apr 14, 2026
29e9ec4
ci: remove push trigger
Phlip79 Apr 14, 2026
50d20c5
ci: skill file — do NOT take main's uv.lock, keep dev's
Phlip79 Apr 14, 2026
7f01046
ci: skill file — keep dev's pyproject.toml AND uv.lock, never manuall…
Phlip79 Apr 14, 2026
33387c6
ci: skill file — Dockerfile.ci.dev joins pyproject.toml and uv.lock a…
Phlip79 Apr 14, 2026
1844bb0
fix: take dev's pyproject.toml, uv.lock, and Dockerfile.ci.dev
Phlip79 Apr 14, 2026
cc6b97f
ci: skill file — lessons from PR #4291 execution
Phlip79 Apr 16, 2026
28df0b2
Merge remote-tracking branch 'origin/add-nightly-sync-workflow'
Phlip79 Apr 22, 2026
d1bb108
Merge branch 'main' into add-nightly-sync-workflow
Phlip79 Apr 22, 2026
9c14a90
ci: temp push trigger
Phlip79 Apr 22, 2026
b6e19d1
ci: remove push trigger
Phlip79 Apr 22, 2026
abb4cfc
ci: strict Phase 4 gate and no-background-task rules for sync bot
Phlip79 Apr 22, 2026
048f2ab
Merge NVIDIA/Megatron-LM add-nightly-sync-workflow
Phlip79 Apr 22, 2026
9f488fa
ci: temp push trigger
Phlip79 Apr 22, 2026
2a75639
ci: remove push trigger
Phlip79 Apr 22, 2026
2f7c58e
Revert: restore main's pyproject.toml, uv.lock, and Dockerfile.ci.dev
Phlip79 Apr 22, 2026
9cfbbeb
ci: forbid CODEOWNERS edits and harden Phase 4 gate for sync bot
Phlip79 Apr 23, 2026
0913da7
ci: include Python-only line-change stats in sync PR body
Phlip79 Apr 23, 2026
0d8ad45
ci: schedule nightly sync to run daily at 21:00 UTC (2 PM PDT)
Phlip79 Apr 23, 2026
ddab623
ci: use rolling opus[1m] alias and raise --max-turns to 1500
Phlip79 Apr 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions .github/workflows/nightly-sync-main-to-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Nightly Sync Main to Dev

on:
workflow_dispatch:
schedule:
# 21:00 UTC = 2 PM PDT (1 PM PST during winter — GitHub Actions cron
# is UTC-only and does not follow DST).
- cron: '0 21 * * *'

concurrency:
group: nightly-sync-main-to-dev
cancel-in-progress: false

permissions:
contents: write
pull-requests: write
issues: write
id-token: write

jobs:
sync-main-to-dev:
runs-on: ubuntu-latest
if: github.repository == 'NVIDIA/Megatron-LM'
timeout-minutes: 360
env:
GH_TOKEN: ${{ secrets.PAT }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.PAT }}

- name: Configure Git
run: |
git config user.name "svcnvidia-nemo-ci"
git config user.email "svcnvidia-nemo-ci@nvidia.com"

- name: Compute branch name
id: vars
run: |
DATE=$(date -u +%d_%m_%Y)
BRANCH="main2dev/${DATE}"
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
echo "date=$DATE" >> "$GITHUB_OUTPUT"

- name: Close previous unmerged sync PRs
run: |
OPEN_PRS=$(gh pr list \
--repo "${{ github.repository }}" \
--base dev \
--state open \
--json number,headRefName \
--jq '.[] | select(.headRefName | startswith("main2dev/")) | .number')

for PR_NUM in $OPEN_PRS; do
echo "Closing stale sync PR #${PR_NUM}"
gh pr close "$PR_NUM" \
--repo "${{ github.repository }}" \
--comment "Superseded by today's nightly sync."
done

- name: Check if sync is needed
id: check-sync
run: |
git fetch origin main dev
AHEAD_COUNT=$(git rev-list --count origin/dev..origin/main)
echo "main is $AHEAD_COUNT commit(s) ahead of dev"
if [ "$AHEAD_COUNT" -eq 0 ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "No changes to sync."
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- name: Run Claude Code to merge, fix, and iterate
if: steps.check-sync.outputs.skip != 'true'
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.PAT }}
prompt: |
You are an automated sync bot. Merge `main` into `dev`, create a
PR, ensure CI passes (fixing failures), and mark the PR ready.
There are 4 phases. You are NOT done until Phase 4 completes.

REPO: ${{ github.repository }}
BRANCH: ${{ steps.vars.outputs.branch }}
DATE: ${{ steps.vars.outputs.date }}

Read `.claude/skills/nightly-sync/SKILL.md` for the detailed
merge strategy, CI architecture, failure investigation procedures,
and known issues. Also read `.claude/skills/build-and-test/SKILL.md`
and `CLAUDE.md` for general CI and contribution guidelines.

## Hard Constraints

**Exit condition:** You MUST run `gh pr ready <PR_NUMBER>` before
exiting. That command is Phase 4. Do NOT exit after Phase 1, 2,
or 3 — not even if CI is "still running" or "stuck in queue."
Keep polling until it resolves, then act.

**NO background tasks. Ever.**
You are running inside a single GitHub Actions step. The step
process owns your shell. When you stop issuing tool calls, the
step ends and the runner container is DESTROYED — every
background process dies with it and cannot resume. There is no
"future session" to wake up into.

The following are strictly forbidden:
- `Bash` with `run_in_background: true`
- `Agent` with `run_in_background: true`
- `ScheduleWakeup` (nothing will ever wake up)
- Any shell command ending in `&`, or using `nohup`, `disown`,
or `setsid` to detach a process
- `tail -f` on a log produced by a backgrounded task

Required shape for every long wait: ONE foreground Bash tool
call containing an inline `while true; do ... sleep <N>; done`
or `until ...; do sleep <N>; done` loop that BLOCKS inside
that single tool call and only returns when the wait is
resolved (success, failure, or a clearly-classified terminal
state). Do NOT break a long wait into many short polls with
conversation in between — that wastes `--max-turns` and
creates windows where the agent could forget the loop.

**Source of truth for CI status:**
`gh pr view <PR_NUMBER> --repo $REPO --json statusCheckRollup`
This lists every required check — GitHub Actions jobs AND
external contexts (GitLab CI, `copy-pr-bot`, etc.). The
`gh api .../actions/runs/<RUN_ID>/jobs` endpoint alone is
NOT sufficient — it misses external contexts.

**Pre-existing failures:** MUST verify against recent dev CI
before classifying any failure as pre-existing. Run
`gh pr checks` on a recently merged dev PR. If the test passes
on dev, the failure is sync-caused and you must fix it. A
check that has never completed on your PR cannot be
pre-existing — wait for it to finish first.

**Phase 4 gate — strict "all terminal, all green":**
Do NOT run `gh pr ready` until every non-exempt required check
in `statusCheckRollup` satisfies BOTH:
- `status == "COMPLETED"` (NOT `QUEUED`, `IN_PROGRESS`,
`PENDING`, `WAITING`, or `REQUESTED`), AND
- `conclusion` ∈ {`SUCCESS`, `SKIPPED`, `NEUTRAL`}.
A check stuck in a runner queue is NOT complete. Never
classify queued/in-progress jobs as "infrastructure-blocked"
and ship anyway — wait for them to reach a terminal
conclusion, then act on that result. When a check fails,
loop: diagnose → fix → commit → push → `/ok to test <sha>` →
poll. Only exit the loop when the gate is satisfied on the
LATEST CI run against the current HEAD SHA.

**Exempt checks (may be ignored for the Phase 4 gate):**
These categories are pre-merge policy signals, not
correctness signals, so their failure must not block the
sync bot from marking the PR ready for human review.

- Approval / code-review: `codeowners-approval`,
`check-approval`, `multi-approval-bot-summary`,
`is-not-external-contributor`, any check whose name
contains `review` or `approval`.
- Code coverage: `Coverage (unit-test)`, `Coverage_Fake`,
any check whose name contains `codecov` or `coverage`
(case-insensitive).
- Docs: `build-docs / Build docs`, `build-docs-summary`,
any check whose name contains `build-docs`, `doc-build`,
`readthedocs`, or `sphinx`.

Everything else — unit tests (`tests/unit_tests/...`),
integration tests (`gpt/...`, `moe/...`, etc.), `linting`,
`cicd-container-build`, `cicd-mbridge-testing`,
`Nemo_CICD_Test`, `copyright-check`, `pre-flight`, wheel
builds, etc. — is NOT exempt and must reach a terminal
green conclusion.
show_full_output: true
claude_args: |
--allowedTools "Bash,Read,Edit,Write,Grep,Glob,Agent"
--model "opus[1m]"
--effort max
--max-turns 1500
Loading
Loading