"""Structured locator candidate model.""" from __future__ import annotations from dataclasses import dataclass, field from typing import Any, Optional SCHEMA_LOCATOR = "openclaw.ui_inspector.locator_candidate.v1" @dataclass class LocatorCandidate: schema: str = SCHEMA_LOCATOR strategy: str = "" scope: dict[str, Any] = field(default_factory=dict) properties: dict[str, Any] = field(default_factory=dict) expression: str = "" expected_count: int = 1 actual_count: Optional[int] = None unique: Optional[bool] = None stability_score: float = 0.0 uses_index: bool = False uses_coordinates: bool = False validation: str = "none" # snapshot_only | live_tree | cross_state | cross_session | none reasons: list[str] = field(default_factory=list) ambiguous: bool = False production_eligible: bool = False def mark_counts(self, actual: int, *, expected: int = 1) -> None: self.expected_count = int(expected) self.actual_count = int(actual) self.unique = self.actual_count == self.expected_count self.ambiguous = not bool(self.unique) # Coordinates / index never become production primary automatically. self.production_eligible = bool( self.unique and not self.uses_coordinates and not (self.uses_index and self.stability_score < 0.7) )