fix(sandbox): resolve codex-prefixed pull request roles - #164
Open
igoraboim wants to merge 1 commit into
Open
Conversation
`githubPullRequestMode` was the only role predicate that did not strip the `codex-` prefix from `runs.mode`, so a Codex-engine reviewer or repair agent resolved to a different role than its Claude counterpart. Because `runs.mode` is the agent's name and Codex agents carry a `codex-` prefix by convention (the seeded `codex-architect` and `codex-builder`), a project that adds `codex-review`, `codex-address-review` or `codex-ci-doctor` gets `checkoutBranch = null` in `buildRunBundle` and clones the default branch instead of the pull request's branch: - `codex-review` silently reviews the default branch while reporting on the pull request. - `codex-address-review` and `codex-ci-doctor` also pin an admitted head via `repairExpectedHeadSha`, which does strip the prefix, so the bundle asks the runner to clone the default branch and verify the pull request's head. The run fails at `repository_head_sha_mismatch` before provisioning. Strip the prefix exactly as `readOnlyRepositoryMode` and `repairPullRequestMode` already do, and pin the invariant that the checked-out branch and the pinned head agree for every repair role. Co-Authored-By: Claude <noreply@anthropic.com>
|
Hit this exact bug independently while auditing the runner/gate boundary, before finding this PR — same fix ( |
adrian-lorenzo
approved these changes
Aug 19, 2026
adrian-lorenzo
left a comment
Member
There was a problem hiding this comment.
Thanks for the solid contribution!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #163.
What changes
githubPullRequestModenow strips thecodex-prefix fromruns.mode, exactly asreadOnlyRepositoryModeandrepairPullRequestModealready do. After this, a Codex-engine reviewer or repair agent resolves to the same governed role as its Claude counterpart and receives the pull request's branch in its run bundle.Why
runs.modeis the agent's name (routes/v1/runs.ts:246) and Codex agents carry acodex-prefix by convention — the seed shipscodex-architectandcodex-builder(packages/db/src/seed.ts:52-53).githubPullRequestModewas the only role predicate that did not normalise that prefix, and it decides whether the bundle gets the PR branch (orchestrator.ts:1733).A project that follows the naming convention and adds a Codex reviewer or repair agent gets
checkoutBranch = nulland clones the default branch:codex-reviewreviews the default branch while reporting on the pull request — silent.codex-address-review/codex-ci-doctoralso pin an admitted head throughrepairExpectedHeadSha, which does strip the prefix. The bundle then asks the runner to clone the default branch and verify the PR's head, so the run fails atrepository_head_sha_mismatch(runner/src/index.ts:460-471) before provisioning.The two predicates disagreed about the same run. The second test added here pins that agreement rather than just the prefix handling, so the invariant survives a future role being added to one list and not the other.
The predicate is exported to make it testable, following the precedent of
repairExpectedHeadSha(exported and covered intest/sandbox.test.ts).Verification
services/apifull suite: 234 passed, 16 skipped (npx vitest run --fileParallelism=false). The skips are the Docker/Postgres-backed tiers — see the caveat below.test/sandbox.test.ts,test/orchestrator-checks.test.ts,test/ci-doctor-policy.test.ts,test/address-review-policy.test.ts,test/sandbox-capabilities.test.ts— 69 passed in the four policy suites.node guards/run.mjs— 2 guards ran, 0 failed.npx tsc --noEmitinservices/api— clean.npx biome checkon both changed files — clean.githubPullRequestModeto its previous body and re-ran: both new cases fail (expected false to be true, at thecodex-assertions and at the branch/head agreement check), then pass again with the fix restored. They are a regression pin, not a restatement.Caveat, stated plainly: I could not run
pnpm verifyend to end — Docker is unavailable on this machine, so the isolated-database integration tier and the sandbox E2E could not execute locally. Everything above is what I could actually run. I also have not exercised this against a live Codex agent; the impact description is traced from the code path, and I would value a maintainer sanity-check on how you expect projects to name Codex agents.pnpm verifypasses locally — not run, no Docker available; see the caveat abovebuildRunBundleto the runner'srepository_head_sha_mismatchcheck