Mandarin validation plan, evidence schema and release gates¶
Status: Proposed P1 verification plan (2026-10-29), not a record of completed testing. Governing ADR: v2-144; evidence owners: #497 foundation, #499 commands, #501 compatibility, #503 ASR, #505 release. Release scope: Mandarin + Simplified/Traditional output, one verified surface at a time.
Verification rules¶
- Treat unit test, packaged integration, real model, real OS/hardware, native speaker, and release signoff as distinct gates. A passing mock or pre-existing source file must never be presented as real-world product validation.
- No human reviewer may be replaced by machine translation, synthetic Chinese phrases, an LLM's confidence or an English maintainer's intuition.
- Default English and the offline/privacy contracts are non-negotiable blocking regressions.
- Every P1 support row needs a named owner, test/protocol, artifact path, date, model revision, OS details if relevant, result, limitations and reviewer signoff. Missing evidence means “experimental/unverified”.
- Run the complete repository gates from
AGENTS.mdwith an up-to-date checkout before merging production code. If a gate cannot run, state why and do not claim it passed.
Layer 1: model-free CI (required for every PR)¶
| Gate | What must be proven | Existing test entrypoint | Additional negative/failure case |
|---|---|---|---|
| G01 profiles | aliases normalize, zh/zh-HK refuse, correct script/model | tests/test_language_profiles.py | invalid override has zero side effects |
| G02 atomic config | one candidate, revisions, lock, comments/unrelated keys preserved, invalid file refused | tests/test_configedit_atomic.py | interrupted/duplicate TOML / malformed value |
| G03 side-effect service | dry-run, preflight, refused install/download, repeated edits, restart guard | tests/test_language_service.py, test_cli_language_set.py | config commits but runtime restart fails |
| G04 command state | auto picks actual speech language; explicit pin is preserved and warned | tests/test_chinese_command_grammar.py, test_doctor_language.py | unsupported grammar never falls back to English |
| G05 command precision | anchored positive + negative Mandarin prose and bounded numerals | tests/test_mandarin_command_safety.py, test_mandarin_command_numerals.py | edit-looking text inside full sentence stays dictation |
| G06 Han conversion | Simplified/Traditional, no-Han pass-through, mixed ASCII and punctuation | tests/test_han_script.py, test_cjk_text.py | missing OpenCC and bad script requested |
| G07 STT decode seams | batch/word-timestamps/streaming inherit configured language, detect actual decoded language | tests/test_stt_language.py, test_cjk_transcripts.py, test_language_reaches_every_decoder.py | no inserting whitespace inside Han across segment boundaries |
| G08 transcripts & meetings | captions/MD/TXT/SRT/VTT/JSON, CJK token-count, notes windows | tests/test_cjk_transcripts.py, test_meeting_cjk_word_count.py | long unspaced turn and 4-byte Unicode |
| G09 decoder compatibility | English-only checkpoints cannot silently decode Mandarin as English | tests/test_language_capability.py, test_stt_factory.py | specialized engine with conflicting language |
| G10 scoring integrity | CER versions, S/D/I sum, no fake script-fold score, schema/license audit | tests/test_bench_mandarin.py | tampered number/revision or absent license fails |
| G11 Settings | same plan/service, no second persistent state, offscreen Qt where available | tests/test_settings_language_profiles.py | consent decline, model install failure, quit mid-apply |
| G12 default regression | English keyboard, command semantics, doc generator, egress and private-path constraints | uv run python -m pytest tests/ -q | Chinese module absent from base install |
Ordinary offline tests must be deterministic and contain neither private speech nor model downloads. Qt-dependent tests legitimately skip where Qt extra is absent; a successful skip is not a GUI smoke result. Negative cases that expose current bugs should first be committed as a red reproducer in a targeted PR, then fixed in a separate code review where practical.
CI commands¶
uv sync
uv run python -m pytest \
tests/test_language_profiles.py \
tests/test_language_service.py \
tests/test_configedit_atomic.py \
tests/test_cli_language.py \
tests/test_cli_language_set.py \
tests/test_chinese_command_grammar.py \
tests/test_mandarin_command_numerals.py \
tests/test_mandarin_command_safety.py \
tests/test_han_script.py \
tests/test_cjk_text.py \
tests/test_cjk_transcripts.py \
tests/test_meeting_cjk_word_count.py \
tests/test_bench_mandarin.py -v
uv run python -m pytest tests/ -q
uv run ruff check src tests scripts
uv run mypy src
When config/CLI/schema changes, regenerate docs with uv run python scripts/gen-docs.py or make docs as directed by AGENTS.md; do not edit generated reference docs by hand. Any new source dependency needs the project's optional-extra, import and egress gates.
Layer 2: language-profile installation and lifecycle¶
For each claimed distribution/channel and the three profiles en, zh-CN, zh-TW:
- Start from a fresh English config, record installed package/version and base
base.enstate. language set zh-CN --dry-run: verify zero file, package, network, cache, daemon changes.language set zh-CN --no-download --no-installwithout artifacts: verify refusal and byte-identical config.- Explicitly approve preparing the script extra and multilingual model; verify cached artifact and coherent one-shot config.
- Start/restart the daemon, dictate a fixed test sentence, verify status/doctor; separate configured from running-effective model.
- Switch to
zh-TWwith existingsmall: only script changes; no redundant model download. - Switch to English in preserve mode: keep compatible multilingual model; optionally
--recommended-modelto return tobase.en. - Concurrent CLI + Settings edit: preserve unrelated changes, one writer wins safely, no partial profile.
- Fail model download, dependency install, config write and process restart separately: record config bytes, cache state, daemon state and messages.
- Remove network after cache provisioning and repeat dictation/file/meeting supported flows; no hidden fetch or telemetry.
Important: package installs and downloads may remain after a failed later step. That is an expected outcome of the current config-only transaction; the UI must report it accurately.
Layer 3: real recognition and quality (mandatory for a “dictation supported” label)¶
Use the model protocol. Run real authorized Mandarin audio with the shipping adapter and pinned weights. At minimum cover zh-CN and zh-TW references, short/long speech, mixed Han+Latin, numbers/names, accent/noise, silence, word timestamps, streaming and file transcription. Record cer_raw, cer_normalized, cer_script_normalized, p50/p95 latency, RTF, RSS and core-seconds.
Set quantitative accept/reject SLOs before evaluating the holdout. Suggested governance: the release manager pre-registers hardware classes, expected max latency and memory, minimum speaker/sample counts and tolerable absolute CER with native reviewers; the repository currently lacks enough representative Mandarin data to defend one universal absolute CER threshold. Do not pick a threshold after viewing model results.
A model-specific advantage cannot compensate for failed Unicode injection, unsafe commands or data egress. Report all failures, not only successful clips.
Layer 4: native phrase and usability review¶
At least one independent native reviewer for Simplified Mandarin and one for Traditional Mandarin must execute:
- Installation, first model/cache preparation, dry-run and offline-after-cache, language switch both ways;
- Natural phrase round-trip for every shipped
commands/grammars/zh.py::PHRASE_REVIEWaction family (all currently provisional);NUMERAL_REVIEWfor counts and line numbers; - Negative set: ordinary prose, quoted instructions, sentence-long occurrences of command verbs, navigation/file-name phrases, disfluencies, homophones and incomplete fragments;
- Dictation in a text editor, browser input and office/document field, including Simplified and Traditional punctuation/IME interactions;
- Return to English without losing previous model/settings and without unexpected command execution.
A phrase is accepted only after native reviewer disposition and matching positive/negative tests. One English speaker's literal translations are insufficient. Use the privacy-safe protocol at human-validation-data-protocol.md. Store approval as a dated decision + reviewer consent; do not require publication of legal names or private emails.
Command false-positive policy¶
A false positive for a destructive/high-impact command is a release blocker on that action family. No broad “Chinese commands supported” claim while any P1 phrase remains unreviewed. A deliberate narrow safe-core subset may be supported with all other families explicitly excluded. The English Tier-2 classifier must remain disabled for Mandarin until a separate safety ADR and benchmark clear it.
Layer 5: desktop Unicode and physical application matrix¶
There are no submitted platform reports in docs/research/mandarin-platform/ as of this audit; keep their status unverified.
| Report | Required platform/session | Targets | Required strings / checks |
|---|---|---|---|
linux-x11.md | a real X11 desktop + exact injector/backend | Two real editable applications | Simplified, Traditional, mixed Latin, punctuation, long burst |
linux-wayland.md | named compositor/portal/backend | Two real editable applications | Same, plus clipboard/portal fallback and focus |
macos.md | macOS version + architecture + input permissions | Two real editable applications | Same, UTF-16/surrogates and restart |
windows.md | Windows build + injection backend/IME state | Two real editable applications | Same, surrogate pairs and clipboard fallback |
Fixed public strings: 你好,世界。今天测试 YazSes 123。; 你好,世界。今天測試 YazSes 123。; 版本 v2.0,文件 test.py,编号 12345。; plus a non-BMP emoji and a burst with a Han prefix/suffix around Latin text. Each report must say exact observed output, not only “worked”; record whether mixed-mode typing duplicated a prefix, lost focus, or required clipboard.
A failed backend is not a reason to hide evidence: mark unsupported or restrict the product's support claim to a verified fallback. Do not classify an OS supported based solely on a test mocking its injector.
Layer 6: cross-surface matrix and regression¶
| Product surface | Automated path today | Extra manual evidence | Default public wording until evidence arrives |
|---|---|---|---|
| Hold-to-talk | Engine/language/script tests | Real Mandarin voice + application injection | Experimental |
| Streaming | decode_window and CJK joining tests | partial/final no-duplication/stability in actual sessions | Experimental |
| File transcription | recimport and renderer tests | real yazses transcribe (short/long, format matrix) | Experimental |
| Meeting live/batch | Han quality-unit and notes tests | real multihour, recovery, timestamps, quality/notes context | Unverified for release |
| Editing/navigation commands | anchored grammar and negative corpus tests | reviewed phrases in Simplified + Traditional | Preview; provisional |
| Terminal/open-ended commands | intentionally absent | independent high-risk safety/design gate | Excluded |
| Offline cache | unit tests | network-disabled packaged use after provisioning | Unverified until physical test |
Cantonese/zh-HK | deliberate profile rejection | requires separate model/corpus/grammar | Not included |
| UI/doc translation | documentation exists | native UI and docs audit | Locale independent of dictation |
Evidence artifact schema¶
Store aggregate results under tracked public design/docs/result locations only when safe. Suggested machine-readable report:
{
"schema": "yazses.mandarin.release/1",
"date_utc": "YYYY-MM-DD",
"yazses_commit": "<immutable SHA>",
"profile": "zh-CN",
"surface": "hold-to-talk",
"platform": {
"os": "<name+version>",
"session": "<X11|Wayland|macOS|Windows>",
"app_versions": ["<target app version>"]
},
"model": {
"id": "small",
"revision": "<immutable model revision>",
"license_id": "MIT",
"weights_sha256": "<sha256>"
},
"corpus_sha256": "<authorized corpus manifest SHA256 or null>",
"evidence": ["<relative public artifact path>"],
"result": "pass|fail|blocked|not-run",
"limitations": ["<named limitation>"],
"review": {
"native_simplified": "pending|approved|not-applicable",
"native_traditional": "pending|approved|not-applicable",
"maintainer": "pending|approved"
}
}
This is a proposed release-report format, not an implemented validator or a claim that those files exist. Raw audio, private transcripts, personal home paths, emails and biometric data must not be committed.
Release checklist and signoff (ADR-v2-144)¶
- All governing ADR decisions reviewed; scope and every deferred capability named.
- CI gates G01–G12 green against exact release commit; full English tests green; lint and import budgets green.
- Model/corpus license provenance pinned and benchmark JSON validated with a frozen split.
- Release hardware SLOs pre-registered and met for each claimed device tier.
- Simplified and Traditional native reviewer approval recorded separately.
- Every advertised platform/session injection report exists and shows tested applications.
- Real short-file and streaming finalization complete; meeting only if separately cleared.
- No undesired network egress; fully offline after provisioning.
- Installer, error-recovery, dry-run, rollback-to-English, and no-restart states verified.
- Product docs clearly distinguish Mandarin and script, commands preview scope, Cantonese exclusion.
- Each surface marked supported/experimental/excluded with citations to exact evidence.
- Maintainer signs/date-stamps release decision and known exceptions; no blanket “Chinese supported” without that matrix.
Until all relevant conditions pass, the release statement is: “YazSes has experimental offline Mandarin dictation with Simplified/Traditional output; availability and quality vary by tested model, application and platform.” Do not imply the same validation for Cantonese, arbitrary code switching, every Mandarin accent or every desktop target.