Repository navigation
Description
Consolidated findings from a 2026-07-14/15 production session (Compiled Growth content/business-parable/protocol — cooking story s007 via gen_scenes_resumable.sh on gflow-cli 0.32.1/0.35.0). Eight dimensions, all confirmed live against real Flow projects. No account/token details included below.
1. Agentic cohort lock has no forced-flip, only detect-and-abort
--ui-mode classic (0.34.0+) correctly detects when Flow's server has pinned a profile to the agentic arm and aborts before submitting (UiModeUnavailableError, exit 28) — this is good, safe behavior. But there's no way to request a flip back to classic; the only lever is blind retry. In this session both test accounts (denon82, ffroliva) got stuck agentic-only for extended periods (one scene needed 13 consecutive retry attempts spanning ~20 minutes before landing classic again). A gflow auth refresh-cohort (force a fresh page load / new tab context) or documented guidance on what actually un-sticks the arm would help — right now the remediation hint ("cohort flaps per page load, RETRY") doesn't hold when it's pinned for tens of minutes.
2. Agentic-mode multi-candidate ambiguity burns real attempts before failing
agentic.py's _compose_directive sends a natural-language "Make me a picture of X" (singular for count=1) rather than a hard UI count control. Google's agentic assistant can ignore this and generate multiple candidates; await_images' ambiguity guard (issue #281 already referenced in the code) correctly refuses to guess and raises MediaAttributionError — but only after the generation already ran. Confirmed live: two consecutive attempts under --ui-mode auto both hit this path with zero usable output. (Image gen itself is free/credit-less on this account tier, so the cost here is wall-clock time, not money — but that may not be universal.) Would be good if agentic mode's count enforcement had a harder guarantee, or if await_images could download-and-let-caller-pick instead of hard-failing when it's unambiguous which is "first"/newest.
3. "Poisoned" character entity smuggles referenceEntities into unrelated calls
Repro: gflow character create --body-prompt ... where the body-triptych step 400s (WireFormatError) still persists the entity (face image done, persist-before-spend saga worked as designed — good). But afterward, plain gflow image i2i --ref <path-or-uuid> calls in the same project — never passing --reference-entity — started including referenceEntities: [{entityId: <broken-entity>}] in the batchGenerateImages request body, which then 400s. Confirmed via the ui_automation.batch_request_body debug log's summary.reference_fields. gflow character rm --id <id> -y immediately fixed it (mentions_reference_entities back to false). Something in local media-tracking is associating a plain uploaded/selected image with an unrelated character entity in the same project — worth tracking down since it's a silent, hard-to-diagnose failure mode for anyone who's ever run character create with a body-prompt that failed.
4. Systemic duplicate uploads — media_refs.py's UUID-avoidance could be replaced by picker name-search
Not a gflow-cli bug per se (this monorepo's own media_refs.py deliberately avoids UUID refs for canonicals + multi-ref scenes, citing two 2026-07-10 findings: a fresh canonical's UUID can be unpickable, and the picker can only select the first UUID ref in a multi-ref call). Owner visually confirmed 8+ duplicate son.jpg uploads in one project's media library as a result. Flow's own picker UI has a search-by-filename field (type "son.jpg" → filtered results sorted "Most Used" → "Add to Prompt") that gflow-cli's automation doesn't use at all today — it only ever fresh-uploads or attempts raw-UUID picker selection. A gflow image i2i --ref-search "<name>" (search picker by name, select top/oldest match, click "Add to Prompt") could dedupe reliably without gflow needing to persist/trust a UUID across runs — worth prototyping in both classic and agentic mode (agentic's chat surface may have no picker-search equivalent at all, needs recon).
5. Zero click/interaction humanization
Every .click()/.fill()/keyboard.insert_text() in ui_automation.py is followed by a hardcoded wait_for_timeout(N) — same literal ms every call site, never randomized. Prompt entry is one atomic insert_text() paste of the whole prompt (a deliberate reliability choice per the code comment — insert_text avoids Slate's fill() incompatibility — but the least human-like way to enter text). No playwright-stealth, no webdriver-property patching beyond --disable-blink-features=AutomationControlled, no mouse-movement paths anywhere. Bonus: _persistent_context_kwargs() hardcodes viewport 1280x720 and locale en-US identically for every launch on every machine — a fixed cross-install fingerprint independent of click timing. Given how much of this issue is plausibly bot-detection-driven (cohort pinning, an "Action required" account-verification flag observed mid-session), jittering the existing timeouts and varying viewport/locale seem like a cheap first experiment.
6. No HAR capture, no traceback-unlock — and the hash-only errors are deliberate, not a bug
Grepped the whole package: no record_har, no context.tracing, no --har/--trace flag anywhere. --verbose only surfaces the structured info-level event stream (ui_automation.* events) — it does not unlock full exception detail. observability.py's emit_unhandled_event() is intentionally hash-only (message_hash/stack_hash, never raw message/traceback) with an explicit privacy-safety docstring about frame locals potentially containing signed URLs/tokens. The CLI's own stdout hint ("Re-run with --verbose to capture details") is misleading for this error class — there is no flag that does what it implies. Two independent, non-conflicting additions would help: (a) a --har <path> flag wired to Playwright's built-in record_har_path context option (the kwargs-builder is already documented as an "overridable seam" for exactly this) — no new dependency; (b) a GFLOW_CLI_DEBUG_TRACEBACK=1 env var that bypasses the redaction with a loud "may leak tokens, don't share this log" warning, for local debugging only.
7. Camoufox — feasible but not a drop-in swap
Browser engine is fully hardcoded at the actual launch call site (self._pw.chromium.launch_persistent_context(...) in client.py) — no engine-selection abstraction exists to plug into (the kwargs-builder "seam" only affects launch options, not engine choice). Bigger blocker: the cookie/session machinery (_preread_flow_session_cookies, Chrome cookie-DB decryption) is Chrome-cookie-format-specific end to end. A Camoufox (Firefox-based) path would need its own fresh interactive login building a new Firefox-format profile from scratch — none of the existing profile_<name> Chrome directories would carry over. Real but contained scope: new engine branch + new auth flow for that engine, evaluated independently before any reliability comparison is meaningful.
8. gflow image batch looks underused for reliability, but adding refs is genuinely harder than "add a field"
gflow image batch mounts one Flow project/editor session for up to 5 prompts ("stay-mounted editor") instead of relaunching per-prompt — this alone would cut the number of "roll the cohort-lock dice" attempts roughly 5x for any multi-scene job (we ran 11 separate t2i/i2i invocations for s007's stills, each independently re-navigating/re-binding UI mode). But BatchPromptItem (image_batch.py) has no ref/reference_entity field at all — batch is t2i-only, unusable for our i2i character-consistency scenes as-is.
Adding --ref support to batch is more than a schema field, though: a batch's later rows may want to reference an image generated by an earlier row in that same batch (e.g. scene 2 referencing scene 1's freshly-generated still), not just a pre-existing canonical. That means the batch executor needs intra-batch dependency ordering (row N can't resolve ref: "row:2" until row 2's media UUID exists), not just "attach a fixed ref to every row independently." Worth scoping as its own design question rather than a quick addition — happy to help think through the ordering/dependency model against our real multi-scene manifests if useful.
Happy to help prototype any of these (picker name-search resolution in particular) against our real production scenes if useful test cases.
Activity
bugfix(ui_automation): intercept and strip unrequested referenceEntities
ffroliva commentedon Jul 15, 2026
To support clean 1-to-1 ticket-to-PR relationships, this issue has been split into individual tickets:
bugfix(ui_automation): intercept and strip unrequested referenceEntities