Installing on Windows: about the SmartScreen prompt.
On first launch you may see a blue "Windows protected your PC" screen. This is normal for newer apps and does not mean anything is wrong. Alpha-OSK is digitally signed by OK Studio Inc. Click More info and you will see that publisher name, then click Run anyway to install. The prompt stops appearing on its own as more people install. (Microsoft removed the SmartScreen fast-pass for code-signed apps in 2024, so reputation now builds from download volume, not from the certificate.)
[1.1.0] (2026-05-19)
Headlines: a new "Data Backup" feature (export your model, lifetime stats, and imported vocabulary packs to a portable .zip; import on a new machine to restore everything in place), pill-click learning now passes through the same 3-sighting candidate gate as free-typed words (a single accidental click can no longer permanently change the model), a clickwrap MIT license page in the Windows installer, live download / install progress in the auto-updater popup and the relauncher splash, and a documentation overhaul (segmented onboarding README, screenshot gallery, and white-paper figures / Data Backup section / macOS section).
Added
- README onboarding rewrite. Plain-language tagline replaces the engine-acronym lead. The dark-theme keyboard screenshot moved to a hero position above the fold. New three-column "Pick your path" card routes visitors by audience (end users → Install + First launch, developers → Architecture +
CLAUDE.md, reviewers → white paper + Status). New "First launch" walkthrough (six numbered steps from installer to first word to settings tour) and a ten-question FAQ covering the actual common stumbles (Slack/Discord/IDE keystroke issues, move/resize, pause learning, theme, opacity, data location, telemetry, vocab packs, emoji). Install restructured into a Platform / File / Notes table. Screenshot gallery moved below First launch. - White-paper refresh. Five inline figures sourced from the live app (full keyboard, Appearance panel, Data & Privacy panel, analytics dashboard, Word Cloud). New §5.5 Data backup (export / import) covering archive contents, replace-not-merge import semantics, the rescue archive, and the allow-list extraction validation. Telemetry renumbered §5.5 → §5.6 and Auto-update threat model §5.6 → §5.7 with all inline cross-references updated. New §7.5 macOS (in progress). Stale test count
450+bumped to640+. Top-of-doc version line clarified as "Document revision" distinct from app version. 78 pre-existing em dashes stripped per the global writing-style preference (paired dashes to parentheticals, bullet term-definitions to colons, others to sentence breaks). assets/screenshots/new directory with six images sourced from the live app: dark theme keyboard, Amethyst theme keyboard, Appearance settings panel, Data & Privacy settings panel, Word Cloud tab, Dashboard tab.- Data export / import (back up your model, move it between machines). New "Data Backup" section in Settings → Data & Privacy with Export Data… and Import Data… buttons. Export bundles the prediction model (
ngram_model.json+ppm_model.json), lifetime analytics (analytics.json), and every imported vocabulary pack into a single.ziparchive with a manifest (schema version, app version, ISO-8601 UTC timestamp, file list, pack ids). Import reads the archive, shows a preview card (app version + export date + file/pack counts), and on confirmation replaces the user's current data, after first writing a timestamped rescue export of the existing state to<config_dir>/exports/rescue-<ts>.zipso the user can roll back by importing that file. The predictor and lifetime analytics live-reload from disk after import (no restart needed); enabled-pack state resets so the user re-enables packs on the new machine.telemetry.jsonis deliberately excluded from exports: copying theanon_idacross machines would link contributions, which the telemetry consent docs explicitly promise not to do, so a freshanon_idis generated on the new machine when telemetry is re-enabled. Settings (theme, layout, toggles, window size) are not exported either; they live in the Qt settings layer (Windows registry / Linux config) and are quick to reconfigure manually, while the irreplaceable bit is the model. Security hardening on import: allow-list extraction (a hand-edited archive can't smuggletelemetry.jsonor arbitrary files past the extractor), zip-slip rejection (..components, absolute paths, drive prefixes, backslashes), per-file (75 MB) / total uncompressed (500 MB) / archive-on-disk (200 MB) size caps that trip onfile_sizemetadata before any bytes hit disk, and forward-compatibility rejection when the manifest'sschema_versionexceeds what this build supports ("upgrade Alpha-OSK first" rather than half-applied state). Atomic-rename writes through.importingtempfiles so a partial copy can't corrupt the existing file. New modulesrc/data_export.py, new bridge slots (exportUserData,inspectUserExport,importUserData,getDefaultExportDir,getSuggestedExportName), newHybridPredictor.reload_from_disk()andTypingAnalytics.reload_from_disk(). 20 regression tests intests/test_data_export.pycover the round-trip, every security gate, and the telemetry-exclusion invariant. Full design in CLAUDE.md § Data Backup (Export / Import). - Pill-click learning now passes through the 3-sighting candidate gate. Clicking a prediction pill for a word that the engine generated but the user has never actually typed (a fuzzy-recogniser completion of a typo, a PPM character-level extrapolation, a vocab-pack word the user hadn't fired before) used to inject the word into
user_vocabpermanently with weight 5 on the very first click, so a single accidental click could permanently change the model. Symptom: words showed up in the Model Visualization dashboard after one keypress when the user expected they wouldn't be added until "really" learned. NewNgramPredictor.learn_from_pill_click(word)mirrors the gate already used by free-typing inlearn(): known words (already in the Google 10K base dict oruser_vocab) get the immediate +5 boost as before, but unknown words go through_candidate_countsand only promote intouser_vocabafter three clicks (landing with cumulative weight 3 × 5 = 15).HybridPredictor.learn_from_selectionroutes through this; trailing bigram / trigram reinforcement still fires immediately on each click since the context edge was validated by the click and a bigram pointing into a not-yet-promoted unigram surfaces the word only in that specific context, which is exactly the loop that drives "click more times to promote." Right-click → Show more and vocab-pack import deliberately bypass the gate (those are explicit user-boost actions, not implicit signals; gating them would breakunprefer's rollback math). Plus: candidates now carry a_candidate_last_seentimestamp, and_sweep_stale_candidates(called from_apply_decay) drops entries older than 30 days so an accidental sighting doesn't sit in the pool indefinitely waiting for the multiplicative decay to drain it. Timestamps persist across save/load; older save files without the field have entries backfilled on the next sweep rather than instantly expired. Coverage intests/test_ngram_predictor.py::TestLearnFromPillClickandTestStaleCandidateSweep, plustests/test_hybrid_predictor.py::test_learn_from_selection_gates_unknown_word/_promotes_after_threshold. - Clickwrap license page in the Windows installer. New
LICENSE.rtf(MIT) shipped underbuild/windows/and wired into the generated NSIS script asMUI_PAGE_LICENSEbetweenWELCOMEandDIRECTORYwithMUI_LICENSEPAGE_CHECKBOXenabled, so the Next button stays disabled until the user ticks "I have read and accept the terms of the license agreement." CustomisedMUI_LICENSEPAGE_TEXT_TOPclarifies the action ("You must accept them to install Alpha-OSK"). The repo-rootLICENSE(already MIT) is unchanged; the RTF is a formatted copy with bold headers, an accessibility-tool disclaimer, and a privacy / auto-update summary, since the NSIS license control renders RTF better than plain text and the recent NSIS high-contrast-mode fix targets it. Silent install (/S, used by the auto-updater) bypasses pages entirely so the EULA never blocks an upgrade. First-install gets the clickwrap, every subsequent auto-update flows through silently. - Streaming download progress for the auto-updater.
KeyboardBridge.updateDownloadProgress(bytes, total)is emitted from the install worker thread as the signed installer downloads. The popup that appears when the user clicks the title-bar ↓ icon now shows live MB / total MB / percentage and a determinateProgressBar; when the server omitsContent-Lengthit falls back to a labelled byte count + indeterminate bar. Emits are throttled at 256 KB to keep the queued-signal connection out of the hot path on a fast link (an 85 MB installer would otherwise fire ~1300 progress events). Closes the silent-download gap that used to read as "did the Install button do anything?". - Indeterminate progress bar on the post-install relauncher splash. The "Updating Alpha-OSK" window that bridges the gap between OSK-vanishes and OSK-relaunches now shows a moving marquee bar under the phase-aware status text. NSIS silent install suppresses its own UI, so we cannot show a real percentage during the install phase; the constant motion is the difference between "is this stuck?" and "still working" and is the same pattern every commercial installer uses. The bar settles full on the Done phase and empty on a failure phase so the eye can tell the work has stopped before the splash dwell expires. Splash widget grew 30 px in height to fit; layout, theming, and the existing ✕ dismiss behaviour are unchanged.
Fixed
- Worker
wstransitive bumped to 8.20.1 to clearGHSA-58qx-3vcg-4xpx. OSV-Scanner flagged a medium-severity (CVSS 4.4) DoS vector inws@8.18.0, reachable through thewrangler@4.92.0 → miniflare@4.20260515.0 → wsdev-only chain. Pinned away via anoverrides: { "ws": "^8.20.1" }block inbackend/cf-worker/package.jsonand a regeneratedpackage-lock.json. Dev-only (the deployed worker on Cloudflare's edge runtime does not include miniflare), but the merge-gating OSV-Scanner CI job from 1.0.18 was failing every push until the bump landed. Localosv-scanner --lockfile=backend/cf-worker/package-lock.json --lockfile=requirements-dev.txtnow reports zero vulnerabilities.