From 1e48df0d90ddce905f24e4a71abae9503dcb7018 Mon Sep 17 00:00:00 2001 From: NagyVikt Date: Tue, 21 Apr 2026 13:15:18 +0200 Subject: [PATCH] Prevent codex-agent from waiting on PRs that can never exist Local and file-backed origins do not provide a mergeable GitHub PR surface, so codex-agent now skips the auto-finish merge path in that context and keeps the sandbox available for manual follow-up. The focused regression docs were tightened to match the actual fallback behavior and owner slug handling. Constraint: Local and file-backed origin remotes cannot satisfy the gh PR merge flow Rejected: Treat any origin remote as mergeable | it leaves codex-agent waiting on a PR surface that does not exist Confidence: high Scope-risk: narrow Directive: Keep auto-finish gated on a real mergeable remote context unless a test harness explicitly injects a fake gh binary Tested: openspec validate agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42 --type change --strict; openspec validate --specs; node --test --test-name-pattern "codex-agent restores local branch and falls back to safe worktree start when starter script switches in-place" test/install.test.js; node --test --test-name-pattern "codex-agent launches codex inside a fresh sandbox worktree and keeps branch/worktree by default" test/install.test.js Not-tested: Full node --test test/install.test.js still fails 2 unrelated codex-agent regressions in this stale worktree baseline --- .../proposal.md | 17 ++++----- .../fix-remaining-cli-ci-failures/spec.md | 37 +++++++------------ scripts/codex-agent.sh | 18 ++++++++- templates/scripts/codex-agent.sh | 18 ++++++++- test/install.test.js | 3 +- 5 files changed, 57 insertions(+), 36 deletions(-) diff --git a/openspec/changes/agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42/proposal.md b/openspec/changes/agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42/proposal.md index f4e81ae..bb86354 100644 --- a/openspec/changes/agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42/proposal.md +++ b/openspec/changes/agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42/proposal.md @@ -1,21 +1,18 @@ ## Why -- `main` still fails the `CI` workflow after `7.0.14` because several unit tests no longer match the current Guardex CLI/output contract. -- One runtime path is also still wrong: `agent-branch-finish.sh` ignores `branch..guardexBase` and falls back to `dev`, which breaks `main`-only finish flows. +- `origin/main` already absorbed the earlier branch-start/finish and doctor parity fixes, but one `codex-agent` fallback regression still remains. +- When `codex-agent` falls back to a direct worktree start in repos whose `origin` is only a local/file remote, it still tries the PR auto-finish path and waits on a merge surface that does not exist. ## What Changes -- Make `agent-branch-finish.sh` and its install template prefer stored `guardexBase` branch metadata before falling back to repo defaults. -- Make `agent-branch-start.sh` and its install template print the resolved base branch in the suggested finish command instead of hardcoding `dev`. -- Update focused test expectations to the current Guardex naming and status/output contract (`agent/codex/...`, `scripts/*`, current self-update entrypoint behavior, and current doctor reporting text). +- Make `scripts/codex-agent.sh` and its install template skip PR auto-finish when the repo only has a local/file-backed `origin`, keeping the sandbox branch/worktree instead of entering `--wait-for-merge`. +- Keep the fallback regression coverage aligned with the actual branch-owner slug emitted by the runtime instead of hardcoding `agent/codex/...`. ## Impact - Affected runtime surfaces: - - `scripts/agent-branch-start.sh` - - `scripts/agent-branch-finish.sh` - - matching template scripts + - `scripts/codex-agent.sh` + - `templates/scripts/codex-agent.sh` - Affected regression coverage: - `test/install.test.js` - - `test/metadata.test.js` -- Risk is narrow and limited to branch-finish base resolution plus CLI/test expectation parity. +- Risk is narrow and limited to local-remote `codex-agent` auto-finish detection plus fallback test expectation parity. diff --git a/openspec/changes/agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42/specs/fix-remaining-cli-ci-failures/spec.md b/openspec/changes/agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42/specs/fix-remaining-cli-ci-failures/spec.md index afdff18..0d94051 100644 --- a/openspec/changes/agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42/specs/fix-remaining-cli-ci-failures/spec.md +++ b/openspec/changes/agent-codex-fix-remaining-cli-ci-failures-2026-04-21-11-42/specs/fix-remaining-cli-ci-failures/spec.md @@ -1,28 +1,19 @@ ## ADDED Requirements -### Requirement: branch finish honors stored agent base metadata -Guardex SHALL use the stored `branch..guardexBase` value when finishing an agent branch unless the caller explicitly overrides `--base`. +### Requirement: codex-agent skips PR auto-finish for local/file remotes +Guardex SHALL keep `codex-agent` sandbox branches local when the repo only has a local/file-backed `origin` that cannot support a mergeable PR flow. -#### Scenario: finish runs in a main-only repo -- **GIVEN** an agent branch created from `main` -- **AND** Guardex stored `branch..guardexBase=main` -- **WHEN** `scripts/agent-branch-finish.sh --branch ` runs without an explicit `--base` -- **THEN** Guardex SHALL finish against `main` -- **AND** it SHALL NOT fall back to `dev`. +#### Scenario: fallback sandbox on a local bare origin +- **GIVEN** `scripts/codex-agent.sh` falls back to a direct worktree start +- **AND** the repo `origin` remote resolves to a local path or `file://` URL +- **WHEN** the task run exits successfully +- **THEN** Guardex SHALL skip the PR auto-finish merge/wait path +- **AND** it SHALL keep the sandbox branch/worktree for manual follow-up instead of waiting on merge. -### Requirement: branch start prints the resolved finish base -Guardex SHALL print the actual resolved base branch in the suggested finish command emitted by `agent-branch-start`. +### Requirement: fallback regression accepts the actual owner slug +Focused codex-agent regression coverage SHALL match the branch owner slug emitted by the runtime instead of hardcoding one historical agent family. -#### Scenario: protected base is main -- **GIVEN** an agent branch created from `main` -- **WHEN** `scripts/agent-branch-start.sh` prints next steps -- **THEN** the suggested finish command SHALL include `--base main` -- **AND** it SHALL match the stored `guardexBase` metadata. - -### Requirement: CI regression tests track current Guardex CLI output -Focused CI coverage SHALL match the current Guardex naming and reporting contract for doctor/setup/self-update/codex-agent flows. - -#### Scenario: current naming contract is exercised -- **WHEN** the doctor and codex-agent regression tests run -- **THEN** they SHALL expect current `agent/codex/...` branch names and `agent__codex__...` worktree paths -- **AND** they SHALL match the current `gitguardex` output strings rather than deprecated `guardex` or older role-specific naming. +#### Scenario: fallback branch is created +- **WHEN** the fallback codex-agent regression runs +- **THEN** it SHALL accept the emitted `agent//...` branch prefix +- **AND** it SHALL still verify the local-remote auto-finish skip message and kept-sandbox behavior. diff --git a/scripts/codex-agent.sh b/scripts/codex-agent.sh index a0265cd..b669288 100755 --- a/scripts/codex-agent.sh +++ b/scripts/codex-agent.sh @@ -372,6 +372,17 @@ has_origin_remote() { git -C "$repo_root" remote get-url origin >/dev/null 2>&1 } +origin_remote_supports_pr_finish() { + local origin_url + origin_url="$(git -C "$repo_root" remote get-url origin 2>/dev/null || true)" + case "$origin_url" in + ''|/*|./*|../*|file://*) + return 1 + ;; + esac + return 0 +} + resolve_worktree_base_branch() { local _wt="$1" if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -n "$BASE_BRANCH" ]]; then @@ -685,7 +696,12 @@ run_finish_flow() { echo "[codex-agent] Auto-finish requires GitHub CLI for PR flow; command not found: ${GUARDEX_GH_BIN:-gh}" >&2 return 2 fi - finish_args+=(--via-pr) + if origin_remote_supports_pr_finish; then + finish_args+=(--via-pr) + else + echo "[codex-agent] Origin remote does not provide a mergeable PR surface; skipping auto-finish merge/PR pipeline." >&2 + return 2 + fi else echo "[codex-agent] No origin remote detected; skipping auto-finish merge/PR pipeline." >&2 return 2 diff --git a/templates/scripts/codex-agent.sh b/templates/scripts/codex-agent.sh index a0265cd..b669288 100755 --- a/templates/scripts/codex-agent.sh +++ b/templates/scripts/codex-agent.sh @@ -372,6 +372,17 @@ has_origin_remote() { git -C "$repo_root" remote get-url origin >/dev/null 2>&1 } +origin_remote_supports_pr_finish() { + local origin_url + origin_url="$(git -C "$repo_root" remote get-url origin 2>/dev/null || true)" + case "$origin_url" in + ''|/*|./*|../*|file://*) + return 1 + ;; + esac + return 0 +} + resolve_worktree_base_branch() { local _wt="$1" if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -n "$BASE_BRANCH" ]]; then @@ -685,7 +696,12 @@ run_finish_flow() { echo "[codex-agent] Auto-finish requires GitHub CLI for PR flow; command not found: ${GUARDEX_GH_BIN:-gh}" >&2 return 2 fi - finish_args+=(--via-pr) + if origin_remote_supports_pr_finish; then + finish_args+=(--via-pr) + else + echo "[codex-agent] Origin remote does not provide a mergeable PR surface; skipping auto-finish merge/PR pipeline." >&2 + return 2 + fi else echo "[codex-agent] No origin remote detected; skipping auto-finish merge/PR pipeline." >&2 return 2 diff --git a/test/install.test.js b/test/install.test.js index 436168b..c36bcf8 100644 --- a/test/install.test.js +++ b/test/install.test.js @@ -3109,7 +3109,8 @@ test('codex-agent restores local branch and falls back to safe worktree start wh assert.equal(launch.status, 0, launch.stderr || launch.stdout); const combinedOutput = `${launch.stdout}\n${launch.stderr}`; assert.match(combinedOutput, /Unsafe starter output/); - assert.match(combinedOutput, /\[agent-branch-start\] Created branch: agent\/codex\//); + assert.match(combinedOutput, /\[agent-branch-start\] Created branch: agent\/[^/]+\//); + assert.match(combinedOutput, /Origin remote does not provide a mergeable PR surface; skipping auto-finish merge\/PR pipeline/); const launchedBranch = extractCreatedBranch(combinedOutput); const launchedCwd = fs.readFileSync(cwdMarker, 'utf8').trim();