fix(runtime): Codex route checks follow openai_base_url the way Codex does, and -smithers paths stay intact in diagnostics - #1210
Merged
Conversation
| // Redirects the built-in openai provider when that is the one selected. | ||
| openai_base_url: config.openai_base_url ?? null | ||
| // Redirects only the built-in openai provider. | ||
| openai_base_url: selected === "openai" ? (config.openai_base_url ?? null) : null |
There was a problem hiding this comment.
Upgrades strand in-flight Codex runs A run planned with a custom Codex provider and a top-level
openai_base_url keeps its original route ID in sealed governance. After an upgrade, a plain resume loads the new runtime, and this line computes a different ID even though the provider endpoint has not changed. The adapter rejects every subsequent Codex task as an unacknowledged route. Preserve compatibility with the recorded ID or provide a way to migrate the run without re-planning it.
Knowledge Base Used: Execution runtime
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/runtime/src/data-governance.ts
Line: 456
Comment:
**Upgrades strand in-flight Codex runs** A run planned with a custom Codex provider and a top-level `openai_base_url` keeps its original route ID in sealed governance. After an upgrade, a plain resume loads the new runtime, and this line computes a different ID even though the provider endpoint has not changed. The adapter rejects every subsequent Codex task as an unacknowledged route. Preserve compatibility with the recorded ID or provide a way to migrate the run without re-planning it.
**Knowledge Base Used:** [Execution runtime](https://app.greptile.com/monad-foudnation/-/custom-context/knowledge-base/monad-developers/ultrafuzz/-/docs/execution-runtime.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.…hen Codex uses it codexRouteConfig digested the top-level openai_base_url only when a model_provider line existed, and then for every selected provider. Codex does neither. With no model_provider it uses its built-in openai provider, and openai_base_url redirects only that provider. A live Codex 0.158.0 run with a fake key against local servers showed both: with only openai_base_url set, all 13 requests went to that URL with the bearer key; with model_provider = "private" (its own base_url) plus openai_base_url, all 6 requests went to the private base_url and none to openai_base_url. So a config.toml holding only openai_base_url = <gateway> planned and acknowledged model:openai while Codex sent every task to the gateway, and a later edit of that URL still passed the per-invocation route check. With a custom provider selected, editing a leftover, unused openai_base_url line changed the route ID, so every later Codex task failed with "effective CodexAgent provider route changed after disclosure acknowledgement". The selection now falls back to "openai" when openai_base_url is non-empty, and openai_base_url is digested only when the selected provider is openai. Codex 0.158.0 drops an empty openai_base_url and uses its default endpoint, so openai_base_url = "" with no model_provider stays model:openai. Configs without openai_base_url keep their route IDs. An openai_base_url-only config now gets the same ID as the explicit model_provider = "openai" form, and a custom provider plus openai_base_url gets the ID it has without that line. Each changed ID needs a new ULTRAFUZZ_DATA_GOVERNANCE_POLICY row plus re-acknowledgement, and a run planned with such a config before this change has to be re-planned rather than resumed. Traced, not run end to end: native resume points the adapters at the installed runtime, so they compute the new ID and every Codex task fails the route check against the run's sealed acknowledgement. Cloud planning now rejects a host config.toml that sets only a non-empty openai_base_url, as it already rejected one that sets model_provider. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…gnostics publicWorkflowText renames the runner's own `smithers <command>` suggestions before the path-preserving scrub runs. #1194 stopped the rename from firing after a path separator or a dot, but it still fired after any other non-word character. A path whose last segment ends in "smithers" after a hyphen (or @, +, ~, ...) and is followed by a space and a word was rewritten before the scrub could keep it whole: "spawn /opt/runner/pre-smithers ENOENT" became "spawn /opt/runner/pre-workflow runner ENOENT", and "Command failed: /opt/tools/pinned-smithers why --run-id r1" became "Command failed: /opt/tools/pinned-`ultrafuzz why` --run-id r1". Exposure is narrow. On Linux the runner is executed through /proc/<pid>/fd paths, so a failed runner query does not name the runner's own path (a probe with a failing runner at <dir>/pinned-smithers reported "Command failed: /proc/<pid>/fd/29 /proc/<pid>/fd/28 why ..."), and a missing runner is reported as "ENOENT: ... open '<path>'", which the rename leaves alone. The rewrite still applies to any other text that reaches publicWorkflowText: runner stderr, `why` prose, event labels and details, and node errors. The rename now fires only where "smithers" starts a word: at the start of the text, or after whitespace, a quote, a backtick, or an opening parenthesis or bracket. The scrub still replaces the name in prose. Over the 1,064 string literals that mention "smithers" in packages/*/src and packages/*/test, main's and the new publicWorkflowText differ only on this change's own new pre-smithers strings. Over the 1,664 distinct lines that mention `smithers <word>` in the pinned Smithers 0.35.0 packages they differ on one, an HTML <title> template in @smthrs/cli's runReport.js. The diagnoseRun fixture now also carries a hint after whitespace ("then run smithers inspect"), the form missing from the tests, so narrowing the lookbehind to the start of the text and backticks fails. Co-Authored-By: Claude Opus 5.5 <[email protected]>
aviggiano
force-pushed
the
claude/g2-runtime-greptile-fixes
branch
from
September 29, 2026 15:31
c03617b to
acf8567
Compare
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.
Problem
openai_base_urlwith nomodel_providerwas acknowledged asmodel:openai(Greptile on #1173).codexRouteConfig(added in fix(runtime): agent adapters never hang or reroute on telemetry and environment quirks #1173) reported no route unless amodel_providerline existed. Aconfig.tomlholding onlyopenai_base_url = "<gateway>"was therefore planned and acknowledged asmodel:openai, and a later edit of that URL still passed the per-invocation route check. When nothing selects a provider, Codex uses its built-inopenaiprovider, andopenai_base_urlredirects it. A live Codex 0.158.0 run whose config set onlyopenai_base_url = "http://127.0.0.1:47211/v1"sent all 13/v1/responsesrequests there, each with the bearer key. The gap predates fix(runtime): agent adapters never hang or reroute on telemetry and environment quirks #1173: the earliercodexConfigAffectsRouteregex never matchedopenai_base_url. fix(runtime): agent adapters never hang or reroute on telemetry and environment quirks #1173 listed it under "Deliberately not built" as a follow-up.openai_base_urlstopped every later Codex task (Greptile on #1173). Whenmodel_providerselected a custom provider,openai_base_urlwas still digested, even though it redirects only the built-inopenaiprovider. In a live run with a custombase_urlon :47212 andopenai_base_urlon :47211, Codex sent 6 requests to :47212 and none to :47211. Editing or deleting that leftover line mid-campaign changed the route ID. Every later Codex task then failed inbuildCommandwitheffective CodexAgent provider route changed after disclosure acknowledgement, although traffic still went to the same endpoint. fix(runtime): agent adapters never hang or reroute on telemetry and environment quirks #1173's field-level digest still includedopenai_base_urlfor every selected provider; before fix(runtime): agent adapters never hang or reroute on telemetry and environment quirks #1173 the whole file was hashed, so any edit failed the same way.-smithers(Greptile on #1194).publicWorkflowTextrenames the runner's ownsmithers <command>suggestions before the path-preserving scrub runs. fix: observers and benchmark harnesses survive transient failures and report real paths #1194's lookbehind skipped only/,\and., so the rename still fired after-,@,+,~and similar characters.spawn /opt/runner/pre-smithers ENOENTbecamespawn /opt/runner/pre-workflow runner ENOENT, andCommand failed: /opt/tools/pinned-smithers why --run-id r1becameCommand failed: /opt/tools/pinned-`ultrafuzz why` --run-id r1. The exposure is narrow. On Linux the runner runs through/proc/<pid>/fd/<n>paths, so a failed runner query does not name the runner's own path. A probe with a failing runner at<dir>/pinned-smithersreportedCommand failed: /proc/<pid>/fd/29 /proc/<pid>/fd/28 why .... A missing runner readsENOENT: ... open '<path>', which the rename leaves alone. The rewrite still hits any other text that reachespublicWorkflowText: runner stderr,whyprose, event labels and details, and node errors.Change
codexRouteConfig(packages/runtime/src/data-governance.ts): when nothing selects a provider butopenai_base_urlis non-empty, the selected provider falls back to"openai". Codex 0.158.0 drops an emptyopenai_base_urland uses its default endpoint (codex-rs/core/src/config/mod.rs:.filter(|value| !value.is_empty())), soopenai_base_url = ""with nomodel_providerstaysmodel:openai, as on main.openai_base_urlis digested only when the selected provider isopenai. Otherwise it isnull, the value a config without the key already had.docs/security.md, the function's doc comment and the inline comment now describe this rule.publicWorkflowText(packages/runtime/src/lifecycle-inspection.ts): the rename's\b(?<![\\/.])becomes(?<=^|[\s"'`([]). The rename now fires only wheresmithersstarts a word: at the start of the text, or after whitespace, a quote, a backtick,(or[.scrubWorkflowRunnerTextstill replaces the name in prose.Overlaps with in-flight work
origin/claude/x04-operator-hints-use-ultrafuzz-commands, fd6015b "a runner error suggests neither a runner command nor an invented one") edits the same regex line: it drops theiflag. Whichever lands second gets a one-hunk conflict inpublicWorkflowText. Resolve it by keeping this branch's lookbehind with x04'sguflags and both comment lines. With that combined regex patched into this branch's compiled module, bothdiagnoseRunpublic-text tests pass. x04'spublicRecoveryTextstill sends non-command text throughpublicWorkflowText, so the two changes compose.git merge-treenow reports come from test(runtime): delete vacuous and source-text tests, keep behavioural coverage #1203 on origin/main, not from this branch. They are x04 and feat(runtime)!: run lifecycle commands from the pnpm-patched install instead of per-command npm installs (#921 step 1) #1201 inlifecycle-inspection.test.ts, and refactor!: remove per-node cloud execution (execution.mode = "cloud") #1197 and fix(runtime): record final-report producer selections in the run instead of querying smithers #1183 ingenerated-workflow-verifier.test.ts. origin/main alone conflicts with those branches in the same hunks, and this branch's test lines merge outside them. x01, x02, x03, x05 and feat(topology)!: a failed property lens no longer skips the rest of the campaign #1198 merge cleanly. fix(modal): keep the model-work flag when a model node has no run-state record #1202 has merged. feat(runtime): let agents record roadblocks in a run-local friction log #1162 conflicts with origin/main in files this branch does not touch.Deliberately not fixed
origin/claude/x05-typed-resume-result, dd04ef2 "doctor stops sizing leftover controller roots after a second"), so it is not repeated here.Follow-up (needs a GitHub issue; this branch opens none)
openai_base_url. This is not a Greptile finding and is not changed here.addCodexProviderRoute(templates/smithers/agents/codex.tsx) setsOPENAI_BASE_URLonly from amodel_providertable. With onlyopenai_base_urlset, it leavesOPENAI_BASE_URLunset, and Smithers' key preflight probes the inherited or default endpoint with the configured key instead of the gateway Codex will use. That is the case the function's own comment says it prevents: "an ambient endpoint can receive the configured provider's credential during preflight". Traced in code, not run. Smithers logs failed preflight probes as non-blocking (seen in the Bun contract run), so this would send a credential to the wrong endpoint but would not stop a campaign.Verification
Discriminating tests (runtime, node:test), on this branch rebased onto origin/main 142ba80. Each variant below patches one compiled module in a copy of
dist-testand runs the named test.data-governance.test.ts› "Codex CLI bookkeeping in config.toml does not change the acknowledged route" gains three assertions:openai_base_urlline inside the "nothing else in the file" custom-provider config;openai_base_url-only config, which must equal the explicitmodel_provider = "openai"form;openai_base_url = "", which must staymodel:openai.Results:
+ 'model:codex-route-ce49f638…' - 'model:codex-route-b40823df…'.openai_base_urlternary: fails at the implicit-openai assertion with+ 'model:openai' - 'model:codex-route-2a585365…'.=== undefineddefault selection: fails at the empty-URL assertion with+ 'model:codex-route-b43c6ddf…' - 'model:openai'.lifecycle-inspection.test.ts› "diagnoseRun keeps a runner path intact in public text" gains the notespawn /opt/runner/pre-smithers ENOENT.+ 'spawn /opt/runner/pre-workflow runner ENOENT' - 'spawn /opt/runner/pre-smithers ENOENT'.lifecycle-inspection.test.ts› "diagnoseRun adapts the engine diagnosis without engine-branded public text" gains the notethen run smithers inspect, expected asthen run `ultrafuzz inspect`. This pins the whitespace case of the new lookbehind, the most common form in the engine's own text. main renames it too, so the test passes on main by design.(?<=^|[`]): fails with+ 'then run workflow runner inspect' - 'then run `ultrafuzz inspect`'.",',(and[cases remain unpinned by tests. The engine scan below covers them.Regression and behaviour checks:
lifecycle-inspection.test.js:^(diagnoseRun|queryWorkflowEvents returns lifecycle|getWorkflowNode includes attempts)pass. These include every test that asserts renamed text.'^Bun adapter contract: (planned routes equal|quoted TOML provider routes|generated Codex)'pass after the rebase. They include the plan-versus-adapter route equality and drift tests.publicWorkflowText, main's against this branch's (built dist, with the real scrub and secret redaction), over string literals that mentionsmithers, re-run after the rebase:packages/*/srcandpackages/*/test: the only outputs that change are this branch's own newpre-smithersstrings.smithers.tssource that the literal scanner picked up.smithers <word>): one output changes, an HTML<title>Smithers run — …template in@smthrs/cli/src/runReport.js. It now readsworkflow runner runinstead of`ultrafuzz run`.Hint:smithers why,x=smithers why,**smithers why**anda,smithers whynow read…workflow runner whyinstead of…`ultrafuzz why`.config.toml;openai_base_url = ""alone (model:openai);model_provider = "openai"with no URL, with URL A or B, or with"";base_url.openai_base_urlalone, or with a profile that selects no provider, now gets the explicitopenaiform's ID for that URL:3dac300ffor URL A,ad647009for URL B. main givesmodel:openai.openai_base_urlA, B or""now gets the ID it has without that line (0ec061c9). main gives08ee3b6e,dd87cc28and12678406.modelDestinationin cloud mode (execution.mode = "cloud", providermodal):config.tomlwith only a non-emptyopenai_base_url: main returnsmodel:openai, and this branch throwscloud execution cannot use host provider-home routing; ….openai_base_url = ""alone: both returnmodel:openai.openai_base_urlset: 13 requests went to it.openai_base_url: 6 requests went to the custombase_url, none toopenai_base_url.[model_providers.openai]table: Codex refuses to load it ("model_providers contains reserved built-in provider IDs:openai"). So a selectedopenaiis always the built-in provider.npx prettier --checkandnpx eslinton the changed files;CI=1 ESLINT_PLUGIN_DIFF_COMMIT=origin/main pnpm -w lint:strict:ci;pnpm -w lint;pnpm --filter @ultrafuzz/runtime typecheck;pnpm -w knip;node scripts/docs-check.mjs.Risk / compatibility
Route IDs change only for Codex configs that set a top-level
openai_base_url:openai_base_urlwith nomodel_provider.model:openaibecomesmodel:codex-route-…, the ID of the explicitmodel_provider = "openai"form with that URL. The old ID named the wrong processor. v0.1.1 also recordedmodel:openaihere, so this change is new relative to v0.1.1. The Codex CLI config mutations change the acknowledged provider route mid-run, failing every sandbox agent #908 changelog entry's "env-only IDs without those inputs are unchanged" no longer covers it. An emptyopenai_base_url, which Codex ignores, keepsmodel:openai, so runs with one are unaffected.model_providerplusopenai_base_url. The ID becomes the one the config has without that line. For upgrades from v0.1.1, the Codex CLI config mutations change the acknowledged provider route mid-run, failing every sandbox agent #908 break already changes this ID.Migration for either shape. Add the new ID to
ULTRAFUZZ_DATA_GOVERNANCE_POLICYand re-acknowledge. Without the policy row,prepareDataGovernancefails planning withDATA_GOVERNANCE_DESTINATION_NOT_ALLOWED, whatever the policy's sensitivity. Modal public benchmark runs are the exception: they derive their policy from the required destinations.In-flight runs. A run planned before this change with either shape fails every Codex task after an upgrade followed by a plain
ultrafuzz resume. This is traced in code, not run end to end:submitSmithersContinuationsetsULTRAFUZZ_RUNTIME_MODULEto the installed runtime (start-run.ts:585).providerRouteDestinationfrom that module (templates/smithers/agents/environment.tsx:13-20), so they compute the new ID.authenticatedContinuationGovernancePath,workflow-integrity.ts:432) still lists the old ID.environment.tsx:248-249therefore throwseffective CodexAgent provider route changed after disclosure acknowledgement.Finish such runs before upgrading, or re-plan them. With a custom provider, no config edit restores the recorded ID, because
openai_base_urlno longer enters that provider's digest. With onlyopenai_base_urlset, deleting the line brings backmodel:openaiand lets the resume continue. Codex traffic then goes to OpenAI, the destination the run acknowledged.Cloud planning. With
execution.mode = "cloud", planning now rejects a host Codex config that sets only a non-emptyopenai_base_url("cloud execution cannot use host provider-home routing; …"). It already rejected one that setsmodel_provider, anddocs/reference/cloud-execution.mddocuments that rejection. main planned this case asmodel:openai. The check runs only at plan time:prepareDataGovernanceinplan-run.tsis its only caller, so no in-flight run is affected. It becomes moot once draft refactor!: remove per-node cloud execution (execution.mode = "cloud") #1197, which deletes the guard, lands.Diagnostic text.
publicWorkflowTextonly affects diagnostic text, so no run outcome changes. A runner suggestion glued to a preceding character other than whitespace, a quote, a backtick,(or[is now scrubbed toworkflow runner <command>instead of renamed to`ultrafuzz <command>`.Validator identity. No validator, schema or contract-description files are touched, so
VALIDATOR_BUILD_IDENTITYdoes not change.Changelog entry
Breaking changes (or fold into the #908 route-ID entry):
config.tomlwith a non-empty top-levelopenai_base_urland nomodel_provideris now acknowledged as its own route (the ID of the explicitmodel_provider = "openai"form) instead ofmodel:openai, and cloud planning rejects it as it rejects amodel_providerconfig; with a custommodel_providerselected,openai_base_url, which Codex then ignores, no longer counts, so editing it no longer fails later Codex tasks with "provider route changed after disclosure acknowledgement". Route IDs change for both config shapes: updateULTRAFUZZ_DATA_GOVERNANCE_POLICY, re-acknowledge, and re-plan rather than resume a run whose acknowledged ID changed (with onlyopenai_base_urlset, deleting that line also lets such a run resume, sending Codex traffic to OpenAI as acknowledged).Other changes:
/opt/tools/pinned-smithersintact instead of rewriting part of it.Greptile follow-up
**smithers why**was scrubbed to**workflow runner why**instead of becoming`ultrafuzz why`(comment).*is now a word boundary for the rename. ThediagnoseRun keeps a runner path intact in public texttest gains that case. It fails with the old boundary set, and paths such aspre-smithersstill pass through unchanged.Rebased onto
mainafter #1207. Both PRs changed the rename's regex; the rebase keeps this PR's standalone-word boundary, #1207's lowercase-only flags and its comment.🤖 Generated with Claude Code
The PR appears safe to merge; no new actionable issue or outstanding previous finding remains.
Fix with agent prompt
Summary
The PR makes Codex route acknowledgement account for a non-empty
openai_base_urlwhen no provider is selected, excludes that URL when a custom provider is selected, and preserves-smitherspath suffixes in diagnostics. Tests and security documentation cover the changed behavior.Reviews (2) · Last reviewed commit: "fix(runtime): a path ending in -smithers..."