Skip to content

VaulType Regression Test Results

  • Date: 2026-02-20
  • macOS Version: 26.2 (Build 25C56)
  • Xcode Version: 26.2 (Build 17C52)
  • Branch: main
  • Architecture: arm64 (Apple Silicon)

Build result: TEST BUILD SUCCEEDED

Command used:

xcodebuild build-for-testing -scheme VaulType -destination 'platform=macOS,arch=arm64' \
-derivedDataPath /tmp/claude/DerivedData CODE_SIGN_IDENTITY="-" \
CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO

Note: The test host (AppDelegate) calls terminateOtherInstances() on launch, which kills test runner processes. Automated test execution via xcodebuild test is unreliable in this environment. The build-for-testing succeeds; manual test execution in Xcode is required for actual run results.

Test FileTest CountCoverage AreaStatus
AccessibilityAuditTests.swift24AppState announcements, OverlayWindow transparency, system preferencesBUILD OK
AppContextServiceTests.swift26Frontmost app detection, per-app profile resolution, smart defaultsBUILD OK
AudioBufferTests.swift13Circular ring buffer, thread safety, overflow, capacityBUILD OK
CommandDetectorTests.swift13Wake phrase matching, case insensitivity, separator handlingBUILD OK
CommandExecutorTests.swift4Disabled command rejection, unknown app handling, chain executionBUILD OK
CommandParserTests.swift42~25 intent patterns, chain parsing (and/then/also), trailing punctuationBUILD OK
CommandRegistryTests.swift14Built-in command registration, enable/disable, intent coverageBUILD OK
DictationEntryTests.swift16SwiftData model, computed properties (outputText, wordsPerMinute), isFavoriteBUILD OK
HistoryViewTests.swift7SwiftData queries, filtering, retention policy enforcementBUILD OK
HotkeyManagerTests.swift11HotkeyBinding parse/serialize, keycode mapping, modifier flagsBUILD OK
LlamaContextTests.swift16GenerationResult, LlamaContextError descriptions, init failure pathsBUILD OK
ModelDownloaderTests.swift20URLSession download, SHA-256 verification, progress tracking, cancellationBUILD OK
ModelManagerTests.swift7Model registry, download state, file validationBUILD OK
ModelRegistryServiceTests.swift10Registry queries, installed model enumeration, disk usageBUILD OK
OnboardingViewTests.swift16OnboardingStepView init, PermissionsManager API, UserDefaults onboarding flagBUILD OK
OverlayWindowTests.swift7OverlayWindow show/hide, Position enum, canBecomeKey/canBecomeMainBUILD OK
PerformanceBenchmarkTests.swift16CommandParser latency, CommandDetector throughput, PowerManagementServiceBUILD OK
ProcessingModeRouterTests.swift12Raw passthrough, Clean/Structure/Code/Prompt/Custom routing, LLM dispatchBUILD OK
PromptTemplateEngineTests.swift21Variable substitution, built-in templates, edge cases (missing vars, empty input)BUILD OK
PromptTemplateTests.swift22PromptTemplate model, render(), variable validation, built-in protectionBUILD OK
TextInjectionServiceTests.swift13CGEvent creation, ClipboardInjector preserve/restore, method selectionBUILD OK
VocabularyServiceTests.swift8Spoken→replacement matching, global vs per-app priority, case sensitivityBUILD OK
VoiceActivityDetectorTests.swift13Silence trimming, voice range detection, sensitivity boundariesBUILD OK

Total automated tests: 371


