Healing

For AI agents: this page is Markdown at https://squiggle.sh/docs/flows/healing.md. Every docs page is listed at https://squiggle.sh/llms.txt, and all of them are one file at https://squiggle.sh/llms-full.txt.

When a selector stops matching, Squiggle looks for the same control, uses it if it's confident, and writes the new selector into your flow file. You review the change in your next diff.

What healing does

Step through a redesign of a sign-in screen, and compare a test that taps a fixed point, a selector that never heals, and Squiggle:

The screen your tests were written against.

  1. Coordinatestap(110, 244)Passed: pressed “Sign in”
  2. Text selectortap(text('Sign in'))Passed: pressed “Sign in”
  3. Squiggle flow- tap: { testID: sign-in }Passed: pressed “Sign in”

When a selector matches nothing, Squiggle scores the controls that could be the same one, by name, testID, role, label, text and the line of source that renders it. If the best one scores high enough, the step uses it and passes, and the run reports what changed:

Terminal
squiggle flow checkouthealed testID: buy-button -> checkout-button (score 82, margin 22)rewrote 1 healed selector(s)  .squiggle/flows/checkout.yaml  review the diff — a heal is a guess that worked once

If no control scores high enough (60 or more), the step fails as a control that wasn’t found, and the flow file is left alone.

How close the call was

The margin is how many points the heal won by: its score minus the higher of 60 and the best score of any other control. A control and the components inside it count as one control. A heal with a margin under 20 is thin: a few points of difference between runs could send the step to a different control, so the run warns you:

Terminal
squiggle flow draftshealed testID: save -> save-draft (score 74, margin 9, thin)! 1 heal(s) with a thin margin  step 3 'save-draft' by 9  under 20 points from a different element — pin the selector to a testID

Accept the heal, or better, give the control a testID, so the next run doesn’t have to guess. A negative margin means the heal scored under 60 and was taken only because the flow uses lossy-fallback, marked lossy. Studio shows the margin beside each healed step, and a red line under a thin one. With --json, each entry in heals carries its margin.

The new selector is written into the flow file, so the next run doesn’t need to heal. Review the change before you commit it: a heal is a good guess, not a proof.

To see how the margin moves, take the tour below. Its flow taps a sort button whose testID has since been renamed, and the demo app lets you rename the button’s label while you watch. Delete a word and the margin shrinks. Change the whole label and the score drops under 60, so the step would fail instead of guessing. Under the margin is every term of the score, so you can see what it was built from.

Loading the live Studio…
A run that healed a renamed selector. Live, in your browser.Open in Studio

Heal & warningsStudio tour · 8 steps

Choose a mode

Set healing at the top of the flow:

YAML
flow: checkouthealing: strictsteps: …
ModeWhat it does
adaptiveThe default. Heals when it is confident, and updates the flow file.
strictNever heals and never changes the file. A moved control fails the step. Use it when the move itself should fail the test.
lossy-fallbackAlso takes the best match when it isn’t confident, and marks it. Useful while a screen is changing every day; noisy after that.

Reading a run that healed

A run that passed with heals isn’t the same as one that passed cleanly. The report lists every heal, and Studio marks healed steps in the run. A flow run from standard input has no file to update, so the run tells you the heal wasn’t saved.