evidence: PR #6368 native keyboard journey

Publish the sanitized exact-head receipt, MP4, AX snapshots, cleanup record, and causal native mutant needed for inspectable review.

Signed-off-by: Thomas Petersen <thomasp@squareup.com>
This commit is contained in:
Thomas Petersen
2026-08-20 08:15:23 -04:00
parent ee03d19030
commit 957886d084
24 changed files with 825 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
23d329e23dfb7fc3a1710af8f29ae44a79896ea6958a5c212ad7e9201aaa5d38 README.md
ebb0a53f87a1e71708510937462b1e927c8ce6d9256c24ef299ccdabea776901 cleanup.txt
a60139a0b5918cec82e63d49c9377091b98c466a3fa56ee4a5eb90da189900e7 environment.txt
36690b6554077cfea3f30aace8b7bd9dbc738a26dd6f9267f758f73379436591 exact-adjacent.json
1e590f5113181a330d7a02e019f039fc18e001c952cd1cf70864c5d75937b39b exact-diagnostics.log
12761900cf63596841eaf546778eeabea80573744e2fa2003221544e1ee07ac2 exact-focus-crop.png
dc99f878a4802783d45b2ca2eeca3faeb71bce3420960d3c64228ea1778d04e4 exact-focused.json
2c39cd7fff5a2c37f15fd451e780359ce1b9aeeda130d74cad0b3a11bd6c40bb exact-journey.mp4
9e3934e6e67a1aa09ddb100f2365f5869bd317369f64b6185852e11f456a171f exact-receipt.json
484533763f9650aa381aff7c51ddc8dd826eddb1df019690b51e084f6b2db072 exact-selected-crop.png
1919e6d1ad9c769cd6c41fb4a225b53f01ad1e500e04ff76fc3e75d3d19bf802 exact-selected.json
36690b6554077cfea3f30aace8b7bd9dbc738a26dd6f9267f758f73379436591 mutant-adjacent.json
8bc29f598afe4a34d0902574b9863c8b4a2a2bf79a762a9721ecb47c7cbb0518 mutant-diagnostics.log
fec3651b16e5abc0852d1ec04dcfb167a42887fbdfbfb713897818b529f1938d mutant-focus-crop.png
dc99f878a4802783d45b2ca2eeca3faeb71bce3420960d3c64228ea1778d04e4 mutant-focused.json
3f0a5d2fc4182d7e966e4ee62a8aacece16180f6a10f5bb0d7606a96dff9de10 mutant-receipt.json
8070b9f873a0f49ccea41765b2dbca30df52a4ece47e6e2b29635b09094ee534 mutant.patch
e3784c2a95178b30fe8580d89d4c164b0a11a66fc3db3b09fc018af22219469f native_journey.swift
06d5865e68cb0085649934a4103df853e5fc305063d81f26485bf2acec0c7481 restored-adjacent.json
005aeada458090833df23d95e86082cf321c0d0dfb28a31cfb5dc94cfbc8a013 restored-diagnostics.log
dcd1a3efe372f5d5bb7ff412a4a59fa3b444c3d6ef850fa64660ec1b792f6794 restored-focused.json
332105d66ccd3b5db46ca2fd54d25492abf71bb3b801603d95b396c4a5305b3d restored-receipt.json
ddbb9a48ae499c31e571fcafde2d37e1b795203e2303a61708c1c3c7cf89d848 restored-selected.json

View File

@@ -0,0 +1,17 @@
# PR #6368 native keyboard evidence (sanitized public bundle)
Exact head: `ffb765e49e2db60fdb167fe58440f3c6d5efa17b`.
The native Tauri/WKWebView harness focused the adjacent row action, delivered macOS Tab (`key code 48`), asserted an entity-specific focused `AXCheckBox`, measured 732 bright focus-ring pixels, delivered Space (`key code 49`), and asserted checkbox value `1`, heading `1 task`, and `Clear selection`.
`exact-journey.mp4` is the complete 30-second interaction timeline cropped to the checkbox region so no workspace content is published on this public OSS PR. `exact-focus-crop.png` and `exact-selected-crop.png` show the focused and selected pixels. Semantic snapshots preserve the entity-specific `Open task` / `Select` prefixes while redacting the fixture title.
The feature-specific `mutant.patch` removes only `group-focus-within:opacity-100`. The same native harness then exited `1`: Tab still reached the named AX checkbox, but the visual measurement fell from 732 to 0 pixels. Restoring the class returned the harness to exit `0` and 732 pixels.
Artifacts:
- exact, mutant, and restored receipts plus AX snapshots
- exact, mutant, and restored step diagnostics
- native harness source and feature-specific mutant patch
- sanitized MP4 and focus/selected/mutant crops
- environment/isolation and cleanup records
- SHA-256 manifest

View File

@@ -0,0 +1,10 @@
Cleanup command: TERM process group 84227
Native launcher completion: observed
PASS app process group exited
PASS Vite port 30355 released
PASS no worktree agent sidecars remain
Post-cleanup HEAD: ffb765e49e2db60fdb167fe58440f3c6d5efa17b
Post-cleanup git status: clean
Post-cleanup git diff --check: pass

View File

@@ -0,0 +1,15 @@
PR: block/buzz#6368
HEAD: ffb765e49e2db60fdb167fe58440f3c6d5efa17b
Branch: projects-v6-pt2-selectable-workspaces
Pre-run git status: clean
Pre-run git diff --check: pass
Application: Buzz Dev (projects-v6-pt2-selectable-workspaces)
Application identifier: xyz.block.buzz.app.dev.projects-v6-pt2-selectable-workspaces
Launch command: BUZZ_SHARE_IDENTITY=1 just production
Vite port: 30355
Binary SHA-256: 1600d8d63cfca8942e7d809879ccd3738b3fc04239839f87be27ee6fd4ec9f4f
OS: macOS 26.6.1 (25G76)
Architecture: arm64
Display: 2560x1440 points, scale 2.0
Isolation: worktree-specific app identifier and Vite port; mutant restored before cleanup.
Publication note: full-screen artifacts remain local because this is a public OSS PR. Published crops, MP4, and semantic records redact workspace content without altering checkbox pixels or harness results.

View File

@@ -0,0 +1,15 @@
{
"description": "",
"focused": true,
"position": [
317,
224
],
"role": "AXButton",
"size": [
1921,
40
],
"title": "Open task [redacted fixture title]",
"value": ""
}

View File