The items below require manual execution on a physical Mac with microphone hardware, accessibility permissions, and downloaded AI models. Check each item off as it is verified.


  • App launches with no dock icon (LSUIElement=1 is effective)
  • Menu bar icon appears in the system menu bar
  • Menu bar popover opens on click and shows current status
  • Menu bar icon changes to indicate recording state (idle/recording/processing)
  • Menu bar icon animates during processing (spinner or pulsing effect)
  • App quits cleanly via the menu bar menu
  • Default hotkey (fn key, push-to-talk) starts recording on press
  • Default hotkey stops recording on release
  • Toggle mode starts/stops recording on successive presses
  • Hotkey is detected globally (works when another app is frontmost)
  • Custom hotkey can be configured in Settings > General
  • Conflict warning appears when a hotkey clashes with a system shortcut
  • Up to 4 hotkey slots can each be assigned a different processing mode
  • Microphone permission dialog appears on first launch
  • Audio capture produces 16 kHz mono Float32 PCM output
  • Input device selection works in Settings > Audio
  • Audio level meter shows live microphone input in Settings > Audio
  • VAD trims leading and trailing silence from captured audio
  • VAD sensitivity slider in Settings > Audio changes trimming aggressiveness
  • whisper.cpp compiles as part of the Xcode build (Run Script build phase)
  • Metal GPU acceleration is active (check Console for ggml-metal.log messages)
  • WhisperContext initializes without crashing on a downloaded model file
  • WhisperContext deinit frees C memory (no leak reported by Instruments)
  • Whisper model loads from ~/Library/Application Support/VaulType/Models/
  • Transcription of clear speech returns sensible text
  • Transcription runs on a background queue (UI remains responsive)
  • Model selection in Settings > Models switches between tiny/base/small/medium/large-v3-turbo
  • Model reloads automatically after selection change without restart
  • Short ASCII text (<50 chars) is injected via CGEvent keystrokes when accessibility is granted
  • Long text or Unicode uses clipboard paste (Cmd+V simulation)
  • Original clipboard contents are restored after clipboard injection
  • Text appears at the current cursor position in the target app (TextEdit, Notes, etc.)
  • Unicode text (CJK, emoji, diacritics) injects correctly via clipboard
  • TextInjectionError.accessibilityNotGranted is thrown when permission is missing and CGEvent is required
  • Settings window opens from menu bar menu
  • Settings window has tabs: General, Audio, Models (minimum MVP tabs)
  • General tab: hotkey configuration field works
  • General tab: push-to-talk vs toggle mode switch persists across restarts
  • General tab: Launch at Login toggle works (SMAppService)
  • Audio tab: input device picker shows all available microphones
  • Models tab: whisper model list shows all registry entries with download status
  • Models tab: Download button initiates background download with progress bar
  • Models tab: Delete button removes model file and updates download status
  • Complete flow: press hotkey -> speak -> release -> text appears at cursor
  • DictationEntry is saved to SwiftData after each transcription
  • DictationEntry contains: rawText, mode=.raw, language, app bundle ID, duration, word count, timestamp
  • Pipeline state (recording/processing/idle) is reflected in AppState and menu bar icon

  • llama.cpp compiles alongside whisper.cpp without duplicate ggml symbol errors
  • LlamaContext initializes with a valid GGUF model file
  • LlamaContext deinit frees C memory cleanly
  • Metal GPU offloading is active for llama.cpp inference
  • LLMService loads a GGUF model via LlamaCppProvider
  • LLMService runs inference on a background thread
  • LLMProvider protocol allows swapping between LlamaCppProvider and other backends
  • OllamaProvider was removed in refactor (verify no OllamaProvider references remain in service layer)
  • Raw mode: transcription passes through unmodified, LLM is never called
  • Clean mode: filler words (um, uh, like) and grammar errors are fixed
  • Structure mode: output contains headings and/or bullet lists
  • Prompt mode: uses the selected PromptTemplate with variable substitution
  • Code mode: spoken programming constructs are converted to source code syntax
  • Custom mode: user-defined template is applied; falls back to Clean if no template selected
  • ProcessingMode.requiresLLM correctly returns true for non-raw modes and false for raw
  • {{transcription}} variable is substituted with actual transcribed text
  • {{language}} variable is substituted with the detected language code
  • {{app_name}} variable is substituted with the active application name
  • {{app_bundle_id}} variable is substituted with the active application bundle ID
  • {{timestamp}} variable is substituted with current date/time
  • Custom user variables specified in PromptTemplate.variables are substituted correctly
  • Missing variable substitution produces a warning but does not crash
  • Built-in templates cannot be deleted
  • User templates can be created, edited, and deleted
  • GGUF model download starts from a valid URL, shows progress in Settings > Models
  • SHA-256 checksum is verified after download; corrupted downloads are rejected
  • Completed download is registered in ModelInfo.isDownloaded
  • Model deletion removes the file from disk and resets ModelInfo.downloadProgress
  • Custom GGUF file can be imported via NSOpenPanel (Settings > Models)
  • Imported file is validated and registered in the model registry
  • Each of 4 hotkey slots can be assigned a different ProcessingMode in Settings
  • Active mode name or icon is shown in the menu bar popover when hotkey is pressed
  • Voice prefix “code mode:” at start of dictation switches to Code mode and strips prefix
  • Voice prefix “clean this up:” switches to Clean mode and strips prefix
  • VoicePrefixDetector strips the prefix before Vocabulary and LLM processing
  • Processing tab renders with mode selection and per-hotkey binding UI
  • Template editor lists built-in and user templates
  • Template editor: system prompt and user prompt editors update template in real time
  • Template editor: variable insertion helper inserts {{transcription}} at cursor
  • Template editor: Preview button shows a mock render
  • Model Management view shows both whisper and LLM models with disk usage
  • LLM processes transcription output before injection when mode != .raw
  • DictationEntry stores both rawText and processedText after LLM run
  • DictationEntry.mode reflects the ProcessingMode used (not always .raw)

  • AppContextService detects the frontmost application on launch
  • AppContextService updates currentAppName when the user switches apps
  • First dictation into an unrecognized app creates a default AppProfile automatically
  • Xcode is auto-mapped to Code mode; Mail to Clean; Terminal to Raw; Notes to Structure
  • AppProfileEditorView shows the per-app profile list with edit/delete controls
  • HistoryView opens from the menu bar menu or Settings
  • History list shows DictationEntry records sorted by timestamp descending
  • Full-text search across rawText and processedText returns correct results
  • Filtering by app, date range, processing mode, and favorites-only works
  • Selecting a past entry and clicking “Re-inject” injects that text at the current cursor
  • Editing a past entry text and re-injecting uses the edited version
  • HistoryCleanupService deletes entries older than historyRetentionDays on launch
  • HistoryCleanupService deletes entries beyond maxHistoryEntries count limit
  • Entries marked as favorites are exempted from all auto-deletion policies
  • “Clear All History” removes all non-favorite entries
  • “Factory Reset” removes all entries including favorites
  • Overlay NSPanel appears floating above all other windows during dictation
  • Overlay does not activate/steal focus from the target app
  • Transcription text updates in the overlay as whisper produces output
  • User can edit text in the overlay before injecting
  • Pressing Enter in the overlay injects the edited text and closes the overlay
  • Pressing Escape in the overlay cancels without injecting
  • Overlay shows mode indicator, language indicator, and latency display
  • Overlay position (near cursor / top center / bottom center / center) is configurable in Settings
  • Overlay transparency/opacity is configurable in Settings
  • VocabularyService replaces spoken forms with configured replacements in transcription output
  • Global vocabulary entries apply to all apps
  • Per-app vocabulary entries take priority over global entries when both match
  • Case-sensitive entries only match the exact case
  • Case-insensitive entries match regardless of case
  • VocabularyEditorView: add, edit, delete entries with spoken form and replacement fields
  • VocabularyEditorView: scope selector toggles between Global and per-app
  • Import/export vocabulary as JSON works
  • Global language selection in Settings > Language persists across restarts
  • Auto-detect language toggle passes null language to whisper for automatic detection
  • Detected language code appears in the menu bar popover and overlay
  • {{language}} variable in PromptTemplates receives the detected language string
  • AppProfile.preferredLanguage overrides the global language setting for that app
  • Settings has exactly 10 tabs: General, Audio, Models, Processing, App Profiles, Vocabulary, Language, History, Commands, Plugins
  • App Profiles tab: lists all per-app profiles; edit and delete controls work
  • App Profiles tab: auto-created profile indicator is shown
  • Vocabulary tab: global and per-app scoped vocabulary editor is functional
  • Language tab: global language picker and auto-detect toggle render correctly
  • History tab: retention policy inputs persist; storage usage updates after clearing history

  • Wake phrase “Hey Type” followed by a command is detected and separated from dictation text
  • Wake phrase detection is case-insensitive (“hey type”, “HEY TYPE”, “Hey Type” all match)
  • Wake phrase followed only by a separator (comma, period) with no command returns nil
  • Custom wake phrase (e.g., “Computer”) can be configured in Settings > Commands
  • CommandParser parses approximately 25 natural language intent patterns
  • CommandParser returns nil for unrecognized text
  • CommandExecutor dispatches parsed commands to the correct handlers
  • CommandExecutor returns a CommandResult with success flag and feedback message
  • Disabled commands return failure without executing
  • “Open Safari” (and “launch”, “start”) launches the named application
  • “Switch to Finder” (and “go to”, “activate”, “bring up”) brings the app to foreground
  • “Close Terminal” closes the frontmost window of that app
  • “Quit Xcode” (and “exit”, “terminate”) terminates the application
  • “Hide Finder” hides the application
  • “Show all windows” triggers Mission Control
  • “Move window left” tiles the active window to the left half of the screen
  • “Move window right” tiles the active window to the right half of the screen
  • “Maximize window” (and “expand”, “fill screen”) zooms the active window
  • “Minimize window” minimizes the active window to the Dock
  • “Center window” centers the active window on the display
  • “Full screen” (and “toggle full screen”, “enter full screen”) toggles native full-screen
  • “Next screen” (and “other screen”, “move to next display”) moves window to next connected display
  • “Volume up” (and “louder”, “increase volume”, “turn it up”) increases system volume by 10%
  • “Volume down” (and “softer”, “decrease volume”) decreases system volume by 10%
  • “Volume 50” (and “set volume to 50”) sets volume to the specified level (0-100)
  • “Mute” (and “toggle mute”, “unmute”) toggles system mute
  • “Brightness up” (and “brighter”, “increase brightness”) increases display brightness
  • “Brightness down” (and “dimmer”, “decrease brightness”) decreases display brightness
  • “Dark mode” toggles macOS dark/light appearance via AppleScript
  • “Do not disturb” toggles Focus/Do Not Disturb mode
  • “Lock screen” locks the macOS login session
  • “Take screenshot” (and “screen capture”, “capture screen”) triggers a screenshot
  • Command chaining with “and”: “volume up and dark mode” executes both in sequence
  • Command chaining with “then”: “mute then lock screen” executes both in sequence
  • Command chaining with “also”: “mute also dark mode” executes both in sequence
  • Command chaining with “and then”: “open Safari and then volume up” executes both
  • Multi-segment chain: “open Safari and close Finder and then volume up” parses to 3 commands
  • Chain stops on first failure (CommandExecutor.executeChain behavior)
  • “Run shortcut Morning Routine” triggers the named Shortcuts app workflow
  • Custom commands defined in SwiftData are executed when matched by name
  • Commands tab lists all built-in commands with enable/disable toggles
  • Disabling a command in Settings prevents it from executing
  • Wake phrase field in Settings > Commands persists across restarts
  • CustomCommandEditorView: create a custom command with a name and action sequence
  • CustomCommandEditorView: test execution button runs the command immediately

  • Saying “Command Shift N” injects Cmd+Shift+N via CGEvent
  • Saying “Command R” injects Cmd+R (useful for “Build and run” in Xcode context)
  • App-specific shortcut alias “Build and run” maps to Cmd+R in Xcode AppProfile
  • App-specific shortcut alias “Save all” maps to Cmd+Option+S in supported apps
  • User-defined global shortcut aliases can be added in Settings > General
  • Pipeline applies app-specific aliases before global aliases before regex patterns
  • A sound plays when recording starts
  • A distinct sound plays when recording stops
  • A success sound plays after a voice command executes successfully
  • An error sound plays when a command fails
  • A completion sound plays after text injection
  • Sound feedback can be disabled entirely in Settings > General
  • “Subtle” theme sounds are soft and unobtrusive
  • “Mechanical” theme sounds are distinct click/clack tones
  • “None” theme produces no audio output
  • All buttons and controls in Settings have meaningful VoiceOver accessibility labels
  • Recording state changes are announced to VoiceOver (“Recording started”, “Processing complete”, etc.)
  • AppState.announceRecordingStarted() / announceRecordingCompleted() / announceProcessing() / announceError() do not crash
  • All Settings tabs are reachable via keyboard Tab navigation without a mouse
  • History list is navigable with keyboard (arrow keys, Enter to select)
  • AppState.prefersReducedMotion reflects NSWorkspace accessibility display preference
  • AppState.prefersReducedTransparency reflects NSWorkspace accessibility display preference
  • AppState.prefersHighContrast reflects NSWorkspace accessibility display preference
  • OverlayWindow.applyTransparencyPreference() makes window opaque when Reduce Transparency is on
  • PowerManagementService.isOnBattery correctly reflects battery vs AC power state
  • On battery power: whisper thread count is reduced (recommendedWhisperThreadCount returns lower value)
  • On battery power: LLM model quality is reduced or GPU layers are capped
  • PowerManagementService.thermalState reflects ProcessInfo.thermalState
  • On critical thermal state: shouldSkipLLMProcessing returns true and LLM is bypassed
  • On memory pressure: LLM model is unloaded; whisper model remains loaded
  • App reaches menu bar readiness within 0.5 seconds of launch (lazy model loading)
  • Idle CPU usage is near zero (no polling loops; event-driven architecture)
  • Onboarding wizard appears on first launch (when com.vaultype.onboardingCompleted is false)
  • Onboarding does not appear on subsequent launches after completion
  • Step 1 (Welcome): title and description render correctly
  • Step 2 (Microphone): “Grant Access” button calls requestMicrophoneAccess() without crash
  • Step 3 (Accessibility): “Open Settings” deep-links to macOS Accessibility settings
  • Step 4 (Model Download): guided download of default whisper base model with progress indicator
  • Step 5 (Done): “Get Started” button sets com.vaultype.onboardingCompleted = true and dismisses
  • Onboarding can be re-triggered via a Settings option or developer defaults override
  • Plugin discovery scans ~/Library/Application Support/VaulType/Plugins/ on launch
  • A valid ProcessingPlugin found in that directory is listed in PluginManagerView
  • A valid CommandPlugin found in that directory adds new voice commands
  • Activating a plugin calls plugin.activate() without crash
  • Deactivating a plugin calls plugin.deactivate() without crash
  • Plugins tab in Settings renders PluginManagerView with install/enable/disable/remove controls
  • Removing a plugin calls deactivate() and removes it from the active plugin list

