Skip to content

Audit tier1 - #51

Open
csmashe wants to merge 342 commits into
linuxfrom
audit-tier1
Open

Audit tier1#51
csmashe wants to merge 342 commits into
linuxfrom
audit-tier1

Conversation

@csmashe

@csmashe csmashe commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Related Issue

Test Plan

  • dotnet test
  • Built and ran locally on Linux
  • Tested the changed functionality manually
  • Checked desktop-environment or X11/Wayland behavior when relevant
  • No regressions in existing features

Notes

Summary by CodeRabbit

  • New Features

    • Added side-effect-free correction preview so users can test dictionary replacements without persisting usage data.
    • Introduced safer atomic settings updates and improved desktop integration setup/restore messaging (including staged restore wording).
  • Bug Fixes

    • Improved Linux dictation/paste confirmation behavior and refined cancellation handling and action-unavailable outcomes.
    • Subtitle timestamps now correctly format durations beyond 24 hours; tokenization now treats all whitespace consistently.
  • Tests

    • Expanded automated coverage for correction preview/CSV import, concurrency, dictation insertion flows, shortcuts/desktop integration, and subtitle formatting.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Too many files!

This PR contains 574 files, which is 424 over the limit of 150.

To get a review, reduce the PR to 150 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to Pro+ to raise the limit.

Usage-priced reviews support at most 300 files.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a28544ed-1087-44bc-8975-435989ba932a

📥 Commits

Reviewing files that changed from the base of the PR and between f800833 and 82d774b.

📒 Files selected for processing (574)
  • .editorconfig
  • .github/workflows/package-dry-run-linux.yml
  • .github/workflows/plugins-smoke.yml
  • .github/workflows/pr-ci-linux.yml
  • .github/workflows/publish-plugins.yml
  • .github/workflows/release-linux.yml
  • README.md
  • TypeWhisper.slnx
  • plugins/Shared/Cuda/CudaRuntimeProvisioner.cs
  • plugins/Shared/Net/InterProcessFileLock.cs
  • plugins/Shared/Net/ResilientDownloader.cs
  • plugins/TypeWhisper.Plugin.AssemblyAi/AssemblyAiPlugin.cs
  • plugins/TypeWhisper.Plugin.AssemblyAi/AssemblyAiStreamingSession.cs
  • plugins/TypeWhisper.Plugin.AssemblyAi/TypeWhisper.Plugin.AssemblyAi.csproj
  • plugins/TypeWhisper.Plugin.AssemblyAi/manifest.json
  • plugins/TypeWhisper.Plugin.Cerebras/CerebrasPlugin.cs
  • plugins/TypeWhisper.Plugin.Cerebras/manifest.json
  • plugins/TypeWhisper.Plugin.Claude/ClaudePlugin.cs
  • plugins/TypeWhisper.Plugin.Claude/manifest.json
  • plugins/TypeWhisper.Plugin.CloudflareAsr/CloudflareAsrPlugin.cs
  • plugins/TypeWhisper.Plugin.CloudflareAsr/TypeWhisper.Plugin.CloudflareAsr.csproj
  • plugins/TypeWhisper.Plugin.CloudflareAsr/manifest.json
  • plugins/TypeWhisper.Plugin.Cohere/CoherePlugin.cs
  • plugins/TypeWhisper.Plugin.Cohere/manifest.json
  • plugins/TypeWhisper.Plugin.Deepgram/DeepgramPlugin.cs
  • plugins/TypeWhisper.Plugin.Deepgram/DeepgramStreamingSession.cs
  • plugins/TypeWhisper.Plugin.Deepgram/TypeWhisper.Plugin.Deepgram.csproj
  • plugins/TypeWhisper.Plugin.Deepgram/manifest.json
  • plugins/TypeWhisper.Plugin.ElevenLabs/ElevenLabsPlugin.cs
  • plugins/TypeWhisper.Plugin.ElevenLabs/ElevenLabsStreamingSession.cs
  • plugins/TypeWhisper.Plugin.ElevenLabs/manifest.json
  • plugins/TypeWhisper.Plugin.FileMemory/FileMemoryPlugin.cs
  • plugins/TypeWhisper.Plugin.FileMemory/manifest.json
  • plugins/TypeWhisper.Plugin.Fireworks/FireworksPlugin.cs
  • plugins/TypeWhisper.Plugin.Fireworks/manifest.json
  • plugins/TypeWhisper.Plugin.Gemini/GeminiPlugin.cs
  • plugins/TypeWhisper.Plugin.Gemini/manifest.json
  • plugins/TypeWhisper.Plugin.GemmaLocal/GemmaLocalPlugin.cs
  • plugins/TypeWhisper.Plugin.GemmaLocal/TypeWhisper.Plugin.GemmaLocal.csproj
  • plugins/TypeWhisper.Plugin.GemmaLocal/manifest.json
  • plugins/TypeWhisper.Plugin.Gladia/GladiaPlugin.cs
  • plugins/TypeWhisper.Plugin.Gladia/GladiaStreamingSession.cs
  • plugins/TypeWhisper.Plugin.Gladia/manifest.json
  • plugins/TypeWhisper.Plugin.GoogleCloudStt/GoogleCloudSttPlugin.cs
  • plugins/TypeWhisper.Plugin.GoogleCloudStt/Localization/de.json
  • plugins/TypeWhisper.Plugin.GoogleCloudStt/Localization/en.json
  • plugins/TypeWhisper.Plugin.GoogleCloudStt/Localization/es.json
  • plugins/TypeWhisper.Plugin.GoogleCloudStt/Localization/ru.json
  • plugins/TypeWhisper.Plugin.GoogleCloudStt/manifest.json
  • plugins/TypeWhisper.Plugin.Groq/GroqPlugin.cs
  • plugins/TypeWhisper.Plugin.Groq/manifest.json
  • plugins/TypeWhisper.Plugin.Linear/LinearPlugin.cs
  • plugins/TypeWhisper.Plugin.Linear/TypeWhisper.Plugin.Linear.csproj
  • plugins/TypeWhisper.Plugin.Linear/manifest.json
  • plugins/TypeWhisper.Plugin.Obsidian/ObsidianPlugin.cs
  • plugins/TypeWhisper.Plugin.Obsidian/TypeWhisper.Plugin.Obsidian.csproj
  • plugins/TypeWhisper.Plugin.Obsidian/manifest.json
  • plugins/TypeWhisper.Plugin.OpenAi/OpenAiChatGptClient.cs
  • plugins/TypeWhisper.Plugin.OpenAi/OpenAiFetchedModel.cs
  • plugins/TypeWhisper.Plugin.OpenAi/OpenAiJson.cs
  • plugins/TypeWhisper.Plugin.OpenAi/OpenAiOAuthSupport.cs
  • plugins/TypeWhisper.Plugin.OpenAi/OpenAiPlugin.cs
  • plugins/TypeWhisper.Plugin.OpenAi/OpenAiRealtimeStreamingSession.cs
  • plugins/TypeWhisper.Plugin.OpenAi/OpenAiResponsesClient.cs
  • plugins/TypeWhisper.Plugin.OpenAi/OpenAiTtsSupport.cs
  • plugins/TypeWhisper.Plugin.OpenAi/manifest.json
  • plugins/TypeWhisper.Plugin.OpenAiCompatible/OpenAiCompatiblePlugin.cs
  • plugins/TypeWhisper.Plugin.OpenAiCompatible/manifest.json
  • plugins/TypeWhisper.Plugin.OpenAiVectorMemory/OpenAiVectorMemoryPlugin.cs
  • plugins/TypeWhisper.Plugin.OpenAiVectorMemory/TypeWhisper.Plugin.OpenAiVectorMemory.csproj
  • plugins/TypeWhisper.Plugin.OpenAiVectorMemory/manifest.json
  • plugins/TypeWhisper.Plugin.OpenRouter/OpenRouterPlugin.cs
  • plugins/TypeWhisper.Plugin.OpenRouter/manifest.json
  • plugins/TypeWhisper.Plugin.Qwen3Stt/Qwen3SttPlugin.cs
  • plugins/TypeWhisper.Plugin.Qwen3Stt/TypeWhisper.Plugin.Qwen3Stt.csproj
  • plugins/TypeWhisper.Plugin.Qwen3Stt/manifest.json
  • plugins/TypeWhisper.Plugin.Reson8/Reson8CustomModel.cs
  • plugins/TypeWhisper.Plugin.Reson8/Reson8Plugin.cs
  • plugins/TypeWhisper.Plugin.Reson8/Reson8StreamingSession.cs
  • plugins/TypeWhisper.Plugin.Reson8/manifest.json
  • plugins/TypeWhisper.Plugin.Script/ScriptPlugin.cs
  • plugins/TypeWhisper.Plugin.Script/manifest.json
  • plugins/TypeWhisper.Plugin.SherpaOnnx/SherpaCudaRuntimeInstaller.cs
  • plugins/TypeWhisper.Plugin.SherpaOnnx/SherpaDecodeCoordinator.cs
  • plugins/TypeWhisper.Plugin.SherpaOnnx/SherpaOnnxNativeRuntime.cs
  • plugins/TypeWhisper.Plugin.SherpaOnnx/SherpaOnnxPlugin.cs
  • plugins/TypeWhisper.Plugin.SherpaOnnx/manifest.json
  • plugins/TypeWhisper.Plugin.SmallestAi/SmallestAiPlugin.cs
  • plugins/TypeWhisper.Plugin.SmallestAi/SmallestAiStreamingSession.cs
  • plugins/TypeWhisper.Plugin.SmallestAi/manifest.json
  • plugins/TypeWhisper.Plugin.Soniox/SonioxPlugin.cs
  • plugins/TypeWhisper.Plugin.Soniox/SonioxStreamingSession.cs
  • plugins/TypeWhisper.Plugin.Soniox/manifest.json
  • plugins/TypeWhisper.Plugin.Speechmatics/SpeechmaticsPlugin.cs
  • plugins/TypeWhisper.Plugin.Speechmatics/SpeechmaticsStreamingSession.cs
  • plugins/TypeWhisper.Plugin.Speechmatics/manifest.json
  • plugins/TypeWhisper.Plugin.SupertonicTts/SupertonicAssetManager.cs
  • plugins/TypeWhisper.Plugin.SupertonicTts/SupertonicOnnxSynthesizer.cs
  • plugins/TypeWhisper.Plugin.SupertonicTts/SupertonicPaths.cs
  • plugins/TypeWhisper.Plugin.SupertonicTts/SupertonicTextProcessor.cs
  • plugins/TypeWhisper.Plugin.SupertonicTts/SupertonicTtsPlayback.cs
  • plugins/TypeWhisper.Plugin.SupertonicTts/SupertonicTtsPlugin.cs
  • plugins/TypeWhisper.Plugin.SupertonicTts/SupertonicVoiceStyle.cs
  • plugins/TypeWhisper.Plugin.SupertonicTts/manifest.json
  • plugins/TypeWhisper.Plugin.Voxtral/TypeWhisper.Plugin.Voxtral.csproj
  • plugins/TypeWhisper.Plugin.Voxtral/VoxtralPlugin.cs
  • plugins/TypeWhisper.Plugin.Voxtral/manifest.json
  • plugins/TypeWhisper.Plugin.Webhook/Localization/de.json
  • plugins/TypeWhisper.Plugin.Webhook/Localization/en.json
  • plugins/TypeWhisper.Plugin.Webhook/Localization/es.json
  • plugins/TypeWhisper.Plugin.Webhook/Localization/ru.json
  • plugins/TypeWhisper.Plugin.Webhook/TypeWhisper.Plugin.Webhook.csproj
  • plugins/TypeWhisper.Plugin.Webhook/WebhookPlugin.cs
  • plugins/TypeWhisper.Plugin.Webhook/manifest.json
  • plugins/TypeWhisper.Plugin.WhisperCpp/WhisperCppPlugin.cs
  • plugins/TypeWhisper.Plugin.WhisperCpp/WhisperCudaRuntimeInstaller.cs
  • plugins/TypeWhisper.Plugin.WhisperCpp/manifest.json
  • plugins/TypeWhisper.Plugin.Xai/XaiJson.cs
  • plugins/TypeWhisper.Plugin.Xai/XaiPlugin.cs
  • plugins/TypeWhisper.Plugin.Xai/XaiResponsesClient.cs
  • plugins/TypeWhisper.Plugin.Xai/XaiStreamingSession.cs
  • plugins/TypeWhisper.Plugin.Xai/XaiTtsSupport.cs
  • plugins/TypeWhisper.Plugin.Xai/manifest.json
  • scripts/build-linux-packages.sh
  • scripts/publish-plugin-release.ps1
  • scripts/smoke-test-linux-packages.sh
  • src/TypeWhisper.Cli/Commands/ModelsCommand.cs
  • src/TypeWhisper.Cli/Commands/StatusCommand.cs
  • src/TypeWhisper.Cli/Commands/TranscribeCommand.cs
  • src/TypeWhisper.Cli/Models/CliOptions.cs
  • src/TypeWhisper.Cli/Models/DiscoveryFile.cs
  • src/TypeWhisper.Cli/Output/ConsoleOutput.cs
  • src/TypeWhisper.Cli/Output/JsonFormatting.cs
  • src/TypeWhisper.Cli/Output/UsageText.cs
  • src/TypeWhisper.Cli/Program.cs
  • src/TypeWhisper.Cli/Services/ApiClient.cs
  • src/TypeWhisper.Cli/Services/ApiResponseValidator.cs
  • src/TypeWhisper.Cli/Services/DiscoveryFileReader.cs
  • src/TypeWhisper.Cli/Services/UnixPeerCredentials.cs
  • src/TypeWhisper.Cli/TypeWhisper.Cli.csproj
  • src/TypeWhisper.Core/Interfaces/IDictionaryService.cs
  • src/TypeWhisper.Core/Interfaces/IProfileService.cs
  • src/TypeWhisper.Core/Interfaces/ISettingsService.cs
  • src/TypeWhisper.Core/Models/CleanupLevel.cs
  • src/TypeWhisper.Core/Models/DictionaryEntrySource.cs
  • src/TypeWhisper.Core/Models/DictionaryEntryType.cs
  • src/TypeWhisper.Core/Models/DiffSegment.cs
  • src/TypeWhisper.Core/Models/ErrorLogEntry.cs
  • src/TypeWhisper.Core/Models/HistoryRetentionMode.cs
  • src/TypeWhisper.Core/Models/IndustryPreset.cs
  • src/TypeWhisper.Core/Models/LocalModelStorageUnavailableReason.cs
  • src/TypeWhisper.Core/Models/MatchKind.cs
  • src/TypeWhisper.Core/Models/ModelStatus.cs
  • src/TypeWhisper.Core/Models/ModelStatusType.cs
  • src/TypeWhisper.Core/Models/OverlayPosition.cs
  • src/TypeWhisper.Core/Models/OverlayWidget.cs
  • src/TypeWhisper.Core/Models/ProfileHotkeyBehavior.cs
  • src/TypeWhisper.Core/Models/ProfileStylePreset.cs
  • src/TypeWhisper.Core/Models/RecentTranscriptionSource.cs
  • src/TypeWhisper.Core/Models/RecordingMode.cs
  • src/TypeWhisper.Core/Models/SnippetTriggerMode.cs
  • src/TypeWhisper.Core/Models/TermPack.cs
  • src/TypeWhisper.Core/Models/TextInsertionStatus.cs
  • src/TypeWhisper.Core/Models/TextInsertionStrategy.cs
  • src/TypeWhisper.Core/Models/TranscriptionTask.cs
  • src/TypeWhisper.Core/Models/TranslationModelInfo.cs
  • src/TypeWhisper.Core/Services/AppFormatterService.cs
  • src/TypeWhisper.Core/Services/AtomicFileWrite.cs
  • src/TypeWhisper.Core/Services/CleanupService.cs
  • src/TypeWhisper.Core/Services/CorrectionSuggestionService.cs
  • src/TypeWhisper.Core/Services/DetectionFailureTracker.cs
  • src/TypeWhisper.Core/Services/DeveloperFormattingService.cs
  • src/TypeWhisper.Core/Services/DictionaryService.Csv.cs
  • src/TypeWhisper.Core/Services/DictionaryService.cs
  • src/TypeWhisper.Core/Services/ErrorLogService.cs
  • src/TypeWhisper.Core/Services/FirstRunDefaults.cs
  • src/TypeWhisper.Core/Services/HistoryInsightsService.cs
  • src/TypeWhisper.Core/Services/HistoryService.Export.cs
  • src/TypeWhisper.Core/Services/IdeFileReferenceService.cs
  • src/TypeWhisper.Core/Services/LocalModelStorageService.cs
  • src/TypeWhisper.Core/Services/NumberNormalization/EnglishNumberWordParser.cs
  • src/TypeWhisper.Core/Services/NumberNormalization/GermanNumberWordParser.cs
  • src/TypeWhisper.Core/Services/NumberNormalization/NumberWordNormalizer.cs
  • src/TypeWhisper.Core/Services/NumberNormalization/SpanishNumberWordParser.cs
  • src/TypeWhisper.Core/Services/NumberNormalization/TranscriptionNumberNormalizationService.cs
  • src/TypeWhisper.Core/Services/PostProcessingPipeline.cs
  • src/TypeWhisper.Core/Services/ProfileService.cs
  • src/TypeWhisper.Core/Services/ProfileStylePresetService.cs
  • src/TypeWhisper.Core/Services/PromptActionService.cs
  • src/TypeWhisper.Core/Services/SettingsService.cs
  • src/TypeWhisper.Core/Services/SnippetService.cs
  • src/TypeWhisper.Core/Services/SubtitleExporter.cs
  • src/TypeWhisper.Core/Services/WhisperHallucinationFilter.cs
  • src/TypeWhisper.Core/Translation/MarianTokenizer.cs
  • src/TypeWhisper.Core/TypeWhisper.Core.csproj
  • src/TypeWhisper.Core/TypeWhisperEnvironment.cs
  • src/TypeWhisper.Linux/App.axaml.cs
  • src/TypeWhisper.Linux/Cli/CommandLineParser.cs
  • src/TypeWhisper.Linux/Cli/Commands/RecordCommand.cs
  • src/TypeWhisper.Linux/DiffKindConverters.cs
  • src/TypeWhisper.Linux/Program.cs
  • src/TypeWhisper.Linux/Resources/Localization/de.json
  • src/TypeWhisper.Linux/Resources/Localization/en.json
  • src/TypeWhisper.Linux/Resources/Localization/es.json
  • src/TypeWhisper.Linux/Resources/Localization/ru.json
  • src/TypeWhisper.Linux/ServiceRegistrations.cs
  • src/TypeWhisper.Linux/Services/ActiveWindow/AccessibilityBusActivationService.cs
  • src/TypeWhisper.Linux/Services/ActiveWindow/AtSpiEventClient.cs
  • src/TypeWhisper.Linux/Services/ActiveWindow/AtSpiUrlExtractor.cs
  • src/TypeWhisper.Linux/Services/ActiveWindow/GnomeWindowCallsProvider.cs
  • src/TypeWhisper.Linux/Services/ActiveWindow/IAtSpiEventClient.cs
  • src/TypeWhisper.Linux/Services/ActiveWindow/ProviderProcessRunner.cs
  • src/TypeWhisper.Linux/Services/ActiveWindowService.cs
  • src/TypeWhisper.Linux/Services/ApiDiscoveryFile.cs
  • src/TypeWhisper.Linux/Services/ApiKeyProtection.cs
  • src/TypeWhisper.Linux/Services/AppVersion.cs
  • src/TypeWhisper.Linux/Services/AudioDuckingService.cs
  • src/TypeWhisper.Linux/Services/AudioFileService.cs
  • src/TypeWhisper.Linux/Services/AudioPlaybackService.cs
  • src/TypeWhisper.Linux/Services/AudioRecordingService.cs
  • src/TypeWhisper.Linux/Services/BrowserAccessibilitySetupHelper.cs
  • src/TypeWhisper.Linux/Services/BundledPluginDeployer.cs
  • src/TypeWhisper.Linux/Services/CliInstallService.cs
  • src/TypeWhisper.Linux/Services/CommandRunner.cs
  • src/TypeWhisper.Linux/Services/DefaultDeviceWatcher.cs
  • src/TypeWhisper.Linux/Services/DictationInFlightSessionTracker.cs
  • src/TypeWhisper.Linux/Services/DictationInsertionOrderGate.cs
  • src/TypeWhisper.Linux/Services/DictationOrchestrator.cs
  • src/TypeWhisper.Linux/Services/DictationToggleGate.cs
  • src/TypeWhisper.Linux/Services/FileTranscriptionProcessor.cs
  • src/TypeWhisper.Linux/Services/GnomeWindowCallsSetupHelper.cs
  • src/TypeWhisper.Linux/Services/HistoryRetentionCoordinator.cs
  • src/TypeWhisper.Linux/Services/Hotkey/BackendSelector.cs
  • src/TypeWhisper.Linux/Services/Hotkey/DeSetup/AtomicFileWriter.cs
  • src/TypeWhisper.Linux/Services/Hotkey/DeSetup/DesktopDetector.cs
  • src/TypeWhisper.Linux/Services/Hotkey/DeSetup/DictationShortcutSpecFactory.cs
  • src/TypeWhisper.Linux/Services/Hotkey/DeSetup/GnomeShortcutWriter.cs
  • src/TypeWhisper.Linux/Services/Hotkey/DeSetup/HyprlandShortcutWriter.cs
  • src/TypeWhisper.Linux/Services/Hotkey/DeSetup/IDeShortcutWriter.cs
  • src/TypeWhisper.Linux/Services/Hotkey/DeSetup/KdeShortcutWriter.cs
  • src/TypeWhisper.Linux/Services/Hotkey/DeSetup/SwayShortcutWriter.cs
  • src/TypeWhisper.Linux/Services/Hotkey/Evdev/EvdevDeviceReader.cs
  • src/TypeWhisper.Linux/Services/Hotkey/Evdev/EvdevGlobalShortcutBackend.cs
  • src/TypeWhisper.Linux/Services/Hotkey/Evdev/IEvdevInputDevice.cs
  • src/TypeWhisper.Linux/Services/Hotkey/Evdev/InputAccessSetupHelper.cs
  • src/TypeWhisper.Linux/Services/Hotkey/Evdev/InputEventStruct.cs
  • src/TypeWhisper.Linux/Services/Hotkey/Evdev/LinuxKeyMap.cs
  • src/TypeWhisper.Linux/Services/Hotkey/Evdev/LogindSessionActivityMonitor.cs
  • src/TypeWhisper.Linux/Services/Hotkey/SharpHookGlobalShortcutBackend.cs
  • src/TypeWhisper.Linux/Services/Hotkey/ShortcutDispatcher.cs
  • src/TypeWhisper.Linux/Services/Hotkey/ShortcutMatcher.cs
  • src/TypeWhisper.Linux/Services/HotkeyService.cs
  • src/TypeWhisper.Linux/Services/HttpApiRequestParser.cs
  • src/TypeWhisper.Linux/Services/HttpApiService.cs
  • src/TypeWhisper.Linux/Services/Insertion/AtSpiPasteConfirmation.cs
  • src/TypeWhisper.Linux/Services/Insertion/IPasteConfirmationSource.cs
  • src/TypeWhisper.Linux/Services/Insertion/YdotoolSetupHelper.cs
  • src/TypeWhisper.Linux/Services/Ipc/ApiSocketOwnership.cs
  • src/TypeWhisper.Linux/Services/Ipc/ControlSocketClient.cs
  • src/TypeWhisper.Linux/Services/Ipc/ControlSocketOwnership.cs
  • src/TypeWhisper.Linux/Services/Ipc/ControlSocketServer.cs
  • src/TypeWhisper.Linux/Services/Ipc/JsonControlProtocol.cs
  • src/TypeWhisper.Linux/Services/Ipc/SocketPathResolver.cs
  • src/TypeWhisper.Linux/Services/Ipc/UnixPeerCredentials.cs
  • src/TypeWhisper.Linux/Services/LearnedCorrectionsFeedbackPresenter.cs
  • src/TypeWhisper.Linux/Services/LearnedCorrectionsNotificationService.cs
  • src/TypeWhisper.Linux/Services/LearnedCorrectionsToastController.cs
  • src/TypeWhisper.Linux/Services/LinuxDictationFinalTextPolicy.cs
  • src/TypeWhisper.Linux/Services/LinuxDictationReadbackLanguagePolicy.cs
  • src/TypeWhisper.Linux/Services/LinuxDictationShortSpeechPolicy.cs
  • src/TypeWhisper.Linux/Services/LinuxLiveTranscriptionStartupPolicy.cs
  • src/TypeWhisper.Linux/Services/LinuxPreferencesService.cs
  • src/TypeWhisper.Linux/Services/LinuxSystemTtsProvider.cs
  • src/TypeWhisper.Linux/Services/Localization/Loc.cs
  • src/TypeWhisper.Linux/Services/Localization/StrExtension.cs
  • src/TypeWhisper.Linux/Services/MediaPauseService.cs
  • src/TypeWhisper.Linux/Services/MemoryService.cs
  • src/TypeWhisper.Linux/Services/ModelManagerService.cs
  • src/TypeWhisper.Linux/Services/Plugins/PluginEventBus.cs
  • src/TypeWhisper.Linux/Services/Plugins/PluginHostServices.cs
  • src/TypeWhisper.Linux/Services/Plugins/PluginLoader.cs
  • src/TypeWhisper.Linux/Services/Plugins/PluginLocalityClassifier.cs
  • src/TypeWhisper.Linux/Services/Plugins/PluginManager.cs
  • src/TypeWhisper.Linux/Services/Plugins/PluginRegistryService.cs
  • src/TypeWhisper.Linux/Services/Plugins/RegistryPlugin.cs
  • src/TypeWhisper.Linux/Services/ProcessPriority.cs
  • src/TypeWhisper.Linux/Services/ProcessRunner.cs
  • src/TypeWhisper.Linux/Services/PromptProcessingService.cs
  • src/TypeWhisper.Linux/Services/RecentTranscriptionsService.cs
  • src/TypeWhisper.Linux/Services/RecordingNotificationService.cs
  • src/TypeWhisper.Linux/Services/SecretProtectionMigrationService.cs
  • src/TypeWhisper.Linux/Services/SettingsBackupService.cs
  • src/TypeWhisper.Linux/Services/Setup/GlobalHotkeySetupTask.cs
  • src/TypeWhisper.Linux/Services/Setup/ISetupTask.cs
  • src/TypeWhisper.Linux/Services/Setup/PackageInstaller.cs
  • src/TypeWhisper.Linux/Services/SoundFeedbackService.cs
  • src/TypeWhisper.Linux/Services/SpeechFeedbackService.cs
  • src/TypeWhisper.Linux/Services/SpokenCommand/SpokenCommandIntent.cs
  • src/TypeWhisper.Linux/Services/SpokenCommand/SpokenCommandKeyphrase.cs
  • src/TypeWhisper.Linux/Services/SpokenCommand/SpokenCommandText.cs
  • src/TypeWhisper.Linux/Services/StartupCancellation.cs
  • src/TypeWhisper.Linux/Services/StartupService.cs
  • src/TypeWhisper.Linux/Services/StreamingTranscriptState.cs
  • src/TypeWhisper.Linux/Services/StreamingTranscriptionCoordinator.cs
  • src/TypeWhisper.Linux/Services/SystemCommandAvailabilityService.cs
  • src/TypeWhisper.Linux/Services/TargetAppCorrectionLearningService.cs
  • src/TypeWhisper.Linux/Services/TextInsertionService.cs
  • src/TypeWhisper.Linux/Services/TransformSelectionService.cs
  • src/TypeWhisper.Linux/Services/TranslationService.cs
  • src/TypeWhisper.Linux/Services/TrayIconService.cs
  • src/TypeWhisper.Linux/Services/UiOperationGuard.cs
  • src/TypeWhisper.Linux/Services/UpdateCheckService.cs
  • src/TypeWhisper.Linux/Services/WatchFolderExportBuilder.cs
  • src/TypeWhisper.Linux/Services/WatchFolderModels.cs
  • src/TypeWhisper.Linux/Services/WatchFolderService.cs
  • src/TypeWhisper.Linux/Services/WaylandSessionDetector.cs
  • src/TypeWhisper.Linux/Services/XdgPaths.cs
  • src/TypeWhisper.Linux/TypeWhisper.Linux.csproj
  • src/TypeWhisper.Linux/ViewModels/DictationOverlayViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/MainWindowViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/AboutSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/AdvancedSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/AppearanceSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/DashboardSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/DictationSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/DictionarySectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/FileTranscriptionQueueItemStatus.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/FileTranscriptionSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/GeneralSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/HistorySectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/PluginCollectionViewModels.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/PluginsSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/ProfilesSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/PromptsSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/RecorderSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/ShortcutsSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/Sections/SnippetsSectionViewModel.cs
  • src/TypeWhisper.Linux/ViewModels/WelcomeWizardViewModel.cs
  • src/TypeWhisper.Linux/Views/DictationOverlayWindow.axaml.cs
  • src/TypeWhisper.Linux/Views/RecentTranscriptionsPaletteWindow.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/AboutSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/AboutSection.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/DashboardSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/DictationSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/DictationSection.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/DictionarySection.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/FileTranscriptionSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/FileTranscriptionSection.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/GeneralSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/HistorySection.axaml
  • src/TypeWhisper.Linux/Views/Sections/HistorySection.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/ProfilesSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/ProfilesSection.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/PromptsSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/RecorderSection.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/ShortcutsSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/ShortcutsSection.axaml.cs
  • src/TypeWhisper.Linux/Views/Sections/SnippetsSection.axaml
  • src/TypeWhisper.Linux/Views/Sections/SnippetsSection.axaml.cs
  • src/TypeWhisper.Linux/Views/WelcomeWizard.axaml.cs
  • src/TypeWhisper.PluginSDK/Helpers/OpenAiApiHelper.cs
  • src/TypeWhisper.PluginSDK/Helpers/OpenAiChatHelper.cs
  • src/TypeWhisper.PluginSDK/Helpers/OpenAiTranscriptionHelper.cs
  • src/TypeWhisper.PluginSDK/IAdditionalLlmProvidersProvider.cs
  • src/TypeWhisper.PluginSDK/IAdditionalTranscriptionEnginesProvider.cs
  • src/TypeWhisper.PluginSDK/ILlmProviderPlugin.cs
  • src/TypeWhisper.PluginSDK/ILlmProviderRole.cs
  • src/TypeWhisper.PluginSDK/ILlmProviderSelectionIdentity.cs
  • src/TypeWhisper.PluginSDK/IPluginEventBus.cs
  • src/TypeWhisper.PluginSDK/IPluginHostServices.cs
  • src/TypeWhisper.PluginSDK/IPluginSettingsActivity.cs
  • src/TypeWhisper.PluginSDK/IPluginSettingsProvider.cs
  • src/TypeWhisper.PluginSDK/ITranscriptionEnginePlugin.cs
  • src/TypeWhisper.PluginSDK/ITranscriptionEngineRole.cs
  • src/TypeWhisper.PluginSDK/ITranscriptionEngineSelectionIdentity.cs
  • src/TypeWhisper.PluginSDK/ITtsProviderPlugin.cs
  • src/TypeWhisper.PluginSDK/Models/LlmResponseTokenEvent.cs
  • src/TypeWhisper.PluginSDK/Models/PartialTranscriptionUpdateEvent.cs
  • src/TypeWhisper.PluginSDK/Models/PluginCategory.cs
  • src/TypeWhisper.PluginSDK/Models/PluginEvent.cs
  • src/TypeWhisper.PluginSDK/Models/PluginLogLevel.cs
  • src/TypeWhisper.PluginSDK/Models/PluginManifest.cs
  • src/TypeWhisper.PluginSDK/Models/PluginNetworkAccess.cs
  • src/TypeWhisper.PluginSDK/Models/TranscriptionAccelerationBackend.cs
  • src/TypeWhisper.PluginSDK/Models/TranscriptionAccelerationPreference.cs
  • src/TypeWhisper.PluginSDK/Models/TtsPurpose.cs
  • src/TypeWhisper.PluginSDK/PluginSelectionExtensions.cs
  • tests/TypeWhisper.Cli.Tests/AssemblyInfo.cs
  • tests/TypeWhisper.Cli.Tests/CommandLineParserTests.cs
  • tests/TypeWhisper.Cli.Tests/DiscoveryFileReaderTests.cs
  • tests/TypeWhisper.Cli.Tests/ProgramDispatchTests.cs
  • tests/TypeWhisper.Cli.Tests/ProtocolResponseValidationTests.cs
  • tests/TypeWhisper.Cli.Tests/QuickCommandTimeoutTests.cs
  • tests/TypeWhisper.Cli.Tests/SocketShutdown.cs
  • tests/TypeWhisper.Cli.Tests/TranscribeCommandTests.cs
  • tests/TypeWhisper.Cli.Tests/UnixSocketApiClientTests.cs
  • tests/TypeWhisper.Cli.Tests/UsageTextTests.cs
  • tests/TypeWhisper.Core.Tests/InterProcessFileLockTests.cs
  • tests/TypeWhisper.Core.Tests/Models/ErrorCategoryGuardTests.cs
  • tests/TypeWhisper.Core.Tests/ResilientDownloaderTests.cs
  • tests/TypeWhisper.Core.Tests/Services/AtomicFileWriteTests.cs
  • tests/TypeWhisper.Core.Tests/Services/CleanupServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/DictionaryServiceCorrectionsTests.cs
  • tests/TypeWhisper.Core.Tests/Services/DictionaryServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/ErrorLogServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/HistoryInsightsServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/HistoryServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/LocalModelStorageServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/MatchProfileCascadeTests.cs
  • tests/TypeWhisper.Core.Tests/Services/NumberWordNormalizerTests.cs
  • tests/TypeWhisper.Core.Tests/Services/PostProcessingPipelineTests.cs
  • tests/TypeWhisper.Core.Tests/Services/ProfileServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/PromptActionServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/SettingsServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/SnippetServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/SubtitleExporterTests.cs
  • tests/TypeWhisper.Core.Tests/Services/TranscriptionNumberNormalizationServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Services/VocabularyBoostingServiceTests.cs
  • tests/TypeWhisper.Core.Tests/Translation/MarianTokenizerTests.cs
  • tests/TypeWhisper.Linux.Tests/AboutSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/AdvancedSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/ApiDiscoveryFileTests.cs
  • tests/TypeWhisper.Linux.Tests/ApiKeyProtectionTests.cs
  • tests/TypeWhisper.Linux.Tests/ApiSocketOwnershipTests.cs
  • tests/TypeWhisper.Linux.Tests/AppBootstrapTests.cs
  • tests/TypeWhisper.Linux.Tests/AppInsertionStrategyRowTests.cs
  • tests/TypeWhisper.Linux.Tests/AppVersionCompareTests.cs
  • tests/TypeWhisper.Linux.Tests/AppearanceSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/AtSpiEventClientFocusTests.cs
  • tests/TypeWhisper.Linux.Tests/AtSpiUrlExtractorTests.cs
  • tests/TypeWhisper.Linux.Tests/AtomicFileWriterTests.cs
  • tests/TypeWhisper.Linux.Tests/AudioDuckingServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/AudioRecordingServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/BrowserAccessibilityLauncherDiscoveryTests.cs
  • tests/TypeWhisper.Linux.Tests/BundledPluginDeployerTests.cs
  • tests/TypeWhisper.Linux.Tests/CliInstallServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/CompositorShortcutWriterConcurrencyTests.cs
  • tests/TypeWhisper.Linux.Tests/ControlSocketOwnershipTests.cs
  • tests/TypeWhisper.Linux.Tests/ControlSocketServerTests.cs
  • tests/TypeWhisper.Linux.Tests/DashboardSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/DefaultDeviceWatcherTests.cs
  • tests/TypeWhisper.Linux.Tests/DesktopWriterFormattingTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationInFlightSessionTrackerTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationInsertionOrderGateTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOrchestratorActionPluginRoutingTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOrchestratorDiscardFeedbackTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOrchestratorInsertionFailureRecordingTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOrchestratorPostProcessingLanguageTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOrchestratorPreviewFallbackTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOrchestratorPromptActionResolutionTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOrchestratorStartFeedbackTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOverlayViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationOverlayWindowTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationSectionViewModelLocalizationTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationShortcutSpecFactoryTests.cs
  • tests/TypeWhisper.Linux.Tests/DictationShutdownTests.cs
  • tests/TypeWhisper.Linux.Tests/DictionarySectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/EvdevDeviceReaderTests.cs
  • tests/TypeWhisper.Linux.Tests/EvdevGlobalShortcutBackendTests.cs
  • tests/TypeWhisper.Linux.Tests/FakeDeShortcutWriter.cs
  • tests/TypeWhisper.Linux.Tests/FakeProcessRunner.cs
  • tests/TypeWhisper.Linux.Tests/FileTranscriptionSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/GlobalHotkeySetupTaskTests.cs
  • tests/TypeWhisper.Linux.Tests/GnomeShortcutWriterTests.cs
  • tests/TypeWhisper.Linux.Tests/HistorySectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/HotkeyServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/HttpApiAccelerationDtoTests.cs
  • tests/TypeWhisper.Linux.Tests/HttpApiCorrectionsDtoTests.cs
  • tests/TypeWhisper.Linux.Tests/HttpApiLocalFileDtoTests.cs
  • tests/TypeWhisper.Linux.Tests/HttpApiRequestDispatcherTests.cs
  • tests/TypeWhisper.Linux.Tests/HttpApiRequestParserTests.cs
  • tests/TypeWhisper.Linux.Tests/HttpApiSecretProtectionTests.cs
  • tests/TypeWhisper.Linux.Tests/HttpApiUnixSocketTests.cs
  • tests/TypeWhisper.Linux.Tests/InputAccessSetupHelperTests.cs
  • tests/TypeWhisper.Linux.Tests/KdeShortcutWriterTests.cs
  • tests/TypeWhisper.Linux.Tests/LearnedCorrectionsFeedbackPresenterTests.cs
  • tests/TypeWhisper.Linux.Tests/LearnedCorrectionsNotificationServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/LinuxDictationFinalTextPolicyPerformanceTests.cs
  • tests/TypeWhisper.Linux.Tests/LinuxDictationReadbackLanguagePolicyTests.cs
  • tests/TypeWhisper.Linux.Tests/LinuxLiveTranscriptionStartupPolicyTests.cs
  • tests/TypeWhisper.Linux.Tests/LinuxPreferencesServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/LinuxSystemTtsProviderTests.cs
  • tests/TypeWhisper.Linux.Tests/LlmCleanupServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/LocalizationResourcesTests.cs
  • tests/TypeWhisper.Linux.Tests/MediaPauseServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/PluginCollectionSettingsViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/PluginMetadataConsumerParityTests.cs
  • tests/TypeWhisper.Linux.Tests/PluginRegistryServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/ProcessRunnerTests.cs
  • tests/TypeWhisper.Linux.Tests/ProfilesSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/PromptProcessingServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/PromptsSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/RecentTranscriptionStoreTests.cs
  • tests/TypeWhisper.Linux.Tests/RecentTranscriptionsServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/RecorderFileNamerTests.cs
  • tests/TypeWhisper.Linux.Tests/RecorderSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/RecordingNotificationServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/SecretProtectionMigrationServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/SentinelBlockTests.cs
  • tests/TypeWhisper.Linux.Tests/SessionAudioFileServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/SettingsBackupServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/SharpHookGlobalShortcutBackendTests.cs
  • tests/TypeWhisper.Linux.Tests/ShortcutDispatcherTests.cs
  • tests/TypeWhisper.Linux.Tests/ShortcutMatcherTests.cs
  • tests/TypeWhisper.Linux.Tests/ShortcutsSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/SnippetsSectionViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/SocketPathResolverTests.cs
  • tests/TypeWhisper.Linux.Tests/SoundFeedbackServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/SpeechFeedbackServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/SpokenCommandActionMatcherTests.cs
  • tests/TypeWhisper.Linux.Tests/StartupServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/StreamingTranscriptStateTests.cs
  • tests/TypeWhisper.Linux.Tests/StreamingTranscriptionCoordinatorTests.cs
  • tests/TypeWhisper.Linux.Tests/SystemCommandAvailabilityServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/TargetAppCorrectionLearningServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/TestPathsTests.cs
  • tests/TypeWhisper.Linux.Tests/TestPluginManagerFactory.cs
  • tests/TypeWhisper.Linux.Tests/TestShortcutBackend.cs
  • tests/TypeWhisper.Linux.Tests/TextInsertionServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/TransformSelectionServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/TrayIconServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/UiOperationGuardTests.cs
  • tests/TypeWhisper.Linux.Tests/WatchFolderExportBuilderTests.cs
  • tests/TypeWhisper.Linux.Tests/WatchFolderServiceTests.cs
  • tests/TypeWhisper.Linux.Tests/WaylandSessionDetectorTests.cs
  • tests/TypeWhisper.Linux.Tests/WelcomeWizardViewModelTests.cs
  • tests/TypeWhisper.Linux.Tests/XdgPathsTests.cs
  • tests/TypeWhisper.Linux.Tests/YdotoolSetupHelperTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/BundledPluginManifestTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/ClaudePluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/CloudflareAsrPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/CudaRuntimeCacheClearTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/CudaRuntimeProvisionerTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/ElevenLabsPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/GemmaLocalPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/GladiaPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/GoogleCloudSttPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/GroqPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/HistoryRetentionCoordinatorTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/LinearPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/ModelManagerServiceTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/ObsidianPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/OpenAiChatGptClientTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/OpenAiChatHelperTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/OpenAiCompatiblePluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/OpenAiPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/OpenAiTranscriptionHelperTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/OpenAiVectorMemoryPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/OpenRouterPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/PluginEventBusTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/PluginEventsTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/PluginHostServicesTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/PluginLoaderTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/PluginManagerTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/PluginManifestTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/PluginRegistryServiceTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/Qwen3SttPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/Reson8PluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/ScriptCollectionSettingsTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/SharedHelperStreamingCohortTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/SherpaOnnxCancellationTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/SherpaOnnxLanguageTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/SmallestAiPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/SonioxPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/SpeechmaticsPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/StreamingProviderDisposalTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/StreamingProviderFailurePropagationTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/SupertonicTtsPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/TypeWhisper.PluginSystem.Tests.csproj
  • tests/TypeWhisper.PluginSystem.Tests/VoxtralPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/WebhookCollectionSettingsTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/WhisperCppPluginTests.cs
  • tests/TypeWhisper.PluginSystem.Tests/XaiPluginTests.cs
  • tests/workflows/PublishPluginReleaseTransaction.Tests.ps1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

