Skip to content

Chore/flow drop legacy rest - #49

Merged
crisng95 merged 4 commits into
mainfrom
chore/flow-drop-legacy-rest
Sep 17, 2026
Merged

crisng95 merged 4 commits into
mainfrom
chore/flow-drop-legacy-rest

Conversation

@crisng95

@crisng95 crisng95 commented Sep 17, 2026 •

Copy link
Copy Markdown
Owner

What

Removes the aisandbox-pa.googleapis.com REST transport, which has had no
reachable caller since Flow moved to flow.google.com in September 2026 and
stopped minting the Bearer ya29.… it needed. Net −1043 lines.

Keeping a dead implementation beside a live one turned out to cost more than it
saved: the Omni module was written against the REST path, so when the migration
landed on FlowClient it missed Omni entirely, and Omni frame/reference
generation has been returning UNSUPPORTED_ON_BATCH_API ever since. Deleting
the template is what stops the next copy.

Removed: the ten _legacy_* methods, the twelve if not USE_BATCH_RPC branches
in FlowClient, _build_url/_client_context, ENDPOINTS, GOOGLE_FLOW_API,
GOOGLE_API_KEY, the browser-fingerprint pools and agent/services/headers.py
that fed them, the tRPC polling branch in omni_flash, and _annotate_polling,
whose only callers were the REST submits. RECAPTCHA_SITE_KEY went too — no
Python caller, and the extension hardcodes its own copy in injected.js.

The extension keeps its api_request/trpc_request proxies for now. No current
agent sends them, but an older agent in the wild might; retiring them is a
manifest.json bump and a user-visible reload, so it is its own change.

Commits

Commit Why
d56a5cc Remove the REST transport
d009dc2 Repair two test mocks that drifted behind refactors
f4e2265 Teach /fk-doctor the NO_INJECTION_RESULT error
0c45b39 Bump extension to 0.3.2, note the working Flow API in the README

Verified against the live Flow API

Not just unit tests — the whole path was exercised end to end through a
signed-in Flow tab, since that is the only thing that can sign these calls:

Call Result
generate-image 200 — media_id 2ad427aa-…, proper UUID
export-image 2K 200 — 3.3 MB JPEG, 1536×2752 from a 768×1376 source
generate-video (i2v, veo) 200 — op cf6f80cd-…
downloaded clip 8.0 s, 720×1280, h264 + AAC, 192 frames
get_media, credits 200 — both replace deleted _legacy_* methods
start+end chaining 502 UNSUPPORTED_ON_BATCH_API — fails loudly, as intended
agent log zero errors

Every response arrived over POST /api/ext/callback with match=yes, i.e. the
primary delivery path, not the WS fallback.

Worth a reviewer's attention