Integration Regression: Full Pipeline Smoke Test

Section titled “Integration Regression: Full Pipeline Smoke Test”

The following sequence exercises the complete pipeline end-to-end. Run this after each significant code change.

  • Launch app fresh (no previous instance)
  • Onboarding is skipped (already completed)
  • Menu bar icon is idle (no recording)
  • Press fn (push-to-talk): icon switches to recording state, overlay appears
  • Speak clearly for 2-3 seconds
  • Release fn: icon switches to processing state
  • Overlay shows transcription text
  • Text is injected at cursor in the active text field
  • DictationEntry appears in History (HistoryView)
  • Say “Hey Type volume up” while recording: volume increases, no text is injected
  • Switch to Xcode: AppContextService detects Xcode bundle ID, mode auto-selects Code
  • Switch back to Notes: AppContextService detects Notes, mode auto-selects Structure
  • Open Settings: all 10 tabs render without crash
  • Close Settings: settings changes are persisted (reopen and verify)
  • Quit app: no orphaned processes remain (no zombie VaulType instances)

IssueReferenceStatus
CGEvent injection requires accessibility permission that is unreliable during development (code signature changes per build)VAULTYPE-60Backlog: remove clipboard fallback for production
Test runner crashes on launch due to AppDelegate.terminateOtherInstances() killing test hostArchitecture note in MEMORY.mdWorkaround: guard with ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
OllamaProvider was removed in refactor; any tests referencing it should be updatedCommit 220e951Verify no stale OllamaProvider test references remain
CLI builds blocked by sandbox — requires dangerouslyDisableSandbox: true on xcodebuildVAULTYPE-59Done (resolved)

