Skip to content

fill repairs and fails on fields that normalize their input #2634

Description

@kylefit

Summary

fill verifies text entry by exact string comparison against element.value. Any field that normalizes what it stores — digit grouping, masks, currency formatting — fails that comparison even when entry succeeded. fill then runs its destructive repair (clear + retype) against an already-correct field, and finally returns TEXT_ENTRY_MISMATCH.

Observed

iOS 26.6.1, physical iPhone SE (3rd generation), agent-device 0.20.5. The relevant logic is unchanged on main. Target: a Flutter text field applying a ## ### ## ## digit-grouping formatter.

$ agent-device fill 187 286 '000629177'
Error (TEXT_ENTRY_MISMATCH): text entry verification failed:
  expected "000629177", observed "00 062 91 77"

00 062 91 77 is exactly the requested digits, formatted. The field held the correct value both before and after the repair. From the runner log, emitted before repair ran:

AGENT_DEVICE_RUNNER_REPAIR_TEXT_ENTRY expectedLength=9 observedLength=12

observedLength=12 is the complete, correctly formatted value.

Entry itself is not the problem. agent-device type '000629188' --delay-ms 0 into the same empty field produces the correct value on the first attempt, so there is no dropped-character or timing issue to repair.

Cause

In apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift on main:

  • textEntryValueMatchesExpected (~line 510) accepts only exact equality, plus an exception for a trailing submit suffix. Any normalization fails.
  • isRepairableTextEntryMismatch (~line 601) returns true unconditionally when repairMode == .replacement, so it never consults isLikelyDroppedCharacterTextEntryMismatch immediately below it. That subsequence check would already classify this mismatch as non-repairable.

So replacement-mode entry into any normalizing field always follows the same path: mismatch, repair, mismatch, error.

Impact

The repair is the more serious half. clearTextInput sends moveCaretToEnd — an edge tap computed from a frame the code's own comment notes may be stale — plus up to 120 delete keystrokes, then retypes. It mutates a field that was already correct, and the retype has no first-character warmup, so it is strictly less reliable than the entry it replaces.

There is no way to opt out. verified == false is a hard error in RunnerTests+CommandExecution.swift, and fill exposes no --no-verify or --expect flag.

Required behavior

  1. fill succeeds when the field's value is a normalization of the requested text — at minimum, when every requested character appears in order in the observed value.
  2. Replacement-mode repair does not run when the observed value already contains the requested characters in order.
  3. Optionally, a way to state the expected post-normalization value:
    agent-device fill <target> '000629177' --expect '00 062 91 77'
    

Completion conditions

  • fill into a field that groups digits as they are typed returns ok and performs no clear/retype.
  • A field that genuinely drops characters still mismatches and still repairs.
  • Regression fixture: examples/test-app's FormScreen already has a field-phone input, which currently stores the raw value. Formatting it on change reproduces this, and fill 'id=field-phone' '000629177' should then pass.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions