# The site changed. Your program didn't.

Every target is recorded with several ranked locators and a fingerprint of the element it found. When the site changes and they stop matching, Kaabist finds the element again, writes the fix down as a proposal, and lets you promote it to a new version.

## Candidates, ranked

Test ids, roles with names, stable ids, exact text, filtered classes: each target keeps several candidates, tried in order until one matches exactly one element. After the first successful run Kaabist adds more, so every target has at least three.

```
{ "click": { "candidates": [
  { "testid": "renew" },
  { "role": "button", "name": "Renew" },
  { "text": "Renew", "exact": true }
] } }
```

## Deterministic first

When every candidate misses, the healer compares the page against the element's fingerprint, then looks for fuzzy anchors such as the text and the shape of the value. A language model is optional, and only ranks or proposes; every candidate is verified against the page.

## Confidence decides

A fix scored 0.90 or higher can carry the current job on, and is still recorded as a proposal. Below that, the job pauses as drift, with the evidence, for you to decide. Nothing is promoted to the program without an approval.

## Before your customers notice

Canary runs exercise your programs on a schedule, so drift shows up as a proposal before a customer's job fails on it.

```
curl -X POST https://api.kaab.ist/v1/proposals/prp_93Hd/approve \
  -H "Authorization: Bearer $KAAB_API_KEY" \
  -d '{"promote": true}'
```

## Questions

### Does healing need an LLM?

No. The pipeline is deterministic by default; an LLM is an optional extra step that only proposes candidates, each verified on the page.

### Can a bad fix slip into my program?

No. Fixes are proposals. Only an approval promotes one into a new program version, and the old version stays one rollback away.