All test files are located in /Users/harungungorer/dev/VaulType/VaulTypeTests/:

Test FilePhaseKey Classes Under Test
AccessibilityAuditTests.swiftPhase 5AppState, OverlayWindow
AppContextServiceTests.swiftPhase 3AppContextService, AppProfile
AudioBufferTests.swiftPhase 1AudioBuffer
CommandDetectorTests.swiftPhase 4CommandDetector
CommandExecutorTests.swiftPhase 4CommandExecutor, CommandRegistry
CommandParserTests.swiftPhase 4CommandParser
CommandRegistryTests.swiftPhase 4CommandRegistry, CommandIntent
DictationEntryTests.swiftPhase 1DictationEntry
HistoryViewTests.swiftPhase 3DictationEntry, HistoryCleanupService
HotkeyManagerTests.swiftPhase 1HotkeyBinding, HotkeyManager
LlamaContextTests.swiftPhase 2LlamaContext, LlamaContextError, GenerationResult
ModelDownloaderTests.swiftPhase 2ModelDownloader
ModelManagerTests.swiftPhase 2ModelManager, ModelInfo
ModelRegistryServiceTests.swiftPhase 2ModelRegistryService
OnboardingViewTests.swiftPhase 5OnboardingStepView, PermissionsManager
OverlayWindowTests.swiftPhase 3OverlayWindow, AppState
PerformanceBenchmarkTests.swiftPhase 5CommandParser, CommandDetector, SoundFeedbackService, PowerManagementService
ProcessingModeRouterTests.swiftPhase 2ProcessingModeRouter, ProcessingMode, LLMService
PromptTemplateEngineTests.swiftPhase 2PromptTemplateEngine
PromptTemplateTests.swiftPhase 2PromptTemplate
TextInjectionServiceTests.swiftPhase 1TextInjectionService, CGEventInjector, ClipboardInjector
VocabularyServiceTests.swiftPhase 3VocabularyService, VocabularyEntry
VoiceActivityDetectorTests.swiftPhase 1VoiceActivityDetector