Skip to content

fix(image): upload a local --ref into a project once, then mention it (#772) - #1098

Merged
ffroliva merged 4 commits into
developfrom
bugfix/772-migrated-ref-dedup
Oct 25, 2026
Merged

ffroliva merged 4 commits into
developfrom
bugfix/772-migrated-ref-dedup

Conversation

@ffroliva

@ffroliva ffroliva commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

On flow.google.com, gflow image i2i --ref <file> uploaded the file again on every call. The reporter's 122-prompt loop left 122 copies of one character image in the project's library. Labs avoids this by searching the picker for the file name (#334); the migrated composer has no such search.

Fix, at the shared layer (CLI and MCP): new services/reference_uploads.generate_reusing_uploads.

  1. For each local --ref, look up the catalog: if this profile already recorded this file (resolved path and sha256) as an image in this project, with a caption, mention that image in place (ImageRef(in_project=True), the image batch: intra-batch references (ref / reference_entity "batch:N") are parsed and never applied (#317) #913/flow.google.com: image i2i --ref <uuid> of an image already in the target project is refused (exit 36) instead of referenced in place #995 path).
  2. Otherwise upload it in place (client.upload_reference_in_place, the same toolbar upload gflow run uses, image batch: intra-batch references (ref / reference_entity "batch:N") are parsed and never applied (#317) #913) and record it (record_upload_image), so the next run finds it.
  3. If a recorded image has since been deleted from the project, the in-place mention raises ReferenceNotFoundError before anything is submitted. The file is then uploaded again and recorded, and the generation retried once, so the next run reuses the fresh copy.
  4. Labs is unchanged. The transport answers None there (no in-place upload), and the path stays on ref_paths for the editor dialog's own dedup.

upload_reference_in_place is upload_reference without the REST fallback, which 401s on labs (#15/#39); upload_reference now calls it.

Wired into cli_image i2i and worker/daemon (MCP gflow_generate_image). One known limit, marked shortcut: in the code: only the newest catalog record of a file is checked, so a file copied to project A, then B, then used again in A uploads once more.

Evidence

Live e2e (denon82, flow.google.com), new tests/e2e/test_local_ref_uploaded_once_bdd.py, both scenarios pass:

  • CLI: 1 passed (151 s). The first i2i uploads (migrated.reference_uploaded). The second, in the same project with the same file, emits reference_uploads.reused with the first run's media id, migrated.existing_references_attached with exactly that id, and no upload event. The submit guard passed.
  • MCP (gflow_generate_image(wait=True) after a CLI first run): 1 passed (99 s), same assertions, status completed, one image on disk.
  • Cost: 4 images of daily quota (plus 2 wasted on a test-harness bug, fixed: INFO events are hidden by default since CLI prints ~10 info log lines on every command; GFLOW_CLI_LOG_LEVEL is documented but ignored #1041, so the child runs with GFLOW_CLI_LOG_LEVEL=INFO, and the labs skip now needs positive evidence). 0 Veo credits.

Offline: tests/services/test_reference_uploads.py, 6 tests, written first and seen failing (module missing):

  • the second run mentions the first upload
  • another project gets its own upload
  • changed bytes at the same path upload again
  • labs keeps the path
  • a deleted recorded image is re-uploaded and retried, and the next run reuses the fresh copy
  • a miss on a fresh upload is not retried

Full offline suite: 5484 passed, 29 skipped. pyright 0 errors. ruff, format and all 5 scripts/ci gates green.

Council review (2 reviewers, both YELLOW) → addressed in 2a8213e6

  • Retry narrowed: it fires only when the ReferenceNotFoundError names a media id this run reused. Any other pre-submit miss (a character, an out-of-order chip) re-raises at once, with no duplicate upload. New test: test_an_unrelated_miss_is_not_retried_with_a_new_upload.
  • The retry path is now live-verified: new e2e scenario a recorded upload the project no longer holds is uploaded again and re-recorded (catalog row pointed at an id the project does not hold, which the composer sees exactly like a deleted tile): 1 passed (232 s, including the up-to-90 s in-place search). It shows reference_uploads.recorded_image_gone, then one migrated.reference_uploaded; the new copy is recorded and the submit guard passed. Cost: 2 more images.
  • A file validate_image_file refuses keeps its pre-image i2i reference dedup (#314/#334) does not appear to apply on the migrated flow.google.com host #772 route (labs dialog / composer upload), instead of a bare ValueError.
  • The file size is checked against MAX_IMAGE_BYTES before it is hashed.
  • docs/USAGE.md (the main --ref description) covers the flow.google.com reuse; #334 (the PR) → #314 (the issue). The labs wording in the CHANGELOG is corrected: a file already recorded in the project is referenced in place on labs too.
  • Reviewers confirmed no double-spend: every ReferenceNotFoundError raise site is before submit on both hosts.

Not covered

Closes #772

Summary by CodeRabbit

  • Bug Fixes
    • Local reference images are reused in the same project when the file path and contents match, avoiding repeat uploads. If the project copy is missing, the image is uploaded again and recorded.
    • The same behavior applies to image generation through the MCP tool.
  • Documentation
    • Updated usage guidance to explain reference-image reuse and re-upload behavior.

…#772)

On flow.google.com every image i2i uploaded its --ref file again, so a loop
over one character image filled the project's library with copies. The
upload is now recorded in the catalog; a later run in the same project with
the same file (same path, same bytes) mentions the recorded image in place.
A recorded image deleted from the project since is uploaded again, recorded,
and the generation retried once (nothing is submitted before the miss).

Shared by the CLI and the MCP worker. Labs keeps its editor-dialog filename
dedup (#334): the transport answers None there and the path is left alone.
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 49 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ef5fe4eb-9031-4613-8277-b290fe25d79e
Commits

Reviewing files that changed from the base of the PR and between c949dec and 2dbcd8d.

Files selected for processing: 12
  • CHANGELOG.md
  • docs/REFERENCE_STRATEGIES.md
  • docs/USAGE.md
  • src/gflow_cli/api/client.py
  • src/gflow_cli/cli_image.py
  • src/gflow_cli/services/reference_uploads.py
  • src/gflow_cli/worker/daemon.py
  • tests/cli/test_cli_image.py
  • tests/e2e/test_local_ref_uploaded_once_bdd.py
  • tests/features/local_ref_uploaded_once.feature
  • tests/services/test_reference_uploads.py
  • website/docs/USAGE.md

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d40aa1f6-6062-4ea8-a1d8-ccad45deb89e
Commits

Reviewing files that changed from the base of the PR and between c13ee66 and c949dec.

Files selected for processing: 12
  • CHANGELOG.md
  • docs/REFERENCE_STRATEGIES.md
  • docs/USAGE.md
  • src/gflow_cli/api/client.py
  • src/gflow_cli/cli_image.py
  • src/gflow_cli/services/reference_uploads.py
  • src/gflow_cli/worker/daemon.py
  • tests/cli/test_cli_image.py
  • tests/e2e/test_local_ref_uploaded_once_bdd.py
  • tests/features/local_ref_uploaded_once.feature
  • tests/services/test_reference_uploads.py
  • website/docs/USAGE.md

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

Walkthrough

Image-to-image generation now reuses a matching recorded reference upload in the same project. If the recorded image is missing, generation uploads the reference again and retries. The CLI and worker use the shared reuse flow, with tests and documentation covering the behavior.

Changes: Reference image reuse

Layer / File(s) Summary
Reference lookup, upload, and retry
src/gflow_cli/services/reference_uploads.py, src/gflow_cli/api/client.py, tests/services/test_reference_uploads.py
The shared service checks the catalog for a matching file and project, attempts in-place upload when reuse is unavailable, and records successful uploads. If generation reports a reused image missing, it re-uploads the reference and retries once. Unit tests cover reuse, changed file bytes, fallback, and retry behavior.
CLI and worker integration
src/gflow_cli/cli_image.py, src/gflow_cli/worker/daemon.py, tests/cli/test_cli_image.py
CLI and worker image generation use the shared reuse service. The worker retains its single-image and batch-generation paths.
Behavior coverage and documentation
tests/features/local_ref_uploaded_once.feature, tests/e2e/test_local_ref_uploaded_once_bdd.py, CHANGELOG.md, docs/REFERENCE_STRATEGIES.md, docs/USAGE.md, website/docs/USAGE.md
End-to-end scenarios cover CLI and MCP reuse and re-upload when the project image is missing. The changelog and usage documentation describe project-scoped reuse on flow.google.com.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant generate_reusing_uploads
  participant OperationRecorder
  participant FlowApiClient
  participant GenerationCallback
  CLI->>generate_reusing_uploads: Submit request and project context
  generate_reusing_uploads->>OperationRecorder: Resolve matching seed image
  generate_reusing_uploads->>FlowApiClient: Attempt in-place upload when reuse is unavailable
  generate_reusing_uploads->>GenerationCallback: Generate with transformed request
  GenerationCallback-->>generate_reusing_uploads: Return generated images
  generate_reusing_uploads->>FlowApiClient: Re-upload reused reference if generation reports it missing
  generate_reusing_uploads->>GenerationCallback: Retry generation once
Loading

Possibly related issues

  • Issue 997: This change retries generation when a reused image is missing, but it does not change the migrated composer’s caret placement described in the issue.
Merge Risk: Minimal · up to c949d

Local references retain a working upload path when reuse is unavailable, and a missing reused image receives one fresh-upload retry. No issue identified here prevents merging after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 42 functions across 7 files. (5 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: reusing a local image reference upload within a project instead of uploading it repeatedly.
Linked Issues check Passed Issue #772 requires reuse for repeated local --ref calls in the same project on flow.google.com, or explicit documentation of the limitation. generate_reusing_uploads matches the resolved path a…
Out of Scope Changes check Passed The changes stay within the stated scope. The shared helper supports the CLI and MCP flows named in the PR. Client changes enable in-place upload behavior. Tests, documentation, changelog updates, and…
Full details: Linked Issues check

Explanation

Issue #772 requires reuse for repeated local --ref calls in the same project on flow.google.com, or explicit documentation of the limitation. generate_reusing_uploads matches the resolved path and SHA-256, checks the current project, mentions a recorded image in place, and records new uploads. CLI and MCP paths use the helper. The service tests and live CLI/MCP scenarios cover reuse, project and byte changes, and recovery after deletion. The documentation states the behavior and its newest-record limitation.

Full details: Out of Scope Changes check

Explanation

The changes stay within the stated scope. The shared helper supports the CLI and MCP flows named in the PR. Client changes enable in-place upload behavior. Tests, documentation, changelog updates, and e2e coverage support the reuse objective. Labs retains its existing path-based deduplication route. gflow run cross-run reuse remains explicitly outside this change, and no unrelated change is demonstrated.

Full details: Docstring Coverage

Explanation

Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 42 functions across 7 files. (5 skipped: 5 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Council review:
- the retry fires only when the ReferenceNotFoundError names a media id this
  run reused; a missing character or an out-of-order chip re-raises at once,
  with no duplicate upload
- a file the upload check refuses keeps its pre-#772 route
- the file size is checked before it is hashed
- a live e2e scenario for a recorded image the project no longer holds
- docs/USAGE.md describes the flow.google.com reuse; #334 -> issue #314
# Conflicts:
#	CHANGELOG.md
@ffroliva
ffroliva marked this pull request as ready for review October 25, 2026 11:16
# Conflicts:
#	CHANGELOG.md
@ffroliva
ffroliva merged commit 293b4e6 into develop Oct 25, 2026
17 checks passed
@ffroliva
ffroliva deleted the bugfix/772-migrated-ref-dedup branch October 28, 2026 11:21
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.

image i2i reference dedup (#314/#334) does not appear to apply on the migrated flow.google.com host

1 participant