Root cause of the owner's repro (board window frontmost, File ▸ Print… enabled, chosen from the menu, alert appears anyway): Kanban.entitlements carried no com.apple.security.print key. The app is sandboxed, and a sandboxed NSPrintOperation is denied by the sandbox with exactly this wording — "This application does not support printing. Please contact the application's developer." — regardless of which code path invokes it. Fix: add the entitlement. Alongside it, hardening for a separate, narrower failure mode that happens to produce the identical alert text by a different mechanism: PrintCommand used to disable itself over a window that published neither a board nor a printable card (welcome, the template chooser, Settings, the restore-bootstrap window, a card window whose board hasn't joined). A disabled SwiftUI Button still owns its .keyboardShortcut, so the unclaimed ⌘P chord fell through to AppKit's own nil-target printDocument: action, whose stock failure is the same system alert. The row now claims ⌘P unconditionally in every window; scope resolves at the moment of the action instead (board, then card, then a polite "Nothing to Print" / "Open a board or a card to print it." refusal in the app's own voice). The boolean isEnabled(hasBoard: hasPrintableCard:) becomes a three-way PrintCommand.resolveScope(...) -> Scope pure function. Also implements AppDelegate's application(_:printFiles:withSettings: showPrintPanels:) — Finder's own File ▸ Print… / drag-to-printer / print-and-open path was previously unhandled, its own separate route to the same stock alert. PrintCoordinator.printFiles loads each path headless through BoardLoader (no store, no window) and either prints it or gives the same one-sentence refusal; the operation-building code shared with the in-app path is factored out of run(_:) into makeOperation(for:showsPrintPanel:) and runOperation(_:session:). Docs: 11-command-nexus.md's Print row, PrintCommand's and PrintCoordinator's doc comments, KanbanApp.swift's CommandGroup comment, and project.yml's entitlements comment all narrate the entitlement as the actual fix and the scope work as hardening beside it. Tests: PrintCommandValidationTests now exercises resolveScope's three arms in place of the old boolean. A new PrintFinderResolutionTests suite covers PrintCoordinator.resolveFinderPrint(atPath:) — the one piece of the Finder half a test can drive without handing AppKit a real print job — against a real board, an empty non-board folder, a plain file, and an unsupported schema. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
35 lines
2.0 KiB
XML
35 lines
2.0 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>com.apple.security.app-sandbox</key>
|
|
<true/>
|
|
<key>com.apple.security.files.user-selected.read-write</key>
|
|
<true/>
|
|
<key>com.apple.security.files.bookmarks.app-scope</key>
|
|
<true/>
|
|
<!-- Print is a v1 feature (11-command-nexus.md's Print row): the sandbox denies
|
|
`NSPrintOperation` outright without this key, and the denial surfaces as the misleading
|
|
system alert "This application does not support printing. Please contact the
|
|
application's developer." — which reads like a missing feature rather than a missing
|
|
entitlement. Needed for both halves of File ▸ Print… (`PrintCoordinator`) and Finder's
|
|
own `printFiles` Apple Event (`AppDelegate`). -->
|
|
<key>com.apple.security.print</key>
|
|
<true/>
|
|
<!-- **Declared now and exercised by nothing.** Nothing in the shipped app opens a socket: the
|
|
git provider that would have used this key is excised (strategy/01-git-excision.md), and
|
|
the ops-based sync capability that will is a design pass still to come. The key stays
|
|
because that capability needs it regardless (12-editions.md ▸ PIVOT 2026-08-08), and
|
|
because a key added later is a new provisioning profile and a new review surface — cheaper
|
|
to carry from the start than to introduce. No `keychain-access-groups` alongside it: a
|
|
group shares items *between* apps, and there is one app, so whatever credentials sync
|
|
eventually holds go to the sandbox's own keychain, which needs no key at all. -->
|
|
<key>com.apple.security.network.client</key>
|
|
<true/>
|
|
<!-- No `com.apple.security.application-groups`: a group exists to share a container *between*
|
|
apps, and there is one app (12-editions.md ▸ App-side state, re-ruled 2026-07-30). The
|
|
board registry and its Application Support peers home in the ordinary sandbox container
|
|
(`AppStateHome`), which the sandbox already scopes to this app alone. -->
|
|
</dict>
|
|
</plist>
|