Skip to main content

Recover locators with Heal

SHAFT Heal is an optional, action-scoped WebDriver locator recovery provider. It is disabled by default and is delivered by io.github.shafthq:shaft-heal. The required shaft-engine artifact owns the integration SPI and continues to throw the original locator failure when the provider is absent, rejects every candidate, or encounters an internal error.

Add and enable the module

Import shaft-bom, then add the optional module beside shaft-engine:

<dependency>
<groupId>io.github.shafthq</groupId>
<artifactId>shaft-heal</artifactId>
</dependency>

Enable deterministic recovery explicitly:

healing.strategy=shaft-heal

Run the test suite with the strategy enabled:

mvn test '-Dhealing.strategy=shaft-heal'

When the original web locator fails, SHAFT evaluates eligible candidates and records the selected candidate, confidence, alternatives, and rejection reason under target/shaft-heal/reports.

The equivalent current-thread override is:

SHAFT.Properties.healing.set()
.strategy("shaft-heal")
.minimumConfidence(0.75)
.ambiguityMargin(0.10);

SHAFT first attempts the original locator. Recovery runs only after a web locator-not-found result, and the engine executes the action only after the provider returns exactly one validated element.

Strategy and Healenium coexistence

ConfigurationEffective behavior
healing.strategy=disabledNo SHAFT Heal. Legacy heal-enabled=true still enables Healenium for compatibility.
healing.strategy=healeniumHealenium only.
healing.strategy=shaft-healSHAFT Heal only, even when heal-enabled=true remains in an older property file.
healing.strategy=compositeHealenium driver wrapping plus SHAFT Heal fallback.

Use healing.strategy=composite only after validating both systems against the same application. It is an explicit opt-in because both providers can add latency and maintain separate histories.

Deterministic decision policy

The provider stores a successful element fingerprint and later discovers a bounded candidate set from stable semantic evidence:

  • accessible name and associated label
  • configured test IDs
  • stable ID and name
  • role, type, placeholder, title, alt, and autocomplete
  • visible text
  • a checksum of the structural DOM path

Each evidence category is scored separately. A candidate is used only when it is unique, remains in the requested frame or shadow context, satisfies the action preconditions, meets healing.minimumConfidence, and leads the next eligible candidate by at least healing.ambiguityMargin. Ties and low confidence preserve the original failure.

Trust threshold and warnings

healing.minimumTrustPercentage is the preferred confidence gate for teams that want a human-readable percentage. Leave it at -1 to keep using healing.minimumConfidence; set it from 0 to 100 to require that minimum trust before any recovered locator can be used.

healing.strategy=shaft-heal
healing.minimumTrustPercentage=85

The deterministic score must pass this gate before optional provider metadata is considered. Visual or AI provider scores can rank eligible candidates, but they cannot rescue a locator candidate that failed the deterministic trust threshold.

When SHAFT accepts a healed locator, it logs a warning and attaches the warning to the report. The warning includes the broken locator, healed locator, trust percentage, configured threshold, provider status, and evidence summary. Common secret-looking tokens are redacted before logging.

History and reports

History is local, versioned, checksummed, bounded, retention-limited, and written atomically:

healing.history.enabled=true
healing.history.path=target/shaft-heal/history.json
healing.history.maxEntries=500
healing.history.retentionDays=30

Attempt reports are attached to Allure and written below target/shaft-heal/reports. Reports include the failed locator, normalized failure category, ranked candidates, per-category scores, selected candidate, decision reason, provider metadata, and post-action outcome. Runtime code can inspect the current thread's latest report with ShaftHeal.lastReport().

Successful original resolutions seed history. A recovered fingerprint replaces the old record only after the engine reports that the intended action succeeded.

Privacy and optional providers

SHAFT Heal uses a whitelist-only evidence model. It does not collect input values, cookies, authorization headers, full page source, or the full DOM. Password fields omit text, labels, accessible names, placeholders, and titles. URLs exclude query strings and fragments, and common token or credential patterns are redacted.

Visual comparison is local and disabled by default:

healing.visual.enabled=false

When enabled, add shaft-visual. Its HealingVisualProvider compares the stored element screenshot with candidate screenshots. Visual scores remain separate and cannot bypass the deterministic confidence threshold.

AI reranking is also disabled by default:

healing.ai.enabled=false

AI uses the provider-neutral controls from shaft-pilot-core. Add shaft-ai only for direct OpenAI, Anthropic, Gemini, or Ollama calls, and configure the Pilot approval, evidence, budget, timeout, and provider properties separately. Only minimized candidate records are eligible for transfer. Provider output may rerank supplied candidate IDs but cannot invent an element or override deterministic acceptance.

Source changes and limits

SHAFT Heal never edits test source during runtime. The healing.sourcePatch.enabled=false property is a consent gate reserved for a separate reviewed SHAFT Doctor proposal workflow; this module always reports sourcePatchProposed=false.

The current provider supports web element actions in the active browsing context. Native mobile recovery is excluded. Frame identity is retained, and shadow-content recovery is supported while the configured shadow host remains resolvable. A changed frame locator or shadow-host locator preserves the original failure.