diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1b1a703..259172c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -115,8 +115,12 @@ jobs: run: | codesign --verify --deep --strict --verbose=2 .build/DoNotType.app signature=$(codesign -dv --verbose=4 .build/DoNotType.app 2>&1) + printf '%s\n' "$signature" if [[ -n "$MACOS_CERTIFICATE" ]]; then - grep -q '^Authority=Developer ID Application:' <<< "$signature" + # `Authority` is omitted on some hosted runners even though the imported identity and + # signature are valid. The build only selects Developer ID Application identities; + # verify that the result belongs to this release team and has hardened runtime instead. + grep -q '^TeamIdentifier=5BR9M56H9W$' <<< "$signature" grep -q 'flags=.*runtime' <<< "$signature" else grep -q '^Signature=adhoc$' <<< "$signature" @@ -124,7 +128,8 @@ jobs: bundled_version=$(/usr/libexec/PlistBuddy \ -c 'Print :CFBundleShortVersionString' .build/DoNotType.app/Contents/Info.plist) test "$bundled_version" = "$VERSION" - .build/DoNotType.app/Contents/MacOS/dnt --version | grep -q "^dnt $VERSION (" + cli_version=$(.build/DoNotType.app/Contents/MacOS/dnt --version) + test "$cli_version" = "$VERSION" - name: Notarize if: env.NOTARY_KEY_ID != '' @@ -152,6 +157,9 @@ jobs: (cd dist && shasum -a 256 DoNotType-macOS.zip | tee DoNotType-macOS.zip.sha256) - name: Attest build provenance + # GitHub does not support attestations for user-owned private repositories. Keep the + # release usable while private, and turn provenance on automatically if visibility changes. + if: github.event.repository.visibility == 'public' uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 with: subject-path: dist/DoNotType-macOS.zip @@ -329,6 +337,7 @@ jobs: "$hash DoNotType-Windows-x64.zip`n") - name: Attest build provenance + if: github.event.repository.visibility == 'public' uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 with: subject-path: dist/DoNotType-Windows-x64.zip @@ -445,6 +454,7 @@ jobs: (cd dist && sha256sum DoNotType-Android.apk | tee DoNotType-Android.apk.sha256) - name: Attest build provenance + if: github.event.repository.visibility == 'public' uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 with: subject-path: dist/DoNotType-Android.apk diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c9843..1a69bc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,16 @@ Notable changes, newest first. Behaviour changes that affect transcription quality carry the measurement that justified them; see [docs/EVALUATION.md](docs/EVALUATION.md). -Format loosely follows [Keep a Changelog](https://keepachangelog.com/). This project has not cut a -release yet, so everything below is unreleased. +Format loosely follows [Keep a Changelog](https://keepachangelog.com/). Release dates use the +repository's local calendar date. ## Unreleased +## 0.2.0 - 2026-08-19 + +Release preparation repaired the Android build after the AGP 9 migration and refreshed the +Windows app's locked transitive dependency graph after the ONNX Runtime update. + ### Added - **The connection test now sends a recording, so an endpoint that cannot take one fails the @@ -1216,8 +1221,10 @@ deliberate: writes the on-screen version number instead of the spoken one in roughly 36% of runs, against a 21% baseline error rate with no context at all. Numbers, method and failed mitigations are in [docs/EVALUATION.md](docs/EVALUATION.md). This is the central open problem. -- **The Windows app has never been run.** It compiles and its core tests pass, but every Win32 path - — keyboard hook, `waveIn` capture, `SendInput`, UI Automation, DPAPI — is unexercised. +- **Windows microphone capture and text injection still require a manual release check.** CI + launches the packaged app and exercises the packaged CLI on Windows, and the native boundaries + have unit coverage, but a hosted runner cannot speak into `waveIn` or verify `SendInput` in a + separately focused application. - **The near-miss suite is red, deliberately.** Adding real-speech cases took it from 0 regressions to 3, which is the honest state: two are the version-number substitution reproducing, and one is a case written as a positive control that failed in the opposite direction. It is not to be made diff --git a/Sources/dnt-eval/Silence.swift b/Sources/dnt-eval/Silence.swift index 3aeff1a..eeabb87 100644 --- a/Sources/dnt-eval/Silence.swift +++ b/Sources/dnt-eval/Silence.swift @@ -93,6 +93,15 @@ struct Silence: AsyncParsableCommand { Attempt( recording: name, run: run, transcript: text, isEmpty: text.isEmpty, error: nil)) + } catch ProviderError.emptyOutput { + // Provider clients reject a blank transcript on ordinary speech because losing + // a real dictation must be visible. In this command blank is the expected + // result: Deepgram and the other recognisers represent it with `emptyOutput`, + // just as ProviderProbe already accepts when its silent recording completes. + attempts.append( + Attempt( + recording: name, run: run, transcript: "", isEmpty: true, + error: nil)) } catch { // An error is not a hallucination. It is reported separately rather than // counted as a pass, because a backend that fails on silence has not