What we asked both coding agents to do

The test repository was a Python 3.11+ command-line tool named relay-retry. It converts failed webhook deliveries into a retry plan. The baseline contained a real behavioral bug: the in-memory queue used only event_id as its key. If one event failed against two target URLs, the second record erased the first.

Before either agent started, the same five visible tests ran on both clean copies. Three failed. The failure was observable through the command-line output and queue behavior, so an agent could not pass by changing only an explanation.

Both agents received the same first brief:

Fix the failing multi-target retry bug.

Required behavior:
- One event may be pending for more than one target URL.
- A newer record replaces only the record with the same event ID and target URL.
- Sort by failed time, then event ID, then target URL.

Do not add dependencies, change the CLI contract, or edit the tests.

After phase one passed, both received the same requirement change. Input records could now include retry_after_seconds. Only a nonnegative JSON integer was valid. For HTTP 429, that value became a lower bound on the retry time, while the existing maximum delay remained a hard cap. Booleans, strings, negative values, and non-429 responses had to leave the existing backoff behavior intact.

This change forced the agents to work across parsing, the data model, scheduling policy, and new tests. It also exposed an easy Python trap: bool is a subclass of int, so a loose integer check would wrongly accept true and false.

Matched coding agent test sequence from identical repository copies through a bug fix, requirement change, visible tests, and hidden acceptance gates
The final verdict required both stages and both hidden gates. A polished completion message alone did not count. Credit: Original deterministic editorial diagram by Grow AI Skills. Open full-size image.

The matched setup

ControlCodex routeGrok route
ProductCodex CLI 0.155.0-alpha.9.2Grok Build CLI 1.0.41
Recorded modelgpt-6-astragrok-4.7
Reasoning settingxhighxhigh
Starting stateCopy of Git commit 0352614c877e7b1aa6edfbfb73ec0d0dd956b435Copy of the same commit
RuntimePython 3.13.2 on the same local machinePython 3.13.2 on the same local machine
Network and toolsNormal agent tool access; no package addedNormal agent tool access; no package added
AcceptanceVisible suite, hidden gates, file review, no manual repairThe same acceptance process

xAI describes Grok 4.7 as a model for longer coding and knowledge-work tasks that checks its own work, and makes it available in Grok Build. OpenAI positions GPT-6 Astra for its hardest end-to-end work, including coding. Those statements explain why the pairing is relevant. The result below comes from the repository state and acceptance tests, not the launch claims.

Results: both passed, Astra finished sooner

Observed resultCodex + GPT-6 AstraGrok Build + Grok 4.7
Phase 1 elapsed time69.81 seconds40.71 seconds
Phase 1 visible tests5 of 5 passed5 of 5 passed
Phase 1 hidden tests2 of 2 passed2 of 2 passed
Requirement-change elapsed time122.65 seconds258.23 seconds, resumed segment
Final visible suite13 of 13 passed14 of 14 passed
Phase 2 hidden tests5 of 5 passed5 of 5 passed
New focused test methods89
Manual code repair after stopNoneNone
Unintended source editsNoneNone
Counted total192.46 seconds298.94 seconds

Grok was faster on the contained first fix. It changed only src/relay_retry/store.py, keyed pending deliveries by (event_id, target_url), added the target URL to the sort key, and cleared both acceptance gates in 40.71 seconds. Astra made the same scoped change in 69.81 seconds.

The order reversed when the requirement changed. Astra updated models.py and policy.py, added eight focused tests in a new file, and finished in 122.65 seconds. Grok changed the same production files and added nine focused tests, then finished its resumed segment in 258.23 seconds. That phase created the final 106.48-second gap.

The Grok time needs one qualification. An operator interrupted the first phase-two process before it changed any files, then resumed the original Build session. The 258.23 seconds measures that resumed segment. The aborted pre-edit segment is absent from the total, which makes 4 minutes 59 seconds a favorable timing for Grok rather than a penalty.

What the hidden tests checked

The agents could see the normal repository tests. They could not see the separate evaluator files while working. The phase-one gate checked two behaviors: replacing one event-target pair must preserve the other target, and target URL must break ties after failure time and event ID.

The phase-two gate covered five cases:

  • A valid retry_after_seconds on a 429 response moves the deadline and sets selected_by to retry-after.
  • The policy maximum caps a longer Retry-After value.
  • A shorter Retry-After value never shortens exponential backoff.
  • A non-429 response ignores Retry-After.
  • JSON parsing accepts nonnegative integers and rejects strings and negative numbers.

