Skip to content

Fix generative preview capture to return image bytes #889

Description

@kylymo

Plan 001: Return image bytes when capturing a generative preview

Executor: follow every step and verification gate. Modify only listed files. Stop and report if a STOP condition occurs.

Status

  • Priority: P1
  • Effort: S
  • Risk: LOW
  • Depends on: none
  • Category: bug
  • Planned at: commit c16bc4f, 2026-07-16

Why this matters

getCaptureImageFile fetches an image, but passes the Response object itself to File instead of its body bytes. Capture/download consumers can therefore receive a file whose contents are not the fetched PNG.

Current state

  • app/utils/generativePreview.ts:27-40, getCaptureImageFile, validates the hash and calls fetch(imageDataPayload.image).
  • Line 40 constructs new File([res], 'image.png', ...); res is a Response, not a Blob or ArrayBuffer.
  • The function is a focused utility and has no visible regression test beside the existing utility test files.

Commands and expected results

Purpose Command Expected result
Tests pnpm run test -- app/utils/generativePreview.spec.ts New capture tests pass
Lint pnpm run lint -- app/utils/generativePreview.ts exit 0
Full tests pnpm run test all tests pass

Scope

In scope:

  • app/utils/generativePreview.ts
  • A colocated test file for capture behavior

Out of scope:

  • Image-provider routing and hash generation semantics
  • UI changes to capture controls

Steps

Step 1: Consume the response body

Use await response.blob() (or an equivalent byte-oriented body method) and preserve the response failure behavior by checking response.ok or mapping failures to the existing error. Keep the existing hash mismatch guard.

Verify: Add a test with a mocked successful Response and assert the returned File has the expected byte size/type.

Step 2: Cover failed fetches and mismatched hashes

Add regression cases for a mismatched hash and an unsuccessful response. Keep error messages actionable and avoid logging image contents.

Verify: pnpm run test -- app/utils/generativePreview.spec.ts → all cases pass.

Test plan

  • Valid matching hash returns a PNG file containing the response body.
  • Hash mismatch rejects before fetch.
  • Non-OK response rejects or follows the chosen documented error contract.

Done criteria

  • File contains fetched bytes, not a Response object
  • Regression tests pass
  • Lint passes
  • Only in-scope files changed

STOP conditions

  • Current response/file API behavior differs materially from the evidence.
  • A test requires browser-only APIs unavailable under the repository's Vitest setup without an approved test-environment change.

Maintenance notes

Keep this utility's network error behavior stable for callers unless tests demonstrate that callers already distinguish error types.

Issue body

Bug Description

getCaptureImageFile passes a fetched Response object directly to File, so generated preview capture may not contain the downloaded image bytes.

Evidence

  • app/utils/generativePreview.ts:39-40
  • const res = (await fetch(...)) as any
  • new File([res], 'image.png', { type: 'image/png' })

Expected Behavior

The returned File contains the response body bytes and has the expected image type.

Acceptance Criteria

  • Add regression tests for successful capture, hash mismatch, and failed response.
  • Use response.blob() or equivalent byte extraction.
  • pnpm run test and pnpm run lint pass.

Environment

  • Repository: chaotic-art/app
  • Baseline: c16bc4f
  • Node: package declares 24.x; audit host had Node 22.22.1
  • pnpm was unavailable during audit

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingjavascriptPull requests that update javascript codep1

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions