← Mac-Diktat
Changelog
Alle nennenswerten Änderungen an Mac-Diktat. Format orientiert an Keep a Changelog, Versionsschema folgt SemVer — siehe ADR-0010.
[Unreleased]
[0.1.12] - 2026-07-01
Fixed
- Spracherkennung ließ sich auf neuen Installationen nicht einrichten: Bei einer Neuinstallation brach der Download des Parakeet-Sprachmodells mit „Integritätsprüfung fehlgeschlagen” ab. Ursache war eine veraltete Prüfsumme nach einem Update der Transkriptions-Bibliothek. Bestehende Installationen waren nicht betroffen.
- Hotkey nach dem Ruhezustand: Der Push-to-Talk-Hotkey wird nach dem Aufwachen des Macs wieder zuverlässig erkannt.
[0.1.11] - 2026-06-20
Added
- Zwei-Toggle-Update-Modell (ADR-0010): Auto-Suche und Auto-Installation von Updates sind jetzt getrennt schaltbar, und die Einstellungen zeigen „Update verfügbar” direkt an, sobald der Feed eine neue Version meldet.
Changed
- Lokales LLM: RAM-abhängige Kontextgröße: Die Kontextfenster-Größe des lokalen Qwen3-Modells wird jetzt am physischen Arbeitsspeicher ausgerichtet, statt fix gewählt zu werden — größerer Kontext auf Maschinen mit genug RAM, sparsamer auf kleinen.
Fixed
- Texteinfügung in nicht-aktivierende Overlays (ADR-0100): Driftet der Fokus in ein Overlay-Panel, das das Fenster nicht aktiviert (z. B. ChatGPT-Desktop), wird der Text jetzt zuverlässig ins tatsächlich fokussierte Ziel eingefügt — über einen HID-Tap statt eines Abbruchs.
- Diktat-Idle-Reset im Aufnahme-Fehlerpfad: Schlägt der Start der Aufnahme fehl, wird der Idle-Reset jetzt korrekt armiert, statt die Zustandsmaschine hängen zu lassen.
- Update-Feed: Negative-Cache: Die Appcast-Validierung nach dem Veröffentlichen nutzt jetzt Backoff gegen einen kurzlebigen Negative-Cache, der frische Releases sonst zu früh als ungültig meldete.
[0.1.10] - 2026-06-15
Added
- Automatische Updates über Sparkle 2 (ADR-0010): Mac-Diktat prüft selbst auf neue Versionen gegen den signierten Update-Feed unter
mac-diktat.de und kann sie auf Wunsch installieren. Der Appcast ist EdDSA-signiert; der echte Public Key liegt in der Info.plist. Dies ist die erste Sparkle-fähige Version — der Auto-Update-Pfad greift ab v0.1.10 aufwärts.
Changed
- Egress-API: Zugriffs- und Authentifizierungsmodell (ADR-0098): Erreichbarkeit und Zugriffsschutz sind jetzt getrennt einstellbar. Drei Zugriffsmodi — „Nur dieser Mac” (Loopback, empfohlen), „Tailscale” (folgt) und „Lokales Netzwerk unverschlüsselt” (Expertenmodus) — plus eine unabhängige Schutz-Wahl (Bearer-Token erforderlich / Ohne Token). Die Statuskarte zeigt den effektiven statt des gewünschten Zustands. Der vollständige Forensik-Export (
history?privacy=full) ist über die tatsächliche Client-IP am Socket abgesichert, nicht über den fälschbaren Host-Header. Der wirkungslose TLS-Schalter wurde entfernt; verschlüsselter Transport kommt im Tailscale-Modus von Tailscale.
Fixed
- Layer-3-Resilienz (llama-server) (ADR-0097): Ein Crash-Loop des lokalen LLM-Servers ist jetzt in der UI sichtbar und wird mit automatischem Qwen-Routing, Liveness-Prüfung, Mid-Diktat-Fallback gegen den Anker und einer GGUF-Integritätsprüfung abgefangen — statt stiller Ausfälle.
- Foundation-Models-Content-Refusal: Eine Inhalts-Ablehnung der Apple-Foundation-Models (macOS 27) wird jetzt als
safetyBlocked klassifiziert und sauber behandelt statt als harter Fehler zu enden.
- Modell-Download-Resume bei Range-ignorierenden Servern: Wenn beim Fortsetzen eines Downloads (
Range: bytes=<offset>-) der Server den Range-Header ignoriert und mit 200 OK plus vollem Body (statt 206) antwortet, wurde der Vollbody an den Teilstand angehängt → korrupte .tmp, die der Post-Download-SHA verwarf und im nächsten Lauf komplett neu lud. Der StreamingDelegate (geteilt von Whisper- und Layer-3-Downloader) erkennt den 200-auf-Range-Fall jetzt, verwirft den Teilstand und schreibt den Body von vorne — ein einziger sauberer Download statt Doppel-Transfer.
[0.1.9] - 2026-06-13
Sammelrelease der Stabilitäts- und Layer-Offensive (Phasen A–C) seit v0.1.8.
Added
- Apple-Speech-Engine als Layer-1-STT-Alternative (ADR-0077): vollwertige Transkriptions-Engine auf Basis von Apple SpeechAnalyzer mit eigenen Logs und Unit-Tests, neben Parakeet wählbar.
- Phantom-Token-Suppressor (ADR-0089, Phase B): Layer-2-Stage, die wiederkehrende Halluzinations-Fragmente unterdrückt.
- Audio-Energie- und VAD-Forensik (ADR-0089, Phase A): HistoryEntry-Schema v11 speichert Energie- und VAD-Kennzahlen pro Diktat für die spätere Failure-Analyse.
- Pausierbarer Layer-3-Modell-Download: ein Abbruch behält den Range-Resume-Teilstand, der Download setzt beim nächsten Start fort statt neu zu laden.
- Egress-API Auto-Restart mit Backoff nach einem Listener-Ausfall — die Forensik-Schnittstelle kommt nach einem Fehler selbsttätig zurück.
- llama-server Crash-Watchdog mit Crash-Loop-Schutz: ein abgestürzter Layer-3-Server wird neu gestartet, eine Absturzschleife wird erkannt und gebremst.
- Adress-Komma-Stage im Layer-2-Chain sowie ein importierbares Coding-/Obsidian-Wörterbuch.
Changed
- Distribution auf arm64-only umgestellt: keine Universal-Binary mehr (Intel-Unterstützung bewusst fallen gelassen).
- FluidAudio von 0.13.6 auf 0.14.7 angehoben.
- Stabilitätsoffensive (C2/C3):
PostProcessor.swift in 15 Step-Dateien aufgeteilt, Boot-Logik in dedizierte Supervisoren extrahiert (Smoothing, StatusBarHealth, STTEngineSwap) — interne Umstrukturierung ohne Verhaltensänderung, durch Golden- und Smoke-Tests abgesichert.
- Migration-Stashes lock-geschützt statt
nonisolated(unsafe).
Fixed
- TextInjector-Warte-Fenster bei App-Shutdown abbrechbar — kein Hängen mehr beim Beenden während eines laufenden Inject.
- Egress-History-Export läuft async statt über
DispatchQueue.main.sync (vermeidet Main-Thread-Blockade).
- Voice-Command: „folgender Punkt” wird als Nomen geschützt statt als Befehl interpretiert.
- Layer-2-Joiner: „rela” wird als Layer-Homophon behandelt.
- Settings: die Auswahl „Apple Intelligence” markiert wieder die zugehörige Radio-Zeile.
[0.1.8] - 2026-05-25
Fixed
- Apple-SpeechAnalyzer-STT meldete „Apple Sprachmodell nicht installiert” trotz vorhandenem Modell (ADR-0077, Amendment V): Die Verfügbarkeitsprüfung hing an
AssetInventory.status(forModules:) == .installed. Unter macOS 26 verlangt dieser Status eine aktive, system-weite Locale-Allokation (AssetInventory.allocate) — ein bloß auf Disk vorhandenes Asset meldet nur .supported. Die App hielt diese Allokation nie selbst; nachdem das System die (geliehene) Reservierung wieder einzog, kippte der Status zurück und es folgten roter Menübar-Punkt, Hotkey-Fehlerton und ein „Sprachmodell laden”, das in einer 3-ms-Phantom-Download-Schleife lief. Behoben: Verfügbarkeit prüft jetzt SpeechTranscriber.installedLocales, und die App reserviert die Locale selbst via AssetInventory.allocate(locale:) beim Laden und best-effort vor jeder Session. Erklärt das Muster „lief stundenlang, nach dem letzten Diktat plötzlich tot”.
[0.1.7] - 2026-05-24
Added
- Wörterbuch-Vorschläge aus der Korrektur-Historie (ADR-0088): eine Mining-Engine wertet abgelehnte/korrigierte Diktate aus und schlägt neue Lexikon-Einträge vor. Eigene Vorschläge-Sammelseite mit Annehmen/Ignorieren, ein Decision-Sidecar merkt sich Entscheidungen. Entdeckbarkeit über Banner und Sidebar-Badge sowie einen Inline-Nudge im CorrectionSheet. Mehrwort-Einträge decken Einzel-Token-Vorschläge mit ab; bei Real-Wort-Aliasen wird die Annahme bewusst bestätigt, „Ignorieren” ist ein direkter Button.
- Zweistufiges Silence-Gate mit optionalem Silero-VAD (ADR-0087): nach dem RMS-Gate kann optional ein hash-gepinntes Silero-VAD-Modell Sprache von Geräte-Rauschen trennen. Eigene Settings-Section mit Toggle und bewusstem Modell-Download; der RMS-Schwellwert
0.85 bleibt der robuste Default.
- Real-Wort-Linter für
soundsLike-Aliase (ADR-0079): warnt, wenn ein Lexikon-Alias ein echtes deutsches oder englisches Wort ist (Kollisionsschutz, z. B. „die” ↔︎ „Tahoe”), inkl. Duplikat-Warnung, Acknowledge-Button und Audit-Aktionen. Per-Eintrag unterdrückbar (suppressRealWordWarning, Lexikon-Schema v7). Die Casing-Erkennung berücksichtigt großgeschriebene deutsche Substantive.
- Fidelity-Direktive für
style=original (ADR-0085): core.minimal erhält eine Treue-Direktive, die bei wörtlicher Glättung den Inhalt unverändert lässt.
- Egress: Pre-Bind-Port-Probe + Konflikt-Diagnose (ADR-0066): der Port wird vor dem Bind geprüft, Konflikte werden mit Diagnose gemeldet statt mit Crash.
- Akronym-Allow-Liste erweitert (ADR-0069 Amendment): zusätzlich
LLM und API.
Changed
- Bearbeiten-Menü zurück: das AppKit-Hauptmenü wird nach der SwiftUI-Initialisierung installiert; die Editing-Shortcuts (⌘C/⌘V/⌘A/⌘Z) funktionieren menüunabhängig auch im
.accessory-Modus und im Menüleisten-Panel — kein System-Beep mehr in Textfeldern.
- Tonalität im Quick-Panel gesperrt, wenn das Backend sie ignoriert: Capability-Gating im Menüleisten-Panel (Apple FM bzw. Layer 3 aus).
- Zielabhängiger Restore-Wait beim Pasteboard-Inject: native Apps 250 ms, langsame Electron-Apps 700 ms (
PasteTargetProfile) — gegen Paste-Races.
- Tail-Drain gegen verschlucktes Schlusswort: Drain-Fenster auf gemessene 300 ms kalibriert.
- Layer-N-Joiner gegen Lexikon-Asymmetrie (ADR-0082).
Fixed
- Few-Shot-Token-Bleed im Layer-3-Prompt behoben (ADR-0080): Beispiel-Substantive leakten in Fragmente.
- Subset-Truncation-Sanity gegen Layer-3-Verstümmelung (ADR-0081).
- Anti-Instruktions-Direktive im Layer-3-Prompt (ADR-0083): Imperative im Diktat werden als Text wiedergegeben, nicht ausgeführt.
- Klammer-Pair-Tracking gegen unpaarierte Schließzeichen (ADR-0084).
- Layer 3 überspringt leeren/whitespace-only Layer-2-Text vor dem Backend-Call.
- Length-Gate-Bypass nur bei Zahlworten, nicht bei Ziffern.
core.numberSequence im .minimalWithLexicon-Default aktiviert.
- Fixmodus-Banner präzisiert: unterscheidet die Layer-2-Wörterbuch- Ersetzung vom Layer-3-Prompt-Einfluss; das Wörterbuch wirkt auch im Fixmodus weiter.
- llama-server-Cleanup auch bei ⌘Q (Repo-Review).
- Concurrency-Races und History-UI-Refresh bereinigt (Repo-Review).
- Drei zurückgestellte strukturelle Performance-Funde sowie Render- und Hotpath-Optimierungen aus dem Repo-Review adressiert.
Intern
- Repo-Review-Nachtrag (ADR-0066 Review):
AudioConstants zentralisiert, toter Code entfernt, Doku-Drift bereinigt.
- STT-Kandidaten-Benchmark (ADR-0086): korpus-agnostisches Phase-0–3-Harness (Runner, Kurz-/Diktat-Scorer); Parakeet TDT v3 bleibt Layer-1-Default. FM-Guided-Generation und STT-
contextualStrings als Re-Bench-Hebel ergänzt.
- Bench-Treue gehärtet: FM-Bench-Prompt und Snapshot-Fixtures waren von Production gedriftet; Bench-CLI-Symlinks nach App-Umzug repariert.
[0.1.6] - 2026-05-22
⚠️ Breaking
- Mindest-macOS auf 26 angehoben (ADR-0074 Amendment, ADR-0077). v0.1.5 lief noch ab macOS 14/15; das Live-Streaming über Apples
SpeechAnalyzer und die vollständig SwiftUI-native Fenster-/Menüleisten-Architektur setzen macOS 26 voraus. LSMinimumSystemVersion und das Package-Deployment- Target stehen jetzt auf 26.0.
Added
- Live-Vorschau beim Diktieren (ADR-0077): Apples
SpeechAnalyzer/SpeechTranscriber (macOS 26) ist als wählbare Final-STT-Engine verfügbar und liefert während des Sprechens partielle Transkripte. Diese erscheinen in einer Topbar-Live-Pille (Waveform
- Text-Vorschau, ab Aufnahmestart groß) und parallel über den neuen Egress-Endpoint
GET /api/v1/stream als Server-Sent-Events. Beide Senken sind getrennt schaltbar (zwei Toggles + Capability-Gating), die Pille zusätzlich per Menüleisten-Quick-Toggle (app-session-lokal). Die Drosselung (8–10 Hz) und das Tail-Window sitzen quellseitig im LiveStreamingSupervisor; ein additiver Live-Chunk-Tap im AudioRecorder speist den Partial-Bus, ohne den Final-Pfad zu stören.
- Forensik-Endpoint
GET /api/v1/history (ADR-0062 Amendment): vollständiger Verlaufs-Export hinter demselben Bearer-Token-Gate wie /transcripts. privacy=full (Roh-/Layer-Daten) ist zusätzlich auf Loopback-Bind beschränkt — bei LAN-Bind liefert der Endpoint 403.
- Layer-2
AcronymCaseNormalizer (ADR-0069): Akronyme aus einer Allow-Liste (GUI, KI, RTT, ADR …) werden korrekt großgeschrieben. Dazu sttEngine im Kurz-Export (ADR-0071).
- Menüleisten-Quick-Settings: STT-/LLM-Picker mit Disabled-Logik direkt im Panel; Lexikon-Quick-Add zeigt die Ziel-Library und erlaubt deren Auswahl. Panel-Health komplett (Modell + Status-Punkt + RAM).
- Liquid-Glass-Material (macOS 26) auf den prominenten Dashboard-Cards und den Wörterbücher-Statistik-Tiles.
- App-Version in der Sidebar-Fußzeile und im Über-Menü.
Changed
- Menüleiste komplett SwiftUI-nativ (ADR-0075):
MenuBarExtra(.window) ersetzt das bisherige NSStatusItem; eine echte WindowGroup-Scene ist jetzt Fenster-Owner. Der App-Start läuft über SwiftUI @main mit zweistufigem (split-timing) Boot. Dock-Aktivierung und Dock-Icon-Reflektion sind in eigene Supervisor extrahiert.
- Reaktivität auf das Observation-Framework migriert (ADR-0078): sämtliche Models, Stores, Controller und UI-Bindings von Combine/
ObservableObject auf @Observable umgestellt (neun Phasen). Der frühere ReactiveLabel-Workaround für verschachtelte Observables entfällt.
- Full-Height-Sidebar + Unified-Toolbar (ADR-0072): separate Icon-Rail entfernt.
- LLM-Glättungs-Picker aus den Quick-Settings entfernt (lebt jetzt nur noch in den Einstellungen).
- Egress:
NWConnection-Teardown deterministisch gemacht.
- Menüleisten-Icon auf 24 pt vergrößert.
Fixed
- Apple-Speech-Datenverlust bei mehreren Sätzen behoben.
- Single-Instance-Guard: keine Doppel-Instanz und kein Doppel-Inject mehr beim Start.
- Sauberes Beenden:
SIGINT/SIGTERM laufen über DispatchSource statt klassischer signal()-Handler — kein Crash mehr beim Shutdown.
- Layer-3-Skip ist im Verlauf sichtbar; die Layer-3-Glättung fließt jetzt in die Volltextsuche ein.
- Dock-Icon-Ausblenden funktioniert zuverlässig.
- Layer-2-Diktat-Direktiven: Spell-Mode-Recovery bei Parakeet-Kollaps + Trigger-Leak-Schutz (ADR-0070), komma-toleranter Spell-Trigger, Unpaired-Quote-Recovery + STT-Anchoring (ADR-0054 F),
als/wie-Determiner-Anker (ADR-0065).
- W-Fragen-Answer-Slip: Passthrough-Anker + Interrogativ-Preservation (ADR-0068 A1).
- Diverse SwiftUI-Boot-Korrekturen (Scene-Delegate nicht überschreiben, redundanten manuellen Sidebar-Toggle entfernt) und drei vorbestehende Compiler-Warnungen bereinigt.
Removed
NSStatusItem-basierte Menüleiste (ersetzt durch MenuBarExtra).
[0.1.5] - 2026-05-17
Added
- Externe Egress-API für Transkripte (ADR-0062, ADR-0066): lokaler HTTP-Server auf
127.0.0.1 mit drei /api/v1-Endpoints — GET /health (öffentlich), GET /transcripts?since=<seq> (Polling-Resync) und GET /events (Server-Sent-Events-Stream finaler Transkripte). Bearer-Token-Auth (32 Byte aus SecRandomCopyBytes, base64url, im Keychain mit kSecAttrAccessibleWhenUnlockedThisDeviceOnly), optionales LAN-Opt-in mit TLS-Cert-Store-Stub, konfigurierbarer Port (Default 8765), automatische Port-Konflikt-Recovery beim Boot (Toggle-Rücksprung + Banner). Schließt Issue #1. Settings-UI „Externe API” mit Live-Status, AppLog-Kategorie egress-api (ohne Token-/Transkript-Inhalt), neues Entitlement com.apple.security.network.server. Lifecycle-Trennung über EgressAPISupervisor.
- Layer-2 Voice-Command-Pass V1.0 → V1.3 (ADR-0065
- 6 Amendments): deutsche Diktat-Direktiven wie „in Klammern X sein/setzen” werden vor Layer-3 erkannt und in Marker-Form auf den Token-Stream gehoben. V1.1 marker-frei + Komma-konsumierend + Suppressor-Bypass, V1.2 Marker immer erhalten + Pattern 4, V1.3 Layer-2 schluckt Marker, Layer-3-Modul
core.bracketDirective ergänzt als adaptiver Schutz gegen Marker-Drop.
- E-Mail-Formatter & Verkettungs-Recovery (ADR-0063): Layer-2 erkennt E-Mail-Diktate, fixt STT-Substitutionen („dott”/„dort” → „.”), Inline-Punkt-Pattern (
<local> at <domain>.<tld>), Vorname-Nachname-Verkettung ohne <at>, plus EmailTLDRepetitionSquash gegen Parakeet-Decoder-Loops auf der letzten TLD. Stages für Build-37-Live-Diktate scharfgestellt.
- Adaptive Status-Icons v4 (ADR-0064): Asset-Tausch (
AppIcon-active, AppIcon-warning, AppIcon-error) statt Laufzeit-Komposition für die Menübar; SF-Symbol-Tinting-Wege waren auf macOS unzuverlässig. Build-Skript synct AppIcon-warning, CLAUDE-Asset-Sync-Regel ergänzt.
- HistoryEntry Schema v9 → v10: Egress-API
sequenceNumber als prozess-übergreifender UInt64-Counter (UserDefaults egressApi.lastSeq), vergeben in HistoryStore.append(_:) — Restart-stabil, deterministische Ordnung auch bei gleichem Millisekunden-Timestamp.
- Pasteboard-Privacy-Marker (ADR-0059): setzt verstecktes Marker-Item beim Inject, Body-Sanitizer entfernt Concealed-Strings vor History-Persistenz.
- Forensik-Copy-Confirm für die JSON-Detailstufen
.medium und .short in der History-Row.
- Lexikon-Rename via Settings-UI statt manueller JSON-Bearbeitung; Kontextmenü statt Pencil-Icon in der Eintragszeile.
- Dateless-Ordinal-Datum-Erkennung im PostProcessor: „zehnte siebte” → „10.07.”, toleriert STT-Pausen-Komma.
Changed
- Layer-3-Modul
core.bracketDirective wird adaptiv eingebunden, sobald Klammer-Direktiven im Stream erkannt werden — verhindert Marker-Drop bei aggressivem Refactoring im Smoothing.
- Passthrough-Few-Shot im Qwen-Default um Refactoring-Beispiele erweitert (
010e112); reduziert Halluzinations-Risiko bei passthroughIfClean-Pfad.
- Antwort-Partikel-Liste im Sanity-Check um Klar/Sicher/Natürlich und Varianten erweitert.
- Layer-2 E-Mail-Stages auf Build-37-Live-Diktate scharfgestellt (Pattern-Reihenfolge + Trigger-Schwellen).
- AppDependencies verliert die
init-basierte Lifecycle-Domäne; Orchestrator, Pipeline, MainViewModel und MainWindowController bauen sich ohne AppDependencies-Konstruktor auf (ADR-0061, Phase B).
Fixed
- Voice-Commands — Multi-Punkt → Ellipsis-Squash + RepetitionSoft-Allowlist, Determiner-Schutz für alle Punctuation-Direktiven, Komma-Asymmetrie zu Punkt geschlossen, Präpositions-Schutz + sein-Disambiguierung, Punkt mit Determiner-Anker auch mitten im Satz schützen, Punkt vor Ziffer als Ordnungsverweis skippen, Pair-Only-Quotes, STT-Drift-Aliase, typografischer Closer.
- Hotkey-Watchdog — Sleep/Wake-Reinstall via Probe-Trigger verifiziert (P1.7, DEBUG-only
MAC_DIKTAT_WATCHDOG_TEST=1); tapEnable(true) reicht nicht, kompletter CFMachPort-Neuaufbau notwendig.
- Egress-API — self-EADDRINUSE durch Single-Listener-Bind beseitigt, async Listener-Failure abgefangen, Port-Konfig in Settings immer editierbar.
- Egress-Settings-UI — Info-Tooltips als Click-Popover statt Hover-
.help (NSHostingView filtert Mouse-Tracking; bestätigt durch 11 fehlgeschlagene Tracking-Versuche am 2026-05-17), .focusable(false) killte NSHelpManager-Tracking, LAN-Switch im Switch-Flucht korrekt platziert.
- DatelessOrdinalDate toleriert STT-Pausen-Komma zwischen Ordinalen.
- HistoryStore — graceful Fail statt
preconditionFailure bei doppeltem Container-Fail; verlorenes Diktat ist besser als Crash.
- HistoryStoreTests auf Schema V10 nachgezogen (ADR-0062-Drift).
- AppLog
try?-Pfad (Tranchen 1–3) durch do/catch mit Fault-Log ersetzt; History-Crypto und Boot-I/O dokumentieren Fehlerursachen.
- History-Search debounced gegen AES-GCM-Thrashing bei Backspace-Tipperei.
Refactor & Architektur
AppSettings-Aggregator-Split (ADR-0057): Sub-Structs für Hotkey, UI, AudioInject, Logging, Layer2, STT, Layer3 (P3.1 T1–T7) — Settings-Datei nicht mehr Monolith.
- HistoryRow Subview-Extraktion (ADR-0058): Tier-1-Sub-Views, Layer-Labels, Layer-AttributedString-Builder, Comparison-Block, Comment+Correction-Block, Forensic Footer, MetaLine, LayerStack (P3.3 T1–T5).
- Layer-3-Settings-Subviews (P3.4): Style-Cards, Download-Banners, Banner-Shell, Feature-Toggles, Backend-Row + Popovers, Remote-API-Felder, Experten-Modus — gemeinsamer
SettingsBannerShell (P3.6 T1), BackendChoiceRow und RemoteAPIFieldsBlock konsolidieren STT-/Layer-3-Picker.
- Modulstruktur (ADR-0056):
Sources/MacDiktat/ in Subordner — Logging/Crypto/Hotkey/AudioStack/ Benchmark (Tranche 1), Models/Transcription/Injection/Lexicon (Tranche 2), UI-Subtree mit Subkategorien (Tranche 3), Bootstrap/Settings/Dictation/Layer3/History (Tranche 4).
- AppDependencies Phasen-Typisierung Phase B (ADR-0061).
- Try-Audit Tranchen 1–3: History-Crypto, Persistence (fetch/purge), Reset/Bootstrap-I/O —
try? durch do/catch + Fault-Log abgelöst.
- KeychainQueryBuilder als Single Source of Truth.
- Smoothing-Magic-Numbers für Sanity-Limits und Import-Toast zentralisiert.
AppLogErrorSanitizer (ADR-0053)
emit(error:)-Overload — Fehler werden geloggt, Diktat-Inhalt bleibt draußen.
Tests
- DictationResultPipeline E2E test-init + 5 Happy/Error-Pfade.
- DictationOrchestrator-Glue-Tests (P1.4).
- Backend-Fallback-Chain-Integration (FM → Qwen → Plain).
- History-Crypto v1 → v2 Key-Rotation, Keychain-Pfad.
- Lexicon Cologne-Min-Code ≥ 3 als direkte Pin-Tests (ADR-0049).
- EgressAPIServer / Supervisor / HealthProbe / TLSCertStore — neue Suite für ADR-0062.
Security
- TOFU strukturell geschlossen (P0.1):
HashSpec.sha256 ist nicht mehr optional. Mismatch beim Download wirft, kein „wird beim ersten Lauf gelernt” mehr — adressiert die alte Lehre aus feedback_security_audit_routine.
- Pasteboard-Concealed-Marker + Body-Sanitizer + Qwen-Hash-Gate (
c7129a3).
- Pinning-Hashes von
String? auf String (non-nil) gehoben.
- ADR-0055 — Gemma-4 Single-Source Risiko-Akzeptanz dokumentiert und am
Layer3/GemmaURLSet referenziert.
Release-Infrastruktur
sync-to-code-repo.sh für Grafik-Sync (Vault → Code-Repo) mit Drift-Check, eingebaut in /gh-hygiene.
- AppIcon-warning im Build-Skript automatisch mitgeführt; CLAUDE.md ergänzt um Asset-Sync-Regel.
[0.1.4] - 2026-05-14
Added
- Adaptiver Layer-3-Systemprompt (ADR-0048):
buildAdaptive(...) generiert aus Layer-2-Signalen (Lexikon-Hits, Anti-Halluzinations-Stufen) einen spezifischen Prompt mit Protected-Terms-Sektion, Anti-Halluzinations-Klausel und Filler-Strip-Strict. Ein Settings-Toggle steuert den Pfad. rawTranscriptForContext gibt Layer 3 zusätzlichen Kontext. Forensik (D6) wird pro Eintrag persistiert.
- Layer-2 deutsche Referenz-Datenbanken Phase 1+2A–D (ADR-0050): Bundesland-Vollnamen-Normalisierung, BNetzA-Vorwahlen-Mapping, OpenGeoDB-PLZ-Lookup und Cities-Gazetteer mit Umlaut-Rückmapping. Vier deterministische Layer-2-Pässe ohne LLM-Aufruf.
- Lexikon-Relevanz-Filter (ADR-0049): Hybrid Levenshtein + Kölner Phonetik mit Mindest-Code-Länge ≥ 3 (verhindert Kurz-Code-Kollisionen wie „die” ↔︎ „Tahoe”) und Bypass für Lexikon-Begriffe ≤ 4 Zeichen.
- Schattenglättung Auto-Off bei Remote-Backend mit Toggle-Layout-Fix für die Settings-Karte.
- History-UI Forensik: JSON-Kopier-Menü mit drei Detailstufen pro Eintrag, Layer-3-Skip vs. Verworfen visuell unterschieden, hellblauer Accent für AI-Glättungs-Blöcke, URLs werden im Verlauf erkennbar und klickbar gerendert.
- Diagnose-Bundle-Export unter „Settings → Debug-Logs”; verpackt redigierte Settings, Logs und Inventur-Bericht für Tester-Bug-Reports.
- AppLog v2 mit Schema v2 und allen Kategorien am File-Sink.
- Voice-Commands: geschweifte, eckige und spitze Klammern plus Comparators (
≤, ≥, ≠, <, >).
- Layer-3-Sanity Tier-Doktrin Phase B Schritt 1 (ADR-0052, Status
proposed/partial): erste Stufe live, restliche Phasen folgen — bewusst als Teil-Implementierung markiert.
Changed
- Length-Gate-Bypass bei effektivem adaptivem Pfad (ADR-0051): Layer 3 wird nicht mehr übersprungen, wenn
Layer2Signals.isEffective aktiv ist (Lexikon-Hits, adaptive Regeln). Adressiert Cluster G aus dem Diktat-Export 2026-05-14.
- Tier-1-Bypass wirkt jetzt über alle Sanity-Lanes (Lossy, Number-Dictation), nicht nur den Default-Pfad.
- Lossy-Sanity bypassed Number-Dictation bei ≥ 3-stelligem Output (verhindert Verwerfen von Zahlen-Diktaten).
- Length-Gate-Bypass bei Zahl-/Ziffern-Diktaten zusätzlich zum adaptiven Pfad.
- TrailingPunctuationSuppressor läuft auch über Layer-3-Output, nicht nur über die Roh-Transkription.
exportSingleEntryJSON akzeptiert injizierbares Datum (Round-Trip-Tests deterministisch).
- D2-v2 Schutzliste ist additiv statt Lexikon-Ersatz.
- Passthrough-Few-Shot bekommt Antwort-Slip-Gegenbeispiele.
core.numberSequence-Modul im Smoothing-Prompt schützt Ziffer-Sequenzen gegen Layer-3-Zerlegung.
Fixed
- VoiceCommandReplacer schützt „Punkt” als Nomen am Satzende und respektiert Adjektiv-Ketten zwischen Determiner und „Punkt”.
- Audio-Engine macht defensiver
reset() vor jedem start(); State-Leak nach Fehlerpfad geschlossen.
- RepetitionSoftFilter reduziert 3+ Duplikate auf 1 Vorkommen (Text statt nur Signal); Trailing-Punctuation wird vor Vergleich gestrippt („Ich, ich, ich” → „Ich”).
number-norm Telefon-Trigger verliert keine Ziffern mehr bei Komma-Sequenzen.
- D3-Anti-Halluzinations-Klausel des adaptiven Prompts feuert jetzt real, nicht nur theoretisch.
- URL-Komprimierung im Layer-2-/Layer-3-Pfad whitelistet die Schemata und vermeidet Lowercase auf Pfadkomponenten.
- AppLog-Tests verwenden die korrekten v2-Schema-Feldnamen (
logger / level / message).
Release-Infrastruktur
- Bench-CLI: Variant-D Adaptive-Pfad in
run-glaettung und _fm_bridge; prompt-adaptive-Subkommando ergänzt.
- Bench-Daten: hand-annotierte Layer-2-Signale für Variant-D-Bench (Qwen3-4B Baseline-Rerun + Adaptive-Lauf 2026-05-14, Ampel grün).
- Bench-CLI Build-Reparatur: Module-Catalog-Symlinks und Swift-5-Mode für die Wiedernutzbarkeit.
[0.1.3] - 2026-05-13
Added
- Shadow-Layer-3 in der Historie (ADR-0033 Amendment): Wenn Layer 3 wegen Längenfilter oder Stil-Skip nicht greift, läuft im Hintergrund trotzdem ein Schatten-Smoothing und wird im Vergleichsblock inklusive Diff-Caption angezeigt. Vergleich bleibt deaktivierbar.
- HistoryEntry Schema v9 mit Sammel-Slots für künftige Forensik-Felder und Build-Reproduktion (Commit-SHA, App-Version, ggf. Modell-Hash) pro Eintrag — Voraussetzung für vergleichbare Bug-Reports.
- Per-Eintrag-Lexikon-Toggle + Bundle-Import-Sheet (ADR-0045): Schema v6 mit
isEnabled pro Eintrag, portables JSON-Format (Single + Bundle), Importer mit Merge-Vorschau, Outcome-Callback und transparentem Disabled-State. Ersetzt den alten Plain-Array-Export.
- Voice-Commands: Satzzeichen-, Klammer- und Zitat-Block-Befehle (
„Punkt", „Komma", „Klammer auf", „Zitat" etc.), inkl. Coalescing mit STT-Auto-Punctuation.
- Verlauf-UI vollständig: Einzel-Löschung, Filter-Bar mit Layer-2-Toggle und Reset-All, Audio-Device-Anzeige pro Eintrag, Rename inline.
- Wörterbuch-Doppel-Aufräum-UI mit Merge-Vorschau (Aliase, Tags, Schutz-Flags via Union — keine destruktive Delete-UI).
- Lexikon-Timestamps (
createdAt / updatedAt) pro Eintrag, lexicon.json Schema v5.
- Inject-Decision-Telemetrie für Layer-3-Sanity-Tuning.
- Debug-Build-Badge am Dashboard-Header (sichtbar nur in Debug-Build).
- Stil-Karten zeigen Schloss-Icon, wenn ein Toggle technisch nicht greift, statt widersprüchlich klickbarem Toggle.
Changed
- NumberNormalizer läuft vor
SentenceCaseAfterBreak, damit „erstens” korrekt großgeschrieben wird, wenn es als Listenanfang nach Punkt steht.
- Wörterbuch-Aktionen als In-Body-Action-Row statt nested NavigationStack-Toolbar (macOS-Bug mit innerer Toolbar im SplitView-Detail).
- Wörterbuch-Übersichts-Buttons sind stil-paritätisch zum Detail-Editor.
- RAM-Priorisierung-Toggle wird bei aktivem Apple-Intelligence-Backend ausgeblendet (keine Wirkung, war verwirrend).
- Distribution-Builds sind jetzt verbindlich Universal (arm64 + x86_64). v0.1.1 war versehentlich arm64-only und ließ sich auf Intel-Empfänger-Macs nicht öffnen. Der
REQUIRE_UNIVERSAL-Check ist nur in der Release-Pipeline aktiv, lokale Debug-Builds bleiben single-arch.
Fixed
- Skip-Banner verspricht keinen Layer-3-Output mehr, wenn der Vergleichs- block leer wäre.
- Decomposer kennt den
.minimalWithLexicon-Pfad und reproduziert die Forensik-Karten korrekt für ältere Einträge.
- AX-Restart-Pfad ist ehrlich: die App sagt jetzt klar, dass nach Re-Sign der CDHash neu ist und macOS die Accessibility-Permission verwirft — inklusive
tccutil reset-Hinweis.
- Voice-Commands schlucken doppelte Satzzeichen, wenn STT bereits automatisch interpunktiert hat.
Release-Infrastruktur
scripts/package-dmg.sh erzeugt signiertes + notarisiertes Universal-DMG mit gestapelter App, Drag-to-Applications-Layout und SHA-256-Sidecar.
scripts/publish-release.sh publiziert Tag + DMG-Assets als GitHub-Release.
LICENSE ergänzt (proprietär, mit Open-Source-Acknowledgments).
[0.1.1] - 2026-05-09
Added
- Layer-3 First-Launch-Onboarding (ADR-0040): frische Installationen sehen ein Auswahl-Sheet (Apple Intelligence / Qwen 3-4B mit Direkt-Download / Aus). Existing User werden via Migration übersprungen.
- Prompt-Module-Aktivierungs-Store + Persistierung mit User-Extension- Textfeldern pro Stil-Karte (Phase 1–3 ADR-0040).
- SmoothingPromptStyle-Enum + Caps-Erweiterung + Experten-Override (ADR-0039): minimal vs. structured wird pro Backend differenziert. Apple-FM-Default bleibt minimal, Qwen-Default rollt zurück auf structured (Praxis schlägt Lab-Bench).
- Lexikon in Layer 2 (ADR-0041 Begleit-Fix): deterministischer
LexiconReplacer aus term + soundsLike, damit geschützte Begriffe auch im Layer-3-Fallback wirken.
- Lexikon-Banner für Asymmetrie-Sichtbarkeit (Pre-Check-Action statt silent fallback).
- Multi-Wörterbuch-Datenmodell + UI (Übersicht, Detail-Editor, Cap-Greying) mit
lexicon.json v2→v3-Migration und Schema v4 (ehemalige Built-ins als editierbare User-Libs).
- HistoryEntry Schema v7→v8 (ADR-0044):
lexiconHitsCipher + LexiconSnapshot-JSON-Store pro Diktat (Wörterbuch-Stand + Trefferbilanz forensisch ablegbar).
- Layer-3-Sanity statt Verwerf-Guardrail (ADR-0041): Persistieren immer, Inject-Sanity nur als Halluzinations-Notbremse, UI macht den Skip transparent. Edit-Distance-Guardrails verwerfen keine Outputs mehr.
- Self-Inject via NSTextInputClient statt Pasteboard-Cmd+V für In-App-Felder. Pasteboard-Inject mit Serialisierung + Sentinels + 150 ms Fixed-Wait (kein Pasteboard-Scrub mehr — PB ist User-Eigentum).
- Compare-Sheet im Verlauf: dual-Apple-FM-Vergleich, prompt-trust chain, einheitliches Forensik-Layout, klickbare Info-Icons als Popover.
- Layer-2-Stage-Counts auf Technik-Seite.
- Post-Processing-Hardening (H4–H15): Token-Overlap-Sanity, Spell-Mode, Euro/PIN-Sequenz, Datum-Casus, Number-Anchor-Concat, CyrillicCleanup als Roh-Filter, Length-Gate + Token-Loss-Sanity.
Changed
- Sampling-Defaults Qwen3-4B (ADR-0042) und Context auf 4096 mit Pre-Decode-Token-Guard.
- Pasteboard-Restore-Limit von 50 KB auf 1 MB angehoben (Memory-Tradeoff für längere Diktate akzeptiert).
- SplitView-Layout stabilisiert (pin host bounds, drop scrollview frame workarounds).
Fixed
- Pasteboard-Secret-Leak geschlossen (Layer 1), Self-Inject-Bypass via AX (Layer 2 — später durch NSTextInputClient ersetzt, siehe oben).
- SIGABRT-Shutdown-Backtrace für FIXME-RELEASE-Diagnose vor
_exit(0).
- Empty-Forensik-Pfade (stt-empty / postproc-empty) werden persistiert statt verworfen.
[0.1.0] - 2026-05-02
Added
- Modell-Download-Onboarding (ADR-0013): First-Run-Sheet für Whisper Large v3 und Parakeet TDT 0.6B v3, Resume-fähiger HTTP-Download mit SHA-256-Verifikation, atomare Installation über
.tmp + Replace, .verified-Marker pro Engine-Ordner. App startet bei fehlendem Modell nicht mehr mit _exit(1), sondern mit einer MissingModelEngine und öffnet das Download-Sheet bei User-Intent.
- Modelle-Sektion in den Einstellungen: geladen/fehlt-Badges pro Engine, Disk-Größe, „Modell entfernen” mit Confirm-Dialog und Live-Rebuild der aktiven Engine.
- Offline-Dialog mit „Andere Engine wählen”: scrollt per
SettingsScrollTarget zur STT-Backend-Sektion (statt stummer Fehlerseite).
- Parakeet TDT 0.6B v3 als lokale STT-Zweitoption (ADR-0012), Engine-Umschaltung zur Laufzeit, asynchroner Swap mit Stale-Guard, damit Settings-UI während des ~1 s WhisperCpp-Reloads responsiv bleibt.
- Remote-STT über OpenAI-kompatible REST-APIs (ADR-0011), Keychain-gebundene API-Keys, Fallback auf lokale Engine bei Remote-Fehlern.
- Layer 3 — LLM-Glättung mit Apple FoundationModels als Auto-Default (ADR-0018) auf macOS 26 mit Apple Intelligence, Qwen3-4B-Instruct-2507 als Fallback-Opt-in.
- Hotkey-Konfigurator mit Live-Visualisierung und kollisionssicherer Validierung (ADR-0007).
- Historie mit 30-Tage-Retention und Copy-to-Clipboard pro Eintrag (ADR-0006).
- Rating-UI in der Historie (ADR-0033): 3-Stufen-Thumbs (-1/nil/+1), CorrectionSheet-Erweiterung, Favorit auf Eintrag-Ebene (
isFavorite), Filter „nur Favoriten”.
- HistoryEntry v2 mit AES-GCM-Verschlüsselung sensibler Felder (ADR-0020), Schlüssel Keychain-gebunden via
HistoryCryptoProvider.
- Hardened Runtime mit Audio-Input-Entitlement und Developer-ID-Notarisierung. Notary-Gate dry-run bestanden 2026-04-23.
Fixed
- FluidAudio-Cache-Pfad-Drift: Parakeet-Ordnername auf den von FluidAudio erwarteten kanonischen Wert
parakeet-tdt-0.6b-v3 ausgerichtet. FluidAudios AsrModels.download(to:) schreibt nach parentDir(to:) + folderName, nicht nach dem übergebenen to:-Pfad — ein abweichender Ordnername erzeugte einen Sibling-Orphan, verfälschte Disk-Größe und ließ „Modell entfernen” unvollständig räumen. Idempotente Legacy-Layout-Migration (Whisper-Root-.bin und Parakeet-Sibling) kickt beim Boot direkt nach Paths.ensureDirectories(). Siehe ADR-0013 Nachtrag 2026-04-19.
- Doppelter „Abbrechen”-Button im Parakeet-Download-Sheet entfernt: bei Engines ohne Pause-Support wird der Pausieren-Button gar nicht mehr gerendert, statt sein Label auf „Abbrechen” umzumappen.
- Engine-Status-Badges kontextuell: aktive Engine + fehlendes Modell → rot (plus zarter
red.opacity(0.06)-Card-Tint), inaktive Engine + fehlend → grau, geladen → grün, Disk-Größe → blau. Gilt einheitlich in Picker, Modelle-Sektion und Technik-Panel.