/** * src/sensors/actionability.ts * * Playwright-Strategy Actionability Engine for WeaveTab * ───────────────────────────────────────────────────── * Implements every correctness principle from playwright-strategy.md: * * 1. RAF-stability gate — element must not be animating before we touch it * 2. Strict hit-target — elementsFromPoint at the computed click point must * confirm the target is on top (or the target's child). * 3. WeaveTab transparency — WeaveTab's own UI (data-wt-ignore nodes) is excluded * from the hit stack so the tool never blocks itself. * 4. 4-way scroll rotation — escape sticky headers / overlays by cycling four * scrollIntoView alignments before giving up. * 5. Per-action backoff — [0, 20, 100, 100, 500] ms retry on transient failures. * 6. Rich blocker report — on permanent occlusion, return the blocking element's * description so the model can reason about it. * * Usage: * import { verifyActionability } from "../sensors/actionability.js"; * const result = await verifyActionability(session, selector); * if (result.status !== "ACTIONABLE") { ... } */ import CDP from "chrome-remote-interface"; export type ActionabilityStatus = "ACTIONABLE" | "NOT_FOUND" | "INVISIBLE" | "UNSTABLE" | "OCCLUDED" | "FINGERPRINT_MISMATCH"; export interface OccluderInfo { tag: string; id: string; className: string; ariaLabel: string | null; isWeavetabOwned: boolean; } export interface ActionabilityResult { status: ActionabilityStatus; /** Computed click center in viewport coordinates. */ x?: number; y?: number; /** Populated only when status === "OCCLUDED". */ occludedBy?: OccluderInfo; /** True if the blocker was WeaveTab's own UI and can be ignored. */ blockerIsWeaveTab?: boolean; } export interface ActionabilityOptions { /** * Maximum time (ms) to wait for stability before giving up. * Default: 600ms. */ stabilityTimeoutMs?: number; /** * Optional fingerprint to verify the element hasn't been replaced by * a framework re-render. Checked once before anything else. */ fingerprint?: { tag?: string; role?: string; }; /** * Total time budget across all retry attempts. * Default: 2000ms. */ totalTimeoutMs?: number; } /** * Full Playwright-strategy actionability verification. * * Runs up to `BACKOFF.length` attempts with 4-way scroll rotation, * RAF stability gating, WeaveTab-transparent hit-target checking, * and per-attempt retry backoff. * * Returns `status: "ACTIONABLE"` with computed (x, y) when safe to dispatch, * or a failure status with an optional `occludedBy` description. */ export declare function verifyActionability(session: CDP.Client, selector: string, opts?: ActionabilityOptions): Promise; /** * Quick check: is an element at these coords actually blocked by a non-WT overlay? * Used for lightweight pre-dispatch validation inside click.ts. */ export declare function quickHitCheck(session: CDP.Client, x: number, y: number, selectorOfTarget: string): Promise<{ clear: boolean; blockerDescription?: string; }>;