Mandarin support: implementation audit and gap analysis (2026-10-29)¶
Status: Evidence-based audit, not a product-release approval. Code snapshot: main at 4fda34030b0cf6e269edad78f8e03ea0d91b0324. Scope: desktop offline Mandarin dictation with Simplified (zh-CN) and Traditional (zh-TW) output. Cantonese, regional lexical localisation and mixed-language recognition are separate work.
Executive verdict¶
The September design package remains a useful design history, but it is no longer an accurate inventory of unimplemented features. Profile selection, transactional config writes, CLI/Settings/doctor, Mandarin's conservative Tier-1 grammar, model-free CJK transcript repairs, and the Mandarin CER harness are present in current main. That is implemented/tested in code, not an evidence-backed claim of native-speaker acceptance, real-model performance, or reliable Unicode injection on every desktop.
Do not reimplement closed work, change the default English model, introduce another mandatory runtime, or call this a completed Mandarin release.
Sources and audit confidence¶
This audit inspected the public files listed below and the existing tests. A test's presence proves coverage was written, not that the full suite passed in this review. No actual microphone, Whisper weights, platform injection, model downloads, Qt window, or end-to-end transcript was executed for this audit. Claims of real-device/model validation therefore remain unverified.
| Slice | Implementation reference | Existing automated evidence | Observed state | Next required proof |
|---|---|---|---|---|
| Profile identities and aliases | src/yazses/language/profiles.py | tests/test_language_profiles.py | Implemented for en, zh-CN/zh-Hans, zh-TW/zh-Hant; zh and zh-HK rejected as ambiguous | P1 CLI/GUI smoke on real installations |
| Pure plan and preserve/recommended choice | language/plan.py | test_language_profiles.py | Implemented; keeps compatible selected model and repairs English-only model when switching to Mandarin | Confirm package/engine compatibility and file-based custom models |
| One coherent config transaction | language/service.py + system/configedit.py | test_language_service.py, test_configedit_atomic.py, test_cli_language_set.py | Implemented; optimistic revision compare, candidate loader validation, retry on concurrent edits | Real install failures, restart failure, process interruption |
| User CLI | src/yazses/cli.py, language list/status/set | tests/test_cli_language.py and test_cli_language_set.py | Implemented with dry-run, explicit model/engine, recommended, no-install, no-download, no-restart, yes | Cross-platform binary/package smoke |
| Settings | settingsui/language_view.py and Settings controller | tests/test_settings_language_profiles.py | Shared service and pure preview exist; Qt tests may skip without PySide6 | Human UX checks on all supported OSes |
| Doctor/readiness | language/status.py, language/capability.py, system/doctor.py | test_doctor_language.py, test_language_capability.py | Derives configured profile and model capability; no separate profile config | Show configured-vs-running distinction and real prerequisite failures |
| Mandarin safe commands | commands/grammars/zh.py, registry.py, commands/grammar.py | test_chinese_command_grammar.py, test_mandarin_command_safety.py, test_mandarin_command_numerals.py | Deterministic anchored edit/navigation subset; English Tier-2 not used for Mandarin | All PHRASE_REVIEW entries and NUMERAL_REVIEW remain provisional; require native-language review |
| Han script normalisation | postprocess/han_script.py + stt/factory.py | test_han_script.py, test_stt_factory.py | Existing optional OpenCC wrapper; source language and output script are distinct | Native Simplified/Traditional lexical QA; dependency/install/air-gapped tests |
| CJK spacing/segments | postprocess/cjk.py, spacing.py, stt/faster_whisper.py | test_cjk_text.py, test_cjk_transcripts.py | CJK join/spacing fixes committed; September audit's F1–F5 status is historical | Run real model segmented/streaming and mixed Han–Latin traces |
| File/meeting output | recimport/, meeting/quality.py, meeting/store.py | test_cjk_transcripts.py, test_meeting_cjk_word_count.py | Han quality units and five renderer paths have model-free tests; previous claim that Han counted as one word is outdated | Real long-form meeting/quality and notes-model context windows |
| Model benchmark instrument | paper/benchmark/bench_mandarin.py, mandarin_metrics.py | test_bench_mandarin.py | zh-eval-v1 CER scorer and JSON schema, smoke and manifest path exist | Publish actual reproducible Mandarin runs + immutable weight licenses |
| Native OS injection | inject/, platform injectors | CJK injection unit tests | In-memory/platform mocking present, but the evidence directory docs/research/mandarin-platform/ still has README only | Physical X11, Wayland, macOS and Windows reports |
| Published scope | design/chinese/surface-support-matrix.md and Chinese how-to | Mostly documentary | Not a measured release contract yet | Release signoff per surface and negative evidence |
Corrections to earlier planning¶
- ADR IDs changed in main: use ADR-v2-140 (profiles), 141 (models), 142 (grammar), 143 (speech/script/locale), 144 (release gate), not the old 135–139 identifiers. ADR-v2-135 is now an unrelated face-gesture decision.
- Design PR #378 was closed without merging; the design files nevertheless exist on current main. Use current source and the current ADR IDs, not the old branch when creating issues.
- Campaign PR #533 was merged. The
CHN-*rows already exist incampaign/tasks.json; avoid duplicate task IDs or separate issues for each small task. - The original
design/chinese/README.mdstatement that coherent switching and Mandarin command recognition are still missing describes the September baseline, not current main. - The original surface matrix calls Meeting Mode's Han token accounting blocked; current
meeting/quality.py::tokenizeand tests explicitly handle Han quality units. Real Mandarin meeting quality remains unmeasured. postprocess-compatibility.mdF1–F5, F7–F9 are marked fixed in its findings table. Open evidence: real model, optional transforms, platform injection, and the reported MCP transcription config propagation defect (F6).- The language-switch config transaction is atomic; optional package installation and model downloads are not rolled back after a later failure, and an already running daemon may require a restart. Do not claim a system-wide ACID transaction.
- The
zh-CN/zh-TWprofiles represent Mandarin plus output script, not separate Mandarin dialect models;zh-HKandyueare deliberately not P1 aliases.
As-built flow (no Chinese fork)¶
user CLI / Settings
-> language.profiles + language.plan [pure, canonical STT config changes]
-> language.service [stable read, preflight, optional install/download]
-> system.configedit [validated atomic replacement]
-> restart policy owned by caller
-> core.daemon -> stt.factory -> existing faster-whisper backend
-> optional Han script wrapper
-> postprocess (pure CJK seam helpers)
-> commands.grammars.registry (zh grammar only when selected)
-> platform injection protocols
File transcription / Meeting Mode reuse STT + render/quality seams
Invariants: the default is base.en + English, Mandarin requires a multilingual model, source speech and output script stay independent, no utterance content leaves the device, new heavyweight dependencies are optional/lazy, supported/experimental status is per surface, and the user owns all installations/downloads.
Live blockers, ordered by potential harm¶
| Priority | Finding | Specific evidence to close it | Tracking |
|---|---|---|---|
| P0 | No native review of Mandarin command intent phrases; false positives can affect editing | Annotated Simplified and Traditional positive/negative command corpora, reviewer disposition, tests | #499, #505 |
| P0 | No completed real-device Han injection reports | Four independent dated platform/session reports and at least two target applications per report | #501 |
| P0 | No larger, reproducible Mandarin ASR/product benchmark for the release | Pinned benchmark manifest, model revision, CER by slice, CPU latency/RAM, artifact hashes | #503 |
| P0 | English default, config safety and offline install must remain intact | Full CI, installer/no-network/restart failure matrix, packaged smoke | #497 |
| P1 | Real multi-segment/streaming and long meeting validation absent | Real-audio paths, segmentation, timestamps, meeting recovery, notes context tests | #501 |
| P1 | MCP transcription config propagation identified as open in F6 | Minimal red test then fix through the existing recimport config interface, no new network path | #501 |
| P1 | Model-card license vs weight revision can diverge | Per-artifact SPDX source, immutable revision, checksums and legal/maintainer review when non-permissive | #503 |
| P2 | Optional CJK text transforms not fully checked | Feature-by-feature safety classification; unsupported transforms disabled/clearly excluded | #501 |
What “done” can mean¶
Maintain four distinct statuses: implemented (code path exists), automated-tested (identified tests pass), validated (real-model/hardware/native evidence exists) and released (maintainer accepted the exact support matrix). Do not infer a later status from an earlier one. Results are to be recorded in release verification.
Review rule: re-run the audit if a language, STT, command, meeting, injection or benchmark PR lands. For every changed line of support wording, link to test + evidence artifact or mark it “not yet verified”.