Skip to content

feat(extend): drive video extend on flow.google.com through Flow's own UI (#639) - #991

Merged
ffroliva merged 27 commits into
developfrom
feature/639-migrated-video-extend
Oct 18, 2026
Merged

ffroliva merged 27 commits into
developfrom
feature/639-migrated-video-extend

Conversation

@ffroliva

@ffroliva ffroliva commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

This is a maintainer takeover of #882 by @stgmt, opened from the main repo so the SonarCloud gate runs. @stgmt's commits stay in the history with their authorship. Their wire research is the foundation of this change. The fork PR will be closed in favour of this one.

What it does

gflow video extend now works on accounts that Flow serves from flow.google.com, for one segment per run. Before this change it exited 36 there.

gflow drives Flow's own extend UI:

  1. It opens /project/<pid>/edit/<media>.
  2. It clicks add-clip, chooses Extend, types the prompt and clicks generate.
  3. The page then sends rqZuUc, uwAyfb and fZytfe itself, with a reCAPTCHA token the page minted. gflow only observes those requests, then follows the status poll and downloads the new clip.

Plan folder: docs/superpowers/plans/2026-10-17-migrated-video-extend/ (PREDICT, SCENARIO, PLAN). The click path and wire were measured at $0 by aborting the route, recorded in the spikes 2026-10-17-migrated-extend-ui-path.md and 2026-09-19-migrated-video-extend-wire.md (the latter by @stgmt).

Why the design differs from #882

#882 replayed fZytfe through page.request.post, using a reCAPTCHA token that gflow minted itself and parameters scraped from WIZ_global_data. Predict was unanimous across five personas that driving the page is safer, for four reasons:

Driving the page removes all four, and it matches every other port to flow.google.com: composer, upscale and characters. The replay code is deleted, and client.py, video_extend.py and extend_chain.py are back to develop's versions apart from the new entry point.

Kept from #882, with tests:

  • the video_result JSON shape;
  • the plan text no longer gets printed before --json output;
  • the fZytfe field map;
  • the as29s/record knowledge.

Safety

  • Refused before the browser opens (exit 36): -n > 1, --scene/--resume-from and --seed. This also applies under the default GFLOW_CLI_FLOW_HOST=auto, where Flow served flow.google.com; previously that path exited 7.
  • Refused before any click (exit 11): a media id that is not in the project, or is an image. The check reads the passive Zzl0ze project read.
  • Route guard, before Flow bills:
    • rqZuUc must name the media and fZytfe slot 1 must carry the source workflow id. Otherwise the request is aborted with a typed error.
    • Every frame of a batched request is checked, and a second fZytfe is aborted.
    • Request bodies are never logged, and a test proves the token never appears in an error.
  • A reply that echoes the source workflow is treated as a failure. The message says the run may already be billed.

