chore(release): v0.72.0 - #771
Merged
Merged
Conversation
Drives `gflow image t2i` and local-file `i2i` on Google's migrated `flow.google.com` frontend through the page-owned `ogiZ0b` batchexecute wire, and skips the labs-only pre-transport reCAPTCHA mint on that route while preserving the labs path. Contributed by @arjhinety, with plan → scenario → spike → BDD → live verification on both the CLI and the queued MCP path. The migrated host now serves t2v, i2v/r2v from local files, character create, and image t2i/i2i from local files — each with `--project`. References by UUID or `@Name`, character entities, Agent instructions, Imagen 4, `image batch` and the 3:4 image aspect are refused before submit with exit 36. Council review across ten dimensions returned RED on the edges of an otherwise sound slice; all seven must-fixes were closed before merge: - The page-owned-reCAPTCHA capability was derived from `page.url`, and the image path parks the page on `about:blank` — which routes as `labs`. The SECOND image in one client session therefore fell back to minting on the pooled bootstrap page and died with the `RecaptchaError` of #673, the exact bug this slice removes. Invisible to every single-image test; reachable from `gflow image batch`, which runs every prompt through one `FlowApiClient`. The transport now latches the observed host, pinned by a regression test verified to fail without the latch. - `generate_images_batch` had no migrated guard and drove labs selectors against `flow.google.com`, surfacing as `UiSelectorDriftError` (exit 23) — telling the user to file a frontend-drift bug about a working frontend. Now exit 36 before any submit. - `--aspect 3:4` mapped to a `crop_portrait` ligature the spike never observed; the aspect radiogroup was enumerated with four radios. Now an unported form, with the measured set kept in its own constant so observed and assumed stay distinct. - `FlowHostMigratedError` printed a remediation contradicting the detail directly above it. Remediation, class docstring and the video path's refusal string all now name the ported matrix. - `llms.txt`, `.env.template`, `docs/INDEX.md` and both `skills/video-production/` files still said images exit 36. `llms.txt` is in the documentation gate's `CURRENT_OPERATOR_DOCS` precisely because a stale claim there costs the most. - `submit_images_and_observe` had zero offline coverage — the trust branches (the route-error listener that refuses to report a text-only generation as i2i, a non-200 submit, the reply timeout) were reachable only from a live account. Four cases added; the i2i BDD step now drives `_image_body_problem` instead of asserting a decoded field. - `migrated_image_can_serve` and `ImageGenerationRecord.reference_ids` removed as dead. Verified: 14/14 CI checks green on 3.11/3.12/3.13; ruff, `pyright` 0 errors, all five hygiene gates, and 3,074 scoped tests locally. E2E: `test_migrated_host_e2e.py` covers CLI t2i and the MCP i2i twin, run by the contributor. DCO: merged without a `Signed-off-by:` trailer, waived by the maintainer. Recorded here rather than left silent. Closes #692 Refs #639
Both found while running the v0.71.1 release gates. Neither is a product bug; both are tests that pass while checking something other than what they claim. #758 — test_key_is_never_forwarded guards a security property: a removed key must never be resurrected as a fallback. It cleared the process env var with delenv, but Settings ALSO reads the dotenv files from config._env_files(), so on any machine whose repo-root .env sets GFLOW_CLI_LLM_API_KEY — the documented dev setup — pydantic-settings loaded it straight back and the assertion failed. CI stayed green because CI has no .env. So it failed for exactly the developers whose environment could exhibit the leak it exists to catch, which is the population most likely to learn to ignore it. The fix is one fixture, not new machinery: clean_env already fences BOTH dotenv entries into tmp_path, and TestCleanEnvHermeticity already documents this exact hazard ('the repo root's gitignored .env is the documented dev setup'). The test simply never used it. #760 — pytest inside a git worktree imports gflow_cli from the MAIN checkout. A worktree has no .venv of its own; the venv's editable install pins src/ in the primary checkout. So a worktree run executes the worktree's TESTS against the other tree's SOURCE, and it fails OPEN: a release branch runs its own gates, sees green, and has validated code it is not shipping — and a regression on that branch passes, because the healthy tree answered for it. /gflow:release step 5 REQUIRES cutting in a worktree, so every release carried this exposure. It surfaced during v0.71.1 only because one newly added assertion happened to differ between the trees. Nothing structural would have caught it, so this is a hard UsageError at pytest_configure rather than a warning. The check is deliberately narrow: it fires only when a local src/gflow_cli exists beside the tests AND the import came from elsewhere. Testing an installed wheel, where no local source tree is present, is untouched. Refs #758, #760
`Dependency audit (pip-audit)` went red on develop against an UNCHANGED lock: neither #750 nor #762 touched `uv.lock` or `pyproject.toml`, and the same job passed on #750's own PR run about an hour earlier. These are newly published advisories, not a regression either PR introduced. httpcore2 2.9.1 CVE-2026-84381 fix 2.10.0 httpx2 2.9.1 CVE-2026-84378 fix 2.10.0 httpx2 2.9.1 CVE-2026-84379 fix 2.11.0 httpx2 2.9.1 CVE-2026-84380 fix 2.11.0 httpx2 2.9.1 CVE-2026-84382 fix 2.12.0 Both arrive transitively through `mcp`. 2.12.0 clears all five. The bump also adds `httpx2-jsfetch` 1.0 to the lock, which is worth naming rather than letting it pass as noise in a lockfile diff: httpx2 2.12.0 splits its transport so a browser build can use JS fetch, and the dependency is marked `sys_platform == 'emscripten'` — Pyodide/WASM only. It is never installed on any platform gflow supports, and `anyio`, `httpcore2` and `truststore` gain the complementary `!= 'emscripten'` markers in the same refactor. Verified: `uvx pip-audit==2.10.1` on the exported requirements reports "No known vulnerabilities found"; `uv sync --frozen` installs 2.12.0; 194 MCP + smoke tests and 1781 api/features/worker tests pass on the new resolution.
…nar gate (#765) `run_images` and the trust branches of `submit_images_and_observe` had no offline coverage at all — every image test mocked `run_images` away. That put `new_coverage` at 77.4% against an 80% gate, so #750's merge turned develop's SonarCloud check red even though the PR itself was 14/14 green: SonarCloud is skipped on fork PRs, so the gate first ran on the merge commit. The coverage gap and the risk were the same thing. What was untested was the orchestration that decides whether a run is trustworthy: - `run_images` end to end against the existing FakePage — the happy t2i path, the pre-submit refusal of an unported form, the missing-`--project` ConfigurationError, and the case where references upload but never become mention chips. That last one is the silent-degrade-to-T2I failure: Flow accepts the submit, bills it, and returns a plausible image that ignored the reference. - The image submit's own credits check. It is a second copy of the video path's, so it needed its own proof: a drained wallet REPLACES Flow's submit button (#721), and reporting that as selector drift tells the user to file a frontend bug that no code change can fix. Both directions are pinned — warning present means insufficient credits, warning absent means the anchor really is gone and drift is correct. - The submit-stays-disabled timeout. migrated_composer.py coverage 88% -> 92%, uncovered lines 92 -> 67; `run_images` (2094-2124) goes from entirely unexecuted to fully covered. No src/ change, so no Flow surface is touched and an e2e run is out of scope for this commit rather than left blank.
`gflow auth login` now drives real Chrome through Playwright, watches for the completed Flow sign-in and closes the window itself. Closing it yourself still verifies. Where Playwright cannot resolve a Chrome channel, or Google rejects the browser, login falls back automatically to the previous subprocess flow — no new flag, nothing to choose. Built on the 2026-09-08 spike (docs/superpowers/spikes/): G12 blocks `navigator.webdriver`, NOT Playwright or bundled Chromium. Real Chrome without the stealth flags was rejected at /v3/signin/rejected in 17.5 s; bundled Chromium with them signed in normally. The `bare` control arm is what made that conclusive. Live-verified on four paths (evidence in the PR thread): - auto-close fires end to end — elapsed_s 84.8, reproduced 3x - manual close verifies from disk — exit 0, never exit 12 - `--browser auto` selects and completes - window closed mid-2FA — noticed in 2 s, exit 8, not a 600 s hang Four defects the live runs and a council review forced out, none of which offline testing had surfaced: - The session poll was hitting `/fx/api/auth/session` every 3 s throughout login, including mid-callback. That is the real cause of the 2026-09-08 600 s timeout, which had been recorded as "timed out un-driven". - Gating that poll on `labs.google` alone would have timed out on every migrated account — i.e. both maintainer accounts. - A host check does not exclude NextAuth's callback at all: it runs on the app's own origin, so `/fx/api/auth/callback/google` passed straight through. The gate now excludes the auth routes too. - `page.is_closed()` was reachable only via `except PlaywrightError`, so a window closed while on Google's host was never noticed — a full deadline wait, session endpoint touched 0 times. Also replaces a fourth copy of the Flow-host set with the existing `flow_host_kind` (https-required, exact-host, ValueError-safe), fixes `POLL_INTERVAL_SECONDS` governing only one of two sleeps, and drops three exit-14 doc remediations prescribing advice the spike disproved.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v0.72.0 — published to PyPI and GitHub Releases from the signed tag
v0.72.0(db5ac82f).Brings the full
developintegration history ontomain.Headline
gflow auth logincloses the browser for you (feat(auth): close the sign-in browser when the sign-in is done #767). Playwright-driven real Chrome, watches for the completed Flow sign-in, closes the window itself; closing it yourself still verifies. Automatic subprocess fallback where Playwright cannot resolve a Chrome channel or Google rejects the browser. No new flag.gflow image t2iand local-filei2ionflow.google.comvia the page-ownedogiZ0bwire.Gates
Live verification
docs/LIVE_VERIFICATION_v0.72.0.md— 7 verified sections, 3 recorded as NOT verified with reasons.Auto-close verified on four paths against a migrated account at $0: auto-close fires (84.8 s, reproduced 3x), manual close still verifies (exit 0, never exit 12),
--browser autocompletes, and a window closed mid-2FA is noticed in 2 s (exit 8) where it previously ran the full 600 s deadline. Migrated-host CLIt2ire-run first-hand this cycle rather than shipping on the contributor's evidence.Recorded as unresolved: the queued-MCP
i2itwin failed with exit 27 naming a dialog it cannot identify — on an account that has already consented, so the message's leading hypothesis does not fit. No incident bundle is written for that error class, so nothing names the dialog. Filed as #770, which also proposes tracking per-account upload consent in the data layer so the guard can stop guessing. Not a regression from this release.The OAuth-callback mechanism behind the poll fix is inferred, not proven — #769 carries the spike that would settle it.
Doc-review
A three-reviewer council found four items the eight green CI gates could not see: an untracked
LIVE_VERIFICATION_v0.72.0.md(links resolved against the working tree and would have 404'd once pushed), the CVE bump missing from the changelog, a disproved claim still stated as fact in an unmirrored tutorial, and a user-facing fix absent from the ledger. All four fixed before the tag.