Skip to content

fix(compose): correct the Cloudflare Images binding contract (F6)#114

Merged
vinsonconsulting merged 1 commit into
mainfrom
fix/f6-cf-images-binding
Jun 28, 2026
Merged

fix(compose): correct the Cloudflare Images binding contract (F6)#114
vinsonconsulting merged 1 commit into
mainfrom
fix/f6-cf-images-binding

Conversation

@vinsonconsulting

Copy link
Copy Markdown
Owner

F6 — limner_compose cf-images ops

Every cf* compose op (cfTransform/cfOverlay/cfBlur/cfSmartCrop/cfBackgroundFill) threw cf-images transform failed: HTTP undefined undefined on the live Worker, despite hasImages:true.

Root cause — a code bug, not provisioning

The stub CFImagesBinding interface (written in Phase 3 before the real binding shipped) modeled .output() as Promise<Response>. But the live Cloudflare Images binding resolves to an ImageTransformationResult whose .response() yields the Response (it also exposes .image()/.contentType()). transform() read .ok/.status/.statusText/.arrayBuffer() straight off the result object — all undefined — so !response.ok was always true and it threw on every call. The unit test mocked the same wrong shape, so CI stayed green while production was 100% broken (CF docs).

Fix

  • Model the result correctly (CFImagesTransformResult.response()) and route through it.
  • New toResponse() guard: when the runtime hands back an unexpected shape (e.g. Images Transformations not enabled and the binding returns a stub), surface a clean, actionable error instead of HTTP undefined undefined.

Provisioning

This is a code fix. Execution reached the transform call past the if (!ctx.images) guard, so the binding is injected — strongly implying Images Transformations is already enabled on the account. That's confirmed at the gated deploy + live verify; if a cf* op still fails there, the existing missing-binding guidance + in-isolate fallbacks (compose.ts) degrade cleanly. I'll surface the provision-vs-degrade decision at the checkpoint only if live verification still fails.

Tests

  • Fixed both mock bindings (core cf-images-transform.test.ts + mcp compose.test.ts) to the real .response() contract — so they validate reality, not the stub (a regression to the old "treat result as Response" shape now fails).
  • Added a malformed-result case at the core layer and end-to-end through the tool, asserting a clean error and not HTTP undefined undefined.

Suite 675 → 677. Typecheck + lint clean.

🤖 Generated with Claude Code

Every cf* compose op (cfTransform/cfOverlay/cfBlur/cfSmartCrop/
cfBackgroundFill) threw "cf-images transform failed: HTTP undefined
undefined" on the live Worker, despite hasImages:true. The stub
CFImagesBinding interface — written before the real binding shipped —
modeled .output() as Promise<Response>, but the live Images binding resolves
to an ImageTransformationResult whose .response() yields the Response (it also
exposes .image()/.contentType()). transform() read .ok/.status/.statusText/
.arrayBuffer() straight off the result object — all undefined — so it threw
on every call. The unit test mocked the same wrong shape, so CI stayed green
while production was 100% broken.

Model the result correctly (CFImagesTransformResult.response()) and route
through it. A new toResponse() guard surfaces a clean, actionable error when
the runtime hands back an unexpected shape (e.g. Images Transformations not
enabled on the account) instead of the "HTTP undefined undefined" — the
binding result is no longer assumed to be a Response.

This is a code fix, not a provisioning gap: execution reached the transform
call past the `if (!ctx.images)` guard, so the binding is injected. Whether
Images Transformations is actually enabled is confirmed at the gated deploy +
live verify; if a cf* op still fails there, the existing missing-binding
guidance + in-isolate fallbacks (compose.ts) degrade cleanly.

Tests: fixed both mock bindings (core + mcp compose) to the real
.response() contract — so they validate reality, not the stub; added a
malformed-result case at the core layer and end-to-end through the tool,
asserting a clean error and NOT "HTTP undefined undefined". Suite 675 -> 677.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jim Vinson <jim@vinson.org>
@vinsonconsulting vinsonconsulting merged commit 502c5c2 into main Jun 28, 2026
2 checks passed
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