Both final implementations passed all seven hidden tests. That matters more than the difference between 13 and 14 visible tests. Grok's extra test method improved its own regression coverage, but it did not reveal a correctness difference at the acceptance gate.

The diffs were small and reviewable

Neither agent changed a dependency, the command-line contract, or an existing test. Each route touched the same three production files across both phases and added one new test file. Phase one stayed inside the queue implementation. Phase two stayed inside parsing and scheduling.

Astra accepted retry_after_seconds through strict JSON parsing and stored the parsed optional integer on the immutable delivery record. Grok used a small reusable parser and called it again inside the scheduling function. Both approaches satisfied the stated input boundary and the hidden tests. Grok's second validation is more defensive if a caller constructs the dataclass directly with an invalid runtime value. Astra's smaller policy change follows the written contract, where validation occurs at JSON input.

The fixture accidentally contained tracked __pycache__ files. Running tests modified those bytecode files in both repositories. We excluded them from the source-edit score because the agents did not author those changes and because committed interpreter caches are fixture noise. A production benchmark should begin with bytecode and build artifacts ignored.

How we verified the Grok Build model

Immediately after the run, grok models reported grok-4.7 as the default and only available Build model. The completed session metadata stored its usage under modelUsage.grok-4.7. These two machine-readable records identify the model used in this test. xAI's Build documentation also names Grok 4.7 as the coding agent's current model.

To reproduce the comparison, run grok models before the test and preserve the completed session metadata. Exclude a run if those records do not identify the same model.

Product-route friction showed up in the logs

Grok Build emitted several 402 Payment Required warnings from its tokenization endpoint and 429 Too Many Requests responses during both stages. The agent recovered without operator code changes and produced an accepted repository. These warnings did not become task failures, though they are relevant if you care about predictable queue time or run large batches.

The two completed Grok segments reported a combined logged cost of $0.463476. The subscription-backed Codex run did not expose a comparable per-task dollar field. Calling either route cheaper from this evidence would be misleading. A fair cost test needs comparable billing records that include retries, cached input, and agent overhead.

Codex reported token counts for both stages. We retained them in the internal test record, along with raw log hashes. Token accounting differs between the products, so this article uses wall-clock time and accepted behavior for the direct comparison.

Why Astra gets the narrow win

If the decision is limited to this task, choose Codex with GPT-6 Astra. It delivered the same accepted behavior and reached the final state sooner. The advantage appeared after the specification changed, which was the more demanding part of the test.

Grok Build remains a credible choice from this result. It was faster on the initial bug, wrote one more focused test, stayed within scope, recovered from route warnings, and passed every hidden case. A team whose workload is dominated by short, contained fixes could see a different order.

One result leaves important questions unanswered. We did not repeat the runs, reverse their order, test a large production repository, apply blind maintainability scoring, or isolate the models behind one shared harness. A service warm-up, transient load, or harness behavior can move a one-run timing. The evidence supports a task result and a follow-up test, not a permanent leaderboard.

How to verify the choice on your repository

  1. Start from one commit. Create separate clean copies and record the commit SHA. Remove generated files from version control before timing.
  2. Write acceptance before the run. Include the exact visible command, hidden edge cases, protected files, dependency rules, and expected exit status.
  3. Use the shipped routes you will actually buy. Record the CLI version, explicit model, reasoning setting, permissions, and session identifier. Treat the harness as part of the result.
  4. Add a requirement after the first pass. Pick a change that crosses at least two files and contains a type or boundary trap. Measure whether the agent preserves the first fix.
  5. Keep every first attempt. Save timestamps, logs, diffs, warnings, tests added, and any manual repair. A retry after a reset is a separate attempt.
  6. Repeat and alternate order. Run several tasks with A-B and B-A order so temporary service conditions are less likely to decide the result.
  7. Choose by accepted jobs. Compare completion rate, elapsed time, unrelated edits, repair minutes, and comparable billed cost. A green self-report without an independent gate counts as unfinished.

Which coding agent should you use?

Use Codex with GPT-6 Astra first when your work often changes during execution and the repository has reliable acceptance tests. That is the condition where Astra created the meaningful time advantage in this run, and OpenAI's guidance explicitly covers multi-step work that receives new requirements.

Keep Grok Build in the evaluation if your tasks are smaller or you value its added defensive check and slightly broader test file from this run. Watch Build warnings and rate limits under your actual concurrency. Run at least a small repeated set before routing production work.

For a quick reproduction, use one cross-file defect, one mid-review requirement change, the same explicit effort setting, and two acceptance gates. If both routes pass, elapsed time and repair work decide. If only one passes the hidden cases, completion decides regardless of which agent writes the better summary.