Verification

  • /gflow:check: hygiene, doc links, website PII, website mirror and council memory checks all pass. ruff and ruff format are clean, pyright reports 0 errors, and the offline suite has 5073 passed.
  • Council (9 dimensions): must-fixes applied test-first. These covered:
    • batched-request guard;
    • exit 36 vs 7 under auto;
    • restoring the labs -o scene render;
    • missing tests;
    • docs drift in CONFIGURATION, the video-production skill and the recon memory.
  • E2E, flow.google.com, maintainer, 2026-10-17/18:
    tests/e2e/test_video_extend_migrated_e2e.py  (e2e_auth, $0, route-abort)
    3 passed  — submit contract (rqZuUc media / fZytfe workflow), unknown media refused before any click, aspect mismatch aborted by the guard
    
    tests/e2e/test_video_extend_migrated_e2e.py::test_e2e_one_paid_extend_downloads_an_mp4  (e2e_video, ONE paid run, owner-approved)
    migrated.submit_observed rpc=fZytfe status=6 workflow_id=93244ee0-…
    1 passed in 81.66s — new media id, mp4 `ftyp`, duration 6.5–8.5 s
    
  • MCP: video extend keeps its recorded parity exemption (tests/mcp/test_cli_parity.py): a long billed chain whose cost confirmation has no MCP equivalent (investigate: clamp long MCP operations to the client tool-timeout (or confirm enqueue already covers it) #481). Nothing in it changes here.

Not covered / not ported to flow.google.com yet

  • Chained extends (-n > 1), --scene/--resume-from and --seed: each is refused with exit 36. Extending from an existing scene has not been measured.
  • -o behaves differently by host. On flow.google.com it writes the new extension clip only, because scene rendering is not ported there. On labs.google it renders the whole scene, as before.
  • No price is shown on flow.google.com before submitting. There is no credits read on that host to reuse.
  • Each extend leaves a scene in the Flow project, as the UI does.

Refs #639. Supersedes #882.

stgmt and others added 23 commits September 19, 2026 07:36
- to_batchexecute_wire: source_workflow_id in media ref, [token,1],
  uuid3 op envelope, compact JSON separators
- _extend_video_batchexecute: resolve workflow_id_for_media, source_path
  /project/<id>/scene/<scene_id>, referer/origin headers
- _batchexecute_post: source_path param, compact f_req
- poll_video_status: workflow_id kwarg routes to _poll_video_status_batchexecute
  (as29s on migrated host; REST batchCheckAsyncVideoGenerationStatus is 401 there)
- extend_chain: pass started.workflow_id to the poller

Live-verified 2026-09-19: wire submit scheduled wf 2bb68ea1, DONE via
jwpduf, mp4 2786225 bytes downloaded (h264 720x1280 7s).
… video extend

Signed-off-by: stgmt <stigmat.rudnev@gmail.com>
…639)

- FlowApiClient.create_scene routes to _create_scene_batchexecute when host is migrated
- _create_scene_batchexecute posts rqZuUc RPC to compose a scene from workflowIds
- _run_extend downloads single completed segment directly without aisandbox concatenation
- Unit tests for create_scene on migrated vs legacy hosts

Signed-off-by: stgmt <stigmat.rudnev@gmail.com>
…rap to flow.google.com (#639)

- FlowApiClient.create_scene_for_extend encapsulates host-specific scene creation
  (media_id for migrated rqZuUc, workflow_id for legacy REST create_scene)
- _bootstrap_and_resolve_locale falls back to flow.google.com on labs connection errors
- Unit tests for create_scene_for_extend on migrated vs legacy hosts

Signed-off-by: stgmt <stigmat.rudnev@gmail.com>
…oll (#639)

- Extract flow-content.google signed CDN URL from as29s terminal record
- Cache signed URL by media_id and workflow_id in FlowApiClient
- download uses cached signed URL directly, eliminating 401 on migrated host

Signed-off-by: stgmt <stigmat.rudnev@gmail.com>
…ent (#639)

Design B: open the clip editor, read media -> workflow + kind from the passive
Zzl0ze reply, guard rqZuUc/fZytfe at the route, reuse the composer observer
(submit_rpcs/submit_selector/request_check) and its signed-URL fetch. Unported
forms (-n > 1, --scene/--resume-from, --seed, a foreign --aspect) exit 36 before
anything is billed.
…nd fZytfe

The route guard read only the first id of rpcids=, so a wrong fZytfe batched
behind another rpc (rpcids=uwAyfb,fZytfe) was released unchecked. It now
judges the URL list plus every f.req frame, and aborts any fZytfe after the
first released one so a run cannot bill twice.

migrated_composer's url_rpcid / body_rpcid / request_body are now public, so
the extend driver drops its reportPrivateUsage ignores.
…com; restore labs scene render

- Default host auto sent -n>1 / --scene / --resume-from / --seed to the labs arm,
  which on a page served flow.google.com read the retired projectInitialData
  (exit 7). _extend_session now checks the served host before that read and
  raises the same exit-36 refusal. client._upscale_route becomes the public
  served_route.
- Labs -o renders the scene again for any N>=1 (source + extensions, as
  KNOWN_ISSUES measured); #882 had downloaded only the new 7 s segment.
- unported_extend_form + unported_error merge into unported_refusal; on_started
  is a plain sync callable typed with ExtendStarted.
- Drop the unreachable labs.google kill switch inside extend_video_migrated
  (the CLI never routes labs.google there) and pin _anchor's selector drift
  (exit 23) with its own test.
…en no submit facts were captured

_source_clip took the first Zzl0ze frame even when it did not hold the media, so a
later reply that did was lost. It now settles on the matching record; at the budget
it returns None (exit 11) if a read answered, else a timeout (exit 9). started()
logs migrated_extend.no_submit_facts when the guard never read the page's fZytfe.
Extend passes its own submit button; a missing or disabled one was still
reported as 'arrow_forward', pointing at the wrong control.
… -o and the cost note

- CONFIGURATION, video-production skill (+ plugin copy), the recon memory and
  AGENTS.md now list single-segment extend as ported; multi-segment, --scene /
  --resume-from and --seed exit 36.
- extend --help and USAGE: -o renders source + extensions on labs.google but
  saves only the new extension clip on flow.google.com (scene concat not ported
  there); the cost-confirmation note is labs.google only.
- New repo memory drive-the-page-dont-replay-the-rpc, cited from the D6 row of
  pr-council-review.
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

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 4 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
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 85bc2cc4-5152-4a7d-aff6-cc113110aeea
📥 Commits

Reviewing files that changed from the base of the PR and between 249a14e and 33a3dfe.

📒 Files selected for processing: 41
  • AGENTS.md
  • CHANGELOG.md
  • KNOWN_ISSUES.md
  • docs/CONFIGURATION.md
  • docs/USAGE.md
  • docs/superpowers/memory/drive-the-page-dont-replay-the-rpc.md
  • docs/superpowers/memory/flow-recon-must-run-on-denon82-ffroliva-migrated.md
  • docs/superpowers/plans/2026-10-17-migrated-video-extend/PLAN.md
  • docs/superpowers/plans/2026-10-17-migrated-video-extend/PREDICT.md
  • docs/superpowers/plans/2026-10-17-migrated-video-extend/SCENARIO.md
  • docs/superpowers/spikes/2026-09-19-migrated-video-extend-wire.md
  • docs/superpowers/spikes/2026-10-17-migrated-extend-ui-path.md
  • llms.txt
  • plugins/gflow/skills/gflow-cli/SKILL.md
  • plugins/gflow/skills/video-production/SKILL.md
  • scripts/dev/spike_image_submit_references.py
  • scripts/dev/spike_migrated_end_frame.py
  • scripts/dev/spike_migrated_extend_ui_path.py
  • scripts/dev/spike_migrated_refusal_envelope.py
  • scripts/dev/spike_nano_banana_21_wire.py
  • skills/gflow-cli/SKILL.md
  • skills/pr-council-review/SKILL.md
  • skills/video-production/SKILL.md
  • src/gflow_cli/api/client.py
  • src/gflow_cli/api/transports/batchexecute.py
  • src/gflow_cli/api/transports/migrated_composer.py
  • src/gflow_cli/api/transports/migrated_extend.py
  • src/gflow_cli/cli_video.py
  • tests/api/test_client_extend.py
  • tests/api/transports/test_migrated_composer.py
  • tests/api/transports/test_migrated_extend.py
  • tests/api/transports/test_migrated_r2v.py
  • tests/api/transports/test_signed_media_retry.py
  • tests/cli/test_cli_video_extend.py
  • tests/e2e/test_migrated_host_e2e.py
  • tests/e2e/test_migrated_refusal_live_bdd.py
  • tests/e2e/test_project_create_e2e.py
  • tests/e2e/test_video_extend_migrated_e2e.py
  • website/docs/CONFIGURATION.md
  • website/docs/KNOWN_ISSUES.md
  • website/docs/USAGE.md
  • 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.

… into helpers

Clears Sonar S3776 x2, S3358 and S7503: the on_started handler is now a plain
function (the composer already accepts a sync callback). No behaviour change.
…report into helpers

Clears Sonar S3776 on _extend_migrated_session. Same output, record call,
log event and exit codes.
@ffroliva
ffroliva merged commit 6600a36 into develop Oct 18, 2026
16 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.

2 participants