Skip to content

Commit d94920d

Browse files
angusbezzinaclaude
andcommitted
test(marquee): probe sub-phase 7g pins the overlay out of every ladder
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2 parents c273dde + 33d9822 commit d94920d

1 file changed

Lines changed: 46 additions & 0 deletions

File tree

Sources/AnnotKitOverlayProbe/main.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,39 @@ final class OverlayProbeDelegate: NSObject, NSApplicationDelegate {
13171317
check7(source.marqueeLadder(in: degenerate).isEmpty,
13181318
"zero-area frame -> [] (a click is not a marquee)")
13191319

1320+
// 7g — NOTHING from AnnotKit's own overlay can enter the candidate set.
1321+
// Sharper for a marquee than for a click: a drag rect by construction
1322+
// spans screen the overlay is drawn across, and overlay elements are
1323+
// genuinely identified and genuinely meaningful, so the rule cannot
1324+
// reject them — a large overlay surface would WIN pass 1 on area and
1325+
// bind the user's note to our own UI. The walk is rooted at the HOST
1326+
// window (the overlay is filtered out of `kAXWindows` by identifier
1327+
// BEFORE the root is picked, never by "key" or "frontmost"), so the
1328+
// overlay's descendants are out of reach by construction. This asserts
1329+
// that construction against the live tree instead of trusting it.
1330+
let app = AXUIElementCreateApplication(ProcessInfo.processInfo.processIdentifier)
1331+
AXUIElementSetAttributeValue(app, "AXEnhancedUserInterface" as CFString, kCFBooleanTrue)
1332+
let rawWindows = AX.windows(app)
1333+
let overlayPanel = rawWindows.first { AX.string($0, kAXIdentifierAttribute) == overlayWindowIdentifier }
1334+
check7(overlayPanel != nil, "the overlay panel IS a live AX window during the drag (a real shadowing risk)")
1335+
if let overlayPanel {
1336+
let panelFrame = AX.frame(overlayPanel)
1337+
// Without this the whole sub-phase would be vacuous: an overlay that
1338+
// does not cover the drag region proves nothing about one that does.
1339+
check7(panelFrame.contains(card.frame),
1340+
"sanity: the expanded overlay SPANS the drag region (the card is drawn beneath it)")
1341+
let overlayIDs = Set(self.axCollectIDs(in: overlayPanel, depth: 0))
1342+
let hostWindow = rawWindows.first { AX.string($0, kAXTitleAttribute) == "AnnotKit Harness W7 (marquee)" }
1343+
let panelIsAXChildOfHost = hostWindow.map { host in
1344+
AX.children(host).contains { CFEqual($0, overlayPanel) }
1345+
} ?? false
1346+
print(" overlay panel \(fmt(panelFrame)) carries \(overlayIDs.count) identified element(s); " +
1347+
"exposed as an AX CHILD of the host window: \(panelIsAXChildOfHost)")
1348+
let everyResult = cardLadder + sectionLadder + buttonLadder + insideLadder
1349+
check7(!everyResult.contains { overlayIDs.contains($0.id) },
1350+
"no marquee result — target or rung — is an element from AnnotKit's own overlay subtree")
1351+
}
1352+
13201353
self.marqueeController?.unmount()
13211354
window.orderOut(nil)
13221355
self.finish()
@@ -1332,6 +1365,19 @@ final class OverlayProbeDelegate: NSObject, NSApplicationDelegate {
13321365
return nil
13331366
}
13341367

1368+
/// Every non-empty AX identifier in `element`'s subtree, including its own —
1369+
/// the set of ids a walk that strayed into the overlay would surface.
1370+
func axCollectIDs(in element: AXUIElement, depth: Int) -> [String] {
1371+
guard depth < 32 else { return [] }
1372+
var out: [String] = []
1373+
let id = AX.string(element, kAXIdentifierAttribute)
1374+
if !id.isEmpty { out.append(id) }
1375+
for child in AX.children(element) {
1376+
out.append(contentsOf: axCollectIDs(in: child, depth: depth + 1))
1377+
}
1378+
return out
1379+
}
1380+
13351381
/// Recursive raw-AX search for elements matching one of `subroles`.
13361382
func axFindAll(in element: AXUIElement, subroles: Set<String>, depth: Int) -> [AXUIElement] {
13371383
guard depth < 12 else { return [] }

0 commit comments

Comments
 (0)