One defect came from the rebase, not from either parent. This branch deleted
the USE_BATCH_RPC definition while the migrated image API (#42) added a new
if not USE_BATCH_RPC: guard inside upscale_image. Different files, so git
merged both cleanly and upscale_image raised NameError on every call. It is
removed here the same way as the other eleven guards, and the 2K export above is
that code path running for real.

The four unported capabilities are listed from the guards, not the docs,
because the docs disagree. flow_client.py blocks start+end chaining, r2v and
video upscale; omni_flash.py:33 blocks Omni frame/reference. CLAUDE.md
calls the third "4K upscale", which reads as the image export — and that one
works (see the 2K result above). docs/CAPTURE.md also still lists an item the
image API merge has since ported. Flagging rather than fixing: correcting those
two docs is not this PR's job.

Tests

266 passed, and the suite now exits.

Two mocks had drifted behind refactors and were failing for reasons unrelated to
this change:

  • test_processor.py patched processor._retry_state, a module global replaced
    by self._retry_after plus a retry_after parameter. mock.patch rejects a
    missing attribute, so three tests raised AttributeError before their bodies ran.
  • test_result_handler.py mocked crud.update_scene but not crud.get_scene,
    which c071cb8 added for the chain cascade in April. Those three tests had been
    hitting a real schema-less database ever since.

That second one also explains why pytest tests/unit never exited: aiosqlite
services each connection on a non-daemon thread, and the connection opened by
accident was never closed, so it outlived the session. Piping the run hid it —
the summary sat in the pipe buffer while the process refused to die.

Not in this PR

  • extension/manifest.json's aisandbox-pa host entry, and the two legacy
    proxies in background.js — they share one lifetime and need a reload.
  • Correcting CLAUDE.md's "4K upscale" wording and docs/CAPTURE.md's stale entry.
  • The 13 drawtext test failures on a stock Homebrew ffmpeg: that build ships
    without --enable-libfreetype, so text-overlay skills need ffmpeg-full on
    PATH. Environmental, pre-existing, unrelated.

Reviewer notes

  • Reload the extension once after merging — /health should then report 0.3.2.
    Before this PR it reported 0.3.1 for both the pre- and post-Expand migrated image API: model selection, edits and 2K export #42 build, so a
    stale extension was indistinguishable from a current one.
  • flow_key_present: false in /api/flow/status is normal on this transport;
    there is no bearer to capture.
  • A status poll answering "Media not found." is not a failure — finished
    jobs report it. Confirm via the media record instead.

🤖 Generated with Claude Code

crisng95 and others added 4 commits September 17, 2026 22:42
Flow moved to flow.google.com in September 2026 and stopped minting the
`Bearer ya29.…` the aisandbox-pa REST path needed. That path has been
unreachable ever since, kept behind USE_BATCH_RPC=0 as a post-mortem tool.

Keeping it cost more than it was worth. A dead implementation sitting beside
a live one is a template: the Omni module was written against it, so when the
migration landed on FlowClient it missed Omni entirely, and Omni frame and
reference generation have been returning UNSUPPORTED_ON_BATCH_API since.
Deleting the template is what stops the next copy.

Removed: the ten _legacy_* methods, the twelve `if not USE_BATCH_RPC` branches
in FlowClient (ten dispatching to those methods, one returning an inline note
from refresh_project_urls, and upscale_image's, which arrived with the migrated
image API this rebased onto), _build_url/_client_context, ENDPOINTS,
GOOGLE_FLOW_API, GOOGLE_API_KEY, the browser-fingerprint pools and
agent/services/headers.py that fed them, the tRPC polling branch in omni_flash,
and omni_flash's _annotate_polling, whose only callers were the REST submits.
RECAPTCHA_SITE_KEY went too: it had no Python caller, and the extension
hardcodes its own copy in injected.js, so the env var was a knob that changed
nothing. Git history has all of it if a payload is ever needed.

One deliberate behavior change, in the unported Omni modes. Previously the
capability check ran first, so a bad duration on frame-to-video answered 502
UNSUPPORTED_ON_BATCH_API. Now validation runs first, so it answers 400
"duration 5s is unsupported". A caller who can fix the duration should hear
about the duration; the gap it cannot fix comes after. No caller exists today
either way — the pipeline uses model_family=veo.

The extension keeps its api_request and trpc_request handlers, so an extension
updated ahead of its agent still serves an older one. To be clear about what
that is worth: on any profile that postdates the migration nothing in the
extension reaches aisandbox-pa either — sendTelemetry early-returns without a
flowKey that is no longer minted. So the host permission is held by the
backward-compat proxy alone, and the two now share one lifetime: when the
oldest agent in the wild speaks batch_rpc, the handlers and manifest.json's
aisandbox-pa entry go together. That is a manifest bump and a user-visible
reload, so it is its own change.

Tests: test_omni_flash.py was pinned to the legacy path by a module-level
autouse fixture setting USE_BATCH_RPC=False, so all 34 of its tests would have
errored on the missing attribute. 10 asserted REST or tRPC contracts for code
this commit deletes and went with it; the remaining 24 — the model-key mapping,
the input validation, the batch-path tests — were kept, and one new test pins
the seven-reference boundary that a deleted test used to cover.

Two tests added for the retry branch in generate_scene_video. It used to be
gated on `bare_uuid and not USE_BATCH_RPC`, so it was dead on the only
transport that exists and had no coverage — and it is the one branch where a
wrong answer abandons a render Flow is already paying for and starts a second.
Checked by forcing the branch off: the test fails. A comment in operations.py
that described that resubmit was removed too; left in place it reads as an
instruction to reintroduce it.

  agent/services/flow_client.py   1290 -> 921
  agent/services/omni_flash.py     672 -> 350
  agent/config.py                  158 -> 111

211 passed, 3 failed — the 3 are pre-existing on main (test_processor.py
patches processor._retry_state, which does not exist). Golden envelope tests
pass, so the Veo submit payload is unchanged byte-for-byte.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DB27wvPQ195KGiQ6VZfCDf
Six tests failed for reasons unrelated to the code under test, and one of
them hung the interpreter.

test_processor.py patched `agent.worker.processor._retry_state`, a module
global that no longer exists: retry state became the instance attribute
`self._retry_after` plus an explicit `retry_after` parameter on
_handle_failure. mock.patch refuses a missing attribute without
create=True, so all three tests raised AttributeError before their bodies
ran. The assertions were always fine — _handle_failure(rid, req, result)
still matches the signature — so the patch line just goes.

test_result_handler.py mocked crud.update_scene but not crud.get_scene,
which c071cb8 added at result_handler.py:61 for the chain cascade. Since
April those three tests hit a real database with no schema, hence "no such
table: scene". They now mock get_scene returning None — the no-parent case,
which keeps update_scene's assert_awaited_once true.

That accidental connection was also why `pytest tests/unit` never exited:
aiosqlite services each connection on a non-daemon worker thread, and this
one was never closed, so the thread outlived the session. Piping the run
hid it, because the summary sat in the pipe buffer while the process
refused to die.

266 passed, and the process exits.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
A live 2K export failed with `SPrCad: NO_INJECTION_RESULT` and the taxonomy
had no entry for it, so diagnosing it meant reading background.js from
scratch — the one thing this skill exists to prevent.

The string comes from extension/background.js:540, where executeScript
resolved with no frame result: the Flow tab was gone or still booting, so
the envelope never ran. It landed on the first captcha-bearing RPC after an
agent restart and cleared on retry.

The row records what the evidence ruled out, because all three are easy to
reach for and wrong: a failed captcha mint reports CAPTCHA_FAILED, an
oversized payload is not it (MAX_RPC_TEXT is 32 MB), and a structured-clone
failure surfaces as 500 rather than 502. Auto-handling is the generic
branch in processor.py — retried with backoff, counted against MAX_RETRIES
— not the captcha branch's ten free attempts.

Also added to the auto-invoke trigger list, so the next one routes here
instead of being guessed at.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
43b0406 changed background.js and injected.js without bumping the manifest,
so /health reported 0.3.1 for both the pre- and post-merge build. There was
no way to tell a stale extension from a current one — which is the first
question you ask when an RPC misbehaves. background.js:229 reports
getManifest().version, so the bump makes it answerable; reload the
extension once and /health says 0.3.2.

README gets the status at the top, where someone landing on the repo sees
it before anything else: the batchexecute transport is verified end to end
against the live API — image generation, 2K export and i2v — and the four
unported capabilities fail loudly rather than guessing.

That list is taken from the guards themselves, not from the docs, because
the docs disagreed. flow_client.py blocks start+end chaining, r2v and video
upscale; omni_flash.py:33 blocks Omni frame/reference. CLAUDE.md calls the
third one "4K upscale", which reads as the image export — and that one in
fact works, verified at 1536x2752 from a 768x1376 source. CAPTURE.md lists
a fourth item the image API merge has since ported. The Architecture
callout's v0.3.0+ was aligned to v0.3.2+ so the two do not contradict.

Also ignore extension/_metadata/, which Chrome generates when it loads the
unpacked extension.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
@crisng95
crisng95 merged commit f50414a into main Sep 17, 2026
crisng95 added a commit that referenced this pull request Sep 17, 2026
First release since v1.1.0 (2026-05-09), and it is one arc: Flow moved to
flow.google.com in September 2026 and stopped minting the bearer the old REST
API needed, so the transport was rebuilt on batchexecute (#39), the dead REST
path deleted (#49), the image API migrated (#42), and the Omni image-conditioned
modes ported back on top of it (#48/#50).

Also fixes a version drift this release would otherwise have deepened. ccf89c6
put "0.2.0" in two places in agent/main.py; 939b956 bumped only the FastAPI
line, so /health has reported 0.2.0 ever since while the app said 1.1.0 — three
releases stale, on the endpoint CLAUDE.md tells you to curl before anything
else. /health now reads app.version, so there is one string to bump instead of
two literals that agree only by luck.

extension/manifest.json is deliberately not bumped. It tracks the extension's
own lifecycle, it is at 0.3.2, and a bump there forces a user-visible reload.

Verified: 272 passed; /health and app.version both report 1.2.0, checked by
calling the handler rather than reading the source.

Not verified: the Omni envelopes from #48. They are live-verified per that PR
and the tests lock their shape, but nothing has submitted through a signed-in
Flow tab since the merge resolution.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5BJVhNgerhFTUgmfnKTSj
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