The PR adds synchronized settings updates, preview-only dictionary corrections, safer model migration, ordered dictation insertion, improved clipboard and AT-SPI verification, model auto-unload lifecycle handling, concurrency protections, text-processing fixes, desktop shortcut mappings, localization, and extensive Core/Linux test coverage.

Changes

Core persistence and text processing

Layer / File(s) Summary
Dictionary and settings persistence
src/TypeWhisper.Core/Interfaces/*, src/TypeWhisper.Core/Services/DictionaryService*, src/TypeWhisper.Core/Services/SettingsService.cs, tests/TypeWhisper.Core.Tests/Services/{DictionaryService,SettingsService,VocabularyBoostingService}Tests.cs
Adds side-effect-free correction previews, case-insensitive CSV correction upserts, and synchronized settings mutation APIs with concurrency coverage.
Text processing and metrics
src/TypeWhisper.Core/Services/{CleanupService,HistoryInsightsService,PostProcessingPipeline,SubtitleExporter}.cs, src/TypeWhisper.Core/Translation/MarianTokenizer.cs, src/TypeWhisper.Core/Models/TextInsertionStatus.cs, tests/TypeWhisper.Core.Tests/...
Tightens filler matching, handles whitespace and long subtitle durations, classifies action outcomes, and distinguishes caller cancellation from internal step cancellation.
Repeated-phrase detection
src/TypeWhisper.Linux/Services/LinuxDictationFinalTextPolicy.cs, tests/TypeWhisper.Linux.Tests/LinuxDictationFinalTextPolicyPerformanceTests.cs
Adds stable rolling-hash precomputation with exact verification and performance coverage.

Model and dictation lifecycle

Layer / File(s) Summary
Safe model storage migration
src/TypeWhisper.Core/Services/LocalModelStorageService.cs, tests/TypeWhisper.Core.Tests/Services/LocalModelStorageServiceTests.cs
Copies model and plugin assets with staging and atomic replacement, commits settings, then performs guarded best-effort source cleanup.
Model auto-unload lifecycle
src/TypeWhisper.Linux/Services/ModelManagerService.cs, tests/TypeWhisper.PluginSystem.Tests/ModelManagerServiceTests.cs, src/TypeWhisper.Linux/Services/{FileTranscriptionProcessor,HttpApiService}.cs
Schedules auto-unload across load and lease paths, supports keepModelWarm, bounds timer intervals, and moves scheduling responsibility into lease/model lifecycle handling.
Ordered dictation orchestration
src/TypeWhisper.Linux/Services/{DictationOrchestrator,DictationInFlightSessionTracker,DictationInsertionOrderGate}.cs, related Linux tests
Tracks session cleanup, orders overlapping insertions, handles unavailable action targets and thrown insertion failures, resolves post-processing language, and avoids duplicate preview corrections.

Insertion and Linux integration

Layer / File(s) Summary
Insertion safety and paste verification
src/TypeWhisper.Linux/Services/TextInsertionService.cs, src/TypeWhisper.Linux/Services/Insertion/*, src/TypeWhisper.Linux/Services/ProcessRunner.cs, related tests
Tracks partial typing, prevents duplicate paste fallback, detects non-text clipboard formats, verifies pasted text through AT-SPI, removes Wayland xdotool fallback, and improves process timeout cleanup.
Concurrency and transform safety
src/TypeWhisper.Linux/Services/{StreamingTranscriptState,TransformSelectionService}.cs, src/TypeWhisper.Linux/Services/ActiveWindow/AtSpiEventClient.cs, src/TypeWhisper.Linux/Services/TargetAppCorrectionLearningService.cs, related tests
Rejects stale transcript commits, preserves newer focus state, disarms failed learning sessions, and avoids replacing selections after target drift.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The template is present, but all required sections are effectively empty placeholders. Fill in Summary, Related Issue, Test Plan, and Notes with concrete details about the changes and validation performed.
Title check ❓ Inconclusive The title is too vague to convey the main change. Rename it to summarize the primary code changes, e.g. settings atomicity, plugin cleanup, and test updates.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch audit-tier1

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

csmashe added 26 commits July 18, 2026 03:27
csmashe added 28 commits August 3, 2026 13:32
FindSystemLauncher only scanned /usr/share/applications and the system-wide
Flatpak export dir, so a browser installed with `flatpak install --user` —
what GNOME Software defaults to — was never found. Setup then patched
nothing, and because HasInstalledLauncher also missed it, IsFullyConfigured
succeeded vacuously: the UI reported success while AT-SPI URL detection kept
failing. Zen on this box was exactly that case.

Discovery now walks XDG_DATA_DIRS in its declared order, led by the per-user
Flatpak export dir, since that copy is the one the application menu launches.
Spec defaults apply only when the variable is unset; a root the session
omitted is one whose launchers the desktop does not read, so it is not
reintroduced. Flatpak's own export roots are the exception — they are placed
in the variable by hooks that miss some session types.

Also resolve XDG_DATA_HOME for the shadow-launcher and backup dirs: a shadow
written under a data home the session ignores never reaches the menu. A
relative value is treated as unset in both places, including the sibling
KdeShortcutWriter this resolution was modelled on.

The Chromium name list gained the Flatpak app IDs, mirroring the Firefox
list, since a Flatpak-only install ships no native launcher.
Brings back the two review fixes made on review/tier1-01. Three conflicts
against later slices, resolved toward the newer audit-tier1 APIs:

- DictationOrchestrator: kept the fix's per-step try/catch isolation but
  called RollBackStartedRecording(captureSession) — later slices made the
  rollback capture-session scoped. Dropped the fix's `_audio.LiveFrameSink
  = null`: that property is gone, and the session-scoped sink is already
  cleared by StopRecording during the rollback.
- SettingsBackupService: took the fix's ReadBounded helper over the older
  inline bounded-read loop; same cap, less duplication.
- TargetAppCorrectionLearningService: took the fix's explanatory comment.

Also repaired a silent auto-merge break: a presenter test call site kept
the two-argument constructor after IErrorLogService became required.

1683 Linux tests pass.
Addresses the QA findings on this branch and the issues surfaced by the
follow-up adversarial/standard review loop.

Data safety:
- LocalModelStorageService: never delete a migrated source based on
  resemblance. Track the targets this run actually wrote, stamped with
  size and mtime, and delete only against an unchanged stamp. Previously
  any pre-existing file at the target counted as "already migrated" and
  the source was removed.
- ProfileService: refuse to save while profiles.json failed to load, and
  retry the load in EnsureCacheLoaded so a transient failure or a repaired
  file recovers without a restart.
- PluginHostServices: do not cache an empty store after an unreadable
  file, and clear the load-failed flag on every recovery path.
- FileMemoryPlugin: write memories owner-only on every write, including
  the first, and commit with a single atomic overwriting rename.
- AtomicFileWrite: fsync the temp file before it becomes the destination,
  and close the check-then-move race on the replace path.

SettingsService:
- Load under the write lock; add Reload so restore-from-backup is atomic.
- Publish SettingsChanged outside the lock but in commit order, via a
  single elected drainer, with per-subscriber exception isolation.

ProcessRunner:
- Caller cancellation now kills the process tree and propagates instead of
  being reported as NotStarted; disposal of a blocked stdin writer can no
  longer displace the cancellation or timeout result.

UI and misc:
- Surface save failures in the Snippets, Prompts, and Profiles sections
  (en/de/es/ru), and show watch-folder warnings on succeeded runs.
- Marshal HttpApiService/settings notifications to the UI thread, guarded
  against persisting a stale snapshot.
- Cache correction regexes per pattern with CultureInvariant matching.
- Order-gate and orchestrator: wait for the insertion turn before the
  status/focus handoff, and never queue an unreserved session.

Tests: 2131 passing. ReSharper: 0 issues at HINT severity.
QA review fixes:
- PluginManager.Dispose: one shutdown budget for the whole plugin pass
  instead of a full timeout per plugin, which multiplied by plugin count.
- WatchFolderService: observe the rescan worker so an unexpected fault
  marks the run failed instead of dying silently while it reports healthy.
- WatchFolderService: carry the committed export path into the failure
  history record, so a post-CommitExport failure still tells the user
  where the transcript landed (critical when DeleteSource removed the
  original).
- Advanced/General section view models: post SettingsChanged through the
  UI thread; the HTTP API and model manager save off-thread and Refresh
  mutates ObservableCollections.
- PluginsSectionViewModel: give the plugin boundary a real cancellation
  token instead of CancellationToken.None, disposed once the boundary
  completes.
- SystemCommandAvailabilityService: kill the nvidia-smi child on every
  early exit; disposing the Process never stopped it.
- HistorySection: replace the hard-coded MM/dd/yyyy timestamp with a
  culture-driven short date plus 24-hour time.

ReSharper inspections: 135 -> 0 at HINT severity (fresh cache). Fixed 83
(target-typed new() style headers, static helpers, IsType/exactMatch,
trailing commas, const locals, Contains, merged try, MemberData discovery
enumeration); suppressed 52 with reason comments where the suggestion was
subjective or would not compile.

Build clean, 2826 tests pass.
Addresses review findings on GnomeShortcutWriter, verified against the
code and hardened over an adversarial plus three standard Codex passes.

- RemoveAsync now drops every occurrence of the managed path. List.Remove
  took only the first, so an externally duplicated entry survived removal
  and left the shortcut registered.
- A failed or cancelled install no longer leaves a half-configured entry
  in GNOME's Settings UI: WriteAsync unpublishes the path it just added
  when a name/command/binding write doesn't land. It skips the cleanup for
  a path that was already listed, and for one another writer has since
  configured in full, so rollback can't delete a working shortcut.
- Cleanup failures are reported rather than swallowed. MutateListAsync
  signals normal failures through its return value, so the outcome is now
  inspected: the result carries a warning naming the leftover entry, and
  any backup the cleanup wrote is merged into FilesChanged.
- Snapshots reserve their filename with FileMode.CreateNew and retry on a
  colliding timestamp, so a backup is never overwritten. Only the create
  step retries; a write that fails afterwards deletes its partial file
  instead of leaving something that reads as a valid snapshot.
- Install and remove are serialized per instance. The writer is a DI
  singleton and the Shortcuts panel exposes the two as separate commands,
  so they could otherwise interleave over the same path.

Cross-process edits remain handled by the existing read/confirm/retry
loop, which is as close to atomic as gsettings allows.

Solution-wide ReSharper inspections are at zero against a fresh cache.
BrowserAccessibilitySetupHelper and KdeShortcutWriter each resolved
XDG_DATA_HOME inline, including the rule that a relative value is invalid and
must be ignored. Duplicating that rule meant a third consumer could easily
miss it, and it left a comment in one file pointing at the other for the
reasoning.

The shared resolver uses GetFolderPath's DoNotVerify option: the default
returns an empty string when HOME names a directory that is not on disk,
which made the fallback itself relative — the very thing the rooted check
exists to prevent. An unset HOME was never affected, since that path falls
back to the passwd entry.

Both env-mutating test classes now touch TypeWhisperEnvironment.BasePath
before redirecting HOME. BasePath freezes on first access and derives from
the same variables, so whichever test reached it first would otherwise pin
the process-wide production root to a temp directory, silently weakening the
TestPaths.EnsureIsolated guard the rest of the suite relies on.
Callers invoke AddEntry from inside their own catch blocks, so a throwing
subscriber would escape and take down the operation that was trying to
report a failure. Raise the event per subscriber with isolated handling,
and keep the diagnostic itself best-effort: interpolating the exception
calls a virtual ToString, and Trace listeners can fail.

This also stops one bad subscriber from starving the ones registered
after it.

Adds ErrorLogServiceTests covering a throwing subscriber, an exception
whose ToString and Message both throw, and the same guarantee on
ClearAll.
Both view models subscribed to SettingsChanged with a bare += Refresh, so
they wrote bound properties on whichever thread called Save. The dictation
path and the model-storage migration both save from background threads.

Route the refresh through an injected post delegate that defaults to the
dispatcher, running inline when already on the UI thread so a save from the
UI still refreshes synchronously. The delegate is injected rather than
calling Dispatcher.UIThread directly because that dispatcher binds to
whichever thread touches it first and nothing pumps it under the test
runner, which made the existing Appearance tests fail under the parallel
runner while passing in isolation.

Follows the same seam LearnedCorrectionsNotificationService already uses.
Once the initiation response yields a valid id the transcription job
exists server-side, but result_url extraction and the HTTPS check threw
before returning an InitiatedJob — and TranscribeAsync only enters the
try/finally that calls DeleteJobBestEffortAsync once it has one. A
missing, malformed, or non-HTTPS result_url therefore orphaned the job
on Gladia's side.

Wrap that stretch so a failure deletes the job before rethrowing, which
leaves the original protocol exception intact.

The two existing theories were asserting the bug: their handlers threw
"Unexpected request: DELETE" on any cleanup call. They now count DELETEs
instead — one for a valid id with a bad result_url, none for the no-id
case, where there is nothing to clean up. Reverting the plugin change
fails exactly those four cases.

Build clean, ReSharper 0 at HINT (fresh cache), 2826 tests pass.
Making the Advanced and Appearance refreshes UI-thread-deferred introduced a
regression: every property Refresh writes has a save-hook guarded only by
equality against _settings.Current, and that guard is sound only while the
refresh runs during the save. Once queued, Current has already advanced, so
the older snapshot looks like a genuine user edit and overwrites the newer
commit.

Read Current when the post runs instead of capturing the event payload, so
queued refreshes coalesce onto the newest commit, and add a hydration flag —
saved and restored rather than cleared, so a nested refresh cannot un-guard
the outer one — that every save-hook checks: 4 in Appearance, 8 in Advanced.

Route the plugin and provider callbacks through the same post delegate too.
They mutate bound properties from background threads and touch the properties
the flag guards, so they have to be serialized with Refresh rather than race
it.

Note this deliberately stops hydration from writing normalized values back.
That write-back also persisted MemoryEnabled=false whenever a plugin was
merely unavailable, discarding the user's preference; the remaining cases are
normalized at the point of use instead.
Reject the redaction placeholder when no stored value backs it. GetItems
renders every stored header value as "<stored securely>", so duplicating a
webhook row or renaming a header carried that text back to a name with
nothing behind it and stored it verbatim - the webhook then sent the
placeholder as its real header value and the settings UI redisplayed it
looking exactly like a kept secret. This reverses the "a placeholder on a
new header is a literal value" clause of 2d17b7f; the test that pinned it
now asserts rejection.

Move the CLI installation off the UI thread. It copies the ~17 MB binary
and runs it once to verify on a 10-second deadline, all of which froze the
window. Commit the launcher by rename with its mode verified first, so an
interrupted install cannot leave a truncated script - and a chmod that
fails cannot replace a working launcher with a non-executable one - and
handle the TimeoutException that CLI verification can raise, which was
previously unhandled.

Stop the transcribe spool cleanup from masking results: File.Delete in the
finally could throw over a successful transcription, and in the catch it
could replace the spool failure. It is now best-effort but reports the path
on stderr, since the file holds the whole recording.

Fail closed explicitly when the Unix-socket peer credential read throws
rather than unwinding into Kestrel, dedupe FormatBudget into ConsoleOutput,
and correct the PluginSelectionExtensions suppression comment, which
claimed a boxed struct enumerator that does not exist - foreach over a
string compiles to indexer access.

Tests: drop a shared temp-directory file count that raced other processes,
handle teardown faults in the stub DisposeAsync paths so they cannot mask
an assertion failure or leak the temp directory, and move Dispose(api) into
finally to match QuickCommandTimeoutTests.
ProvidersChanged was the one subscription set up before Refresh applied the
persisted settings. RefreshSpokenFeedbackProviders falls back to the default
provider when the selected one is absent, and that write is not under the
hydration guard, so a notification arriving in that window would reconcile
against an un-hydrated selection and persist the default over the user's
saved provider.

Moving it below hydration also lines it up with the SettingsChanged and
PluginStateChanged subscriptions, which already ran after Refresh.
14 conflicting files. Slice 2 was cut 235 commits behind the tip, so most
conflicts were the same problem solved twice; resolved toward whichever
design the rest of audit-tier1 already assumes, keeping slice 2's fixes
wherever they add behavior rather than duplicate it.

Kept audit-tier1's design (slice 2 re-solved it independently):
- ProfilesSectionViewModel: UiOperationGuard over slice 2's TryMutate —
  same logging, rollback and status, but catches only expected failure
  kinds instead of bare Exception. ProfilesSection.axaml reverted with it,
  since its error banner bound HasError/ErrorText from the dropped design.
- ProcessRunner: audit §6 M1 covers the same cancellation hardening with
  five tests; the two rewrites had incompatible block structure.
- AboutSectionViewModel: staged restore supersedes RestoreBackup + reload.
- AdvancedSectionViewModel: _isProgrammaticRefresh over _hydratingFromSettings.

Kept slice 2's work (genuinely new):
- LocalModelStorageService: the MigratedTargets provenance ledger, which
  the auto-merged body already threads through every helper. This reverses
  audit-tier1's contract — migration now refuses to overwrite an unrelated
  target and never deletes a source it cannot prove it wrote, so the two
  tests asserting replace-and-delete were removed in favour of slice 2's
  three. Kept audit-tier1's TryCleanUp wrapper on top; dropped the now
  unreferenced FilesHaveIdenticalContent.
- SettingsService.Reload(), which the merged ISettingsService declares.
- FileMemoryPlugin owner-only permissions on every write.
- GeneralSectionViewModel UI-thread marshalling, plus audit-tier1's
  LanguageChanged handler that slice 2's cut predated.
- App.axaml.cs: seed-failure guard spliced into the newer reconcile design.
- ProfileService: union ctor carrying both the atomic-write seam and errorLog.
- New tests for unreadable profile files and settings publication ordering.

Full solution green: 514 Core, 1700 Linux, 897 PluginSystem, 108 CLI.
Fixes the settings-UI row collision where the "normalize numbers" toggle sat on
the same two grid rows as the realtime-streaming live preview, and stops
reporting a Translate task downstream when the engine does not support
translation (dictation, file transcription and the HTTP API all forced number
normalization to treat source-language text as English).

Installer: the unsafe-INSTALL_ROOT check now guards the reinstall cleanup loop
as well as uninstall, and the KEEP list is defined once instead of twice, since
two copies could drift and silently delete user data. The tarball smoke test
now plants a fixture on a KEEP path and asserts it survives both cleanup loops.

Number parsers: a bare singular "millón"/"Million" is a noun, not a number, and
"menos" no longer licenses the articles "un"/"una" — it also means
"except/less", so "todos menos un estudiante" was becoming "todos -1
estudiante". Regression tests cover both.

Also drains-by-not-redirecting pactl stderr (a full pipe buffer would block the
child and stall the device-change stream), clears the stale native-audio
failure reason after a later successful init, and matches the test time
provider's TimestampFrequency to the ticks it hands out.

Closes the whole-solution ReSharper pass at 0 issues (HINT severity, fresh
cache): trailing commas per .editorconfig, pattern merges, a dead public
NormalizeSegments overload removed, and reasoned suppressions where the
suggested rewrite would read worse.
Five conflicting files, resolved per hunk rather than per file — this slice
contained both genuine fixes and re-solutions of problems audit-tier1 had
already addressed.

Kept slice 3's work:
- ShortcutDispatcher: its rekeying of _pendingSelectionWorkflows from
  KeyCode to SelectionWorkflowId. The KeyCode map is the older design and
  cannot hold two selection workflows that share a trigger key under
  different modifiers; slice 3 ships three tests covering that and the
  rebound-key-after-ClearShortcuts guards. Kept audit-tier1's ReSharper
  annotations on the loops.
- GnomeShortcutWriter: the recoverable-mutation try wrapper.
- UpdateCheckService: the guard so a failed preferences write costs only
  rate-limit bookkeeping, not the check result.
- HttpApiService: _requestDispatcher.Dispose(), which audit-tier1 never
  called. Dropped the accompanying _cts/_listenTask drain — the Kestrel
  migration removed both fields.

Kept audit-tier1's:
- App.axaml.cs reconcile revision guard; dropped the now-dead snapshot
  locals, since the merged body reads both services under reconcileLock.

Full solution green: 514 Core, 1715 Linux, 897 PluginSystem, 108 CLI.
Four conflicting files.

Kept slice 4's work:
- AtomicFileWrite: its PublishReplace/PublishCreateNew helpers, which keep
  the destination-mode copy and additionally survive a concurrent writer
  creating the destination between the check and the link. Kept
  audit-tier1's FlushToDisk call, which slice 4's arm dropped — without it
  the durability flush is silently lost.
- GemmaLocalPlugin: the SelectedModelId selection lock, alongside
  audit-tier1's model-routing guard (unrelated fields, both kept).

Kept audit-tier1's:
- ObsidianPlugin: same trailing-separator fix on both sides; audit-tier1's
  falls back to the vault key rather than showing a full path in the picker.
- RecentTranscriptionsService.StatusTextFor: localized catalog lookups over
  slice 4's snapshot read and hardcoded English failure string.

Corrected both sides in IsError: slice 4 inverted it so an unrecognized
result fails closed (right call), but that swept ActionHandled in with the
failures even though a plugin action consuming the text is a success.
audit-tier1's allowlist was wrong the other way, omitting ActionFailed and
ActionUnavailable. Kept the fail-closed shape with ActionHandled as success.

Full solution green: 514 Core, 1715 Linux, 899 PluginSystem, 108 CLI.
Slice 5's only commit re-applied the 714 trailing commas that ec14e81
already carries into audit-tier1 (via slices 6a/6b), so all 17 conflicts
were the same formatting landing twice over code audit-tier1 had since
moved on from. Verified slice 5 introduces no symbol its cut point lacked,
then took audit-tier1 throughout.

Notable: this drops s_defaultEnabledPluginIds, which slice 5 still carried.
That is correct — 4b7ff31 removed it upstream when plugin manifests became
authoritative for locality and category.

Full solution green: 514 Core, 1715 Linux, 899 PluginSystem, 108 CLI.
Brings in XdgPaths centralization and per-user Flatpak browser launcher
discovery. Eight of the nine conflicts were the trailing-comma sweep again
(files untouched by either real commit) and took audit-tier1's side.

BrowserAccessibilitySetupHelper resolved by hand:
- Launcher names: union, keeping slice 6's Flatpak application IDs
  (com.vivaldi.Vivaldi, com.opera.Opera) alongside the existing entries.
- s_flatpakExportRoots: took slice 6's single "/var/lib/flatpak/exports/share".
  The merged consumer does Path.Join(root, "applications"), so audit-tier1's
  entries would have resolved to .../applications/applications and matched
  nothing. Its /usr/share entry is also deliberately absent per the comment
  there — system roots the session omitted are not force-appended.

Full solution green: 514 Core, 1735 Linux, 899 PluginSystem, 108 CLI.
Second half of the mechanical trailing-comma split. No conflicts and no
content change — ec14e81 already carries these commas into audit-tier1,
and slice 7 added no commits of its own beyond the split's rejoin merge.
33 conflicts, nearly all from slice 9's ReSharper sweep colliding with the
one audit-tier1 already ran — the two runs wrote different justification
wordings for the same disable pragmas. Took audit-tier1's wordings, which
are the more specific of the two.

Real resolutions:
- AdvancedSectionViewModel: adopted slice 9's UI-thread marshalling for
  SettingsChanged (Refresh mutates the provider/voice ObservableCollections
  and the event can fire off the HTTP API or model-manager threads), kept
  on top of the subscribe-after-hydration ordering resolved in slice 2.
- GeneralSectionViewModel: kept audit-tier1's arm, which re-reads Current
  inside the post so queued refreshes coalesce onto the newest commit,
  rather than posting the captured payload.
- WatchFolderServiceTests: slice 9 moved a local function above its uses to
  satisfy MoveLocalFunctionAfterJumpStatement; the merge produced both
  copies, so kept audit-tier1's single declaration (legal C# either way).
- UiOperationGuardTests: kept slice 9's added explanation comment.

The Gladia result_url job-deletion fix merged without conflict and is
present (DeleteJobBestEffortAsync).

Full solution green: 514 Core, 1735 Linux, 899 PluginSystem, 108 CLI.
…atches

process.Start() raises Win32Exception when exec itself fails - the install
directory mounted noexec, or a copy that is not a valid binary - which
happens after the chmod-and-verify step has already passed. That type is
outside the catch filter InstallCliAsync uses, so it escaped the command
and took the app down instead of reaching CliStatusText. Normalize it to
InvalidOperationException, keeping the original as inner, so it lands on
the same path as every other verification failure.

Narrow the stub teardown catches from bare SocketException to the shutdown
error codes. Disposal cancels before awaiting, so a cancellation-state
guard would always pass and suppress every socket error, letting a genuine
listener or protocol fault masquerade as a shutdown reset and the test go
green. The predicate lives in one place rather than in each stub.

UnixSocketApiClientTests was the third stub still missing the teardown
handling the other two received: its ServeAsync has no internal try/catch,
and _cts.Dispose() plus the temp-directory delete sat after the try, so an
unexpected fault both masked the assertion and leaked the directory. Both
now run from a finally.
QA review, verified against current code before acting:

- Gladia leaked the server-side job whenever polling failed, timed out or
  was cancelled, leaving the user's uploaded audio on the provider. Moved
  the try/finally to cover polling. Two tests asserted the old contract
  and were updated; note this means a cancelled dictation now awaits a
  bounded DELETE.
- LLM call provenance looked the owning plugin up by selection ID. For an
  OpenAI-Compatible profile role that is the profile's ID, which matches
  no manifest, so RanLocally was always recorded false. Use PluginId.
- Sherpa's Canary parse called GetString() on "text"/"lang" without
  checking the kind, so a numeric or boolean value threw
  InvalidOperationException past the JsonException handler.
- The OpenAI realtime receive loop swallowed all cancellation, stranding
  finalize's waiters when it came from an aborted socket or a subscriber.
- The ChatGPT SSE reader failed a response.completed event with a missing
  status; the sibling xAI client already rejects only an explicit
  mismatch.
- OpenAI-Compatible enumerated _additionalProfiles across awaits while a
  settings save replaced it wholesale. Snapshot under the existing lock,
  and re-resolve a fetched catalog by ID so it is not applied to an
  orphaned profile or one whose endpoint or key has since changed.

Skipped, with reasons in the review notes: the PluginSelectionExtensions
legacy overloads, the shared SDK JSON helper, and MapLegacyCategory
aliases for forms no manifest ever used.

Test fixes: the streaming fault-propagation handshake only proved a frame
was dequeued, not that the session had captured the fault, so
SendAudioAsync could legitimately succeed; FakeWebSocket state is now
lock-guarded. Gladia's malformed-status theory gets a bounded poll window.

ReSharper inspections: 132 at HINT severity to 0, verified against a
fresh --caches-home. Fixed 13 (CA1068 parameter order, CA2249, two
static members, two unresolvable crefs, constants, trailing commas,
xUnit2032). Suppressed 118 with per-site reasons, matching the
convention already in tree.
pactl exits whenever the sound server does, and AudioRecordingService latches
_watcherStarted, so a PipeWire/PulseAudio restart silently ended live
default-device following for the rest of the session — the read loop already
cleared its state for a restart nobody ever triggered.

The watcher now reconnects itself. A run that survived reconnects at once; one
that died young backs off (1s doubling to 16s) because the first attempt after
a restart routinely lands before the server is listening again, bounded by
MaxAutoRestarts so a permanently broken server cannot respawn pactl forever.
One task owns the backoff sequence, so a failed launch — which starts no read
loop — cannot silently end recovery. Each reconnect signals the dispatcher
once: pactl does not replay events, so a default that changed while the
subscription was down would otherwise go unnoticed.

Lifecycle fixes this needed: the self-teardown path now disposes the
CancellationTokenSource (only Stop() did, so every EOF leaked one) and kills
the subscription before disposing it (Process.Dispose does not terminate the
child, so a read error with pactl still alive orphaned it). Reconnects publish
their replacement without releasing the lock, and Stop() clears the intent
first and bumps a session counter, so neither a reconnect racing Stop nor a
retry worker sleeping across a Stop/Start cycle can resurrect a stopped watcher
or start a second retry chain. Start() no longer overwrites the callback while
a run is live, keeping its documented idempotence.

Four tests cover recovery, the bounded give-up, self-reconnect and the
Stop-versus-reconnect race.
…ests

A launch failure during Start() logged and stayed down forever, while the same
failure at runtime retried on the backoff schedule. Extracted that schedule
into ScheduleRetryLocked and called it from both, so the startup path can no
longer leave the watcher silently dead. Start() bumps the session first, which
retires any sleeping worker, so it cannot produce a duplicate one.

PactlWatcher_Restarts_AfterReadLoopExitsOnEof predates the auto-reconnect and
had started relying on it not firing: its instant-EOF fakes now schedule a
one-second retry that could bump the count under the assertions. Both reconnect
knobs are pinned out of reach so it tests the explicit restart again, and the
cross-thread counter is interlocked on both sides.

PactlWatcher_Reconnects_WhenASurvivingSubscriptionEnds claimed the factory
throw ended the chain; SpawnLocked catches it and falls into the retry budget,
so the count kept climbing and the assertion had been weakened to match. The
third subscription now stays open, ending the chain at exactly three.
QA findings, each checked against current code first:

- Gladia created the job before validating result_url, so a missing,
  non-string or non-HTTPS value leaked the uploaded audio server-side.
  Delete the job once its id is known and any later initiation step
  fails.
- SelectProfileModel mutated the profile FindAdditional returned. That is
  a snapshot, so a concurrent save could orphan it and drop the user's
  model choice on the next persist. Re-resolve by id under the lock.
- _additionalApiKeys was read by the transcription/LLM paths while the
  settings-save and activation paths rewrote it. A Dictionary read racing
  a resize can loop or return the wrong entry, so it now shares the
  profile lock.
- Failed webhook activation left Service pointing at a disposed instance
  when the event-bus subscribe threw.

Codex review on top of those:

- SetItemsAsync applied each secret to the live cache as it was written
  but only swapped the profiles in afterwards, so a later secret failure
  left a new credential paired with the old BaseUrl. Stage the keys and
  publish both together.
- Publishing and reading them as two lock acquisitions had the same
  window, so profiles and credentials are now written and resolved in one
  critical section.

Tightened the watch-folder worker-failure assertion to an exact
ArgumentException match, verified against the actual exception.

Skipped: rejecting an orphaned "<stored securely>" header placeholder.
SetItems_NewHeaderPlaceholderStoresLiteralValue pins the opposite
contract by name, so flipping it is a decision, not a fix. Worth
revisiting - duplicating a webhook row can persist the placeholder as a
real header value.

ReSharper: 0 at HINT severity, verified against a fresh cache. The
refactor orphaned five now-unreachable helpers; deleted them.
35 conflicts, again dominated by two independent ReSharper sweeps writing
different justification wordings for the same pragmas. Took audit-tier1's
wordings and kept slice 10's substantive changes:

- SherpaDecodeCoordinator: the ValueKind guard on "lang" (GetString() throws
  on a non-string element, so a canary payload with a numeric or boolean
  lang faulted the whole decode), and the <= tie-break in the quiet-cut
  search, which keeps the latest candidate so a digitally silent window
  yields the longest chunk rather than the shortest.
- StreamingProviderFailurePropagationTests: lock-guarded CloseStatus/
  CloseStatusDescription/State on the fake socket.

Kept audit-tier1's PluginLoader form. Slice 10 restructured that method —
nesting validation under `categories is not null` with legacy inference as
the fallthrough — which is equivalent, but the merge spliced its inverted
condition onto audit-tier1's body. That would have returned legacy metadata
for plugins that declare categories and then dereferenced a null.

Full solution green: 514 Core, 1735 Linux, 903 PluginSystem, 108 CLI.
Clean merge, no conflicts. Brings in the audit §10 QA/Codex review findings
and the CLI verification launch-failure surfacing with narrowed socket
teardown catches.
Final slice, clean merge. Brings in the tier1-11 QA review findings plus
the default-device watcher reconnecting when its subscription ends and a
retry for a failed initial pactl launch.
Each of the three Ubuntu smoke containers installed the same ~95 MB of
GUI and audio dependencies, and that download ran inside the 10-minute
per-format timeout. When archive.ubuntu.com dropped to ~140 kB/s the apt
work alone outlasted the budget, so the run was killed before a single
assertion executed - twice, at a different container each time.

Bake the dependencies into one prepared image per distribution up front,
outside the timeout, so the per-format containers touch no package
manager and the budget covers only the install and execute checks. Add
apt and dnf retries so a dropped connection retries instead of failing
the run, and raise the workflow step budget to cover the remaining
one-time download. The release workflow gated on the same script and
would have failed a real release identically.

Also stage the rpm payload through a file instead of a pipe: cpio stops
at the archive trailer and closes the pipe while rpm2cpio is still
writing padding, so pipefail failed the run despite a complete
extraction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants