Skip to content

dom- selector IDs are invisible to representation.interactive — three validation/lookup paths degrade #220

Description

@TickTockBent

Summary

Selector-mode (dom-) element IDs from charlotte_find's CSS selector mode (#191) are stored in a separate durable registration map (ElementIdGenerator.domQueryIds) and are never present in representation.interactive (which is AX-tree-only). Three code paths validate or look up element IDs solely against representation.interactive, so they silently degrade when handed a dom- ID.

None of these block the v0.7.0 release — they are edge cases on the new selector-mode feature, and the primary AX-tree paths are correct. Filing as a fast-follow. Surfaced during review of #219.

Symptoms

1. charlotte_toggle skips its toggleable-control guard for dom- IDssrc/tools/interaction.ts:349-352

The guard is if (targetElement && !TOGGLEABLE_TYPES.has(targetElement.type)). For a dom- ID, targetElement (looked up in preToggleRepresentation.interactive) is undefined, so the guard is skipped and toggle fires an unvalidated left-click on whatever the selector resolved to — the exact misrouted-click case #204 set out to prevent.

2. near / within throw a misleading error for a dom- spatial anchorsrc/tools/observation.ts:355,387

The reference element is resolved via representation.interactive.find(el => el.id === near). A dom- reference is never found, so the bounds check throws "Reference element '<id>' has no bounds; cannot apply spatial filter." The real reason is that the element isn't in the interactive list, not that it lacks bounds.

3. matchIndex skew between registration and re-resolutionsrc/tools/observation.ts:121 vs src/tools/tool-helpers.ts:252

findBySelector increments matchIndex only after a successful DOM.describeNode (nodes that throw hit catch { continue } without incrementing). But reResolveDomQueryId uses the stored matchIndex as a direct index into the raw nodeIds[] returned by DOM.querySelectorAll (which includes every match). If any earlier match fails describeNode, re-resolution indexes the wrong node — resolving a cached dom- ID onto a different element. Low probability (requires a querySelectorAll match that fails describeNode), but it is the class of silent ID-migration bug the salted-hash change (#190) set out to eliminate.

Suggested fix

A single change closes all three: make dom- registrations resolvable for bounds/type validation — e.g. store bounds + a coarse type on the DomQueryRegistration and have these paths consult the ElementIdGenerator registration when the ID is absent from representation.interactive. For symptom 3, track the raw loop position separately from matchIndex (or filter nodeIds at re-resolution using the same describe-fallibility).

Verification

Each symptom confirmed by reading the cited file:line on release/0.7.0 @ 4ceffd2.

// ticktockbent

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinginteractionBrowser interaction toolsobservationPage observation and content extractionpriority: mediumModerate impact improvement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions