Skip to content

fix(click): observe post-click effects + scope snapshot locators to modal#11

Merged
kepptic merged 1 commit into
mainfrom
fix/click-observation-and-modal-scope
Apr 30, 2026
Merged

fix(click): observe post-click effects + scope snapshot locators to modal#11
kepptic merged 1 commit into
mainfrom
fix/click-observation-and-modal-scope

Conversation

@kepptic
Copy link
Copy Markdown
Owner

@kepptic kepptic commented Apr 30, 2026

Summary

  • ghax click now reports observable downstream effectsdialogDismissed, urlChanged, preDialogCount, postDialogCount, observedMs — alongside the existing ok. Default 300ms budget, configurable via --observe-ms <n>, opt-out via --no-observe. Fixes the silent-no-op confusion where loc.click() resolved before React actually unmounted a confirm modal.
  • ghax snapshot now scopes per-node Locators to the auto-detected modal when dialog-scope kicks in. Previously the rendered ARIA tree was modal-only but getByRole(...) ran page-wide, so a same-named button outside the modal could trigger strict-mode errors or, where Playwright's pick resolved uniquely, silently click the wrong element. Stacked dialogs (HubSpot stacks an alertdialog over an already-open dialog) hit this routinely.
  • Smoke flake fixconsole --dedup test now uses a per-run marker so the daemon's CircularBuffer can no longer cause count=10 on a second smoke run against the same daemon.

Why this matters

A field report described ghax click @e<ref> returning {ok: true} on the HubSpot "Yes, save" confirmation modal but the modal not dismissing. Reproduced live: the click was dispatched correctly via Playwright's CDP Input.dispatchMouseEvent (so isTrusted: true — that hypothesis was wrong); HubSpot just runs an async network round-trip before unmounting the dialog, ~1.3s later. The old {ok: true} told callers nothing about whether the effect landed. Agents retry, double-save.

The new fields let agents write deterministic checks like if (!result.dialogDismissed && !result.urlChanged) retry().

Test plan

  • npm run typecheck
  • npm run build
  • cargo build --release
  • GHAX_BIN=$PWD/target/release/ghax npm run test:smoke — 99/99 pass in ~400s
  • Live HubSpot repro on /service-keys/21999358/key/38111555:
    • click EditurlChanged: true, postDialogCount: 1
    • click SavepreDialogCount: 1, postDialogCount: 2 (alertdialog stacks)
    • click "Yes, save" --observe-ms 2500urlChanged: true

New smoke checks

  • click reports dialogDismissed when a modal closes
  • click reports dialogDismissed=false when nothing changes
  • click --no-observe skips post-click observation
  • snapshot scopes locators to the auto-detected modal

- click handler now observes downstream effects within a 300ms budget
  (configurable via --observe-ms, opt-out via --no-observe) and returns
  dialogDismissed, urlChanged, preDialogCount, postDialogCount,
  observedMs alongside ok. Eliminates the silent-no-op confusion seen
  on HubSpot's "Save changes?" alertdialog where the trusted click was
  dispatched correctly but loc.click() resolved ~1.3s before React
  unmounted the modal — agents would see ok:true, retry, and
  double-save.
- snapshot now scopes per-node Locators to the auto-detected modal.
  Previously the rendered ARIA tree was modal-only but getByRole(...)
  ran page-wide, so a same-named button outside the modal (zombie
  React subtree, stacked dialogs) could trigger strict-mode or pick
  the wrong element.
- console --dedup smoke check uses a per-run marker so a warm daemon's
  CircularBuffer can no longer cause count=10 on the second smoke run.

99/99 smoke checks pass. Live-verified on HubSpot service-keys page.
@kepptic kepptic merged commit 32597bf into main Apr 30, 2026
1 check passed
@kepptic kepptic deleted the fix/click-observation-and-modal-scope branch April 30, 2026 03:59
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.

1 participant