Better Fetch

· Paul Crossland

Punctuation, Placeholders, and Pressed Buttons

Fresh browser-automation bugs show why input intent, device state, page events, and application outcomes must reconcile.

A browser agent enters A+B, chooses the placeholder entry in a select, and releases a mouse button during cleanup. Every tool call returns normally. The page may still receive no plus sign, a different option value, or a different click event than the same task produces through another browser protocol.

These adapter decisions have production consequences. They can change a search result set, make an empty form look valid, or emit click where another backend emits auxclick before extraction starts.

The practical thesis is: browser interaction should be compiled from typed intent into an explicit device-state transition, then accepted only when page-observed events and the intended application postcondition agree; punctuation, empty values, and cleanup order are data semantics, not adapter details.

This is reliability guidance for owned or properly authorized browser tasks. A correct input adapter does not authorize form submission, account access, purchases, consent, or interaction past a denial, challenge, rate limit, or publisher restriction. Those remain policy stops or explicit review points.

Fresh evidence at three semantic boundaries

Primary sourceDateWhat it contributes
Browser Use issue 55692026-08-28Reproduces a literal + entering the shortcut parser, becoming empty key components, and producing no character event. It also identifies Control++ as an affected ambiguous form.
Browser Use issue 5573 and pull request 55952026-08-28 and 2026-08-29Show ordinary text such as center triggering Enter-specific delay because scheduling was inferred from a substring rather than from the key event actually dispatched. The proposed fix tracks whether Enter was emitted.
Browser Use pull request 55542026-08-26Shows a DOM serializer collapsing explicit value="" and an absent value attribute for select options, changing placeholder metadata and format inference.
Puppeteer issue 15379 and pull request 153802026-08-24Document CDP and WebDriver BiDi mouse-state differences: repeated down() behavior and button-release order during reset can change the event sequence observed by the page.

All cited fixes are open at publication time. They are evidence to test, not proof that an installed package or hosted browser already behaves differently.

Earlier Better Fetch posts already require action completion proof, browser revision evidence, and pagination-transition receipts. The repeated angle would merely say to log actions or verify the final page. The new surplus is the interaction compiler contract: intent encoding, DOM metadata, protocol device state, page events, and application state can disagree before outcome validation begins.

One string cannot safely mean text, a key, and a chord

An API named send_keys often accepts all of these:

  • literal text such as center;
  • one named key such as Enter;
  • a chord such as Control+A;
  • punctuation such as + that may also delimit a chord.

That is a compact interface, but it creates a grammar. The literal plus report demonstrates the ambiguity: checking whether the string contains + is not enough to decide that it represents a shortcut. Splitting the literal character yields empty operands, and an apparently successful high-level action emits no useful character.

The Enter-delay report shows grammar leaking into timing. The adapter dispatched the text correctly but searched the original input for enter and added a navigation delay. Across many fields or near a deadline, false delays can move later actions across hydration, validation, or timeout boundaries. Scheduling then describes the request's spelling, not what reached the browser.

Prefer typed operations at the agent boundary:

  • insert_text(text) for literal text;
  • press_key(key) for one physical or semantic key;
  • press_chord(modifiers, key) for a shortcut;
  • select_option(value, label, selection_policy) for a select;
  • pointer_down(button), pointer_up(button), and explicit reset policy for pointer state.

If compatibility requires a string shorthand, parse it once into that typed representation and return the parse result in the action receipt. Reject ambiguous or empty operands. Downstream timing should follow emitted semantic events, not rescan the source string.

Empty, missing, and placeholder are different states

The select-option change exposes the observation side of the same contract. In HTML, an option with an explicitly empty value and an option with no value attribute are not interchangeable metadata. The first commonly represents a placeholder whose submitted value is empty. For the second, text can supply the effective value.

A serializer that uses “value is truthy” to decide whether the attribute existed collapses those states. The agent may see Choose a quantity as the value instead of an empty placeholder. A format detector can also infer a type from no samples because “all elements match” is true for an empty set in several languages.

Preserve at least four fields in an agent-facing option snapshot:

  • attribute presence;
  • raw attribute value, including an explicit empty string;
  • effective browser value;
  • visible label and selected or disabled state.

