> ## Documentation Index
> Fetch the complete documentation index at: https://piyushvyas.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Element Identity

> Stable refs, identity signals, and the PageElementRegistry

BAP tracks elements across observations using a stable identity system. Instead of fragile positional refs that change every time the page updates, BAP generates refs based on element identity signals that persist across DOM changes.

## Stable Refs

When you run `bap observe`, each interactive element gets a stable ref like `@submitBtn` or `@e7f3a2`:

```
@submitbtn    button    "Submit"          role:button:"Submit"
@emailinput   textbox   "Email address"   label:"Email address"
@e7f3a2       link      "Learn more"      text:"Learn more"
```

These refs persist across multiple observations of the same page. Clicking `@submitbtn` works whether you observed the page 1 second or 30 seconds ago, even if the DOM shifted.

## Identity Signals

BAP uses a priority-ordered set of signals to identify elements:

<Steps>
  <Step title="data-testid (highest stability)">
    Developer-controlled, unlikely to change between deployments.

    ```
    Element: <button data-testid="submit-btn">Submit</button>
    Ref:     @submitbtn
    ```
  </Step>

  <Step title="HTML id">
    Fairly stable, but can be auto-generated by frameworks. `Element: <input id="email-field" />
          Ref: @emailfield`
  </Step>

  <Step title="aria-label">
    Human-readable, good for accessibility-conscious apps. `Element:{" "}   <button aria-label="Close dialog">X</button>
          Ref: @closedialog`
  </Step>

  <Step title="Hash-based (fallback)">
    Combined hash of role, name, tagName, parentRole, and siblingIndex.

    ```
    Element: <a href="/about">Learn more</a>
    Ref:     @e7f3a2
    ```
  </Step>
</Steps>

## Ref Generation

The `generateStableRef()` function follows this priority:

```
1. data-testid → normalize → @submitbtn
2. HTML id     → normalize → @emailfield
3. aria-label  → normalize → @closedialog
4. Hash        → base36    → @e7f3a2
```

Normalization lowercases the string, removes special characters, and truncates to 12 characters. The `@` prefix distinguishes stable refs from positional `e<N>` refs.

## Identity Comparison

BAP compares element identities using a weighted scoring system:

| Signal         | Weight | Description                            |
| -------------- | ------ | -------------------------------------- |
| `testId`       | 3      | Highest weight -- developer-controlled |
| `id`           | 3      | High weight -- usually stable          |
| `ariaLabel`    | 2      | Medium-high -- accessibility attribute |
| `role`         | 2      | Medium -- ARIA role                    |
| `name`         | 2      | Medium -- accessible name              |
| `tagName`      | 1      | Low -- HTML tag                        |
| `parentRole`   | 1      | Low -- structural context              |
| `siblingIndex` | 1      | Low -- position among siblings         |

The `compareIdentities()` function returns a confidence score between 0 and 1. A score of 1.0 means perfect match; a score below 0.5 suggests the elements are different.

## PageElementRegistry

Each page maintains an element registry that maps stable refs to element info:

```typescript theme={null}
interface PageElementRegistry {
  elements: Map<string, ElementRegistryEntry>;
  lastObservation: number;
  pageUrl: string;
}

interface ElementRegistryEntry {
  ref: string; // Stable ref (e.g., "@submitbtn")
  selector: BAPSelector; // Best selector for this element
  identity: ElementIdentity; // Identity signals
  lastSeen: number; // Timestamp of last observation
  bounds?: BoundingBox; // Visual position
  cachedCssSelector?: string; // Fusion 4: cached CSS path
}
```

### Registry Lifecycle

1. **Created** when a page is first observed
2. **Updated** on each `bap observe` -- existing elements get `lastSeen` refreshed, new elements are added
3. **Preserved** across session park/restore (dormant sessions keep registries)
4. **Cleaned up** when entries go stale (not seen for 60 seconds)

### Size Limits

The registry is capped at 2,000 entries per page (`ELEMENT_REGISTRY_MAX_SIZE`). When exceeded, the oldest entries by `lastSeen` are evicted first. This prevents unbounded memory growth on pages with heavy DOM churn.

## Stale Entry Cleanup

The `cleanupStaleEntries()` function runs in two phases:

1. **Time-based**: Remove entries not seen for longer than `ELEMENT_STALE_THRESHOLD` (60 seconds)
2. **Size-based**: If still over 2,000 entries, evict the oldest by `lastSeen`

## Self-Healing Selectors

When a primary selector fails (element moved or was removed), BAP tries fallback identity signals in order:

1. `data-testid` (if available)
2. `aria-label` + `role` combination
3. `id` attribute
4. `name` attribute

This `resolveSelectorWithHealing()` mechanism means agents can use the same ref across page navigations and dynamic content updates without manual correction.

<Tip>
  For the most stable element targeting, encourage your web application to use `data-testid`
  attributes. BAP will generate predictable, human-readable refs like `@submitbtn` that survive
  across deployments.
</Tip>

## Alternative Selectors

Each `InteractiveElement` returned by `observe` includes an `alternativeSelectors` array, ordered by reliability:

1. `testId` selector (if element has `data-testid`)
2. `role` selector (ARIA role + name)
3. `id`-based CSS selector (with special character escaping)
4. `text` selector
5. `css` selector (computed CSS path)

<Warning>
  Element IDs from the DOM can contain dots, colons, and brackets (valid in HTML, invalid bare in
  CSS). BAP escapes special characters when constructing `#id` CSS selectors for alternative
  selectors.
</Warning>