@@ -0,0 +1,9 @@
[2026-08-20T11:58:25Z] application=Buzz Dev (projects-v6-pt2-selectable-workspaces) pid=84587 windowId=29941 mode=exact
[2026-08-20T11:58:25Z] AXPress Projects
[2026-08-20T11:58:26Z] AXPress Tasks
[2026-08-20T11:58:26Z] AXPress List layout
[2026-08-20T11:58:27Z] focused setup control Open task [redacted fixture title]
[2026-08-20T11:58:28Z] posted macOS HID Tab
[2026-08-20T11:58:30Z] focus-ring bright pixels=732
[2026-08-20T11:58:30Z] posted macOS HID Space
[2026-08-20T11:58:31Z] PASS native Tab → entity checkbox → visible focus ring → Space selection

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,15 @@
{
"description": "Select [redacted fixture title]",
"focused": true,
"position": [
335,
238
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "0"
}

Binary file not shown.

View File

@@ -0,0 +1,55 @@
{
"adjacentControl": {
"description": "",
"focused": true,
"position": [
317,
224
],
"role": "AXButton",
"size": [
1921,
40
],
"title": "Open task [redacted fixture title]",
"value": ""
},
"applicationTitle": "Buzz Dev (projects-v6-pt2-selectable-workspaces)",
"clearSelectionFound": true,
"focusRingBrightPixels": 732,
"focusedCheckbox": {
"description": "Select [redacted fixture title]",
"focused": true,
"position": [
335,
238
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "0"
},
"mode": "exact",
"pid": 84587,
"selectedCheckbox": {
"description": "Select [redacted fixture title]",
"focused": true,
"position": [
335,
238
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "1"
},
"selectedHeadingFound": true,
"status": "passed",
"windowId": 29941
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,15 @@
{
"description": "Select [redacted fixture title]",
"focused": true,
"position": [
335,
238
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "1"
}

View File

@@ -0,0 +1,15 @@
{
"description": "",
"focused": true,
"position": [
317,
224
],
"role": "AXButton",
"size": [
1921,
40
],
"title": "Open task [redacted fixture title]",
"value": ""
}

View File

@@ -0,0 +1,9 @@
[2026-08-20T12:09:37Z] application=Buzz Dev (projects-v6-pt2-selectable-workspaces) pid=84587 windowId=29941 mode=mutant
[2026-08-20T12:09:37Z] AXPress Projects
[2026-08-20T12:09:38Z] AXPress Tasks
[2026-08-20T12:09:39Z] AXPress List layout
[2026-08-20T12:09:40Z] focused setup control Open task [redacted fixture title]
[2026-08-20T12:09:41Z] posted macOS HID Tab
[2026-08-20T12:09:43Z] focus-ring bright pixels=0
[2026-08-20T12:09:43Z] FAIL visible focus-ring assertion failed: expected >=100 bright pixels, got 0
Exit status: 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,15 @@
{
"description": "Select [redacted fixture title]",
"focused": true,
"position": [
335,
238
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "0"
}

View File

@@ -0,0 +1,41 @@
{
"adjacentControl": {
"description": "",
"focused": true,
"position": [
317,
224
],
"role": "AXButton",
"size": [
1921,
40
],
"title": "Open task [redacted fixture title]",
"value": ""
},
"applicationTitle": "Buzz Dev (projects-v6-pt2-selectable-workspaces)",
"clearSelectionFound": false,
"failure": "visible focus-ring assertion failed: expected >=100 bright pixels, got 0",
"focusRingBrightPixels": 0,
"focusedCheckbox": {
"description": "Select [redacted fixture title]",
"focused": true,
"position": [
335,
238
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "0"
},
"mode": "mutant",
"pid": 84587,
"selectedHeadingFound": false,
"status": "failed",
"windowId": 29941
}

View File

@@ -0,0 +1,6 @@
diff --git a/desktop/src/features/projects/ui/ProjectEntityListRow.tsx b/desktop/src/features/projects/ui/ProjectEntityListRow.tsx
--- a/desktop/src/features/projects/ui/ProjectEntityListRow.tsx
+++ b/desktop/src/features/projects/ui/ProjectEntityListRow.tsx
@@
- "absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 group-focus-within:opacity-100",
+ "absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100",

View File

@@ -0,0 +1,455 @@
import AppKit
import ApplicationServices
import CoreGraphics
import Foundation
import ImageIO
import UniformTypeIdentifiers
struct Snapshot: Codable {
let role: String
let title: String
let description: String
let value: String
let focused: Bool
let position: [Double]
let size: [Double]
}
struct Receipt: Codable {
let status: String
let mode: String
let pid: Int32
let applicationTitle: String
let windowId: Int
let adjacentControl: Snapshot
let focusedCheckbox: Snapshot
let focusRingBrightPixels: Int
let selectedCheckbox: Snapshot?
let selectedHeadingFound: Bool
let clearSelectionFound: Bool
let failure: String?
}
enum HarnessError: Error, CustomStringConvertible {
case message(String)
var description: String {
switch self {
case let .message(message):
return message
}
}
}
let arguments = CommandLine.arguments
guard arguments.count == 4, let pid = Int32(arguments[1]) else {
fputs("usage: native_journey.swift <pid> <output-directory> <mode>\n", stderr)
exit(2)
}
let outputDirectory = URL(fileURLWithPath: arguments[2], isDirectory: true)
let mode = arguments[3]
let application = AXUIElementCreateApplication(pid)
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]
func timestamp() -> String {
ISO8601DateFormatter().string(from: Date())
}
func diagnostic(_ message: String) {
print("[\(timestamp())] \(message)")
fflush(stdout)
}
func attribute(_ element: AXUIElement, _ name: String) -> AnyObject? {
var result: CFTypeRef?
guard AXUIElementCopyAttributeValue(element, name as CFString, &result) == .success else {
return nil
}
return result as AnyObject?
}
func stringAttribute(_ element: AXUIElement, _ name: String) -> String {
attribute(element, name) as? String ?? ""
}
func boolAttribute(_ element: AXUIElement, _ name: String) -> Bool {
attribute(element, name) as? Bool ?? false
}
func pointAttribute(_ element: AXUIElement, _ name: String) -> CGPoint {
guard let rawValue = attribute(element, name) else {
return .zero
}
let value = rawValue as! AXValue
var point = CGPoint.zero
AXValueGetValue(value, .cgPoint, &point)
return point
}
func sizeAttribute(_ element: AXUIElement, _ name: String) -> CGSize {
guard let rawValue = attribute(element, name) else {
return .zero
}
let value = rawValue as! AXValue
var size = CGSize.zero
AXValueGetValue(value, .cgSize, &size)
return size
}
func snapshot(_ element: AXUIElement) -> Snapshot {
let position = pointAttribute(element, kAXPositionAttribute)
let size = sizeAttribute(element, kAXSizeAttribute)
return Snapshot(
role: stringAttribute(element, kAXRoleAttribute),
title: stringAttribute(element, kAXTitleAttribute),
description: stringAttribute(element, kAXDescriptionAttribute),
value: String(describing: attribute(element, kAXValueAttribute) ?? "" as AnyObject),
focused: boolAttribute(element, kAXFocusedAttribute),
position: [position.x, position.y],
size: [size.width, size.height]
)
}
func children(_ element: AXUIElement) -> [AXUIElement] {
attribute(element, kAXChildrenAttribute) as? [AXUIElement] ?? []
}
func find(
_ element: AXUIElement,
role: String? = nil,
title: String? = nil,
titlePrefix: String? = nil,
focused: Bool? = nil
) -> AXUIElement? {
let elementRole = stringAttribute(element, kAXRoleAttribute)
let elementTitle = stringAttribute(element, kAXTitleAttribute)
let matches =
(role == nil || elementRole == role) &&
(title == nil || elementTitle == title) &&
(titlePrefix == nil || elementTitle.hasPrefix(titlePrefix ?? "")) &&
(focused == nil || boolAttribute(element, kAXFocusedAttribute) == focused)
if matches {
return element
}
for child in children(element) {
if let match = find(
child,
role: role,
title: title,
titlePrefix: titlePrefix,
focused: focused
) {
return match
}
}
return nil
}
func waitFor(
role: String? = nil,
title: String? = nil,
titlePrefix: String? = nil,
focused: Bool? = nil,
timeout: TimeInterval = 12
) throws -> AXUIElement {
let deadline = Date().addingTimeInterval(timeout)
repeat {
if let match = find(
application,
role: role,
title: title,
titlePrefix: titlePrefix,
focused: focused
) {
return match
}
Thread.sleep(forTimeInterval: 0.2)
} while Date() < deadline
throw HarnessError.message(
"timed out waiting for role=\(role ?? "*") title=\(title ?? titlePrefix ?? "*") focused=\(String(describing: focused))"
)
}
func press(_ element: AXUIElement, label: String) throws {
let result = AXUIElementPerformAction(element, kAXPressAction as CFString)
guard result == .success else {
throw HarnessError.message("AXPress failed for \(label): \(result.rawValue)")
}
diagnostic("AXPress \(label)")
Thread.sleep(forTimeInterval: 0.7)
}
func focus(_ element: AXUIElement, label: String) throws {
let result = AXUIElementSetAttributeValue(
element,
kAXFocusedAttribute as CFString,
kCFBooleanTrue
)
guard result == .success else {
throw HarnessError.message("AX focus failed for \(label): \(result.rawValue)")
}
diagnostic("focused setup control \(label)")
Thread.sleep(forTimeInterval: 0.8)
}
func key(_ virtualKey: CGKeyCode, label: String) throws {
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/osascript")
process.arguments = [
"-e", "tell application \"System Events\"",
"-e", "set frontmost of first application process whose unix id is \(pid) to true",
"-e", "key code \(virtualKey)",
"-e", "end tell",
]
try process.run()
process.waitUntilExit()
guard process.terminationStatus == 0 else {
throw HarnessError.message(
"osascript could not deliver \(label): \(process.terminationStatus)"
)
}
diagnostic("posted macOS HID \(label)")
Thread.sleep(forTimeInterval: 1.2)
}
func writeJSON<T: Encodable>(_ value: T, to name: String) throws {
try encoder.encode(value).write(to: outputDirectory.appendingPathComponent(name))
}
func windowId() throws -> Int {
let windows =
CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID)
as? [[String: Any]] ?? []
for window in windows where window[kCGWindowOwnerPID as String] as? Int32 == pid {
if let number = window[kCGWindowNumber as String] as? Int {
return number
}
}
throw HarnessError.message("no onscreen window found for pid \(pid)")
}
func captureScreen(to url: URL) throws -> CGImage {
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/sbin/screencapture")
process.arguments = ["-x", "-D1", url.path]
try process.run()
process.waitUntilExit()
guard process.terminationStatus == 0 else {
throw HarnessError.message("screencapture failed with \(process.terminationStatus)")
}
guard
let source = CGImageSourceCreateWithURL(url as CFURL, nil),
let image = CGImageSourceCreateImageAtIndex(source, 0, nil)
else {
throw HarnessError.message("could not decode screenshot \(url.path)")
}
return image
}
func writePNG(_ image: CGImage, to url: URL) throws {
guard
let destination = CGImageDestinationCreateWithURL(
url as CFURL,
UTType.png.identifier as CFString,
1,
nil
)
else {
throw HarnessError.message("could not create PNG destination \(url.path)")
}
CGImageDestinationAddImage(destination, image, nil)
guard CGImageDestinationFinalize(destination) else {
throw HarnessError.message("could not write PNG \(url.path)")
}
}
func brightPixelCount(around element: AXUIElement, screenshot: CGImage) throws -> Int {
let position = pointAttribute(element, kAXPositionAttribute)
let size = sizeAttribute(element, kAXSizeAttribute)
let displayBounds = CGDisplayBounds(CGMainDisplayID())
let scale = Double(screenshot.width) / displayBounds.width
let padding = 6.0
let rect = CGRect(
x: (position.x - displayBounds.origin.x - padding) * scale,
y: (position.y - displayBounds.origin.y - padding) * scale,
width: (size.width + padding * 2) * scale,
height: (size.height + padding * 2) * scale
).integral
guard let crop = screenshot.cropping(to: rect) else {
throw HarnessError.message("could not crop checkbox at \(rect)")
}
try writePNG(crop, to: outputDirectory.appendingPathComponent("\(mode)-focus-crop.png"))
let width = crop.width
let height = crop.height
var pixels = [UInt8](repeating: 0, count: width * height * 4)
guard
let context = CGContext(
data: &pixels,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: width * 4,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
)
else {
throw HarnessError.message("could not create pixel-analysis context")
}
context.draw(crop, in: CGRect(x: 0, y: 0, width: width, height: height))
var count = 0
for index in stride(from: 0, to: pixels.count, by: 4) {
let red = Int(pixels[index])
let green = Int(pixels[index + 1])
let blue = Int(pixels[index + 2])
if max(red, green, blue) >= 150 {
count += 1
}
}
return count
}
func writeFailure(_ message: String, adjacent: Snapshot?, focused: Snapshot?, bright: Int?) {
let receipt = Receipt(
status: "failed",
mode: mode,
pid: pid,
applicationTitle: stringAttribute(application, kAXTitleAttribute),
windowId: (try? windowId()) ?? 0,
adjacentControl: adjacent ?? Snapshot(
role: "",
title: "",
description: "",
value: "",
focused: false,
position: [],
size: []
),
focusedCheckbox: focused ?? Snapshot(
role: "",
title: "",
description: "",
value: "",
focused: false,
position: [],
size: []
),
focusRingBrightPixels: bright ?? 0,
selectedCheckbox: nil,
selectedHeadingFound: false,
clearSelectionFound: false,
failure: message
)
try? writeJSON(receipt, to: "\(mode)-receipt.json")
}
var adjacentSnapshot: Snapshot?
var focusedSnapshot: Snapshot?
var measuredBrightPixels: Int?
do {
try FileManager.default.createDirectory(
at: outputDirectory,
withIntermediateDirectories: true
)
let appTitle = stringAttribute(application, kAXTitleAttribute)
guard appTitle == "Buzz Dev (projects-v6-pt2-selectable-workspaces)" else {
throw HarnessError.message("unexpected application title: \(appTitle)")
}
let nativeWindowId = try windowId()
diagnostic("application=\(appTitle) pid=\(pid) windowId=\(nativeWindowId) mode=\(mode)")
let projects = try waitFor(role: kAXButtonRole as String, title: "Projects")
try press(projects, label: "Projects")
let tasks = try waitFor(role: kAXCheckBoxRole as String, title: "Tasks")
try press(tasks, label: "Tasks")
let listLayout = try waitFor(role: kAXCheckBoxRole as String, title: "List layout")
try press(listLayout, label: "List layout")
if let clearSelection = find(application, role: kAXButtonRole as String, title: "Clear selection") {
try press(clearSelection, label: "Clear selection")
}
let adjacent = try waitFor(role: kAXButtonRole as String, titlePrefix: "Open task ")
try focus(adjacent, label: stringAttribute(adjacent, kAXTitleAttribute))
adjacentSnapshot = snapshot(adjacent)
try writeJSON(adjacentSnapshot, to: "\(mode)-adjacent.json")
try key(48, label: "Tab")
let focused = try waitFor(role: kAXCheckBoxRole as String, focused: true)
focusedSnapshot = snapshot(focused)
try writeJSON(focusedSnapshot, to: "\(mode)-focused.json")
guard focusedSnapshot?.title.hasPrefix("Select ") == true else {
throw HarnessError.message("Tab did not reach an entity-specific checkbox")
}
guard focusedSnapshot?.value == "0" else {
throw HarnessError.message("focused checkbox did not start unchecked")
}
let focusedScreen = try captureScreen(
to: outputDirectory.appendingPathComponent("\(mode)-focused-screen.png")
)
let brightPixels = try brightPixelCount(around: focused, screenshot: focusedScreen)
measuredBrightPixels = brightPixels
diagnostic("focus-ring bright pixels=\(brightPixels)")
guard brightPixels >= 100 else {
throw HarnessError.message(
"visible focus-ring assertion failed: expected >=100 bright pixels, got \(brightPixels)"
)
}
try key(49, label: "Space")
let selectionDeadline = Date().addingTimeInterval(6)
var selected = snapshot(focused)
var selectedHeadingFound = false
var clearSelectionFound = false
repeat {
selected = snapshot(focused)
selectedHeadingFound =
find(application, role: kAXHeadingRole as String, title: "1 task") != nil
clearSelectionFound =
find(application, role: kAXButtonRole as String, title: "Clear selection") != nil
if selected.value == "1", selectedHeadingFound, clearSelectionFound {
break
}
Thread.sleep(forTimeInterval: 0.2)
} while Date() < selectionDeadline
try writeJSON(selected, to: "\(mode)-selected.json")
guard selected.value == "1", selectedHeadingFound, clearSelectionFound else {
throw HarnessError.message(
"Space did not produce selected checkbox, 1 task heading, and Clear selection"
)
}
_ = try captureScreen(
to: outputDirectory.appendingPathComponent("\(mode)-selected-screen.png")
)
let receipt = Receipt(
status: "passed",
mode: mode,
pid: pid,
applicationTitle: appTitle,
windowId: nativeWindowId,
adjacentControl: adjacentSnapshot ?? snapshot(adjacent),
focusedCheckbox: focusedSnapshot ?? snapshot(focused),
focusRingBrightPixels: brightPixels,
selectedCheckbox: selected,
selectedHeadingFound: selectedHeadingFound,
clearSelectionFound: clearSelectionFound,
failure: nil
)
try writeJSON(receipt, to: "\(mode)-receipt.json")
diagnostic("PASS native Tab → entity checkbox → visible focus ring → Space selection")
} catch {
let message = String(describing: error)
diagnostic("FAIL \(message)")
writeFailure(
message,
adjacent: adjacentSnapshot,
focused: focusedSnapshot,
bright: measuredBrightPixels
)
exit(1)
}

View File

@@ -0,0 +1,15 @@
{
"description": "",
"focused": true,
"position": [
317,
208
],
"role": "AXButton",
"size": [
1921,
40
],
"title": "Open task [redacted fixture title]",
"value": ""
}

View File

@@ -0,0 +1,10 @@
[2026-08-20T12:10:02Z] application=Buzz Dev (projects-v6-pt2-selectable-workspaces) pid=84587 windowId=29941 mode=restored
[2026-08-20T12:10:02Z] AXPress Projects
[2026-08-20T12:10:03Z] AXPress Tasks
[2026-08-20T12:10:03Z] AXPress List layout
[2026-08-20T12:10:04Z] focused setup control Open task [redacted fixture title]
[2026-08-20T12:10:05Z] posted macOS HID Tab
[2026-08-20T12:10:07Z] focus-ring bright pixels=732
[2026-08-20T12:10:07Z] posted macOS HID Space
[2026-08-20T12:10:08Z] PASS native Tab → entity checkbox → visible focus ring → Space selection
Exit status: 0

View File

@@ -0,0 +1,15 @@
{
"description": "Select [redacted fixture title]",
"focused": true,
"position": [
335,
294
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "0"
}

View File

@@ -0,0 +1,55 @@
{
"adjacentControl": {
"description": "",
"focused": true,
"position": [
317,
208
],
"role": "AXButton",
"size": [
1921,
40
],
"title": "Open task [redacted fixture title]",
"value": ""
},
"applicationTitle": "Buzz Dev (projects-v6-pt2-selectable-workspaces)",
"clearSelectionFound": true,
"focusRingBrightPixels": 732,
"focusedCheckbox": {
"description": "Select [redacted fixture title]",
"focused": true,
"position": [
335,
294
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "0"
},
"mode": "restored",
"pid": 84587,
"selectedCheckbox": {
"description": "Select [redacted fixture title]",
"focused": false,
"position": [
335,
294
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "1"
},
"selectedHeadingFound": true,
"status": "passed",
"windowId": 29941
}

View File

@@ -0,0 +1,15 @@
{
"description": "Select [redacted fixture title]",
"focused": false,
"position": [
335,
294
],
"role": "AXCheckBox",
"size": [
12,
12
],
"title": "Select [redacted fixture title]",
"value": "1"
}