Repository navigation
Description
Summary
On the migrated host's video path, the incident bundle is captured after the pooled page has been parked at about:blank. So every such bundle ships:
"tag_counts": {"div": 0, "button": 0, "input": 0, "textarea": 0,
"dialog": 0, "iframe": 0, "video": 0, "img": 0},
"ligatures": [], "ligature_count": 0, "overlays": [],
"title": {"category": "other", "length": 0},
"url": {"host_category": "other", "route": "other"}and a blank white screenshot.
Why this is worse than a missing artifact
The bundle is not empty, it is confidently empty. It looks like a successful capture of a dead page, so a reader concludes "the page was gone" — when the truth is "we blanked it before looking". A missing artifact prompts you to go and measure. A zeroed one answers the question, wrongly, and stops the investigation.
This is the same failure family the project has been correcting all week: a measurement that could not be taken, recorded as a measurement of absence. Here the diagnostics themselves manufacture it, on every incident.
It has already cost. #692's reporter attached a bundle with ligature_count: 0 and every element count at zero, and that was read as evidence about the migrated DOM. It was evidence about capture ordering.
Mechanism
_generate_video_locked wraps the migrated composer call in a try/finally, and the finally parks the pooled page:
finally:
# The pooled page would otherwise stay on flow.google.com/project/<id>, and the
# NEXT request on this client would be routed by that URL instead of by its own shape
await page.goto("about:blank", wait_until="commit", timeout=5_000)The park is correct and should stay — it prevents the next request being routed by a stale URL. The problem is ordering: incident capture happens at the CLI layer (run_with_handlers), which is outside the transport, so it runs after the finally has already blanked the page it is about to photograph.
Measured today
Two UiSelectorDriftError incidents from gflow video t2v on the migrated host, both with all element counts zero and a blank screenshot:
20260907T101449Z-3beb72d8-…20260907T101604Z-d3f87d23-…
Both were undiagnosable from their bundles. The actual cause — the account was out of Veo credits, and Flow had replaced the submit control with a prompt-warning-button (#721) — was only findable by writing a probe that inspects the page while it is still alive. The information was on screen at failure time and the bundle threw it away.
Suggested fix
Capture the page state before the teardown runs, not after. Options, roughly in order of cost:
- Snapshot inside the transport at the point of failure and attach it to the raised error, so the CLI-layer bundle writes a snapshot taken while the page was live.
- Have the
finallyskip the park when an exception is propagating, and let the incident capture park it afterwards. - Failing both, make the capture detect
about:blank/ an all-zero tally and recordcapture_status: "post_teardown"instead of"complete"— so at minimum the bundle stops asserting a blank page as a finding.
(3) alone would have prevented today's dead end and is the smallest change; (1) is the one that actually preserves the evidence.
Not measured
Whether the same ordering affects the image path or the labs video path. I only observed it on the migrated video path, twice. Worth checking the other finally blocks that park or close a page before assuming it is unique to this one.
Activity
feat(723): attach character entities on the migrated composer -- atta…
ffroliva commentedon Sep 7, 2026
Third independent instance, and this bundle carries a discriminator the all-zero ones do not: it proves the page moved between the failure and the capture, rather than merely being empty when captured.
Run:
tests/e2e/test_insufficient_credits_e2e.pyagainstci-probe, 2026-09-07 13:49 (migrated host,$0, nothing submitted).The failure was raised here:
The bundle written for that failure records:
host_category: "other", on a failure that occurred onflow.google.com. That field is derived from the URL at capture time. A page still sitting onhttps://flow.google.com/aboutwould classify as the Flow host;"other"is whatabout:blankclassifies as. So the URL the error reports and the URL the bundle captured are different pages — which is the mechanism this issue names, caught in the act rather than inferred from a zero count.Why that distinction earns a comment: an all-zero bundle is ambiguous on its own, because a genuinely dead or unrendered page also produces zeros. This one is not ambiguous. The failure happened on one URL and the evidence was gathered from another, so the zeros are not a measurement of the failing page at all.
That is what makes the bundle actively misleading rather than merely thin. It reads as a successful capture of an empty page, and a reader draws "the DOM was gone" from something that only shows "we blanked it before looking". The #692 precedent in this issue is exactly that read: a reporter's
div: 0, button: 0was taken as evidence the labs DOM had disappeared.Suggested acceptance criterion, since the fix should be checkable rather than eyeballed: a regression test asserting that for a captured failure, the bundle's recorded URL equals the URL in the raised error. Cheap, mechanical, and it fails today.
test(723): pin submode-follows-reference, and measure the picker's am…
feat(723): attach character entities on the migrated composer -- atta…
test(723): pin submode-follows-reference, and measure the picker's am…
fix(character): stop claiming a success gflow never observed
fix(character): --format-prompt now waits for the rewrite it asked for
spike(723): read the wire live — the entity submit is REJECTED, not u…
docs(723): the entity guard refuses for a different reason than it says