From 6b9061517e9a975c46b2199d600625c525bf3a9d Mon Sep 17 00:00:00 2001 From: stranske Date: Mon, 12 Jan 2026 00:23:41 +0000 Subject: [PATCH 1/3] fix: surface merge conflicts before invoking Codex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The keepalive loop detects conflicts and routes to fix_merge_conflicts.md, but Codex was checking git status and reporting 'no conflicts' because the merge hadn't been attempted yet. The prompt instructs 'Do NOT check git status first, run git merge', but Codex checks git status anyway and exits early. Solution: Add workflow step that runs git merge BEFORE invoking Codex. This surfaces conflicts in the workspace so they're visible when Codex checks git status, regardless of whether Codex follows the prompt order. Fixes conflict resolution flow end-to-end: 1. Keepalive detects conflicts (✓ already working) 2. Workflow allows Codex to run for action='conflict' (✓ PR #773) 3. Workflow surfaces conflicts in workspace (✓ this fix) 4. Codex sees conflicts and resolves them (✓ with this fix) Ref: Trend_Model_Project PR #4339 --- .github/workflows/reusable-codex-run.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/reusable-codex-run.yml b/.github/workflows/reusable-codex-run.yml index 569e122e7..27f0f3a6a 100644 --- a/.github/workflows/reusable-codex-run.yml +++ b/.github/workflows/reusable-codex-run.yml @@ -227,6 +227,26 @@ jobs: path: .workflows-lib token: ${{ steps.auth_token.outputs.checkout_token }} + + # Surface merge conflicts before Codex runs + # When action='conflict', we need to attempt the merge BEFORE invoking Codex + # so that conflicts are visible in the workspace. Otherwise Codex checks + # git status, sees no conflicts (because merge hasn't been attempted yet), + # and exits early despite prompt instructions to run the merge. + - name: Surface merge conflicts + if: inputs.prompt_file == '.github/codex/prompts/fix_merge_conflicts.md' + run: | + set +e # Don't exit on merge failure - conflicts are expected + git fetch origin main + git merge --no-commit --no-ff origin/main + merge_exit=$? + if [ $merge_exit -ne 0 ]; then + echo "Merge conflicts detected (expected for conflict resolution)" + git status + else + echo "No merge conflicts - merge succeeded automatically" + fi + set -e - name: Set up Python uses: actions/setup-python@v6 with: From 70ca70b95b0cb9e5e50341c29ca731f769551b2e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 00:27:27 +0000 Subject: [PATCH 2/3] chore(codex-keepalive): apply updates (PR #812) --- tests/workflows/test_keepalive_workflow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/workflows/test_keepalive_workflow.py b/tests/workflows/test_keepalive_workflow.py index f2fc28df7..368206ca1 100644 --- a/tests/workflows/test_keepalive_workflow.py +++ b/tests/workflows/test_keepalive_workflow.py @@ -68,7 +68,7 @@ def _assert_no_dispatch(data: dict) -> None: assert _dispatch_events(data) == [] -# First line of the keepalive instruction from .github/templates/keepalive-instruction.md +# First line of the keepalive instruction from .github/codex/prompts/keepalive_next_task.md # The full instruction is multi-line; tests check that the instruction starts correctly. DEFAULT_COMMAND_PREFIX = ( "@codex Your objective is to satisfy the **Acceptance Criteria** by completing each " @@ -157,6 +157,7 @@ def test_keepalive_idle_threshold_logic() -> None: assert body_lines[2] == "" assert "" in created[0]["body"] From 425e472f338ea89ed35526dc40ad1f875d2f56b2 Mon Sep 17 00:00:00 2001 From: stranske Date: Mon, 12 Jan 2026 00:39:30 +0000 Subject: [PATCH 3/3] fix: address bot review feedback - move merge step and make branch detection dynamic Addresses three critical review comments: 1. **Codex P1 (CRITICAL)**: Move merge step AFTER dependency installation - Problem: If conflicts touch requirements*.txt or pyproject.toml, pip install fails when trying to parse files with conflict markers - Solution: Moved 'Surface merge conflicts' step from before Python setup (line 236) to just before 'Run Codex' (line 485) - This ensures dependencies are installed cleanly before conflicts are surfaced 2. **Copilot**: Dynamic base branch detection instead of hardcoded 'origin/main' - Added logic to detect base branch from GITHUB_BASE_REF, workflow input, origin/HEAD, or fallback to 'main' - Makes workflow portable across repos with different default branches 3. **Copilot**: Simplified error handling - Removed unnecessary set +e / set -e toggling - Use 'merge_exit=0; git merge ... || merge_exit=$?' pattern - Maintains set -euo pipefail throughout for consistency --- .github/workflows/reusable-codex-run.yml | 64 +++++++++++++++++------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/.github/workflows/reusable-codex-run.yml b/.github/workflows/reusable-codex-run.yml index 27f0f3a6a..41418bd46 100644 --- a/.github/workflows/reusable-codex-run.yml +++ b/.github/workflows/reusable-codex-run.yml @@ -228,25 +228,6 @@ jobs: token: ${{ steps.auth_token.outputs.checkout_token }} - # Surface merge conflicts before Codex runs - # When action='conflict', we need to attempt the merge BEFORE invoking Codex - # so that conflicts are visible in the workspace. Otherwise Codex checks - # git status, sees no conflicts (because merge hasn't been attempted yet), - # and exits early despite prompt instructions to run the merge. - - name: Surface merge conflicts - if: inputs.prompt_file == '.github/codex/prompts/fix_merge_conflicts.md' - run: | - set +e # Don't exit on merge failure - conflicts are expected - git fetch origin main - git merge --no-commit --no-ff origin/main - merge_exit=$? - if [ $merge_exit -ne 0 ]; then - echo "Merge conflicts detected (expected for conflict resolution)" - git status - else - echo "No merge conflicts - merge succeeded automatically" - fi - set -e - name: Set up Python uses: actions/setup-python@v6 with: @@ -482,6 +463,51 @@ jobs: echo "Workspace is clean for Codex." fi + + # Surface merge conflicts before Codex runs + # When action='conflict', we need to attempt the merge BEFORE invoking Codex + # so that conflicts are visible in the workspace. Otherwise Codex checks + # git status, sees no conflicts (because merge hasn't been attempted yet), + # and exits early despite prompt instructions to run the merge. + # IMPORTANT: This runs AFTER dependency installation to avoid breaking + # pip install if requirements files contain conflict markers. + - name: Surface merge conflicts + if: inputs.prompt_file == '.github/codex/prompts/fix_merge_conflicts.md' + env: + WORKFLOW_BASE_REF: ${{ github.event.pull_request.base.ref || '' }} + run: | + set -euo pipefail + + # Determine the base branch to merge from: + # 1. Use GITHUB_BASE_REF if set (PR workflows). + # 2. Use WORKFLOW_BASE_REF from the workflow_call context if provided. + # 3. Derive the default branch from origin/HEAD. + # 4. Fall back to 'main' for backward compatibility. + base_branch="${GITHUB_BASE_REF:-}" + if [ -z "$base_branch" ] && [ -n "${WORKFLOW_BASE_REF:-}" ]; then + base_branch="$WORKFLOW_BASE_REF" + fi + if [ -z "$base_branch" ]; then + base_branch="$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || true)" + fi + if [ -z "$base_branch" ]; then + echo "Warning: could not determine base branch automatically; defaulting to 'main'." + base_branch="main" + fi + + echo "Using base branch '$base_branch' to surface merge conflicts." + git fetch origin "$base_branch" + + # Attempt merge but do not fail the job on expected conflicts + merge_exit=0 + git merge --no-commit --no-ff "origin/$base_branch" || merge_exit=$? + if [ $merge_exit -ne 0 ]; then + echo "Merge conflicts detected (expected for conflict resolution)" + git status + else + echo "No merge conflicts - merge succeeded automatically" + fi + - name: Run Codex id: run_codex env: