Calendarr liefert Termine über den Gruppencontainer. Streng lesend: keine
eigene Anmeldung, kein Netz, kein Schreiben zurück.
Die Abdeckung ist der Kern und kein Detail. Der Schnappschuss reicht 49
Tage nach vorne, und das steht nirgends in der Datei — es ist zugesagtes
Verhalten des Schreibers. Außerhalb liegt keine Information vor, nicht
keine Termine; das Monatsraster graut solche Tage aus, statt „frei" zu
behaupten. Verlockend wäre, die Abdeckung aus dem frühesten Termin
abzuleiten. Das ist falsch, und ein Test hält es fest: mehrtägige Termine
ragen ins Fenster hinein und werden mitgeschrieben, obwohl ihr Anfang
nicht abgedeckt ist.
Bei „beide Quellen" ist die Abdeckung der Schnitt, nicht die Vereinigung.
Ein Tag gilt nur als bekannt, wenn ihn jede Quelle abdeckt. Umgekehrt
darf ein Ausfall einer Quelle die andere nicht mitreißen: Calendarr nie
geöffnet zu haben knipst den Apple-Kalender nicht aus.
Die Ablage kopiert, statt zu verweisen. Anhänge aus Mail oder WhatsApp
liegen in temporären Verzeichnissen — ein Verweis wäre in Stunden tot,
und die Ablage wäre leer, wenn man sie braucht. Aus demselben Grund nimmt
die Fläche UTType.item statt public.file-url an: solche Anhänge kommen
als Dateiversprechen, und loadFileRepresentation löst beides ein. Die
übergebene Datei existiert nur innerhalb des Rückrufs, also wird sie dort
sofort gesichert statt später auf dem MainActor.
Gelöscht wird in den Papierkorb. Automatisches Aufräumen ist standardmäßig
aus — eine Ablage, die ungefragt löscht, ist ein Papierkorb mit
Zeitschaltuhr.
Nebenbei: „mixer.on" und „network.vpn.active" standen als rohe Schlüssel
in der Oberfläche. Label(_:systemImage:) kennt kein Bundle und sucht immer
im Hauptbundle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Core Audio meldet Prozesse, nicht Programme. Angezeigt wurden deshalb
Kennungen wie „com.apple.WebKit.GPU" und Dutzende Systemdienste, die
theoretisch Ton ausgeben könnten, es aber nie tun.
ProcessNaming fragt erst das laufende Programm, kürzt sonst bekannte
Hilfsprozess-Endungen weg und schlägt das übergeordnete Programm nach —
Chromes Ton kommt aus einem Helfer, angezeigt gehört Chrome. Symbole
gehen denselben Weg, sonst steht neben dem Namen ein Platzhalter.
ProcessVisibility zeigt, was klingt, kürzlich klang oder geregelt wird.
Die Nachlaufzeit von zwei Minuten ist der eigentliche Punkt: ohne sie
verschwindet Spotify beim Pausieren aus der Liste, und man kann die
Lautstärke genau dann nicht mehr einstellen, wenn man es will. Geregelte
Programme bleiben immer — wer etwas leiser gedreht hat, muss es auch
zurückdrehen können.
Die Prozentzahl wandert vom Namen zum Regler. Oben war sie genau die
Breite, die den Namen abgeschnitten hat.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Xcode meldete beim Start "Could not attach to pid — ensure that scarriffle has
permission to debug Onyx". Ursache war mein eigener Build-Schritt: er signierte
die App mit Onyx.entitlements neu, und darin fehlt get-task-allow — die
Entitlement, die das Anhängen eines Debuggers überhaupt erlaubt. Xcode setzt sie
im Debug-Build selbst; mein Neusignieren entfernte sie stillschweigend wieder.
Die Reihenfolge im Bauprotokoll zeigt, dass der Schritt gar nicht nötig war:
CodeSign OnyxHelper (Zeile 943)
PhaseScriptExecution (Zeile 1092)
CodeSign Onyx.app (Zeile 1743)
Xcode signiert die App als Letztes, nach dem Skript. Damit repariert es das
Siegel von selbst, das durch das Einbetten des Helfers bricht — mein
Neusignieren war ein Nachbau von etwas, das ohnehin passiert, nur ohne die
Entitlements, die Xcode beilegt.
Der Schritt kopiert jetzt nur noch und signiert ausschließlich den Helfer, der
sein eigenes Siegel braucht. Nachgeprüft: App-Siegel gültig, get-task-allow im
Debug vorhanden, Helfer trägt den richtigen Bezeichner und weiterhin keine
Entitlements.
Dass get-task-allow auch im Release-Build steht, ist kein Fehler: Xcode legt sie
bei jedem mit einem Development-Zertifikat signierten Build bei. Mit einem
Developer-ID-Zertifikat entfällt sie — das kommt in Phase 9 mit der
Notarisierung.
Ein Tap mit mutedWhenTapped schaltet die ursprüngliche Ausgabe eines Programms
stumm und liefert das Signal stattdessen bei Onyx ab; ein privates
Aggregate-Device aus Tap und echtem Ausgabegerät gibt es nach der Verstärkung
wieder aus. Das ist der einzige Weg, den macOS ohne eigenen Treiber anbietet.
Die Kennlinie ist hergeleitet, nicht geraten: halbe empfundene Lautstärke sind
rund −10 dB, also Faktor 0,316. Aus 0,5^k = 0,316 folgt k ≈ 1,66. Die Skala ist
damit symmetrisch — 50 % sind −10 dB, 200 % sind +10 dB. Mein erster Ansatz mit
der vierten Potenz ergab bei halbem Regler 6 % statt 32 %; der Test hat das
gefangen, bevor es an einen Lautsprecher kam.
Über 100 % greift ein weicher Begrenzer. Ohne ihn schneidet die Hardware die
Werte hart ab, und das knackt hörbar. Er arbeitet erst ab 0,7, weil eine
Begrenzung, die schon bei Zimmerlautstärke einsetzt, matt klingt.
Der Mixer ist standardmäßig aus, und auch eingeschaltet greift er nur bei
ausdrücklich gewählten Programmen ein. Alles andere läuft unverändert vorbei.
Der Notausschalter steht sichtbar in der Ansicht, nicht in einem Menü: wenn der
Ton weg ist, ist das der Knopf, den man sucht.
Drei Fehlerfälle sind eingeplant, weil jeder von ihnen ein stummes Programm
bedeutet. Der Wachhund baut Taps neu auf, die nur noch Stille liefern — der
bekannte Fall aus Spike C. Ein Wechsel des Ausgabegeräts baut alle Taps neu
auf, weil sie am alten Gerät hängen. Und ein fehlgeschlagener Aufbau räumt sich
selbst weg, statt in einem halben Zustand zu verharren.
Beim Beenden von Onyx wird der Mixer abgebaut: sonst bleiben die abgegriffenen
Programme stumm zurück.
178 Tests grün, App-Signatur gültig.