Do not ask a model to reconstruct presence from a normalized value. For deterministic workflows, select by a reviewed stable value and verify the control's effective value afterward. If duplicate values, dynamic replacement, or an empty placeholder make the target ambiguous, stop before submission rather than guessing from the label.

Cleanup is another input operation

Mouse reset sounds like teardown, but a page can observe it. The Puppeteer report shows why order matters. If left, middle, and right buttons are down, releasing them in fixed order is not equivalent to undoing them in reverse press order. The remaining button mask changes after every release, and the page can receive different click or auxclick events.

Cancellation, drag recovery, lost connections, retries, and worker reuse all invoke cleanup. A page-visible reset can open a menu, activate a target, or end a drag over the wrong element. If CDP and BiDi implement one high-level method differently, a protocol migration can change data without changing selectors or the page.

Track keyboard and pointer state as an ordered state machine: pressed keys, modifier mask, pressed buttons in acquisition order, pointer position, active target generation, and the operation that owns each state. Release sequentially so each event carries the state produced by the prior release. When ownership or state is unknown, quarantine or recycle the context instead of sending a speculative reset into a live third-party page.

Issue an interaction receipt

A useful receipt separates six milestones:

  1. Intent: typed operation, literal payload digest or approved bounded value, target element generation, and expected postcondition.
  2. Compilation: parser version, normalized key or button names, modifiers, attribute-presence decisions, and any rejected ambiguity.
  3. Dispatch: protocol backend, ordered low-level event classes, timing, and device state before and after.
  4. Page observation: event types and trusted owned-fixture markers when available, active element, effective control value, and unexpected click or navigation signals.
  5. Application transition: expected URL, request, validation marker, result-set digest, or other source-specific state change.
  6. Settlement: remaining pressed state, cleanup events, target generation, policy outcome, and final verdict.

Useful verdicts include intent_preserved, ambiguous_blocked, dispatch_incomplete, page_event_mismatch, postcondition_missing, cleanup_side_effect, policy_stop, and unknown.

Do not broadly log form text, credentials, personal data, cookies, or complete authenticated URLs. Operation classes, lengths, bounded digests, semantic key names, state masks, approved test markers, and restricted evidence references are normally enough.

An owned-fixture interaction matrix

Run the complete deployed stack against pages you control:

  1. Insert literal +, text containing enter and return, Unicode text, newlines, and supported shortcuts. Compare requested semantics with browser events and final field values.
  2. Test a literal plus and a modifier-plus chord separately. Require no empty key events and no ambiguity in the compiled plan.
  3. Present options with an explicit empty value, no value attribute, duplicate values, numeric values, and disabled placeholders. Verify raw presence, effective value, format hint, and selection result.
  4. Hold several mouse buttons in different orders, repeat a down, then reset. Compare CDP and BiDi page-event sequences and final button masks.
  5. Cancel during a key chord and during a drag. Require bounded cleanup with no unexpected activation, submission, or navigation.
  6. Re-render the control between planning and dispatch. Reject the stale element generation instead of typing into whichever element now has focus.
  7. Make input validation asynchronous. Prove that event dispatch success cannot substitute for the required application marker or network response.
  8. Return login, challenge, denial, payment, and 429 fixtures. Require a policy verdict and prohibit input retries, protocol switching, or session rotation from broadening the task.

Run the matrix after automation-library, browser, protocol, keyboard-layout, device-emulation, or agent-tool changes. Direct DOM assignment can help in owned tests, but it may skip keyboard, input, change, validation, or framework handlers. Choose the interaction mode explicitly and test the required semantics.

The operator decision rule

When a browser task enters the wrong value or changes unexpected state, find the first disagreement. If typed intent became an ambiguous parse, block before dispatch. If dispatch differs across protocols, repair or pin the adapter before blaming the page. If page events disagree with the plan, do not infer success from the tool response. If events match but the application postcondition does not, preserve the attempt as possibly side-effecting and apply a bounded, source-safe retry policy. If cleanup generated a transition, quarantine the context and dependent extraction.

A browser action is not a string sent to a page. It is a compilation pipeline with state, ordering, observable events, and application consequences. Preserve those semantics end to end, and tiny punctuation or placeholder differences stop becoming plausible, silent changes in production web data.