What
#703 swept three selector constants for the labs/migrated ligature-carrier split (<i class="google-symbols"> vs <mat-icon>) — add_2, arrow_drop_down, accessibility_new. It missed PROMPT_FORMAT_SELECTORS, which became a silent no-op and shipped as #727.
Nothing proves that was the last one. Measured on 2026-09-07 at 7c1d4c6d:
git grep "i\.google-symbols" src/gflow_cli --include=*.py | grep -v "mat-icon" | wc -l
55
55 single-carrier literals across ui_automation.py, ui_automation_video.py, mode_control.py, diagnostics.py and drivers/{agentic,factory}.py. Two consecutive PRs have now fixed one of these by hand, which is the signal that this is a sweep problem, not a selector problem.
Named candidates from the #729 council (all pre-existing, none introduced there):
| Constant |
Location |
Exposure |
IMAGE_MODEL_PICKER_TRIGGER |
ui_automation.py:104 |
Sharpest. Sole selector, no mat-icon twin — while its sibling _CHARACTER_MODEL_PICKER_TRIGGER_SELECTORS in the same file carries both and a comment recording that omitting mat-icon logged model-picker trigger not found on the migrated host. Likely masked today because _select_image_model only runs after a panel that warn-returns first — not verified on the migrated host. |
ui_automation_video.py:251 |
same shape |
same class |
OVERLAY_CLOSE_BUTTON_SELECTORS |
ui_automation.py:490-494 |
clear / close are <i>-only. Degraded, not dead — the [role=dialog]:has(a[href*=changelog]), button[data-dismiss] and Escape fallbacks remain. |
NEW_PROJECT_SELECTORS |
ui_automation.py:329-331 |
add_2 tier is <i>-only; falls back to a regex + 14 localised labels. |
Why nothing caught it, and why nothing will catch the next one
.github/workflows/selector-probe.yml drives run_probe.py --surface editor against src/gflow_cli/flow_selectors/registry.py. That registry has zero entries for the Format button:
grep -rn "personal_recommendations\|format" src/gflow_cli/flow_selectors/ --include=*.py
(no output)
And e2e_character is opt-in (GFLOW_CLI_E2E_RUN_CHARACTER=1); the nightly canary runs e2e_auth only — 18 of 87 tests. So the drift was invisible from both directions at once: no probe watched the selector, and no nightly test exercised the command.
Suggested shape
- Sweep the 55, both carriers — or better, anchor on the shared
.google-symbols class, which matches <i> and <mat-icon> alike, since the class was never the discriminator (the tag was).
- Prefer custom elements where one exists —
<flow-format-prompt-button>, <flow-slot-chip-button>, <flow-generate-icon-button> are component boundaries that survive both a carrier change and a translation.
- Register the surfaced anchors in
flow_selectors/registry.py so selector-probe.yml watches them nightly. This is the half that makes the fix durable.
Worth a /gflow:predict first — item 1 touches ~55 call sites across 6 files and item 3 changes what the nightly probe asserts.
Evidence
What
#703swept three selector constants for the labs/migrated ligature-carrier split (<i class="google-symbols">vs<mat-icon>) —add_2,arrow_drop_down,accessibility_new. It missedPROMPT_FORMAT_SELECTORS, which became a silent no-op and shipped as #727.Nothing proves that was the last one. Measured on 2026-09-07 at
7c1d4c6d:55 single-carrier literals across
ui_automation.py,ui_automation_video.py,mode_control.py,diagnostics.pyanddrivers/{agentic,factory}.py. Two consecutive PRs have now fixed one of these by hand, which is the signal that this is a sweep problem, not a selector problem.Named candidates from the #729 council (all pre-existing, none introduced there):
IMAGE_MODEL_PICKER_TRIGGERui_automation.py:104mat-icontwin — while its sibling_CHARACTER_MODEL_PICKER_TRIGGER_SELECTORSin the same file carries both and a comment recording that omitting mat-icon loggedmodel-picker trigger not foundon the migrated host. Likely masked today because_select_image_modelonly runs after a panel that warn-returns first — not verified on the migrated host.ui_automation_video.py:251OVERLAY_CLOSE_BUTTON_SELECTORSui_automation.py:490-494clear/closeare<i>-only. Degraded, not dead — the[role=dialog]:has(a[href*=changelog]),button[data-dismiss]and Escape fallbacks remain.NEW_PROJECT_SELECTORSui_automation.py:329-331add_2tier is<i>-only; falls back to a regex + 14 localised labels.Why nothing caught it, and why nothing will catch the next one
.github/workflows/selector-probe.ymldrivesrun_probe.py --surface editoragainstsrc/gflow_cli/flow_selectors/registry.py. That registry has zero entries for the Format button:And
e2e_characteris opt-in (GFLOW_CLI_E2E_RUN_CHARACTER=1); the nightly canary runse2e_authonly — 18 of 87 tests. So the drift was invisible from both directions at once: no probe watched the selector, and no nightly test exercised the command.Suggested shape
.google-symbolsclass, which matches<i>and<mat-icon>alike, since the class was never the discriminator (the tag was).<flow-format-prompt-button>,<flow-slot-chip-button>,<flow-generate-icon-button>are component boundaries that survive both a carrier change and a translation.flow_selectors/registry.pysoselector-probe.ymlwatches them nightly. This is the half that makes the fix durable.Worth a
/gflow:predictfirst — item 1 touches ~55 call sites across 6 files and item 3 changes what the nightly probe asserts.Evidence
docs/superpowers/spikes/2026-09-07-character-format-button-anchor.mddocs/superpowers/memory/ligature-carrier-differs-by-host.md