NEC-301: The e2e harness can send a click or keystroke twice when WebDriver retries it #304

Merged
nectenda-agent merged 3 commits from worktree-nec-301-the-e2e-harness-can-send-a-click-or-keys into main 2026-10-17 23:36:30 +01:00
Collaborator

Task: NEC-301 — https://projectron.nerchure.com/tasks/320

webdriver re-sends a failed command up to three times. NEC-300 made scripts run at most once, but a click or keystroke that had already landed when its error came back was sent again, doubling an Enter or a typed word, which looks like a sync duplication. The harness now fails an input on its first error answer, through webdriver's transformResponse hook, with an error that names the input, the driver's error and NEC-301, and keeps the driver's error name so webdriverio's own recoveries (wait until clickable, scroll and re-click, refetch a stale element) still run. The success check is a port of webdriver's isSuccessfulResponse. A request.retry listener was tried first and cannot work for element commands (webdriverio wraps an element's emit as an async command). Timeouts, broken sockets and unreadable 5xx answers never reach the hook and are still re-sent; the spec lists them as limits, accepted by the user. Three Kanban tests that clicked a card editor while a span still covered it relied on the old back-off and now wait for the editor to be clickable.

Spec: docs/changes/NEC-301-refuse-input-resend/spec.md

Changelog

NONE

Task: NEC-301 — https://projectron.nerchure.com/tasks/320 webdriver re-sends a failed command up to three times. NEC-300 made scripts run at most once, but a click or keystroke that had already landed when its error came back was sent again, doubling an Enter or a typed word, which looks like a sync duplication. The harness now fails an input on its first error answer, through webdriver's transformResponse hook, with an error that names the input, the driver's error and NEC-301, and keeps the driver's error name so webdriverio's own recoveries (wait until clickable, scroll and re-click, refetch a stale element) still run. The success check is a port of webdriver's isSuccessfulResponse. A request.retry listener was tried first and cannot work for element commands (webdriverio wraps an element's emit as an async command). Timeouts, broken sockets and unreadable 5xx answers never reach the hook and are still re-sent; the spec lists them as limits, accepted by the user. Three Kanban tests that clicked a card editor while a span still covered it relied on the old back-off and now wait for the editor to be clickable. Spec: `docs/changes/NEC-301-refuse-input-resend/spec.md` ## Changelog NONE
webdriver re-sends nearly any failed command up to three times. A click or
keystroke that had already landed when its error came back would land again:
one Enter becomes two, which looks exactly like a sync duplication. Inputs
cannot be tagged in the renderer the way NEC-300 tagged scripts, so the harness
now fails an input on its first error answer, through webdriver's
transformResponse hook, with a message naming the input, the driver's error and
NEC-301.

A request.retry listener was tried first and does not work: on an element,
webdriverio wraps emit as an async command, so the listener's throw became an
unhandled rejection while the click was re-sent 3+3 times. Transport failures
never reach transformResponse and are still re-sent; the spec records that.

In the container, a click under an overlay now fails at once with no re-send;
with the hook removed it was re-sent for 11.6 s.

Task: NEC-301

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqRATumbRDjG4cMYAiuA6i
Review found the first cut's error check disagreed with webdriver's own
isSuccessfulResponse both ways, so some failed answers could still be re-sent
and some accepted ones refused. It is now a branch-for-branch port, tested row
by row.

The refusal also threw a plain Error, which hid the driver's error name from
webdriverio's element-not-interactable recovery (wait until clickable, send
once more). The error now carries that name, as webdriver's own does.

The spec and README now also name timeouts and unreadable 5xx answers, which,
like a broken socket, never reach the hook and are still re-sent.

Task: NEC-301

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqRATumbRDjG4cMYAiuA6i
Wait for a Kanban card's editor to be clickable before clicking it
All checks were successful
Release note / release-note (pull_request) Successful in 20s
CI / build (pull_request) Successful in 5m26s
CI / e2e (pull_request) Successful in 12m18s
CI / promote (pull_request) Has been skipped
CI / build (push) Successful in 6m17s
CI / e2e (push) Successful in 12m23s
CI / promote (push) Successful in 32s
1f9885e450
While Kanban redraws after a remote card arrives, a span still covers the
editor a double-click just opened. The click used to land only because
webdriver re-sent it through ~3.75 s of back-off; with inputs no longer
re-sent (NEC-301), the gate's container run failed there. The three tests that
open a card editor now wait for what they need, not for retries.

Task: NEC-301

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqRATumbRDjG4cMYAiuA6i
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Nectenda/nectenda!304
No description provided.