Zwischenablage, Notizen und der Gesichtsvergleich

Drei neue Module nach dem Bauplan von `ShelfProvider`: reine Regeln getrennt vom
Zustand, versionierte Indexdatei, Inhalte in Dateien statt in `UserDefaults` —
was dort steht, liest jedes Programm mit `defaults read` mit.

Die Zwischenablage achtet `ConcealedType`, `TransientType` und
`AutoGeneratedType`. Diese Marken sind eine Verabredung zwischen Programmen und
kein Systemdienst; wer sie missachtet, sammelt fremde Passwörter ein.

Der Gesichtsvergleich stand im Plan als der eine echte Unsicherheitsfaktor. Ein
Spike hat ihn erledigt: `VNGenerateFaceprintRequest` gibt es nicht, aber
`VNGenerateImageFeaturePrintRequest` ist öffentlich, liefert 768 Elemente und
ein Abstandsmaß — Faktor 3,5 Trennschärfe. Kein eigenes CoreML-Modell nötig.

`FaceMatcher` entscheidet über mehrere Posen, mehrere Einzelbilder und eine
Sperre nach Fehlversuchen. Die Schwelle liegt bewusst nicht mittig: ein falsches
Ja ist ein Fremder am entsperrten Rechner, ein falsches Nein nur ein Passwort,
das man ohnehin kennt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-05 21:06:06 +02:00
co-authored by Claude Opus 5
parent f289d02c37
commit 3da673662f
17 changed files with 1536 additions and 4 deletions
+19
View File
@@ -21,6 +21,10 @@ let package = Package(
.library(name: "NetworkProvider", targets: ["NetworkProvider"]),
.library(name: "AudioProvider", targets: ["AudioProvider"]),
.library(name: "ShelfProvider", targets: ["ShelfProvider"]),
.library(name: "ActivityProvider", targets: ["ActivityProvider"]),
.library(name: "ClipboardProvider", targets: ["ClipboardProvider"]),
.library(name: "NotesProvider", targets: ["NotesProvider"]),
.library(name: "FaceProvider", targets: ["FaceProvider"]),
],
targets: [
// Der String-Katalog muss ausdrücklich als Ressource stehen — sonst gibt
@@ -73,8 +77,23 @@ let package = Package(
resources: [.process("Localizable.xcstrings")]),
.testTarget(name: "AudioProviderTests", dependencies: ["AudioProvider"]),
.target(name: "FaceProvider"),
.testTarget(name: "FaceProviderTests", dependencies: ["FaceProvider"]),
.target(name: "NotesProvider", dependencies: ["OnyxDesign", "OnyxWidgetKit"],
resources: [.process("Localizable.xcstrings")]),
.testTarget(name: "NotesProviderTests", dependencies: ["NotesProvider"]),
.target(name: "ClipboardProvider", dependencies: ["OnyxDesign", "OnyxWidgetKit"],
resources: [.process("Localizable.xcstrings")]),
.testTarget(name: "ClipboardProviderTests", dependencies: ["ClipboardProvider"]),
.target(name: "ShelfProvider", dependencies: ["OnyxDesign", "OnyxWidgetKit"],
resources: [.process("Localizable.xcstrings")]),
// Live Activities: die Warteschlange ist reine Rechnung ohne AppKit,
// die Darstellung hängt am Notch-Panel.
.target(name: "ActivityProvider", dependencies: ["OnyxDesign", "OnyxNotch"]),
.testTarget(name: "ShelfProviderTests", dependencies: ["ShelfProvider"]),
.testTarget(name: "ActivityProviderTests", dependencies: ["ActivityProvider"]),
]
)