Skip to content

feat(run): preflight Cloudflare AI Gateway seats for required env vars (#394) - #415

Merged
solomonneas merged 2 commits into
mainfrom
fix/394-cloudflare-preflight
Jul 21, 2026
Merged

feat(run): preflight Cloudflare AI Gateway seats for required env vars (#394)#415
solomonneas merged 2 commits into
mainfrom
fix/394-cloudflare-preflight

Conversation

@solomonneas

@solomonneas solomonneas commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

Fixes #394. A worker seat on a cloudflare-ai-gateway/<provider>/<model> route could reach dispatch and then die inside the child with Error: CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_GATEWAY_ID missing, recorded as a generic adapter failure. The route identifies the Cloudflare AI Gateway path and the required variable names are static, so this is diagnosable at plan/dispatch time.

Changes

  • Detection helpers (agents.py): is_cloudflare_ai_gateway_route (exact first-segment match, so cloudflare-ai-gateway-other/... is rejected), missing_cloudflare_ai_gateway_env_vars (empty-string counts as missing), and cloudflare_ai_gateway_preflight_detail. Names only — the secret values are never read, logged, or interpolated.
  • roster doctor (roster_cmd.py): a Cloudflare seat missing either CLOUDFLARE_ACCOUNT_ID / CLOUDFLARE_GATEWAY_ID fails, naming the missing var(s) and smallest remediation without printing values. Endpoint-mode seats are intentionally exempt.
  • Dispatch preflight on every child-launch path (run_transport.py, aboyeur.py): direct worker, the grok invalid-final fallback agent, and the orchestrator seat all preflight before launching. Missing env → failure_phase=preflight, failure_kind=provider-config, no child launched.
  • Classification propagation: the provider-config kind reaches worker results, the top-level run.json failure fields, and the human summary — not a generic adapter error.

Tests

test_agents.py (route classification incl. near-miss, missing-var lists, empty-string), test_roster_cmd.py (doctor OK/FAIL + values-not-echoed), test_run_transport_env.py (worker + fallback preflight, no child launched, values-not-echoed), test_aboyeur.py (orchestrator preflight fails before planning, run_agent asserted never called, run.json top-level classification).

Verification

./scripts/verify green (coverage 82.42% ≥ 78 floor). Captured receipt 20260721-162830-work-verify-e170be.

Local reviewers on this machine: run verify with TMPDIR=/tmp (a .cache-path TMPDIR makes tests/guard/ spuriously fail; the scanner excludes .cache). CI is unaffected.


Note

Low Risk
Additive configuration checks on a specific model route; no changes to auth, data handling, or default run paths when env is set.

Overview
Adds early validation for seats whose model is a cloudflare-ai-gateway/... route so missing CLOUDFLARE_ACCOUNT_ID / CLOUDFLARE_GATEWAY_ID fails before any child CLI is launched, with preflight / provider-config classification instead of a generic adapter error.

New helpers in agents.py detect the route (exact first path segment), list missing env vars (empty string counts as missing; only names are surfaced), and build the preflight message. roster doctor fails or passes a per-agent Cloudflare gateway check; endpoint-mode agents stay exempt.

Preflight runs on the orchestrator (aboyeur), every worker dispatch (run_transport), and the grok invalid-final fallback agent. Plan failures that originated from orchestrator preflight now write failure_phase: preflight on run.json, and top-level failure_kind is only set when a kind is known.

Reviewed by Cursor Bugbot for commit 04cc3f8. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added preflight validation for Cloudflare AI Gateway configuration before agents run.
    • Added clear diagnostics identifying missing required configuration.
    • Added roster health checks showing whether Cloudflare Gateway configuration is ready.
  • Bug Fixes

    • Runs now stop safely before execution when provider configuration is incomplete.
    • Run receipts accurately record preflight failures without exposing sensitive configuration values.
    • Fallback execution is skipped when its provider configuration fails validation.

A worker seat on a `cloudflare-ai-gateway/<provider>/<model>` route could
reach dispatch and then die inside the child with
`CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_GATEWAY_ID missing`, recorded as a
generic adapter error. The route names the Cloudflare path and the required
variable names are static, so this is diagnosable before the child launches.

- Add `is_cloudflare_ai_gateway_route` / `missing_cloudflare_ai_gateway_env_vars`
  / `cloudflare_ai_gateway_preflight_detail` helpers (exact first-segment match;
  empty-string values count as missing; names only, never values).
- `roster doctor` fails a Cloudflare seat that is missing either variable,
  naming the missing var(s) with the smallest remediation, never printing values.
- Preflight every child-launch path before dispatch: direct worker, the grok
  invalid-final fallback agent, and the orchestrator seat. Missing env yields a
  provider-config failure (`failure_phase=preflight`, `failure_kind=provider-config`)
  instead of launching the child.
- Propagate the provider-config classification into worker results, the
  top-level run.json failure fields, and the human summary.

Endpoint-mode seats are intentionally exempt from the doctor check.

Closes #394

Co-authored-by: Cursor <cursoragent@cursor.com>
@solomonneas

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@solomonneas

Copy link
Copy Markdown
Collaborator Author

bugbot run

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • coderabbit-review

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: escoffier-labs/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 13b4ba8d-944b-418e-a009-55db03255b6b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Cloudflare AI Gateway routes now validate required environment variables during roster checks, worker dispatch, fallback dispatch, and orchestration. Missing configuration produces provider-config preflight failures, and receipts preserve the corresponding failure phase and metadata.

Changes

Cloudflare AI Gateway preflight

Layer / File(s) Summary
Provider configuration validation
src/brigade/agents.py, src/brigade/roster_cmd.py, tests/test_agents.py, tests/test_roster_cmd.py
Cloudflare route detection and required environment-variable checks are added, with roster doctor reporting missing variables without printing their values.
Worker dispatch preflight gates
src/brigade/run_transport.py, tests/test_run_transport_env.py
Worker and invalid-final fallback dispatch return provider-config preflight failures before process execution when Cloudflare configuration is missing.
Orchestrator failure receipts
src/brigade/aboyeur.py, tests/test_aboyeur.py
Orchestrator planning failures preserve the preflight phase and provider-config kind in run.json, while null failure kinds are omitted.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BrigadeRun
  participant run_transport.dispatch
  participant CloudflareGateway
  participant WorkerCLI
  BrigadeRun->>run_transport.dispatch: dispatch Cloudflare-routed worker
  run_transport.dispatch->>CloudflareGateway: check required environment variables
  CloudflareGateway-->>run_transport.dispatch: return configuration status
  alt configuration missing
    run_transport.dispatch-->>BrigadeRun: provider-config preflight failure
  else configuration present
    run_transport.dispatch->>WorkerCLI: launch worker process
    WorkerCLI-->>BrigadeRun: return worker result
  end
Loading

Suggested labels: coderabbit-review

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes match #394 by checking missing Cloudflare env vars early, classifying failures correctly, and covering both missing and present cases.
Out of Scope Changes check ✅ Passed The diff stays focused on Cloudflare AI Gateway preflight, diagnostics, result propagation, and tests with no unrelated feature work.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding preflight checks for Cloudflare AI Gateway seats and required environment variables.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/394-cloudflare-preflight

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 04cc3f8. Configure here.

Comment thread src/brigade/agents.py
missing = missing_cloudflare_ai_gateway_env_vars()
if not missing:
return None
return f"Cloudflare AI Gateway seat missing required env vars: {', '.join(missing)}; set them before running"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preflight ignores seat env

Medium Severity

Cloudflare gateway preflight calls missing_cloudflare_ai_gateway_env_vars() against os.environ only. Worker and orchestrator dispatch already merge seat env (and *_REF targets) into the child via run_agent, so seats that supply CLOUDFLARE_ACCOUNT_ID / CLOUDFLARE_GATEWAY_ID only in roster env can fail preflight with provider-config even though the adapter would receive those variables.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 04cc3f8. Configure here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/brigade/run_transport.py`:
- Around line 574-577: The fallback preflight failure path in the run flow must
preserve the prior Grok attempt history and elapsed duration. Update the
`_cloudflare_preflight_failure` result handling around `fallback_agent` so it
threads the accumulated `attempts` into the returned failure, or routes through
`finish()` while retaining that metadata; ensure the persisted WorkerResult
includes both earlier attempts. Extend
`test_cloudflare_gateway_preflight_fallback_agent_fails_without_launch` to
assert `result.attempts`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: escoffier-labs/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 798ea65d-e927-432c-b903-a179e75aeecf

📥 Commits

Reviewing files that changed from the base of the PR and between f588957 and 04cc3f8.

📒 Files selected for processing (8)
  • src/brigade/aboyeur.py
  • src/brigade/agents.py
  • src/brigade/roster_cmd.py
  • src/brigade/run_transport.py
  • tests/test_aboyeur.py
  • tests/test_agents.py
  • tests/test_roster_cmd.py
  • tests/test_run_transport_env.py

Comment thread src/brigade/run_transport.py Outdated
Comment on lines +574 to +577
fallback_agent = roster.agents[fallback_name]
fallback_preflight = _cloudflare_preflight_failure(fallback_agent, assignment)
if fallback_preflight is not None:
return fallback_preflight

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Fallback-preflight failure drops the prior grok attempt history.

By the time this fallback preflight check fires, attempts already holds the initial and continuation grok attempts (built at lines 524-534 and 545-558). Returning fallback_preflight directly bypasses finish(), so those attempts (and elapsed duration_seconds) never reach the persisted WorkerResult — the receipt for this case will show only the Cloudflare provider-config failure with an empty attempts tuple, hiding the two real grok invocations that preceded the fallback.

🔧 Proposed fix: thread `attempts` into the preflight failure
-def _cloudflare_preflight_failure(agent: Agent, assignment: Assignment) -> WorkerResult | None:
+def _cloudflare_preflight_failure(
+    agent: Agent,
+    assignment: Assignment,
+    *,
+    attempts: tuple[WorkerAttempt, ...] = (),
+) -> WorkerResult | None:
     """Return a preflight failure if the agent's Cloudflare route lacks env.

     Empty string values are treated as missing.
     """

     detail = agents.cloudflare_ai_gateway_preflight_detail(agent.model)
     if detail is None:
         return None
     return WorkerResult(
         worker=assignment.worker,
         task=assignment.task,
         text="",
         ok=False,
         detail=detail,
         failure_phase="preflight",
         failure_kind="provider-config",
+        attempts=attempts,
     )
         fallback_agent = roster.agents[fallback_name]
-        fallback_preflight = _cloudflare_preflight_failure(fallback_agent, assignment)
+        fallback_preflight = _cloudflare_preflight_failure(fallback_agent, assignment, attempts=tuple(attempts))
         if fallback_preflight is not None:
             return fallback_preflight

Consider also asserting result.attempts in test_cloudflare_gateway_preflight_fallback_agent_fails_without_launch once fixed.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fallback_agent = roster.agents[fallback_name]
fallback_preflight = _cloudflare_preflight_failure(fallback_agent, assignment)
if fallback_preflight is not None:
return fallback_preflight
fallback_agent = roster.agents[fallback_name]
fallback_preflight = _cloudflare_preflight_failure(fallback_agent, assignment, attempts=tuple(attempts))
if fallback_preflight is not None:
return fallback_preflight
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/brigade/run_transport.py` around lines 574 - 577, The fallback preflight
failure path in the run flow must preserve the prior Grok attempt history and
elapsed duration. Update the `_cloudflare_preflight_failure` result handling
around `fallback_agent` so it threads the accumulated `attempts` into the
returned failure, or routes through `finish()` while retaining that metadata;
ensure the persisted WorkerResult includes both earlier attempts. Extend
`test_cloudflare_gateway_preflight_fallback_agent_fails_without_launch` to
assert `result.attempts`.

@solomonneas solomonneas self-assigned this Jul 21, 2026
Route the Cloudflare fallback-agent preflight failure through finish() so the
accumulated grok attempt history and elapsed duration are preserved in the
persisted WorkerResult, instead of returning a bare preflight result that
dropped them.

Co-authored-by: Claude <noreply@anthropic.com>
@solomonneas
solomonneas merged commit 2323895 into main Jul 21, 2026
26 checks passed
@solomonneas
solomonneas deleted the fix/394-cloudflare-preflight branch July 21, 2026 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

run: preflight Cloudflare AI Gateway seats for required env vars

1 participant