Skip to content

ci: verify harness runtime in Cloudflare Workers#127

Merged
minpeter merged 3 commits into
mainfrom
codex/add-worker-edge-ci
Apr 27, 2026
Merged

ci: verify harness runtime in Cloudflare Workers#127
minpeter merged 3 commits into
mainfrom
codex/add-worker-edge-ci

Conversation

@minpeter
Copy link
Copy Markdown
Owner

@minpeter minpeter commented Apr 27, 2026

Summary

  • Add test:edge-safe to build @ai-sdk-tool/harness, run wrangler deploy --dry-run, start local wrangler dev, and fetch a Worker fixture importing @ai-sdk-tool/harness/runtime.
  • Add an edge-safe GitHub Actions job for the Wrangler/Cloudflare Worker smoke.
  • Keep optional Node-only MCP and skills modules behind late dynamic imports so the runtime subpath can bundle for Workers when those features are not configured.
  • Add a patch changeset for @ai-sdk-tool/harness.

Why this is not duplicate coverage

The existing runtime-edge-imports Vitest check only exercises browser-condition importing. This Worker smoke asks Wrangler to bundle the public runtime export, then serves it through local workerd and verifies a real fetch response. This caught the Node-only optional import edges locally before the fix.

Verification

  • CI=true pnpm install --frozen-lockfile
  • pnpm run check
  • pnpm run typecheck
  • pnpm run test:edge-safe
  • pnpm run build
  • pnpm run test

Notes

  • test:edge-safe requires local loopback access because wrangler dev starts workerd on 127.0.0.1.
  • No remote Cloudflare account deploy or production binding is used.

Summary by cubic

Adds a Cloudflare Worker smoke test to verify @ai-sdk-tool/harness/runtime bundles and runs under Workers, and makes the CI check more reliable with bounded waits.

  • New Features

    • test:edge-safe builds @ai-sdk-tool/harness, runs wrangler deploy --dry-run, starts local wrangler dev, and fetches a Worker fixture.
    • GitHub Actions job edge-safe runs the smoke test locally with workerd; no Cloudflare account needed.
  • Bug Fixes

    • Kept optional Node-only MCP and skills behind late string dynamic imports so the public runtime subpath doesn’t pull them into Worker bundles.
    • Removed flaky port pre-reservation; wrangler dev now binds port 0 and the runner uses the emitted ready URL.
    • Added explicit timeouts for wrangler readiness and fetch/json so CI fails fast instead of hanging.

Written for commit d743a0d. Summary will update on new commits. Review in cubic

Wrangler is now part of the edge-safety signal: CI builds the harness package, dry-runs a Worker deployment, starts local workerd through wrangler dev, and fetches a fixture that imports @ai-sdk-tool/harness/runtime. The smoke caught optional Node-only MCP and skills modules being pulled into edge bundles, so those imports are now late string dynamic imports while keeping TypeScript type checking through typeof import(...).

Constraint: Cloudflare Worker bundles must import the public runtime subpath without process, fs, child_process, or other Node-only globals.
Rejected: Keep only the browser-condition Vitest check | it did not exercise Wrangler/workerd bundling and missed optional Node-only dependency edges.
Confidence: high
Scope-risk: moderate
Directive: Do not replace the Wrangler smoke with a pure import test unless it still runs a real Worker bundle and request.
Tested: CI=true pnpm install --frozen-lockfile
Tested: pnpm run check
Tested: pnpm run typecheck
Tested: pnpm run test:edge-safe
Tested: pnpm run build
Tested: pnpm run test
Not-tested: Remote Cloudflare deploy with account credentials or production bindings.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Important

Review skipped

Auto reviews are disabled on this repository. To trigger a review, include @crb review in the PR description. 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9e78f304-e721-40c4-83d6-96f39c01bf82

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/add-worker-edge-ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a Cloudflare Worker edge smoke test to verify runtime subpaths and ensure Node-only modules are excluded from edge bundles. Key changes include the addition of a smoke test worker, configuration files, and a test runner script. The review feedback highlights opportunities to improve the test runner script by properly managing temporary directories and log paths to prevent resource leaks and potential collisions during concurrent runs.

@@ -0,0 +1,152 @@
import { spawn, spawnSync } from "node:child_process";
import { mkdtempSync } from "node:fs";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Add rmSync to the imports from node:fs to enable cleanup of the temporary directory created for the smoke test.

import { mkdtempSync, rmSync } from "node:fs";

