Windows engineering invariants
Use these invariants when reviewing Windows adapters and workflow changes. Pair them with the native acceptance checklist; passing deterministic tests alone does not establish desktop behavior.
| Change area | Start with |
|---|---|
| Text delivery or Copy | Focus and insertion, Clipboard |
| Recording or shortcuts | Audio, Keyboard hooks and hotkeys |
| Settings or new renderer methods | Credentials, WebView boundary |
| Background work or shutdown | Runtime configuration, Process lifecycle |
| Retention or server probes | Transcript history, Endpoint safety |
Focus and insertion
Section titled “Focus and insertion”| At this boundary | Required behavior |
|---|---|
| Recording starts | Capture the target’s HWND/thread/process identity |
| Before delivery and each chunk | Revalidate the captured target and focus |
| Before every Unicode dispatch | Wait within a fixed bound for Ctrl, Alt, Shift, and Windows keys to be released; recheck focus and cancellation while waiting |
| Focus changes or modifier wait times out | Keep the result in backend memory and offer explicit Copy; never write to the clipboard automatically or release keys synthetically |
Clipboard
Section titled “Clipboard”| Concern | Requirement |
|---|---|
| Content | Use Unicode; never log clipboard content |
| Contention | Retry clipboard-open failures only within a bound |
| Explicit Copy ownership | Own a message-only window and pin the complete transaction to one OS thread |
| Transaction order | Open with that owner before emptying; close before destroying the owner |
| Failure before mutation | Allocation/cancellation failure leaves existing contents untouched |
| History | Every entry needs an explicit Copy action |
Transcript history
Section titled “Transcript history”| Rule | Required behavior |
|---|---|
| Default | Disabled; retain nothing until a saved setting enables history |
| Allowed content | Finalized raw/processed text and bounded non-secret run details |
| Storage | History-owned 20-entry, 2 MiB in-memory ring |
| Every mutation | Reapply both limits, including completion and cleanup updates; one entry cannot exceed the total byte budget |
| Processed text overflows | Prefer an explicitly marked raw-only fallback |
| Raw text cannot fit | Remove the entry; never truncate text or exceed the budget |
| Removal | Release an individually removed entry immediately |
| Disable, Clear, shutdown | Clear the ring |
Never retain audio, provisional text, target identity, credentials, headers, or full paths. Never send transcript content to logs/crash reports, or historical text to generic status/overlay events.
Keyboard hooks and hotkeys
Section titled “Keyboard hooks and hotkeys”The complete action matrix and normalization rules are documented in Shortcut policy.
- Toggle mode may use
RegisterHotKeywith non-repeat behavior. - Hold-to-talk requires both press and release events through a low-level hook or another proven key-state mechanism.
- Keep callbacks minimal and move work to the owning Go feature.
- Match the native callback ABI:
nCodeis a signed 32-bit integer. Negative codes forward immediately without dereferencing the event pointer. - Unhook and unregister deterministically during shutdown.
- Hold-hook and temporary-capture Close each wait at most two seconds for their native source and tracked callback work together. Fence new input first; recorder callbacks must not block the native unhook/message-loop completion or prevent Wails from reaching bounded feature shutdown.
- Report shortcut conflicts instead of silently falling back.
Runtime configuration and shutdown
Section titled “Runtime configuration and shutdown”- Snapshot before work starts. Capture the complete profile and both applicable credentials under the settings transaction lock. Later saves affect later operations; never combine an old endpoint/model with a new credential.
- Own work through the application context. Microphone, stored-file, connection-test, shortcut-capture, and preparation work derive from Wails and have explicit cancellation or timeout paths.
- Fence and cancel during shutdown. Stop accepting work, cancel active work, suppress late publication, and close stored-file/dictation work before history. Native capture checks its closed fence around preparation so late warmup cannot recreate resources.
| Owner | Teardown wait budget |
|---|---|
| Dictation service | 5 seconds |
| Stored-file service | 5 seconds |
| Speech service | 2 seconds |
These are per-service waits, not a shared process-exit deadline or a guarantee that every native call is interruptible.
WebView boundary
Section titled “WebView boundary”- The WebView is presentation, not a file or device authority. Go opens the native stored-audio picker and retains its result as a private selection capability; the renderer has no bound path argument.
- Reject direct symbolic-link selections. Before upload, reopen the private path and require the same regular-file identity, size, and modification time; disappearance, replacement, or mutation requires reselection.
- Explicitly deny WebView microphone, camera, geolocation, notification, and clipboard-read permissions because those capabilities are implemented by native Go code.
- Keep Wails simple event emission disabled. Adding remote content, raw HTML rendering, or a new WebView permission requires a security review.
- Shared mode only for the initial release.
- Bound recording duration and in-memory buffer size.
- Handle microphone removal and default-device change without wedging the state machine.
- An unexpected native stop signals ordinary Go control flow without blocking the audio callback. Discard and zero the interrupted recording; never transcribe a partial utterance after device loss.
- Follow Windows default-device rerouting only when the user selected System default. Never silently fall back from an explicitly selected microphone.
- Device enumeration refreshes only on user-visible settings actions, not background polling, and never rewrites a missing saved device choice.
- Do not retain audio or write predictable temporary paths.
- If a temporary file becomes necessary, use restrictive unique creation and delete it on every terminal path.
Credentials
Section titled “Credentials”| Location or action | Requirement |
|---|---|
| Durable API key | Windows Credential Manager only |
| Renderer password draft | Transient and strictly bounded; clear after save, settings exit/hide, and teardown |
| Returned Wails/Svelte data | Availability and credential-reference metadata only; never a stored key |
| Logs | No Authorization, API keys, cookies, secret headers, transcripts, or audio |
| Change/delete profile | Never implicitly copy another profile’s credential |
Process lifecycle
Section titled “Process lifecycle”- One process owns recording resources.
- A second launch cannot register duplicate hooks or start capture.
- Quit cancels requests and waits for bounded cleanup.
- Crashes must not leave the microphone active because capture belongs to the process.
Endpoint safety
Section titled “Endpoint safety”Only metadata may be checked automatically:
GET /healthGET /v1/modelsGET /v1/audio/voices # qualified speech-profile metadata onlyThe settings UI must describe its endpoint test as metadata-only. Discovered model IDs may populate a selector, but selection itself performs no network request. Connection failures cross the Wails boundary only as stable status metadata; peer-controlled response bodies and credential material do not.