Reviewer: reviewer (task #6)
Date: 2026-04-19
Scope: full repo audit against ~/.claude/plans/do-it-structured-lantern.md
- HIGH severity: 0 (no in-place fixes required)
- MEDIUM severity: 1
- LOW severity: 5
All 10 focus areas from the team-lead brief verified clean: action coverage (39 cases), 3×3 grid tiling (integer-boundary math, tested at 1920×1080 / 1000×1000 / 4K / offset screens), AX↔Cocoa coordinate discipline (single conversion in ActionRunner.performGeometry, AX preserved through Geometry and AXWindow), Carbon hotkey rebind (HotkeyManager.apply calls clear() first, unregistering all prior refs), preferences round-trip (codable + export/import tests pass), no force-unwraps on fallible AX calls, [weak self] throughout, .gitignore adequate, README documents the unsigned-build re-grant workflow.
- File:
Sources/PreferencesUI/PreferencesWindow.swift - Issue:
set(_:for:)callsstore.set(...)followed bystore.save().PreferencesStore.set()already invokescommit()which persists, so the explicitstore.save()writes toUserDefaultstwice on every shortcut edit. - Fix: Remove the trailing
store.save()in the view-model setter, or document thatstore.setis fire-and-forget.
- File:
Sources/PreferencesUI/PreferencesWindow.swift - Issue: Recorder UI clears the existing binding owner before calling
store.set, which meansConflict?is never observed at this call-site. Intended UX (last-writer-wins with implicit reassignment), but the store API supports a richer "show conflict marker" path that the UI doesn't use. - Fix: Document the design choice in a one-line comment or surface conflicts in the UI per VERIFICATION step M12.
- File:
Sources/HotkeyManager/HotkeyManager.swift - Issue:
deinititeratesregistrations(MainActor-isolated) to callUnregisterEventHotKey. Carbon calls are documented thread-safe and the existing comment notes this, but Swift 6 strict concurrency will flag it. - Fix: Hop to MainActor in deinit via
Task { @MainActor in ... }capturing the refs by value, or annotate the storagenonisolated(unsafe).
- File:
Sources/PermissionsCoordinator/AccessibilityTrust.swift - Issue: Combine
Timer.publishruns for the lifetime of any subscriber. Currently onlyOnboardingViewsubscribes, so it stops with the view, but a future caller could leak a 1 Hz timer. - Fix: Add a doc comment noting subscriber-lifecycle responsibility, or expose an explicit
start/stopAPI.
- File:
Sources/WindowEngine/AXWindow.swift - Issue:
UnsafeRawPointerinitialization warnings inherent to the Swift↔Carbon generic bridge. Pre-existing; called out inVERIFICATION.mdP1. - Fix: Wrap the AXValue creation in a typed helper that encapsulates the unsafe cast, or silence with a targeted
// swiftlint:disableif SwiftLint is added later.
- File:
App/ActionRunner.swift - Issue:
redoFrames: [CGRect]is owned byActionRunnerinstead of being a first-classUndoStackprimitive. Acceptable for v0.1 per VERIFICATION known-limitations; promote toUndoStackwhen per-window keying lands. - Fix: Future refactor — extend
UndoStackwithredo()returningSnapshot?and removeredoFramesfromActionRunner.
- Plan action set vs
WindowActionenum: all 39 cases present and routed. Geometry.boundaries(length:count:)integer rounding guarantees exact tiling at all tested sizes including non-divisible widths.CoordinateConverter.cocoaToAX/axToCocoais a true involution; round-trip test green.HotkeyManager.apply(bindings:)correctly invokesclear()before re-registering — no leaks across rebind.- Preferences codable round-trip + export/import green; default bindings have no internal collisions.
- No force-unwraps on
AXUIElementCopy*results — all useguard let. [weak self]inHotkeyManagerevent dispatcher andWindowKitAppDelegateCombine sinks — no retain cycles..gitignorecovers.DS_Store,.build/,build/,.swiftpm/,DerivedData/, xcuserdata,Package.resolved.- README "Unsigned-build caveat" section accurately describes per-rebuild AX re-grant flow.
None. Proceed with VERIFICATION.md M1–M14 on a real macOS 14+ session.