Comment on lines +14 to +20
const WRANGLER_ENV = {
...process.env,
FORCE_COLOR: "0",
WRANGLER_LOG_PATH: join(tmpdir(), "plugsuits-wrangler-logs"),
WRANGLER_SEND_METRICS: "false",
};
const WORK_DIR = mkdtempSync(join(tmpdir(), "plugsuits-worker-edge-"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The WRANGLER_LOG_PATH currently uses a fixed filename in the system temp directory, which can lead to collisions if multiple smoke tests run concurrently (e.g., in different CI jobs or local runs). It is safer to place the logs inside the unique WORK_DIR. Reordering these constants ensures WORK_DIR is available when defining WRANGLER_ENV.

const WORK_DIR = mkdtempSync(join(tmpdir(), "plugsuits-worker-edge-"));
const WRANGLER_ENV = {
  ...process.env,
  FORCE_COLOR: "0",
  WRANGLER_LOG_PATH: join(WORK_DIR, "wrangler.log"),
  WRANGLER_SEND_METRICS: "false",
};

Comment on lines +150 to +152
} finally {
await stopChild(child);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The temporary directory WORK_DIR is created but never deleted. It should be cleaned up in the finally block to avoid leaving orphaned files on the system or CI runner after the test completes.

} finally {
  await stopChild(child);
  rmSync(WORK_DIR, { recursive: true, force: true });
}

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 9 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/cloudflare-worker-edge-smoke/run.mjs">

<violation number="1" location="scripts/cloudflare-worker-edge-smoke/run.mjs:144">
P2: Selecting a port by binding/closing it before starting `wrangler dev` introduces a race that can make this smoke test flaky if another process takes the port.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread scripts/cloudflare-worker-edge-smoke/run.mjs Outdated
The smoke runner previously opened an ephemeral port and closed it before starting wrangler dev on that same numeric port. That made the chosen port advisory rather than reserved, so another process could take it between close and bind and make the CI check flaky.

Constraint: The smoke test must run as a real local Wrangler/workerd server without requiring a fixed port.
Rejected: Retry on EADDRINUSE | this still leaves the race in place and adds slower failure handling.
Confidence: high
Scope-risk: narrow
Directive: Let Wrangler bind port 0 and consume the emitted ready URL instead of pre-selecting a local port.
Tested: pnpm run check
Tested: pnpm run test:edge-safe
Not-tested: Remote Cloudflare deploy with account credentials.
@minpeter
Copy link
Copy Markdown
Owner Author

@cubic review

@minpeter
Copy link
Copy Markdown
Owner Author

@codex review

@cubic-dev-ai
Copy link
Copy Markdown

cubic-dev-ai Bot commented Apr 27, 2026

@cubic review

@minpeter I have started the AI code review. It will take a few minutes to complete.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 9 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/cloudflare-worker-edge-smoke/run.mjs">

<violation number="1" location="scripts/cloudflare-worker-edge-smoke/run.mjs:57">
P2: Add a per-request timeout to the smoke-test fetch so the 30s polling deadline cannot be bypassed by a hanging response.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread scripts/cloudflare-worker-edge-smoke/run.mjs Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/cloudflare-worker-edge-smoke/run.mjs">

<violation number="1" location="scripts/cloudflare-worker-edge-smoke/run.mjs:169">
P1: `readyUrl` is awaited without a timeout, so the smoke script can hang indefinitely if wrangler never emits a matching readiness log line.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread scripts/cloudflare-worker-edge-smoke/run.mjs Outdated
The smoke runner already had a 30s polling loop, but the awaited operations inside it were not individually bounded. A hung response could keep a single fetch/json read past the polling deadline, and wrangler dev could keep running forever if it stayed alive without emitting the expected ready URL.

Constraint: CI needs a bounded failure path even when wrangler output or the local HTTP response is malformed or incomplete.
Rejected: Rely on the outer polling deadline only | awaited fetch/json and readiness promises can bypass that deadline.
Confidence: high
Scope-risk: narrow
Directive: Keep all long-running external waits in this smoke runner behind explicit timeouts.
Tested: pnpm run check
Tested: pnpm run test:edge-safe
Not-tested: Remote Cloudflare deploy with account credentials.
@minpeter
Copy link
Copy Markdown
Owner Author

@cubic review

@cubic-dev-ai
Copy link
Copy Markdown

cubic-dev-ai Bot commented Apr 27, 2026

@cubic review

@minpeter I have started the AI code review. It will take a few minutes to complete.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 9 files

@minpeter minpeter merged commit c40f690 into main Apr 27, 2026
8 checks passed
@minpeter minpeter deleted the codex/add-worker-edge-ci branch April 27, 2026 17:34
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d743a0d25d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

DefinedAgent,
} from "./types";

const SKILLS_MODULE = "../skills.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use extensionless specifier for skills dynamic import

The new "../skills.js" specifier in source TypeScript violates the repo rule in AGENTS.md (root) that source imports must stay extensionless, and it can break @ai-sdk-tool/source consumers that execute/compile TS sources directly (where skills.js does not exist alongside skills.ts), causing runtime resolution failures when definition.skills is enabled. Please keep the source specifier extensionless and handle .js rewriting only in build output.

Useful? React with 👍 / 👎.

}
export type StopCondition = (input: StopConditionInput) => boolean;

const MCP_INIT_MODULE = "./mcp-init.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use extensionless specifier for MCP init dynamic import

This change introduces "./mcp-init.js" in source TS, which conflicts with the root AGENTS.md guideline requiring extensionless source imports and risks module-not-found errors for source-condition users/toolchains that don’t map .js back to .ts; that failure path is triggered specifically when config.mcp is provided. Keep the source import extensionless and apply extension fixes in compiled dist instead.

Useful? React with 👍 / 👎.

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.

1 participant