# English for CFO

Адаптивное настольное приложение для Windows, которое готовит финансового специалиста с уровнем английского A1 к собеседованию на позиции Finance Manager, Financial Controller, Head of Finance, Finance Director и CFO примерно за 90 дней.

Приложение не объясняет финансовые понятия. Оно учит говорить о них по-английски: P&L, cash flow, working capital, IFRS, audit, treasury, tax и т. д.

Основные возможности (MVP):

- входное тестирование и персональная карта навыков (Skill Map);
- ежедневная адаптивная тренировка (по умолчанию 75 минут);
- словарь фраз с интервальным повторением;
- тренировка устной речи с оценкой;
- симулятор интервью с AI-интервьюером;
- раздел «Мои ошибки» и прогресс с прогнозом готовности.

Прогресс считается локально движком обучения. LLM только поставляет измерения и не определяет прогресс сам. Всё, кроме облачного AI, работает офлайн.

## Требования

- Windows 10 (2004+) или Windows 11, x64.
- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0). Для запуска собранного приложения достаточно .NET 8 Desktop Runtime.
- Микрофон. Нужен для устных упражнений и интервью.
- Английский голос Windows (TTS). Установка: **Параметры → Время и язык → Речь → Добавить голоса → English (United Kingdom)** или **English (United States)**.
- Интернет нужен только для облачного AI (по желанию) и для однократной загрузки модели распознавания речи.

## Сборка и запуск

```powershell
dotnet build EnglishForCfo.sln
dotnet run --project src/EnglishForCfo.App
```

## Проверка

Все журналы и скриншоты проверок пишутся в `%LOCALAPPDATA%\EnglishForCfo\logs\`. Код выхода каждой команды равен числу ошибок (0 — всё в порядке).

1. **Модульные и интеграционные тесты** (движок, данные, миграции, AI, контент):

   ```powershell
   dotnet test tests/EnglishForCfo.Tests
   ```

2. **Самопроверка интерфейса** `--selfcheck`:
   - открывает каждую страницу из `PageRegistry` в тёмной и светлой теме, все шаблоны упражнений (включая **все шаги**
     карточки фразы: обе кнопки до показа перевода, вопрос «совпало?», путь «Не помню» и все три объективные
     проверки — выбором, вводом и «Сказать перевод» со всеми тремя вердиктами) и все общие контролы, а также первый шаг обучающей подсказки;
   - проверяет, что у каждого типа упражнения есть русская инструкция, что инструкция не обещает поля, которого на
     экране нет, что карточка не показывает перевод до отметки и что объективная проверка не задаёт вопрос о самооценке;
   - проверяет и фотографирует закреплённую строку действий: она не внутри прокручиваемой области, целиком видна и
     на 1280×800, а после ответа разбор сам поднимается в видимую часть экрана;
   - фотографирует аудирование до и после ответа: «Показать перевод вопроса» с переводом только вопроса, затем
     расшифровку прозвучавшего с русским переводом;
   - фотографирует грамматическое задание с его собственной инструкцией и русским правилом темы вместо несуществующего
     русского предложения;
   - фотографирует два экрана из последнего отчёта: разбор ошибки с его подсказкой (смысл фразы + сама ошибка, своя
     инструкция) и задание по посмотренному слову, подобранное под уровень — слово с коротким примером из знакомых
     слов вместо длинного предложения; оба проверяются на решаемость и на честность инструкции;
   - фотографирует и проверяет шесть умений и баллы: точки с русской строкой «осталось: …» на карточке фразы и в
     «Мои слова», строку «проверяем умение: … » в занятии, отзыв после ответа, закрывшего умение, вместе с
     начисленными баллами, итоги занятия с «очки за занятие», строку на Dashboard и карточку баллов со ступенями в
     Progress — в тёмной и светлой теме;
   - проходит еженедельную проверку уровня пробным прогоном по вашему настоящему банку вопросов (ничего не сохраняется,
     карта навыков не меняется) и фотографирует вступление, вопрос, вопрос на чтение или аудирование, результаты с
     диапазонами, карточку на «Обзоре» и «Сегодня» и историю в Progress (если вы ещё не проходили проверку — на
     образце из трёх недель, который никуда не записывается) — в тёмной и светлой теме;
   - фотографирует ответ плитками: банк слов до и после того, как ответ собран, и то же задание, переключённое ссылкой
     «печатать с клавиатуры» на обычный ввод; проверяет, что плиток хватает, что на первом слове нет заглавной буквы и
     что на плитках нет знаков препинания;
   - проверяет и фотографирует «Медленнее»: кнопку рядом с «Послушать» в задании (с подсказкой про Shift+Space) и
     у карточки фразы на странице «Фразы и слова» — в тёмной и светлой теме;
   - фотографирует и проверяет источники распознавания речи: все четыре варианта с их строками готовности, список
     моделей, найденных на этом компьютере (включая те, что найдены, но не подходят — с объяснением), настоящую
     проверку выбранной ggml-модели (синтез фразы → распознавание → время) и настоящую проверку внешней программы
     на одноразовом скрипте; отдельно — задание с устным ответом в режиме диктовки и живой разговор в нём же, где
     страница должна честно переключиться на ответы текстом по очереди — в тёмной и светлой теме;
   - собирает исключения и ошибки привязок WPF;
   - пишет `logs\selfcheck.log` и скриншоты в `logs\selfcheck\` (`<Page>.png`, `<Page>-light.png`);
   - работает с вашей обычной базой, но ничего в ней не меняет.

   ```powershell
   dotnet run --project src/EnglishForCfo.App -- --selfcheck
   ```

3. **Сквозная проверка MVP** `--e2e` (критерии готовности ТЗ §68):
   - запускает настоящее приложение (DI, страницы, ViewModel) на **временной базе** `%TEMP%\EnglishForCfo-e2e-<id>`; ваша база не открывается;
   - микрофон, распознавание речи и озвучка заменены детерминированными заглушками, облачный AI выключен, поэтому работают локальные оценки;
   - через команды ViewModel проходит: онбординг и входной тест → Skill Map → START → адаптивный план → словарные упражнения (верно, ошибка с повтором, «угадал») → ответ голосом → оценка ответа → завершение занятия → обновлённый прогресс → план на завтра;
   - карточки фразы проходятся по новому циклу «отметка → показ перевода → сверка»: проверяется, что вопрос «совпало?» нельзя ответить до отметки, что перевод не показан заранее и что «Не помню» ничего больше не спрашивает;
   - дополнительно проверяет: «Мои ошибки», практику из Vocabulary, Quick Practice → Interview, симулятор интервью (2 вопроса и отчёт), Speaking и кнопку «Open Settings» у рекордера, добавление и удаление своего AI-провайдера и модели, повторное открытие всех страниц;
   - отдельный шаг для слов из просмотров: открывает настоящие карточки перевода → слова появляются в «Мои слова» со статусом *In training* → в плане на завтра появляется блок «Words you looked up» с упражнениями по ним → ответ на такое упражнение записывается как попытка;
   - отдельный шаг для самого занятия: проверяется, что при появлении задания фраза действительно произносится и что
     там, где озвучка выдала бы ответ, не произносится ничего; что строка действий есть, находится вне прокручиваемой
     области и целиком на экране у каждого задания; что Esc останавливает озвучку; и что у проверки слова вопрос,
     условие и варианты ответа описывают один и тот же материал;
   - отдельный шаг для шести умений и баллов: правильный объективный ответ в два разных дня закрывает умение, самооценка «помню» не закрывает ничего, начисляются баллы с бонусом ×2 за первое закрытие — и всё это проверяется в том виде, в каком его видит интерфейс (строка «закрыто умение: …», шесть точек, «очки за неделю … уровень …», карточка баллов и ступени в Progress);
   - отдельный шаг для ответа плитками и «Медленнее»: перевод собирается из банка слов (клавиша «1», Backspace, возврат
     плитки нажатием, сборка всего ответа), проверяется, что ответ принят и записан как «выбрать вариант» и «вставить в
     предложение», а «написать» не засчитано; затем Shift+Space проигрывает фразу на медленной скорости (проверяется
     именно та скорость, что дошла до голоса), Esc её останавливает — и то же для отдельной кнопки «Медленнее»;
   - отдельный шаг для CFO-историй: не меньше 12 историй доступны новому ученику, рекомендованная проходит словарный фильтр, история проигрывается в плеере по репликам, первый вопрос отвечается неверно (объяснение + подсвеченная реплика), остальные верно — и каждый ответ оказывается в модели навыков как попытка по теме истории;
   - отдельный шаг для еженедельной проверки уровня: в первую неделю цели проверка не предлагается, через неделю появляется карточка на «Обзоре» и «Сегодня»; проверку проходит «ученик» с заданным уровнем B1 — оценка по каждому разделу должна оказаться рядом с ним; проверяется, что результат, ответы и уточнённые сложности вопросов сохранены, что навыки получили по одному измерению, а Speaking не изменился, что карточка исчезла до следующей недели и что в «Прогрессе» появилась история;
   - отдельный шаг для внешней программы распознавания: во временной папке создаётся настоящий `.cmd`, который играет роль распознавателя, и проверяется весь путь — текст из файла `{output}` и из консоли, путь записи с пробелом и кириллицей, отчёт об ошибке с кодом возврата и сообщением программы, и принудительное завершение зависшей программы по таймауту;
   - отдельный шаг для диктовки: с выбранным источником «Диктовка» рекордер показывает поле вместо микрофона, надиктованный текст оценивается, темп речи и паузы возвращаются как «не измерено» и не сохраняются, умение «произнести» не закрывается, а живой разговор переключается на ответы текстом по очереди;
   - отдельный шаг для проверки смысла: карточка фразы предлагает «Сказать перевод» рядом с двумя старыми проверками, пересказ своими словами («в этом году доход вырос» на «Revenue went up this year.») **засчитывается**, тот же ответ с числом, которого во фразе нет, — **отклоняется**, при этом промах не записывается, пока вы не решили; «Это тоже верно» записывает попытку как верную, сохраняет пару в базу и в `meaning-disputes.jsonl`, **не меняя** эталонный перевод фразы; и проверяется, что засчитано только умение «прочитать», а «написать» и «произнести» не тронуты;
   - отдельный шаг для сложности материала: каждый разбор в «Моих ошибках» строится с подсказкой (у варианта выбора —
     обязательно, иначе это те самые два варианта без условия) и с инструкцией, которая не обещает лишнего; затем
     смотрится настоящее слово (`traffic` в предложении из отчёта) — материал, который система для него выбрала, и
     всё, что выпускает блок «Слова, которые вы смотрели», не выходит за словарный лимит, а показанное предложение
     «в котором вы встретили слово» вам по силам;
   - пишет `logs\e2e.log` (PASS/FAIL по шагам) и скриншот каждого шага в `logs\e2e\`;
   - после успешного прогона временная папка удаляется, после неудачного остаётся (путь указан в `e2e.log`).

   ```powershell
   dotnet run --project src/EnglishForCfo.App -- --e2e
   ```

## Как проходит занятие

Интерфейс — на русском: всё, что говорит, **что делать**, написано по-русски; по-английски только сам учебный материал.
То же объяснение есть в приложении — кнопка «Как это работает» в верхней панели занятия и на странице «Сегодня»,
а при первом занятии показывается короткая подсказка из четырёх шагов (её можно пропустить и открыть снова).

1. **План.** Каждый день занятие собирается заново: сначала фразы, срок повторения которых подошёл, затем самые слабые
   навыки, повторяющиеся ошибки и новые фразы. Длительность — из настройки «минут в день». На странице «Сегодня»
   кнопка сразу говорит, что произойдёт («Начать занятие · 5 блоков, 75 минут»), а строка под ней — какой первый блок и почему.
2. **Блоки.** Занятие идёт блоками (повторение фраз, стартовый словарь — только пока он не пройден, новые фразы,
   грамматика, аудирование, говорение, кейс, интервью, слова, которые вы смотрели). Наверху видно, какой блок идёт, почему он в плане и сколько времени занятие длится.
3. **Задание.** В центре — одно задание. Над ним серая строка по-русски говорит, что нужно сделать прямо сейчас
   («Напишите эту фразу по-английски», «Послушайте и выберите, что вы услышали», «Нажмите запись и произнесите фразу вслух»).
   Инструкция обещает только то, что действительно есть на экране: у грамматики нет русского предложения, поэтому там
   написано «Впишите правильную форму слова в предложение — правило по-русски рядом», а не «прочитайте русское
   предложение». Каждое задание всегда показывает **подсказку-условие** — то, что говорит, *что нужно произвести*, — и
   никогда не показывает сам ответ заранее (см. «Каждое задание можно решить»).
4. **Фраза произносится сама.** Как только задание появляется, английская фраза звучит голосом Windows — внимание
   идёт на то, что учим, а не на кнопку. Озвучка **молчит** там, где она выдала бы ответ: пропущенное слово, перевод
   на английский, порядок слов, «произнести по памяти». Кнопка «Послушать» повторяет фразу, а пока она звучит, та же
   кнопка читается **«Остановить»**; **Esc** останавливает озвучку откуда угодно, и переход к следующему заданию или
   выход со страницы тоже её обрывают — из другого задания вы больше ничего не услышите. Выключается в
   **Settings → Training → «Проговаривать фразу при появлении задания»**.
5. **«Как ответить» — одна заметная группа под самой фразой.** Все способы ответить на текущий шаг собраны в один
   блок сразу под заданием: одинаковые крупные кнопки, у каждой — строка, которая объясняет, что она значит, и
   клавиша, которая её нажимает («1 · Enter», «2», «3»…). Раньше они были разного размера и в разных местах экрана —
   две кнопки внизу страницы и три мелких ссылки под карточкой, — и понять, что это **варианты одного выбора**,
   было невозможно.
   Внизу экрана остаётся **одно главное действие** шага (и тихое «Пропустить задание»), закреплённое и не
   прокручивающееся вместе с заданием, со строкой клавиш под ним («Enter — помню — проверить · 1–5 — кнопки выше ·
   Esc — остановить озвучку»). **Enter** всегда выполняет главное действие, в какой бы части страницы вы ни
   находились. После ответа разбор сам поднимается в видимую часть экрана. Исключение по замыслу: вопрос
   «совпало?» и вопрос об уверенности Enter не отвечает — эти отметки делаются осознанно, кнопкой или цифрой.
   И группа, и нижняя строка целиком помещаются на экран ноутбука 1280×800 — это проверяется автоматически.
6. **Карточка фразы — решение до ответа.** Сначала на экране только английская фраза (и озвучка), а под ней — группа
   «Как ответить» со всеми пятью способами сразу:
   - **«Помню — проверить»** (1 · Enter или Space) — *скажите про себя перевод и откройте ответ — сверимся*:
     открывается перевод, пример, схема и визуальная подсказка, и задаётся один короткий вопрос:
     **«Совпало с тем, что вы вспомнили?»** — «Да, совпало» / «Почти» / «Нет, не совпало» (тоже отдельной группой,
     рядом с переводом, который вы сверяете).
   - **«Не помню»** (2) — *честный ответ: покажем перевод и вернём фразу сегодня*: попытка сразу записывается как
     неверная, после чего фраза показывается для изучения и больше ничего не спрашивается.

   Отметка попадает в расчёт **до** показа перевода, а вопрос после него лишь уточняет её. Время ответа измеряется
   до нажатия кнопки, а не до оценки. Так самооценка перестаёт быть взглядом назад: «знал» задним числом ничего
   не измеряет.
7. **Проверка вместо самооценки.** В той же группе — ещё три кнопки того же размера: **«Проверить выбором»** (3;
   английская фраза и четыре русских перевода: один верный, остальные — из фраз того же раздела и уровня),
   **«Проверить вводом»** (4; написать фразу по-английски по её русскому смыслу; предлагается для фраз не длиннее
   шести слов, сравнение терпимо к регистру и знакам) и **«Сказать перевод»** (5; сказать своими словами по-русски,
   что значит фраза — сверка **по смыслу, а не дословно**; см. «Сказать перевод своими словами»). Карточка при этом
   заменяется настоящим заданием, результат которого — объективная попытка, и вопроса «насколько вы знали?» в ней
   нет вообще.
8. **Каждая новая фраза проверяется в том же блоке.** В блоке «Новые фразы» после карточек идут объективные проверки
   тех же фраз (выбор или ввод), поэтому фраза никогда не считается выученной по одной самооценке (ТЗ §35).
   Если объективная проверка опровергает отметку «помню», сделанную в этом же занятии, срабатывает путь неверного
   ответа: оценка Again, состояние карточки сбрасывается, а ошибка попадает в «Мои ошибки» отдельным шаблоном
   «Отметили „помню“, но проверка не пройдена». Объективный правильный ответ всегда весит больше самоотчёта:
   максимум для самоотчёта — «Хорошо», «Легко» можно получить только за проверенный ответ.
9. **Самооценка и интервальное повторение.** «Не помню» вернёт фразу уже сегодня, «Почти» — через день-два,
   «Да, совпало» — через несколько дней. Одного правильного ответа недостаточно, чтобы считать фразу выученной: нужны
   правильные ответы в разные дни. После ответа под заданием видны устойчивость, сложность и вероятность вспомнить.
10. **Помощь — по запросу и после ошибки.** «Подсказка» даёт наводку (и учитывается в оценке — интервал станет короче).
   В заданиях, где ответ вводится текстом, после неверной попытки помощь нарастает сама: первая буква → первые две
   буквы → правильный ответ с просьбой «напишите его ещё раз сами». Каждая ступень считается подсказкой, поэтому
   оценка за такое задание — не выше «Сложно», а показанный ответ записывается как неверный: его прочитали, а не
   вспомнили. «Спросить AI-репетитора» открывает панель поверх задания; сама она открывается только после неверного
   ответа, не сжимает задание и, если её закрыть, до конца занятия больше не появляется сама.
11. **Пропуск дня.** Штрафов нет: накопившиеся повторения распределяются на несколько занятий, план пересчитывается
   под сегодняшний день.

### Каждое задание можно решить

Правило: **подсказка-условие — это само задание, а не утечка ответа.** Утечка — это то, что позволяет ответить,
не вспоминая английский: озвучка, которая произносит ровно ответ, ответ, напечатанный рядом с полем ввода, или
русский вариант, по которому однозначно узнаётся правильная английская фраза из списка. Поэтому у каждого типа
упражнения в ядре (`ExerciseCues`) записано, **какое поле несёт условие** и **что не должно быть видно**; фабрика
упражнений отказывается выпускать задание, условие которого взять негде, и выбирает другой тип, а тест
(`SeededContentSolvabilityTests`) прогоняет весь контент из `content/**` через каждый тип и проверяет, что условие
есть, ответа не видно, озвучка его не произносит, а у вариантов ответа ровно один правильный и нет повторов.

Тем же правилом связана и **автоматическая озвучка при появлении задания** (`AutoSpeak`): она произносит ровно то, что
произнесла бы кнопка «Послушать», поэтому там, где озвучка — утечка, задание появляется молча.

**Инструкция не обещает того, чего нет.** У каждой русской инструкции в ядре записано, к каким полям экрана она
отправляет учащегося (`ExerciseInstruction.Promises`), и тест (`SeededInstructionPromiseTests`) прогоняет весь контент
из `content/**` и проваливается, если инструкция обещает поле, которого у задания нет. Так была найдена ошибка из
отчёта: грамматическое задание показывало «Прочитайте русское предложение и впишите пропущенное английское слово», а
русского предложения там нет и быть не может — задание про **форму**. Теперь у грамматики своя инструкция и свой
условный ориентир — русское правило темы.

**Разбор ошибки тоже должен быть решаемым.** Из отчёта: в «Моих ошибках» на экране было «Выберите английскую фразу,
которая передаёт этот смысл» и два варианта — `summer is different` / `sometimes it is different` — и больше ничего.
«Какой этот смысл? Непонятно о чём задание.» Так и было: английская строка задания пряталась как «служебная»,
русская — как «инструкция, а не перевод», а разбор показывался только **после** ответа. Формально правило
выполнялось, потому что в таблице условий у такого задания условием считались **сами варианты ответа** — то есть
любая карточка с двумя вариантами проходила проверку по определению. Теперь:

- у каждого разбора есть **своя подсказка** (`MistakeDrills.CueRu`): смысл фразы, на которой была сделана ошибка
  (он записывается в момент ошибки — `ErrorExample.MeaningRu`), сама ошибка по-русски и — там, где это не вариант
  ответа — предложение, в котором вы её допустили;
- у разбора выбором **своя инструкция** — «Это ваша частая ошибка — выберите вариант, в котором её нет»;
- задание, для которого сказать нечего, **не выпускается** выбором вообще: вместо него разбор, который объясняет сам
  себя (вписать форму, повторить вслух);
- общая проверка контента теперь **прогоняет и разборы ошибок** — все ошибки, которые приложение вообще умеет
  записывать, построенные настоящим детектором по настоящим фразам из `content/**`, в обоих языках интерфейса и в
  обоих проигрывателях (занятие и страница «Мои ошибки»), с проверкой и условия, и обещаний инструкции.

**Варианты ответа одной формы.** Слово проверяется другими словами, а целое предложение — другими предложениями
(`ExerciseFactory.SameShape`). Это правило появилось из скриншота, где к вопросу «What does "What a lovely day!" mean?»
предлагался вариант «выбирать»: блок «Слова, которые вы смотрели» держит и отдельные слова, и живые фразы, которыми
эти слова учат. Тест `SeededWordCheckConsistencyTests` проверяет по всему контенту, что вопрос, условие, правильный
вариант и отвлекающие варианты описывают один и тот же материал.

| Тип задания | Условие на экране | Чего не видно |
|---|---|---|
| Выбор фразы (MultipleChoice) | русский смысл фразы + варианты по-английски | — (правильный вариант в списке по определению) |
| Проверка выбором (MultipleChoice, англ→рус) | английская фраза в вопросе + варианты русского перевода | русская строка-подсказка (она была бы одним из вариантов) |
| Карточка фразы (Flashcard) | английская фраза | перевод — до «Помню — проверить» / «Не помню» |
| Написать по-английски (TypeTranslation) | русский смысл фразы | английский текст, озвучка ответа |
| Пропущенное слово (GapFill) | русское предложение с **выделенным** нужным словом (или чип «нужное слово: …») + пропуск по длине слова | само слово, озвучка ответа |
| Своё предложение (UseInSentence) | целевая фраза в задании | — (единственного правильного ответа нет) |
| Порядок слов (Reorder) | русский смысл фразы + перемешанные слова (не меньше трёх) | озвучка ответа |
| Послушать и выбрать (ListenAndChoose) | озвучка — это и есть вопрос + варианты; «Показать перевод вопроса» — только вопрос | перевод вариантов ответа (его нет нигде и никогда) |
| Послушать и написать (ListenAndType) | озвучка — это и есть вопрос | текст ответа |
| Произнести вслух (SayAloud) | фраза на экране и образец озвучки; на шаге «по памяти» — только русский смысл | на шаге «по памяти» — английский текст и озвучка |
| Говорение (SpeakingAnswer) | вопрос по-английски | образцовый ответ — до ответа |
| CFO-кейс (CaseAnswer) | цифры кейса + вопрос | образцовый ответ — до ответа |
| Вопрос собеседования (InterviewAnswer) | вопрос собеседования | образцовый ответ — до ответа |
| Грамматика, выбор (GrammarChoice) | предложение с пропуском + варианты формы | — (задание про форму, а не про слово) |
| Грамматика, ввод (GapFill по теме грамматики) | предложение с пропуском + русское правило темы рядом | разбор именно этого примера («с I используется am») — до ответа |
| Разбор ошибки, выбор (MultipleChoice из «Мои ошибки») | русская подсказка разбора: смысл фразы, на которой была ошибка, и сама ошибка + два варианта | само предложение с ошибкой (оно одно из вариантов — иначе ответ угадывается исключением) |
| Разбор ошибки, ввод / диктант / вслух | своё предложение задания (пропуск, «Correct the sentence: …», правильная фраза) + та же русская подсказка, включая «раньше вы написали: …» | — |
| Визуальная карточка (VisualCard) | пояснение на карточке (для слова — само слово) + варианты | — |

В режиме «только английский» русского условия нет, поэтому типы, которые держатся на нём (пропущенное слово,
«произнести по памяти»), не выпускаются вовсе — вместо них подставляется задание с английским условием
(диктант по озвучке, карточка).

### Задание не сложнее, чем вы сейчас

Из отчёта: «Это очень сложные фразы. Система должна распознавать мой уровень и количество выученных слов и не давать
такие сложные задания, пока я не выучу слова из этих предложений.» Так и было: словарный фильтр (SPEC §14, бюджет
новых слов) работал только на **заданиях на понимание** — аудировании, историях, кейсах, вопросах интервью. Учебные
задания — фраза, которой учат посмотренное слово, новые фразы, разборы ошибок — не фильтровались вообще, и одно
посмотренное слово могло привести предложение, в котором вы не знаете ничего, кроме него.

Правило (ядро, `TrainingDifficulty`): у каждого кандидата считаются **незнакомые слова сверх того, которому учат**
(само изучаемое слово не считается — ради него всё и затевается), по тому же списку выученного, что и словарный
фильтр. Дальше:

- **не больше двух** таких слов, идеально — ноль или одно;
- уровень — ваш, ниже вашего или на одну ступень выше;
- из подходящих берётся **самая лёгкая**, а не первая попавшаяся;
- если не подходит ничего, «ближайшего всё равно» не бывает: слово учится **отдельно**, с коротким примером,
  собранным из служебных слов, которые известны всем («This is the invoice.»), или вовсе без примера;
- то же правило — для новых фраз (новая фраза может принести своё ключевое слово, но не пять незнакомых сразу) и для
  разборов ошибок (сначала те примеры, которые вы можете прочитать).

Измерено на настоящей библиотеке (`TrainingDifficultyMeasurementTests`) — незнакомых слов в задании, сверх изучаемого:
у новичка **было 5.47 в среднем (худшее 11), стало 0.24**; на профиле из отчёта (65 выученных фраз, ~100 посмотренных
слов) **было 3.10 (худшее 9), стало 0.56**; сверх лимита не остаётся ни одного задания. «Учим слово отдельно»
срабатывает у новичка в 86 % случаев и на профиле из отчёта — в 51 %, и это честно: пока учить нечем, лучше короткая
карточка. Дальше доля доступной библиотеки растёт сама: **22 % → 54 % → 97 %** выученных фраз по мере прохождения
общего трека.

## Что реализовано в MVP

- Onboarding (профиль, приватность, AI-провайдер, речь) и входной тест из шести разделов с адаптивной остановкой.
- Персональная Skill Map: отдельный уровень по каждому навыку, готовность к CFO-интервью, прогноз, этапы.
- Dashboard и Today: кнопка START, адаптивный план дня с причинами, Quick Practice, план на завтра.
- Session Runner: 15 типов упражнений с русской инструкцией и проверенным условием к каждому (см. «Каждое задание можно решить»), автоматическая озвучка фразы при появлении задания, закреплённая внизу строка действий, двухшаговая карточка фразы, нарастающая помощь после ошибки, лестница подачи после ошибок, уверенность ответа, AI Tutor поверх задания, итоги занятия (см. «Как проходит занятие»).
- Сказать перевод своими словами: на карточке фразы — третья объективная проверка, сверка **по смыслу, а не дословно**, работает и без AI (см. раздел ниже).
- CFO-истории: 40 рабочих сцен с вопросами внутри истории, подобранных под ваш словарь, плеер по одной реплике и генерация новой истории под словарь (см. раздел ниже).
- Аудирование: **вопрос всегда на экране** перед ответом (читать вопрос — не проверяемое умение), «Показать перевод вопроса» (только вопрос, никогда варианты), «Послушать» и «Медленнее» в любой момент, **«Показать текст»** — открыть расшифровку до ответа, честно записав попытку как с подсказкой; после ответа — расшифровка с русским переводом.
- Задания на понимание берут только те слова, которые вы действительно проходили: карточки, дошедшие до «Familiar», слова со статусом «Знаю» в «Мои слова» и слова, которые приложение показало вам перед заданием. Частотные слова больше не считаются известными «по умолчанию».
- **Сколько нового допускается в задании (§14).** Не процент понятного текста, а **бюджет новых слов**: `3 + N / 20`, где `N` — количество разных значимых слов в тексте, но не больше 8 (столько помещается в полосу «Перед прослушиванием»). Вопрос собеседования — 3 новых слова, кейс — 4, диалог — 4, CFO-история — 5, самые длинные диалоги — 8. Задание берётся, только если (1) новых слов не больше бюджета, (2) у каждого из них есть перевод и транскрипция в глоссарии — иначе показать их нечем, и (3) ни одного нового слова нет в вопросе и в правильном ответе. «Понятно ~N %» осталось, но теперь это только подсказка при выборе: из подходящих заданий берётся то, где нового меньше. Если не проходит ничего, блок не пустеет — берётся самое дешёвое задание не выше вашего уровня, это пишется в лог.
- Над каждым заданием на понимание — одна строка: **«новых слов: 4 — покажем их перед заданием и добавим в «Мои слова»»**. Если показать удаётся не все (так бывает только у «запасного» задания), строка так и говорит: «новых слов: 12 — 8 из них покажем перед заданием…».
- Vocabulary: интервальное повторение (планировщик в стиле FSRS), состояния запоминания, статистика карточки, практика по категории.
- Speaking: ответ голосом (локальный Whisper, своя модель, внешняя программа) или диктовка своей горячей клавишей, оценка ответа (AI или локальная эвристика), темп речи, слова-паразиты.
- Симулятор интервью: AI-интервьюер или офлайн-сценарий по банку вопросов, отчёт с узким местом и лучшими ответами.
- My Mistakes: повторяющиеся ошибки (грамматика по темам, путаница терминов, артикли, did, -s) и тренировка только их.
- Progress: метрики, графики, профиль обучения и объяснение стратегии, недельные обзоры.
- Интерактивные слова: любое английское слово в приложении можно навести, перевести и озвучить (см. раздел ниже).
- Слова, которые вы смотрели: просмотр перевода автоматически добавляет слово в тренировку, список — Vocabulary → My words (см. раздел ниже).
- Шесть умений на каждую фразу (прочитать, услышать, произнести, написать, вставить в предложение, выбрать вариант) с чередованием упражнений и условием «выучено = все умения закрыты» (см. раздел ниже).
- Баллы: взрослая система вознаграждения — итоги занятия, строка на Dashboard, карточка и карьерные ступени в Progress; на расписание и оценку знаний не влияют (см. раздел ниже).
- Settings: тренировка, тема, приватность, AI-провайдеры (Anthropic, OpenAI, OpenRouter, любые OpenAI-совместимые), источник распознавания речи (встроенный Whisper / модель на диске / внешняя программа / диктовка), модели Whisper, голос, сброс прогресса.

## Интерактивные слова

Приложение рассчитано на уровень A1, который читает профессиональный английский, поэтому **любое английское слово на любом экране можно разобрать на месте**, не выходя из задания.

- **Наведите курсор** на слово (примерно на четверть секунды) — появится карточка: само слово, базовая форма (`form of: liability`), транскрипция с ударением, перевод на русский, короткая заметка для «ложных друзей» и значок **AI**, если перевод сгенерирован моделью и ещё не проверен.
- **Клик по слову** — слово произносится голосом Windows (голос и скорость берутся из Settings → Speech). **Ctrl+клик** или кнопка **Sentence** в карточке произносит всё предложение, кнопка **Word** — только слово.
- **Клавиатура:** войдите в текст клавишей Tab, затем ← → переходят между словами, **Enter** открывает карточку, **Пробел** произносит слово, **Esc** закрывает карточку. Карточка не забирает фокус.
- **Слова без перевода тоже озвучиваются.** Если слова нет в словаре (около 4800 слов) и AI недоступен, карточка всё равно покажет слово и кнопку динамика, а вместо перевода — «перевод не найден».
- **Копирование:** Ctrl+C копирует весь текст, правый клик даёт «Copy word» / «Copy text» (в WPF обычный `TextBlock` не поддерживает выделение мышью, поэтому копирование сделано через меню и горячую клавишу).
- Подчёркивание появляется **только под словом под курсором** — текст остаётся чистым.

Переключатели в **Settings → Training**:

| Переключатель | По умолчанию | Что делает |
|---|---|---|
| **Interactive words** | включён | Выключает всю интерактивность — тексты рисуются как обычные подписи. |
| **Speak the word on click** | включён | Выключает озвучку по клику; кнопка динамика в карточке продолжает работать. |
| **Use AI for unknown words** | включён | Разрешает спросить перевод у AI-провайдера для слов вне словаря. Требует включённого **Privacy → Allow cloud AI processing**; без него переключатель ни на что не влияет. |
| **Автоматически добавлять просмотренные слова в тренировку** | включён | Просмотренный перевод добавляет слово в «Мои слова» и в занятия (см. раздел ниже). Выключенный переключатель останавливает только запись новых просмотров. |
| **Проговаривать фразу при появлении задания** | включён | Как только задание появляется, английская фраза произносится голосом Windows. В заданиях, где озвучка выдала бы ответ (пропущенное слово, перевод на английский, порядок слов, «произнести по памяти»), она молчит до ответа. Esc останавливает озвучку. Без установленного английского голоса переключатель ни на что не влияет. |

Что намеренно **не** переводится, чтобы не подсказывать ответ: варианты ответа в упражнениях на значение слова (Choose the phrase, визуальные карточки) и весь входной тест (Baseline). Там слово можно послушать и увидеть транскрипцию, но не перевод.

Перевод во время **неотвеченного** упражнения засчитывается как подсказка (как кнопка Hint) — один раз на слово. Просто озвучить слово подсказкой не считается.

## Стартовый словарь — первые дни

Словарь ученика считается **только по доказательствам**: слово известно, если вы его тренировали, отметили в «Моих словах» или оно было показано перед заданием. Это честно — и это имеет цену. У человека, который открыл приложение сегодня, доказательств нет, поэтому измерение показывает: в первый день из библиотеки доступны **0 из 40 CFO-историй, 0 из 100 диалогов и 0 из 100 кейсов**, а проходят фильтр только 39 коротких вопросов собеседования. Всё остальное приходит как «запасной» вариант с пометкой в логе.

Лечится это не порогом, а **обучением**: приложение просто берёт и учит стартовый словарь — быстро и явно, чтобы слова стали настоящим доказательством **и** появились в ваших списках.

- **Что это.** **261 слово** — самые частые значимые слова общего трека (из 300 отброшены те, что и так считаются известными: числительные, артикли, местоимения — и формы слов, которые уже есть в курсе: `costs` после `cost`). Каждое слово — обычная карточка (`core:<слово>`): перевод, ударение, часть речи и, где библиотека даёт, короткое предложение уровня A1–A2 с этим словом (таких 231 из 261). Курс собирается из глоссария при запуске приложения, повторный запуск ничего не дублирует.
- **Сколько это занимает.** Порции по 25 слов, по две порции в день = 50 слов, 11 порций всего → **6 дней**. При вашей норме 75 минут блок занимает **15 минут в день** (20 % занятия; потолок — 25 %, так что говорение не страдает). При 30 минутах в день блок ограничен 7 минутами → 24 слова в день → 11 дней.
- **Как учится.** Отдельный блок **«Стартовый словарь»** в занятии, пока курс не пройден. Формат быстрый — узнать значение, набрать, услышать: новое слово показывается карточкой и тут же проверяется, уже показанное возвращается коротким заданием. **Это обычные попытки по обычным карточкам** — никаких «выданных авансом» слов: слово считается известным для словарного фильтра (§14) только когда его карточка дошла до состояния **Familiar**, то есть после вашего правильного ответа.
- **Где это видно.** Строка на **Обзоре** и на **Сегодня**: «Стартовый словарь: 120 из 261 слова — откроет 29 историй и 15 диалогов» (числа измеряются прогоном фильтра по реальной библиотеке, а не берутся на глаз). В **«Мои слова»** слова курса лежат как любые другие — со статусом, оценкой знания и кнопкой «Я знаю это слово»; в счётчики «слова, перевод которых вы смотрели» они не попадают, потому что вы их не смотрели. В библиотеке **CFO-историй** закрытая только из-за словаря история говорит: **«откроется после стартового словаря»**.
- **Что это открывает** (измерено на реальной библиотеке):

  | Выучено слов курса | Историй (из 40) | Диалогов (из 100) | Вопросов собеседования (из 200) | Кейсов (из 100) | Дней при 75 мин |
  |---|---|---|---|---|---|
  | 0 | 0 | 0 | 39 | 0 | 0 |
  | 25 | 0 | 1 | 72 | 0 | 1 |
  | 100 | 0 | 1 | 128 | 0 | 2 |
  | 200 | 15 | 9 | 165 | 0 | 4 |
  | **261 (весь курс)** | **26** | **12** | **176** | **3** | **6** |

  Честно о том, чего курс не делает: **кейсы почти не открываются** (3 из 100). Кейс написан финансовой лексикой — EBITDA, covenant, accrual, — а стартовый словарь это общий английский. Кейсы открывает финансовый трек, а не он. Диалоги открываются частично (12 из 100): они длиннее историй и тоже написаны под уже занимавшегося ученика.
- **Можно пропустить.** На экране знакомства есть кнопка **«Пропустить»** — и рядом с ней сказано, чего это стоит: истории, диалоги и кейсы останутся закрытыми, пока эти же слова не наберутся обычными занятиями. Включить обратно: **Settings → Training → «Стартовый словарь в первые дни»**; курс продолжится с того места, где остановился, всё выученное сохраняется.

## Слова, которые вы смотрели

Правило простое: **посмотрели перевод слова — значит вы его не знаете.** Такое слово автоматически попадает в список незнакомых и периодически тренируется в следующих занятиях, пока система не убедится, что вы его знаете.

- **Когда слово попадает в список.** Только в момент, когда на экране действительно показан русский перевод — на любом экране: занятие, словарь, говорение, интервью, «Мои ошибки», дашборд, ответы AI-тьютора. **Прослушивание произношения не считается.** Не считаются и карточки, где перевод намеренно скрыт (варианты в заданиях на значение слова, входной тест), и слова, для которых перевода не нашлось.
- **Слова, которые показало само приложение, тоже попадают сюда.** Если заданию на понимание (аудирование, CFO-история, кейс) нужно слово, которого вы ещё не проходили, оно показывается перед заданием в полосе «Перед прослушиванием» — и **в тот же момент добавляется в «Мои слова»** (в тренировку или в очередь, если на сегодня уже набрано 20). Строка над заданием так и говорит: «новых слов: 3 — покажем их перед заданием и добавим в «Мои слова»». Раньше это была просто подпись: слово показывали, а в списке его не было, и на следующий день оно снова было новым — это и был отчёт «задания применяются слова, которые мы ещё не учили, а в перечне их нет».
- **Не больше 20 новых слов в день.** Остальные ждут в очереди и подключаются в ближайшие дни — план занятия никогда не «затапливает» новыми словами.
- **Как тренируется.** Система сама подбирает материал: сначала ищет живую фразу из контента, где это слово встречается, и только если такой нет — делает карточку самого слова. Задание всегда говорит о том материале, который на экране: у фразы и варианты ответа — переводы фраз, у слова — переводы слов, а предложение «в котором вы встретили слово» показывается только если оно действительно содержит это слово. Дальше слово идёт по лестнице заданий: выбор значения → карточка → перевод с русского → пропуск в предложении / своё предложение → произнести вслух. От трёх слов и больше в занятии появляется отдельный блок **«Words you looked up»**; если слов меньше — их карточки просто попадают в блок повторения и не теряются.
- **Фраза выбирается по вашему словарю, а не только по уровню** (см. «Задание не сложнее, чем вы сейчас»). Из отчёта: одно посмотренное слово приводило целое предложение **«Sorry I'm late. The traffic was terrible this morning.»** — четыре слова, которых вы ещё не учили. Теперь из фраз, где слово встречается, берётся **самая понятная**: та, в которой незнакомых слов, кроме самого изучаемого, меньше всего (и не больше двух). Если такой нет — слово учится **отдельно**, с коротким примером из слов, которые вы точно знаете («invoice — счёт · This is the invoice.»), а не в предложении, которое вы не можете прочитать. Предложение, в котором вы встретили слово, показывается ровно до тех пор, пока оно вам по силам, и возвращается, как только вы выучите слова вокруг него. Материал, подобранный раньше по старому правилу, пересматривается при каждой сборке блока — поэтому список чинится сам.
- **Где смотреть список.** **Vocabulary → My words · Мои слова**: счётчики (просмотрено / в тренировке / выучено / в очереди, «принято сегодня N из 20» и строка **«исключено автоматически: N · вернулось: M · ждут проверки: K»**), список слов с транскрипцией, переводом, числом просмотров, статусом (Queued / In training / Known / Ignored), состоянием карточки и датой следующего повторения, предложением, в котором слово встретилось, и — главное — **оценкой знания** (см. ниже). Есть поиск и фильтр: по статусу и по вердикту («Учим», «Похоже, знаете», «Знаете», «Забылось»). Кнопка **«Тренировать сейчас»** запускает короткую тренировку только по этим словам. Короткая сводка и ссылка на этот список есть на **Dashboard**, а счётчики Words looked up / Words in training / Learned from lookups / **Слов исключено автоматически** / **Слов вернулось в тренировку** — на странице **Progress**.
- **Как убрать слово.** Прямо во всплывающей карточке или в списке нажмите **«Я знаю это слово»** — слово больше не появится в занятиях. Вернуть его можно кнопкой **«Вернуть в тренировку»** (статус Ignored в списке).
- **Как отключить целиком.** **Settings → Training → «Автоматически добавлять просмотренные слова в тренировку»** (по умолчанию включено). Когда выключено, новые просмотры не записываются, а слова, которые уже тренируются, продолжают повторяться как обычно.

### Как система понимает, что вы выучили слово

Никаких жёстких «трёх правильных ответов». Система собирает **все признаки знания**, которые может наблюдать, и держит по каждому слову одну непрерывную оценку от 0 до 100 %.

| Что вы сделали | Как это влияет на оценку |
|---|---|
| Ответили правильно в задании (без подсказки, уверенно) | заметно поднимает |
| То же, но медленно / с подсказкой / «угадал» | поднимает слабее |
| Ответили неправильно | опускает |
| **Сами употребили слово** — в устном ответе, в интервью, в своём предложении | поднимает сильнее всего (учитывается не больше 2 раз в день) |
| Слово стояло у вас на экране ≥ 3 секунд, и вы **не открыли перевод** | поднимает понемногу; считается только на экранах, где вы действительно работали (отвечали, записывали, слушали, нажимали), и общий вклад ограничен |
| Слово поправил AI или локальная проверка | опускает |
| Взяли подсказку именно на этом слове | опускает |
| **Снова посмотрели перевод** | сильно опускает и **обнуляет** весь накопленный вклад «видел и не смотрел перевод» |
| Длинный интервал повторения у карточки | сам по себе считается признаком знания |

Старые события «выцветают» (вклад события падает примерно вдвое за полтора месяца), поэтому оценка отражает то, как вы знаете слово **сейчас**, а не год назад.

Рядом с оценкой система показывает **уверенность** — насколько много разных свидетельств за ней стоит (сколько событий, сколько разных типов, сколько разных дней). Чем ниже уверенность, тем бледнее полоска знания: система честно показывает, что пока догадывается.

**Вердикт** в карточке слова:

| Бейдж | Что это значит | Что происходит с тренировкой |
|---|---|---|
| **учим** | оценка ниже 70 % | обычная тренировка незнакомых слов |
| **похоже, знаете** | оценка 70 % и выше | слово тренируется реже, а в ближайшее занятие ставится **проверочное задание** |
| **знаете** | проверка пройдена и все условия выполнены | слово **исключается** из блока незнакомых слов; карточка остаётся в обычном интервальном повторении |
| **забылось** | слово считалось выученным, но оценка упала ниже 40 % | слово возвращается в тренировку, карточка становится «нестабильной» и приходит на повторение сегодня же |

**Проверочное задание.** Вместо того чтобы просто решить за вас, система проверяет себя: в занятии появляется одно короткое задание с тихой строкой **«Проверяем, помните ли вы это слово»** — без подсказок, без перевода, без счётчика просмотров, чтобы ответ действительно что-то измерял. Сразу после ответа вы видите, что он изменил: **«Слово исключено из тренировки — вы его знаете.»** или **«Оставляем в тренировке — проверим ещё раз позже.»**

**Автоисключение** происходит только когда сошлось всё сразу: оценка ≥ 85 %, уверенность ≥ 60 %, есть хотя бы один правильный ответ, есть хотя бы одно подтверждение «вы сами употребили слово» (или 5 просмотров без перевода, или стабильность карточки ≥ 21 дня), вы не открывали перевод последние 7–21 день (тем меньше, чем чаще вы употребляли слово сами) и **пройдена проверка** — кроме случая, когда карточка и так дошла до Mastered.

**Возврат в тренировку** работает в обе стороны и без задержек: одного нового просмотра перевода достаточно, чтобы слово снова стало незнакомым — счётчик «вернулось» в шапке списка и строка «возвращалось в тренировку N раз» в карточке слова показывают это честно.

**Почему именно так.** Под оценкой в списке есть до трёх коротких причин на человеческом языке: «вы 5 раз употребили это слово в своей речи», «9 раз видели и не смотрели перевод», «вчера снова смотрели перевод», «интервал повторения уже 25 дней». Там же — когда система вернётся к слову («проверка: завтра», «проверка через 14 дней»).

**Ваше слово — последнее.** Кнопки **«Я знаю это слово»** и **«Вернуть в тренировку»** всегда важнее оценки: они сделаны заметнее бейджа и отменяют любой вердикт системы.

## Сказать перевод своими словами

На карточке фразы есть **третий** способ ответить — рядом с «Проверить выбором» и «Проверить вводом» кнопка
**«Сказать перевод»**. Вы говорите (или надиктовываете, или печатаете) по-русски своими словами, что значит
английская фраза, а программа сверяет **по смыслу, а не дословно**. Это объективная проверка: вопроса «насколько вы
знали?» в ней нет вообще, а результат записывается так же, как результат двух других проверок.

Ответить можно четырьмя способами, и все они на одном экране: **«Ответить голосом»** (сказать по-русски в микрофон —
нужна многоязычная модель, см. [«Ответить голосом по-русски»](#ответить-голосом-по-русски)), **«Надиктовать»** своей
программой, **«Вставить»** из буфера обмена или просто напечатать.

Три ответа:

| Вердикт | Когда | Что дальше |
|---|---|---|
| **По смыслу верно** | вы сказали то же самое другими словами | засчитано как верный ответ |
| **Почти** | смысл вы поняли, но одного куска не хватило или он сдвинут | засчитано, но фраза вернётся раньше |
| **Не совпало** | это другое утверждение | не засчитано — и можно возразить, см. ниже |

### Что считается «тем же самым»

Сравниваются не буквы, а **значимые слова**. Перед сравнением обе фразы приводятся к общему виду: регистр, ё/е,
знаки препинания; **«12%», «12 процентов» и «двенадцать процентов» — одно и то же число**; «1 500 000» — одно число;
окончания снимаются, поэтому «выручка», «выручки» и «выручку» — одно слово, «вырос» и «выросла» — тоже. Служебные
слова (местоимения, предлоги, союзы) выбрасываются: «мы», «в», «который» не решают ничего.

**Синонимы берутся из собственного словаря приложения.** В словаре `content/glossary` у одного английского слова
часто несколько русских вариантов — `revenue` → «выручка, доход от продаж». Значит, для этой проверки «доход» и
«выручка» — одно слово, и «в этом году доход вырос» засчитывается как перевод «Revenue went up this year.». Список
таких пар **выводится из словаря автоматически** (1675 групп из 4816 слов) и проверяется тестом, а вручную
дописано только то, чего в словаре быть не может: разговорные сокращения финансиста — «кэшфлоу» = «денежный поток»,
«дебиторка» = «дебиторская задолженность», «пассивы» = «обязательства», «опекс», «капекс», «дедлайн».

**Глаголы движения — целиком.** Самая частая фраза в библиотеке — «что-то выросло или упало за период», и именно её
пересказывают свободнее всего: в отчёте «снизилась», вы говорите «упала». Словарь даёт пару-другую таких слов и
никогда всю семью, поэтому она дописана руками: упал / снизился / сократился / уменьшился, вырос / увеличился /
поднялся / прирост, резкие варианты (обвалился, рухнул, подскочил, взлетел), «не двигалось» (остался, стабильный,
неизменный) — и ещё несколько повседневных пар из этих же фраз: выручка/продажи, затраты/издержки,
задержали/опоздали. Слово «просесть» сознательно не добавлено: после снятия окончаний оно совпадает с «просить»,
которое в библиотеке встречается десятки раз.

Поэтому проходят: другой порядок слов, синонимы, пропущенные местоимения и артикли, другой вид глагола, короче или
длиннее — лишь бы утверждение было тем же. **«Прибыль снизилась в прошлом месяце» → «Прибыль в прошлом месяце
упала» — засчитывается.**

### Что не проходит никогда

Четыре правила сильнее любого процента совпадения — потому что фраза с неверным числом остаётся неверной, как бы
похоже она ни выглядела:

- **числа и проценты должны совпасть.** «на 20%» вместо «на 10%» — не совпало. Если число вы просто **не назвали**,
  это не ошибка, а неполный ответ: будет «почти»;
- **отрицание должно совпасть.** «мы закрыли месяц» вместо «мы не закрыли месяц» — не совпало. Отрицание читается и
  в английском оригинале, поэтому «We did not close the books» считается отрицательным, даже если русский перевод
  сформулирован иначе;
- **противоположное слово — не «почти», а «не совпало».** «выручка упала» вместо «выручка выросла» совпадает по всем
  словам, кроме одного, и любой процент назовёт это близким. Для направления движения, знака, размера и пар, о
  которых предупреждает сам контент (дебиторская/кредиторская, актив/пассив, прибыль/убыток, выручка/прибыль),
  ведётся короткий список противоположностей; «небольшой» как противоположность «большому» выводится автоматически.
  Список пополнен всей семьёй глаголов движения, поэтому «прибыль выросла» вместо «прибыль снизилась» отклоняется,
  каким бы словом вы ни сказали;
- **направление не должно перепрыгивать на другую строчку.** «Хотя продажи снизились, прибыль выросла» и «хотя
  продажи выросли, прибыль снизилась» состоят из одних и тех же слов, совпадение — 100 %, а сказано ровно
  противоположное. Каждое слово движения привязывается к ближайшему существительному, и если у одного и того же
  существительного направления разошлись — не совпало;
- **«кто кому» не должно переворачиваться.** «поставщик платит нам» вместо «мы платим поставщику» — не совпало.

Порог: совпадение **≥ 75 %** при выполненных правилах — «по смыслу верно»; **55–75 %** или одно недостающее слово —
«почти»; остальное — «не совпало».

**Короткая фраза считается иначе.** Процент говорит, *сколько* разошлось, и никогда — *что именно*. На трёх
значимых словах одно несовпадение — это треть, на восьми — восьмая часть, и одна и та же разница наказывается втрое
строже. Поэтому у фразы не длиннее **четырёх** значимых слов есть второй путь к «верно»: вы назвали **всё**, что
есть во фразе, и добавили не больше двух своих слов. Этот путь умеет только **признавать** то, что процент
отклонил бы, и он закрыт, пока сработало хоть одно правило выше, — поэтому направление, числа, отрицание и «кто
кому» остались ровно такими же строгими: «Прибыль выросла в прошлом месяце» и «Выручка снизилась в прошлом
месяце» по-прежнему не совпадают.

### Насколько точно это работает

Проверено на **170 парах** к **72 настоящим фразам** из библиотеки (85 переводов, которые обязаны пройти, 26 «почти»
и 59, которые обязаны быть отклонены). Оценки в этом списке проставлены **до** запуска и не переписывались под
результат.

| | было | стало |
|---|---|---|
| совпадение с человеческой оценкой | 88,8 % (151 из 170) | **98,8 %** (168 из 170) |
| точность признания («верно» действительно верно) | 91,5 % | **97,7 %** |
| полнота признания (все верные переводы признаны) | 88,2 % | **100 %** |
| верных переводов, отклонённых по ошибке | 5 | **0** |
| неверных переводов, признанных по ошибке | 5 | **1** |

«Было» — те же самые 170 пар до правок 22.09: тогда среди отклонённых по ошибке был и тот самый «Прибыль в прошлом
месяце упала».

**Где слабое место — честно.** Два расхождения, оба были и раньше:

1. если в длинном предложении вы опустили одно уточняющее слово («заявка на капитальные затраты требует
   обоснования» вместо «…экономического обоснования»), ответ всё равно пройдёт как верный, хотя заслуживает «почти»:
   при шести значимых словах одна потеря не опускает совпадение ниже 75 %;
2. переворот ролей в страдательном залоге с неодушевлённым деятелем и обратным порядком слов («независимого
   оценщика проверила переоценка» вместо «Переоценка была проведена независимым оценщиком») выглядит для всех
   правил как обычная перестановка слов. Чтобы отличить одно от другого, нужно знать, что переоценка не может
   никого проверять, — такого знания у программы нет.

Пороги закреплены тестом: если точность упадёт ниже 96 %, или неверных переводов будет признано больше одного,
сборка не пройдёт, а тест напечатает таблицу ошибок и каждую расходящуюся строку.

### Когда есть AI

Если подключён AI-провайдер, его мнение спрашивается **дополнительно**, и правило простое: **локальная проверка
всегда считает факты, AI — формулировки.**

- если числа, отрицание или «кто кому» не совпали, вердикт AI «верно» **отменяется** — это не вопрос мнения;
- если AI сам не уверен (меньше 0,5), решает локальная проверка;
- в остальном слово за AI: оценить незнакомый пересказ он умеет лучше, чем подсчёт слов;
- **каждое расхождение записывается** — в базу и в файл `meaning-disputes.jsonl`, чтобы проверку можно было
  настраивать по реальным ответам.

Сбой провайдера вы не увидите: вердикт уже есть от локальной проверки. Без AI всё работает точно так же, и под
вердиктом написано: «Проверено локально, без AI — сравнение по смыслу работает и без подключения».

### Как отвечать голосом, если модель понимает только английский

Здесь вы говорите **по-русски**, а во всех остальных устных заданиях — по-английски. Поэтому у вас, скорее всего,
выбрана английская модель (`base.en`, `ggml-small.en.bin`), а она русскую речь распознать не может в принципе и
вернёт уверенную бессмыслицу. Приложение это **само определяет** по имени модели (по метке `.en`) или по
`--language en` во внешней команде и в таком случае сразу показывает **поле для ответа вместо микрофона** — без
всякой ошибки, с одной строкой:

> Модель распознавания «small.en» понимает только английскую речь, а здесь нужно говорить по-русски. Надиктуйте
> ответ своей программой (Handy, Win+H) прямо в поле ниже или напишите его — либо выберите в Настройках
> многоязычную модель (например, `ggml-small.bin` без «.en»).

Печатать в это же поле можно всегда. Если выбран источник «Диктовка», поле и так на месте — ничего не меняется.

### Какое умение закрывается

Только **«прочитать»** — вы поняли английский текст. Не «написать» (по-английски вы ничего не писали), не
«произнести» (речь была русская, а «произнести» — это про английскую фразу) и не «выбрать вариант» (выбирать было
не из чего — в этом весь смысл проверки). Надиктовали вы ответ, сказали в микрофон или напечатали — «прочитать»
засчитывается одинаково.

### «Это тоже верно»

Если ответ отклонён, а вы считаете, что сказали то же самое другими словами, нажмите **«Это тоже верно»** — кнопка
стоит рядом с «Далее» внизу экрана. Ответ засчитается как верный, а пара «фраза — ваш перевод» сохранится: в базе и
в файле `meaning-disputes.jsonl` в папке с данными, чтобы пороги проверки можно было потом настроить по вашим
настоящим ответам.

Пока вы не решили, **попытка не записана**: нажали «Далее» — записывается промах, нажали «Это тоже верно» —
записывается верный ответ. Так у карточки не появляется провала, которого не было.

**Эталонный перевод фразы при этом не меняется.** Вы говорите «мой вариант тоже правильный», а не «ваш неправильный»,
и одно нажатие не должно портить библиотеку и все будущие сравнения с этой фразой.

## Когда вы произносите фразу вслух

Это другое упражнение — **«Произнести вслух»**: на экране английская фраза, вы её говорите, программа сверяет
распознанный текст с фразой. Раньше сверка была одна строчка — процент совпадения букв, — и она ошибалась в обе
стороны сразу: «The margin **rose** by three points» вместо «…**fell**…» отличается четырьмя буквами из тридцати
одной, набирало 87 % и засчитывалось как верно сказанная фраза, хотя смысл был перевёрнут; а Whisper, написавший
«terribly» там, где вы сказали «terrible», записывался вам в ошибку.

Теперь правило одно: **произношение прощается, содержание — нет.**

**Что прощается.** Два слова считаются одним, если они отличаются только английским окончанием («terrible» /
«terribly», «report» / «reported», «profit» / «profits») или одной буквой при одинаковом начале («rise» / «rose»).
Число, написанное словами, равно числу цифрами; «10 %» = «ten percent»; сокращение — не пропущенное слово («didn't»
= «did not»); а слово, которое распознаватель склеил из двух («cashflow» вместо «cash flow»), разбирается обратно.
Поблажка **не действует** между двумя числами и между двумя словами противоположного направления — никакая
снисходительность к произношению не может превратить «fell» в «rose».

**Что не прощается — и о чём вам прямо напишут:**

- **направление перевёрнуто** — «rose» вместо «fell», «went down» вместо «went up»; и даже если оба движения
  на месте, но поменялись местами («sales went down, but profit went up» вместо «sales went up, but profit went
  down») — во фразе есть все слова, а отчёт перевёрнут;
- **не то число** — «by 20 %» вместо «by 10 %». Число, которое вы просто не назвали, — это не ошибка, а неполный
  ответ: будет «почти»;
- **отрицание появилось или пропало**;
- **ключевые слова фразы не прозвучали** — на короткой фразе в ней нет ничего лишнего;
- **это вообще не та фраза** — от неё почти ничего не осталось.

Порог: совпадение **≥ 75 %** и покрытие фразы **≥ 75 %** — «сказано верно»; от 55 % — «почти»; ниже, либо любая
ошибка из списка — «не совпало». Покрытие считается отдельно, потому что задача — сказать **эту** фразу: две трети
фразы, сказанные безупречно, — всё-таки две трети.

Проверено на **60 расшифровках** к **30 настоящим фразам** (26 обязаны пройти — из них восемь с типичными ошибками
распознавания, 8 «почти», 26 обязаны быть отклонены). Старая проверка по буквам совпадала с человеческой оценкой на
**31 из 60** — и из 34 строк, которые она была обязана отклонить, **26 засчитала**. Новая — **60 из 60**. Оценки
проставлены до запуска; список небольшой, и тест держит его как страховку от регресса, а не как доказательство
безупречности.

## Шесть умений

Знать слово — это не одно умение, а шесть. Поэтому «выучено» ставится только тогда, когда вы умеете это слово или фразу:

| Точка | Умение | Чем проверяется |
|---|---|---|
| 1 | **прочитать** | английская фраза в задании, варианты — русские значения; **«Сказать перевод»** — сказать своими словами, что фраза значит |
| 2 | **услышать** | задания на слух: послушать и выбрать / послушать и напечатать |
| 3 | **произнести** | произнести вслух по памяти или повторить за репетитором (запись + распознавание) |
| 4 | **написать** | напечатать по-английски, вписать пропущенное слово |
| 5 | **вставить в предложение** | пропуск в предложении, своё предложение, порядок слов |
| 6 | **выбрать вариант** | узнать нужный вариант среди похожих |

**Ответ плитками закрывает другие умения.** Если перевод, пропуск или диктант собраны **из плиток** (см. «Ответ плитками»), это доказывает, что вы узнали нужные слова среди похожих и расставили их по порядку, но не что умеете их написать. Поэтому такой ответ закрывает **«выбрать вариант»** и **«вставить в предложение»** (у диктанта — ещё «услышать»), но **не «написать»**. Тот же ответ, напечатанный с клавиатуры, закрывает «написать», как раньше. Баллы начисляются по обычной таблице.

**«Сказать перевод» закрывает только «прочитать».** Вы поняли английский текст — но по-английски ничего не написали (значит, не «написать»), английскую фразу вслух не произносили (речь была русская — значит, не «произнести») и ни из чего не выбирали (значит, не «выбрать вариант»). Надиктовали, сказали в микрофон или напечатали — «прочитать» засчитывается одинаково.

**Когда умение считается закрытым.** Два правильных ответа в **разные дни**, **без подсказки**, и только в заданиях, которые проверяет программа. Самооценка «помню» не закрывает ничего — она вообще не является доказательством (см. «Часть заданий проверяет объективно»).

**Где это видно.** Рядом с фразой или словом — компактный ряд из шести точек и русская строка, что осталось:

- `✓` — умение закрыто, `◐` — начато, `○` — ещё не проверяли, `—` — недоступно на этом компьютере;
- состояние читается без цвета (значок + подсказка при наведении), а подсказка над всем рядом объясняет правило;
- под точками — строка **«осталось: произнести, написать»** или **«все шесть умений закрыты»**;
- если чего-то не хватает на компьютере, вместо требования появляется честная строка **«произношение недоступно: нет микрофона или модели распознавания речи»** со ссылкой в настройки. Такое умение помечается как «ждёт», исключается из условия «выучено» и включается обратно, как только микрофон или голос появятся.

Точки есть в **Vocabulary → Phrases** (карточка фразы, блок «Six skills · Шесть умений»), в **Vocabulary → My words** (в каждой строке слова), в **итогах занятия** (какие умения закрылись) и в **Progress** (сколько фраз закрыло каждое из шести умений и сколько фраз «почти выучено» — осталось одно умение).

**Почему одно и то же слово приходит в разных упражнениях.** Каждое упражнение закрывает своё умение, поэтому одна фраза возвращается в разных видах — и не подряд: между двумя заданиями одной фразы всегда минимум три других, а за одно занятие открывается не больше одного нового умения (остальные распределяются на другие дни). Чтобы это не выглядело случайным, в занятии видно, зачем именно это задание:

- над заданием — строка **«проверяем умение: написать — оно давно не проверялось»** (или «проверяем новое умение: …», «закрепляем умение: … — оно уже закрыто, это обычное повторение»);
- в шапке блока — одна общая строка про чередование;
- после ответа, который закрыл умение, — **«закрыто умение: написать — осталось: произнести»**;
- полное объяснение — в кнопке **«Как это работает»** наверху занятия, раздел «Почему одно и то же слово приходит в разных упражнениях».

## Ответ плитками

Пока письмо на уровне **A2+ и ниже** (уровень берётся из карты навыков), задания «напишите по-английски», «вставьте пропущенное слово» и «послушайте и напечатайте» по умолчанию отвечаются **плитками со словами**: под заданием — банк слов, в нём слова ответа и столько же (не меньше трёх) похожих, но неверных слов, всё перемешано.

- нажмите на слово — оно встаёт в строку ответа; нажмите на слово в строке — оно возвращается в банк;
- клавиши **1–9** выбирают слово по номеру, **Backspace** убирает последнее, **Enter** — проверить;
- использованное слово остаётся в банке бледным местом, поэтому номера не «съезжают»;
- ссылка **«печатать с клавиатуры»** переключает это задание на обычный ввод, а **«собрать из слов»** — обратно. Выбор запоминается для этого типа заданий **до конца занятия**. Выше A2+ по умолчанию клавиатура, и плитки можно включить той же ссылкой;
- если задание пришло именно для того, чтобы проверить умение **«написать»**, оно открывается с клавиатурой: плитки это умение не закрывают, иначе фраза никогда не стала бы выученной.

**Почему это не подсказка.** Неверные слова подобраны той же формы: та же часть речи, то же окончание (-s, -ed, -ing, -ly), похожая длина, из фраз того же трека и уровня. Среди них нет слова, которое проверка приняла бы вместо правильного (например, «costs» вместо «cost» в длинной фразе) — такое слово в банк не попадает. Порядок не угадывается по мелочам: у первого слова нет заглавной буквы, на плитках нет запятых и точек, а точка или вопросительный знак в конце фразы нарисованы отдельно. Ответ проверяется так же, как напечатанный.

**Что засчитывается.** Ответ плитками закрывает «выбрать вариант» и «вставить в предложение» (у диктанта ещё «услышать»), но не «написать» — см. «Шесть умений».

## Медленнее

Рядом с каждой кнопкой **«Послушать»** теперь есть **«Медленнее»** — та же фраза примерно в **0,7** вашей скорости (скорость голоса Windows логарифмическая: это на три шага медленнее вашей настройки в Settings, но не медленнее самого медленного).

Где: в заданиях (выбор, набор текста, диктант, говорение, «скажите вслух», разбор ответа), в блоке фразы после ответа, в карточке фразы на странице «Фразы и слова», в строках «Мои слова», у вопроса в тренажёре говорения, у образцовых ответов, в «Моих ошибках», в полосе «Перед прослушиванием», у вопроса собеседования и у последней реплики в «Живом разговоре», в CFO-историях.

Клавиши в занятии: **Space** — послушать, **Shift+Space** — медленнее (в поле ввода — Ctrl+Space и Ctrl+Shift+Space), **Esc** — остановить. Переход к следующему заданию и уход со страницы тоже останавливают озвучку. В еженедельной проверке уровня и во входном тесте кнопки «Медленнее» нет: они измеряют, а не помогают.

## Баллы

Система вознаграждения для взрослого: никаких монет, талисманов, серий и «вы всё потеряли». Баллы **только начисляются** и **ни на что не влияют**, кроме мотивации.

| За что | Сколько |
|---|---|
| правильный ответ, который проверила программа | 10 × множитель уровня (A1 0,8 → B2 1,5) |
| **первое закрытие умения** для фразы | ×2 к баллам этого ответа |
| «помню», подтверждённое объективной проверкой | +5 |
| правильно, но с подсказкой | +1 |
| ответ показан после подсказок | 0 |
| выполненный блок плана | +20 |
| завершённое занятие | +50 |
| выполненный недельный план | +100 |
| каждая записанная минута речи | +2 |

**Где видно.**

- **Итоги занятия** — «очки за занятие: 237» и короткая расшивка по источникам: *задания 96 · занятие 50 · блоки 40 · первое умение 24 · речь 24*;
- **Dashboard** — одна компактная строка «очки за неделю: 340 · уровень: Controller (от готовности 47%)»;
- **Progress** — карточка баллов (сегодня / за неделю / всего), график по дням недели, расшивка по источникам и **вклад по типам заданий**, а рядом — карьерная шкала из пяти ступеней с отметкой текущей и порогом следующей.

**Ступени карьерной шкалы** — Analyst, Senior, Controller, Head of Finance, CFO-ready — считаются от **готовности к собеседованию**, а не от баллов: 0–20 %, 20–40 %, 40–60 %, 60–80 %, 80 % и выше. Накопить баллы и «купить» ступень нельзя.

Рядом с каждым числом стоит строка **«баллы — только для мотивации, на расписание повторений и оценку знаний они не влияют»**. Это буквально так: таблица баллов не участвует ни в интервальном повторении, ни в оценке навыков, ни в оценке знания слова, ни в проценте готовности.

**Как выключить.** **Settings → Training → «Показывать баллы»** (по умолчанию включено). Когда выключено, числа просто не показываются; движок продолжает их считать, и ни расписание, ни ступень от этого не меняются.

## CFO-истории

Страница **«CFO-истории»** (бывшая Listening) — библиотека коротких рабочих сцен финансового директора на Кипре: совещание по бюджету, звонок CEO о деньгах, банк проверяет ковенант, аудитор спрашивает о резерве, вопрос совета директоров, звонок рекрутера, первый день в офисе в Лимасоле, закрытие месяца, условия оплаты поставщику и ещё три десятка. Идея взята у Duolingo Stories и подогнана под цель: вопросы стоят **внутри** истории, а сама история написана под ваш словарь.

**Библиотека.** 40 авторских историй (уровни A1+ … B1+, 6–14 реплик, 3–5 вопросов, до трёх новых слов с переводом и ударением). На карточке — название по-английски и по-русски, уровень, тема, **«понятно ~92 %»** для вас лично, строка **«новых слов: 4 — покажем их перед заданием и добавим в «Мои слова»»** и статус (новая / начата / пройдена · понято 80 %). Закрытая история говорит, почему: **«много новых слов: 24 (за раз показываем не больше 5)»**, «вопрос опирается на новое слово: covenant» или «нет перевода для новых слов: …» — открыть её всё равно можно. Фильтры по уровню и теме, «только доступные по словарю». Сверху — «Рекомендуем сейчас».

**Какая история предлагается.** Только та, что проходит словарный фильтр (§14): новых слов в ней не больше бюджета (для истории это 5), каждое из них можно показать перед заданием, и ни в одном вопросе и правильном ответе нет незнакомого слова. Среди таких — ещё не пройденная, ближе всего к вашему уровню, по теме из самых слабых навыков. Если не проходит ни одна — берётся самая дешёвая для вас не выше вашего уровня (меньше всего новых слов в вопросах, потом — меньше всего слов, которые придётся показать), её слова показываются перед историей и попадают в «Мои слова», а сам выбор пишется в лог. В ежедневном занятии блок аудирования предлагает историю раньше «сырого» диалога.

Сколько историй открыто — зависит от того, что вы уже прошли (словарь теперь считается только по доказательствам, см. §14): после 400 фраз общего трека фильтр проходят **29 из 40**, после всего трека — **35 из 40**. В самый первый день не проходит ни одна: ученик, который ещё ничего не учил, не знает ни одного из 21–69 значимых слов любой истории — поэтому в первый день библиотека предлагает самую дешёвую историю как «запасную», с показом всех её новых слов, и никогда не остаётся запертой дверью.

Самый короткий путь к библиотеке — **стартовый словарь** (см. раздел выше): его 261 слово открывают **26 из 40 историй** примерно за шесть дней. Пока курс идёт, закрытая только из-за словаря история прямо говорит «откроется после стартового словаря», а приложение проверяет это прогоном фильтра, а не обещанием.

**Как проходит история.**
- по одной реплике; каждая произносится при появлении (переключатель «Проговаривать фразу при появлении задания»), все слова интерактивные — навели, увидели перевод, щёлкнули — услышали;
- у каждой реплики — «перевод»; внизу — «Повторить» и **«Медленнее»** (≈ 0,7 скорости);
- на вопросе история **останавливается** и ждёт ответа (клавиши 1–4); неверно — короткое объяснение по-русски, правильный ответ, а реплика с ответом подсвечивается и звучит ещё раз;
- полоса прогресса по истории и закреплённая строка действий, как в занятии;
- в конце — «Понято: 80 %», новые слова из истории (если вы открывали перевод — слово уже в «Моих словах»), «Ещё раз» / «Следующая история».

Клавиши: Enter — дальше, 1–4 — ответ, Space — повторить реплику, Shift+Space — медленнее, Esc — остановить озвучку.

**Что записывается.** Каждый ответ на вопрос — объективная попытка аудирования и чтения по теме истории (бюджет, казначейство, аудит…): обновляются навыки, эффективность методов, баллы и дневная статистика, как у любого задания. Отдельно хранится прогресс по истории: начата, пройдена сколько раз, понято в последний раз и лучший результат.

**Новая история под ваш словарь.** Когда AI подключён, в библиотеке есть кнопка «Сгенерировать новую историю под мой словарь». AI получает список слов, которые вы уже выучили, и 2–3 слова, которые вы сейчас тренируете. Перед сохранением история проходит локальную проверку: понятно не меньше **90 %**, у каждого вопроса ровно один верный ответ, ответ не подсказан в самом вопросе, все реплики и вопросы переведены. Потом её проверяет второй AI-запрос. Не прошла — ничего не сохраняется, причина видна на странице. Если AI недоступен или провайдер вернул ошибку — показывается обычная панель ошибки AI с выходом в настройки.

## Еженедельная проверка уровня

Раз в неделю приложение предлагает короткую **адаптивную проверку уровня** (10–12 минут). Идея взята у Duolingo English Test: вопросы подбираются под вас по ходу теста, поэтому хватает небольшого числа вопросов.

**Когда предлагается.** Один раз в каждую 7-дневную неделю, считая от старта цели, начиная со второй недели (первая — это неделя входного теста). На «Обзоре» и «Сегодня» появляется спокойная карточка **«Проверка уровня доступна · 10 минут»**. Проверка не обязательна и ничего не блокирует: план занятий от неё не зависит, пропуск ничего не меняет — на следующей неделе карточка появится снова.

**Как проходит.** Пять разделов: лексика, грамматика, чтение, аудирование, финансовая лексика (Speaking в проверку не входит). В начале — объяснение по-русски: «Проверка измеряет, а не учит: ответы не подсказываются, пропуск дня ничего не меняет». После ответа правильный вариант **не показывается** — это измерение, а не упражнение. Есть кнопка «I don't know». В аудировании текст не показывается, запись можно переслушать 2 раза. Из урока можно выйти — ответы этой проверки просто не сохранятся.

**Какие вопросы.**
- 54 вопроса входного теста (все, кроме Speaking);
- «что означает эта фраза?» — английская фраза и четыре русских значения (общая и финансовая лексика);
- грамматика — выбор правильной формы;
- чтение и аудирование — вопросы по CFO-историям и диалогам. Текст допускается, только если его слова соответствуют уровню задания (словарный фильтр §14 «для уровня задания»: ≥ 85 % слов из фраз этого уровня и ниже, в вопросе и правильном ответе нет слов выше уровня).
- **лёгкий край чтения и аудирования** — 28 коротких текстов уровня A1 и A1+ (1–3 предложения, один вопрос, четыре варианта), по 14 на чтение и аудирование. Они написаны только из 300 базовых слов: новичок понимает не меньше 95 % каждого текста, а в вопросе и правильном ответе нет ни одного незнакомого слова. Раньше ниже A1+ в чтении не было ничего, и слабый ученик получал шесть непосильных вопросов подряд и оценку ниже шкалы.
- Всё, что вы тренировали **за последние 7 дней**, в проверку не попадает: она показывает, что вы умеете, а не что помните с карточек.
- Вопрос, который вы видели за последние 4 недели (в проверке или во входном тесте), не повторяется.
- Каждый вопрос проходит ту же проверку «можно ли решить по тому, что на экране», что и упражнения.

**Как считается.** Модель 3PL с общим наклоном и фиксированной вероятностью угадать: P = c + (1 − c) / (1 + e^(−1,7·(θ − b))), где θ — ваш уровень в разделе, b — сложность вопроса, c = 1 / число вариантов (¼ при четырёх вариантах). Смысл c: даже не зная ответа, из четырёх вариантов вы угадаете в четверти случаев. Прежняя модель Раша (1PL) этого не учитывала и принимала каждое удачное угадывание за знание — оценка слабого ученика получалась завышенной.
- Шкала θ: центр каждого уровня CEFR на расстоянии 0,6 от соседнего, B1 = 0: A1 −2,4 · A1+ −1,8 · A2 −1,2 · A2+ −0,6 · B1 0 · B1+ 0,6 · B2 1,2 · C1 1,8 · C2 2,4. Уровень — ближайший центр.
- Начальная сложность вопроса b = центр его уровня CEFR. После каждого использования она немного уточняется (шаг Эло: b ← b + η·(P − x), η = 0,08 / (1 + использований/10)), но не уходит дальше ±0,6 (один подуровень) от начальной.
- После каждого ответа уровень пересчитывается методом EAP с априорным распределением N(прошлый результат, 1). Для первой проверки «прошлый результат» — ваш уровень из карты навыков.
- Следующий вопрос — самый информативный при текущей оценке (сложность ближе всего к вашему уровню), с учётом разнообразия тем внутри раздела.
- Раздел заканчивается, когда погрешность SE < 0,45 или после 6 вопросов. На практике это почти всегда 6 вопросов: при такой модели погрешность ниже 0,45 достигается только к седьмому вопросу.

**Результат.** По каждому разделу: уровень CEFR с диапазоном точности (например, «B1 (A2+–B1+)» — это θ ± SE), изменение по сравнению с прошлой проверкой («+0.4 — выше, чем 12 сент.» или «в пределах точности»), что этот уровень значит простыми словами. Результат записывается в карту навыков как **объективное измерение повышенного веса**: вес 2 (при SE ≤ 0,45, ниже при большей погрешности, но не меньше 1,25) против 1 у обычного упражнения. Одна проверка сдвигает навык не больше чем на половину расстояния до измеренного значения, поэтому не может, например, перевести навык из A1 сразу в B2. Финансовая лексика записывается во все профессиональные навыки (с полным весом — в те, по которым были вопросы, с половинным — в остальные).

**История.** В «Прогрессе» — раздел «Weekly level check»: график уровня по каждому разделу по неделям с полосой точности и шкалой A1…C2, под ним — последняя проверка с диапазонами и изменением.

**Точность.** Шести вопросов на раздел достаточно, чтобы определить уровень примерно ± один подуровень. В симуляции (200 прогонов, ученик с известным уровнем, который **угадывает**, когда не знает, — как в жизни): ошибка ≤ 0,5 — в 60 % прогонов (71,5 % при повторной проверке через неделю), ≤ 0,6 (один подуровень) — в 81 %, ≤ 1,0 — в 90–95 %; систематического сдвига нет (−0,04…−0,06). Прежняя модель на том же угадывающем ученике давала 55 % / 64,5 % / 69 % / 83–91 % и **завышала** оценку на +0,32. (Опубликованные раньше 69 % / 76 % / 83 % были получены на ученике, который никогда не угадывает.) Для ученика уровня A1 на настоящем банке вопросов: чтение и аудирование определяются с точностью ± один подуровень в 73,5 % прогонов (раньше 54 % и 52,5 % с завышением на полуровень–уровень); если карта навыков ошибочно считает его A2 — в 71 % (раньше 33 % и 30,5 %).

## Распознавание речи: варианты

Скачивать нашу модель Whisper — **не обязательно**. Если у вас уже стоит своя программа диктовки (например, [Handy](https://github.com/cjpais/handy)) или на диске уже лежит модель, приложение умеет с ними работать. Выберите вариант в **Settings → Speech → «Источник распознавания речи»**.

| Вариант | Чем хорош | Чем платите |
|---|---|---|
| **Встроенный Whisper (скачать)** | Ничего настраивать не нужно | Один раз скачать модель (140–470 МБ) и держать её на диске |
| **Уже скачанная модель на диске** | Ничего не качаем — берём ggml-модель, которая уже есть | Нужна именно ggml-модель (`ggml-*.bin`) |
| **Внешняя программа** | Любая программа и любая модель, любая скорость | Нужно один раз настроить команду; программа запускается на каждый ответ |
| **Диктовка (Handy, Win+H)** | Ничего скачивать и настраивать не нужно | Приложение не слышит запись: произношение и темп речи **не измеряются** |

Во всех вариантах, кроме внешней программы, голос остаётся на компьютере. Внешняя программа — это ваш выбор: приложение передаёт ей только WAV-файл и не знает, что она делает дальше.

### Если у вас уже стоит Handy

Handy — это локальная диктовка по горячей клавише: вы удерживаете клавишу, говорите, и программа сама вставляет текст в активное поле. Своего API она не предоставляет, поэтому есть два пути — и оба работают.

**Путь 1 (проще всего) — «Диктовка».** Выберите четвёртый вариант. Везде, где ждут устный ответ, появляются три
одинаковые кнопки — **«Надиктовать»**, **«Вставить»** и **«Готово»** — и поле ответа под ними:

- **курсор встаёт в поле сам**, как только задание появилось. Под полем прямо написано, где он: «Курсор в поле —
  можно диктовать». Пока поле в фокусе, у него подсвеченная рамка;
- вы удерживаете свою горячую клавишу Handy, говорите по-английски, отпускаете — текст оказывается в поле, и справа
  появляется **«Текст получен: N символ(ов)»**;
- если ваша программа кладёт текст в **буфер обмена**, а вставить его не смогла, приложение подхватывает его само
  (пока поле пустое) — или нажмите **«Вставить»**. **Ctrl+V работает в любом месте задания**, даже если курсор не в
  поле: текст всё равно попадёт в поле ответа;
- **Enter** в этом поле — это и есть «Готово» (Shift+Enter оставляет перенос строки, если реплик несколько).

Скачивать и настраивать не нужно ничего.

> **Если горячая клавиша уводит фокус.** Handy вставляет текст в то окно, которое активно в момент нажатия, — а её
> собственная панель фокус забирает, и вставка уходит мимо. Поэтому приложение **следит за буфером обмена всё время,
> пока задание на экране, даже когда окно неактивно**: как только там появляется новый текст, он попадает в пустое
> поле ответа сам. Если вы уже что-то написали, ваш текст не затирается — приложение предложит нажать «Вставить».
> Под полем прямо написано, активно ли окно и куда сейчас попадёт текст. После прослушивания фразы курсор
> возвращается в поле сам.

> Если что-то не доходит — **Settings → Speech → «Проверка диктовки»**. Панель показывает по шагам, что именно
> случилось: попал ли курсор в поле, доходят ли до приложения нажатия клавиш, работает ли слежение за буфером обмена
> (и сколько раз оно уже сработало), есть ли текст в буфере и сколько символов реально пришло, — и одной строкой
> говорит, что с этим делать. Можно специально переключиться в другое окно, продиктовать там и посмотреть, как текст
> приходит.

> Если вместо «Диктовки» выбран микрофон, а он занят Handy, приложение так и пишет: «Микрофон сейчас занят другой
> программой… Можно не закрывать её: нажмите «Надиктовать» и продиктуйте ответ той же программой» — вместо
> прежнего молчаливого таймера 00:00.

Что при этом **не измеряется** (и честно помечается как «не измерено», а не выдумывается):

- произношение (оно считается по уверенности распознавания — записи нет);
- темп речи (слов в минуту) и паузы;
- слов-паразитов в минуту (само количество слов-паразитов в тексте по-прежнему считается);
- беглость и уверенность.

Грамматика, лексика, содержание, структура и то, насколько ответ отвечает на вопрос, оцениваются как обычно. И одно важное следствие: **надиктованный ответ не закрывает умение «произнести»** (§13 «Шесть умений») — приложение не слышало, как вы это сказали. Умение показывается как «недоступно», не блокирует остальное и снова включится, как только вы выберете источник с записью.

**Путь 2 — взять модель Handy и распознавать у себя.** Handy хранит модели в `%APPDATA%\com.pais.handy\models` и пользуется общим кэшем Hugging Face (`%USERPROFILE%\.cache\huggingface\hub`). Выберите вариант **«Уже скачанная модель на диске»** — приложение само просмотрит обе папки (и свою папку моделей) и покажет, что нашло: имя файла, размер и откуда он. Нажмите «Выбрать» — модель сразу проверяется: приложение синтезирует короткую английскую фразу, загружает модель, распознаёт её и показывает результат и время.

> **Важно:** приложение распознаёт через Whisper.net (whisper.cpp), а он читает **только ggml-файлы вида `ggml-*.bin`**. Если Handy скачал Parakeet или Moonshine (`.gguf`, `.onnx`, `.nemo`), такой файл тоже будет показан в списке — но помечен как «не подходит», с объяснением почему. Тогда либо скачайте ggml-модель (`ggml-base.en.bin` ≈ 140 МБ, `ggml-small.en.bin` ≈ 465 МБ), либо используйте эту модель через вариант «Внешняя программа» или «Диктовку».

### Ответить голосом по-русски

Одно задание в приложении ждёт ответа **по-русски** — «Сказать перевод» (см. раздел ниже). Английская модель для него
не годится: файл с тегом `.en` (`base.en`, `ggml-small.en.bin`) русскую речь не распознаёт **в принципе** — он вернёт
уверенный английский текст, не имеющий отношения к сказанному. Поэтому для русского используется **вторая,
многоязычная модель**, и переключается она сама, по языку ожидаемого ответа: английские задания — английская модель,
«Сказать перевод» — многоязычная.

В задании «Сказать перевод» появляется кнопка **«Ответить голосом»** — над обычной группой «Надиктовать / Вставить /
Готово», а не вместо неё. Нажали, сказали по-русски своими словами, нажали ещё раз — приложение распознаёт локально и
проверяет смысл.

- **Модель нужна одна** — **Settings → Speech → «Модель для русской речи» → `base` (≈ 142 МБ)**, одна кнопка Download.
- **Может и не понадобиться:** нажмите **«Найти на диске»** — приложение просмотрит свою папку моделей, папку Handy и
  кэш Hugging Face. Любая ggml-модель без `.en` в имени (`ggml-base.bin`, `ggml-small.bin`, `ggml-large-v3.bin`)
  подойдёт, качать ничего не нужно.
- **Пока модели нет**, кнопка остаётся на месте и одной строкой говорит, что скачать, а ответить можно диктовкой или
  с клавиатуры — как раньше.
- **Если распознанный текст оказался латиницей**, ответ **не засчитывается**: это значит, что распознавала английская
  модель, и такая запись ничего не говорит о ваших знаниях. Приложение так и пишет, вместо того чтобы записать промах.

### Внешняя программа

Приложение записывает WAV и запускает вашу команду. Пример:

```
whisper-cli.exe -m C:\models\ggml-small.en.bin -f {input} --output-txt --language en
```

- `{input}` — путь к WAV-файлу записи, подставляется автоматически.
- `{output}` — путь к временному `.txt`, откуда приложение прочитает текст. Если `{output}` в команде нет, читается то, что программа напечатала в консоль.
- Пути с пробелами и кириллицей заключаются в кавычки автоматически.
- Можно задать **рабочую папку** и **таймаут** (по умолчанию 60 секунд). По таймауту процесс принудительно завершается вместе с дочерними — зависшая программа не заблокирует занятие.
- Кнопка **«Проверить»** запускает команду на тестовой записи и показывает распознанный текст и время. Если не получилось — код возврата и сообщение самой программы (stderr).

Источник считается готовым **только после успешной проверки**. Если вы поменяли команду, рабочую папку или таймаут, проверку нужно пройти заново.

### Живой разговор

Живой голосовой разговор (Conversation) работает с первыми тремя вариантами. В режиме «Диктовка» он честно переключается на **разговор по очереди с набором текста**: приложение не слышит вас и не может само закончить вашу реплику по паузе, поэтому вы надиктовываете реплику своей горячей клавишей и нажимаете «Отправить». Собеседник по-прежнему говорит голосом, стенограмма и отчёт — такие же. Страница пишет об этом прямо, а не делает вид, что слушает.

## Что будет в Phase 2–3

- **Phase 2:** режимы скорости и акцентов для аудирования, оценка произношения, CFO Cases как отдельный режим, анализ вакансии и CV, режим Career, оптимизация стратегии.
- **Phase 3:** синхронизация с мобильным приложением, облачный профиль, живой разговор и интервьюер в реальном времени, симуляция рекрутера.

Страницы CFO Cases и Career уже есть в меню. Они показывают, что появится, и превью контента.

## Известные ограничения

- Реальные микрофон (NAudio), распознавание Whisper, голоса Windows и запросы к AI-провайдерам проверяются только вручную. В `--e2e` они заменены заглушками, в тестах используются поддельные HTTP-ответы.
- Без облачного AI оценка устной речи приблизительная. Локальная эвристика смотрит на длину, ключевые фразы и темп, но не на смысл, поэтому хорошо оформленный ответ может получить завышенную оценку.
- Кнопка «Open Settings» в рекордере во время входного теста открывает Settings, и меню снова появляется. Через Dashboard → Take baseline тест продолжится с того же места, но только пока приложение открыто. Если так уйти с onboarding, мастер откроется снова при следующем запуске.
- В режиме «Диктовка» произношение, темп речи, паузы и слова-паразиты в минуту не измеряются — записи нет. Они помечены как «не измерено» и не участвуют в оценке, а умение «произнести» остаётся незакрытым, пока вы не ответите с записью (любой из трёх других источников).
- Приложение не управляет вашей программой диктовки и не знает её горячую клавишу: оно только ставит курсор в поле. Если Handy настроен вставлять текст не в активное поле, текст не появится — проверьте его настройки.
- Сверка перевода по смыслу ошибается примерно в 1 случае из 100 (измерено на 170 парах). Два известных случая: если в длинном предложении опущено одно уточняющее слово, ответ пройдёт как верный, хотя заслуживает «почти»; и переворот ролей в страдательном залоге с неодушевлённым деятелем («переоценка проверила оценщика») не распознаётся — для этого нужно знать, кто вообще может что-то делать. Верных переводов проверка не отклоняет (0 из 85), а если всё же отклонит — есть кнопка «Это тоже верно» (см. «Сказать перевод своими словами»).
- Сверка сказанной вслух фразы понимает направление, числа и отрицание, но не синонимы: «revenue rose this year» вместо «revenue went up this year» — это «почти», а не «верно». Задание называется «произнести вслух эту фразу», а не «пересказать её», поэтому так и задумано; пересказ своими словами проверяет «Сказать перевод».

## Первый запуск

1. **Onboarding.** Укажите имя, целевую роль и время тренировки в день.
2. **Стартовый словарь.** Экран рассказывает про курс первых дней: 261 самое частое слово, порциями по 25, около 15 минут в день из ваших 75, примерно 6 дней — и после него открываются истории и диалоги (числа считаются под вашу норму и по реальной библиотеке). Кнопка **«Пропустить»** есть, и рядом сказано, чего пропуск стоит. См. раздел [«Стартовый словарь — первые дни»](#стартовый-словарь--первые-дни).
3. **Приватность.** Переключатель **Allow cloud AI processing** (Settings → Privacy):
   - когда он выключен, тексты ответов никуда не отправляются, а оценка речи работает в упрощённом локальном режиме;
   - когда включён, расшифровки ответов уходят выбранному AI-провайдеру;
   - голосовые записи не покидают компьютер в любом случае.
4. **AI-провайдер** (Settings → AI providers):
   - **Anthropic (Claude)**: выберите провайдера, вставьте API-ключ из console.anthropic.com, нажмите **Save key**, выберите модель и нажмите **Make active**;
   - **OpenAI** и **OpenRouter** настраиваются так же (ключи на platform.openai.com и openrouter.ai);
   - **Свой провайдер**: **Add provider** → пресет (Groq, DeepSeek, Mistral, Ollama, LM Studio) или любой OpenAI-совместимый Base URL. Список моделей можно подтянуть кнопкой **Fetch models from API**;
   - кнопка **Test connection** проверяет ключ и модель;
   - ключи шифруются Windows DPAPI и никогда не показываются повторно;
   - локальные провайдеры (Ollama `http://localhost:11434/v1`, LM Studio `http://localhost:1234/v1`) работают без ключа и без облачного разрешения.
5. **Распознавание речи** (Settings → Speech) — см. раздел [«Распознавание речи: варианты»](#распознавание-речи-варианты):
   - выберите **источник распознавания**. Если у вас уже стоит Handy или другая диктовка — берите «Диктовку» или «Уже скачанную модель на диске», качать ничего не нужно;
   - для встроенного Whisper выберите модель: `tiny.en` (~75 MB, быстрая), `base.en` (~142 MB, рекомендуется) или `small.en` (~466 MB, точнее), и нажмите **Download**;
   - если хотите **отвечать голосом по-русски** в задании «Сказать перевод» — там же, ниже, **«Модель для русской речи»**: нажмите «Найти на диске» (вдруг подходящая уже есть) или скачайте `base` (≈ 142 МБ). Без неё задание работает как раньше — диктовкой или с клавиатуры;
   - проверьте микрофон кнопкой **Record 3 seconds**, а голос — кнопкой **Test voice**.
6. **Baseline.** Пройдите входной тест (20–30 минут), после него откроется Dashboard.

## Где хранятся данные

`%LOCALAPPDATA%\EnglishForCfo\`:

| Путь | Что внутри |
|---|---|
| `app.db` | SQLite: профиль, прогресс, ответы, ошибки, сессии, настройки, AI-провайдеры (схема через EF Core Migrations) |
| `recordings\` | записи голоса (WAV) |
| `models\` | модели Whisper |
| `logs\` | журналы `app-yyyyMMdd.log`, `selfcheck.log`, `e2e.log` и скриншоты проверок `selfcheck\`, `e2e\` |
| `meaning-disputes.jsonl` | спорные проверки смысла: ваши нажатия «Это тоже верно» и расхождения AI с локальной проверкой — по одной JSON-строке, чтобы пороги можно было настроить по настоящим ответам (см. «Сказать перевод своими словами») |
| `notifications.json` | когда последний раз показывались напоминания |

Папку открывает кнопка **Settings → Data → Open data folder**. **Reset progress** удаляет прогресс, но сохраняет настройки и провайдеров.

Если база была создана старой сборкой без миграций, при запуске она копируется в `app.db.bak-<дата>` и создаётся заново.

## Структура проекта

```
EnglishForCfo.sln
src/
  EnglishForCfo.Core/    домен, абстракции, Learning Engine (SRS, адаптация, стратегия, навыки, готовность) — чистый C#
  EnglishForCfo.Data/    EF Core + SQLite, репозитории, миграции (Migrations/), импорт контента из content/
  EnglishForCfo.AI/      провайдеры LLM (Anthropic, OpenAI-совместимые), AiGateway, оценка речи, интервьюер, AI Tutor, промпты
  EnglishForCfo.Speech/  запись (NAudio), Whisper.net (локальное STT), голоса Windows (TTS), загрузка моделей,
                         поиск готовых моделей на диске, запуск внешней программы распознавания
  EnglishForCfo.App/     WPF (WPF-UI Fluent, MVVM CommunityToolkit, Generic Host)
    App.xaml(.cs)        запуск: один экземпляр, обработка ошибок, заставка, миграции, --selfcheck, --e2e
    MainWindow.xaml      оболочка: заголовок, переключатель темы, навигация
    Themes/              Typography.xaml, Controls.xaml (стили, отступы, конвертеры)
    Controls/            общие контролы: SkillBar, StatCard, TargetBar, ScoreBreakdown, ListenButton,
                         RecorderControl, AiUnavailableBanner, EmptyState, PhaseTwoPlaceholder
    Services/            AppServices (DI), PageRegistry, AppNavigator, AppDialogs, ProfileService,
                         AppThemeService, NotificationService, ViewModelBase, SelfCheck, FileLogger,
                         EndToEndCheck + EndToEndFakes (только для --e2e)
    Views/<Feature>/     страница + её ViewModel (Dashboard, Today, Session, Vocabulary, Speaking,
                         Interview, MyMistakes, Progress, Listening, Cases, Career, Settings, Onboarding, Baseline,
                         LevelCheck — еженедельная проверка уровня; её IRT-ядро — Core/Engine/LevelCheck/)
tests/
  EnglishForCfo.Tests/   xUnit: движок, данные, миграции, AI, контент
content/                 JSON-контент: фразы, грамматика, вопросы интервью, кейсы, диалоги, baseline
docs/                    SPEC.md (решения и контракты), TZ.md (техническое задание), TICKETS.md
```

Новая миграция после изменения модели данных:

```powershell
dotnet tool restore
dotnet ef migrations add <Name> --project src/EnglishForCfo.Data --startup-project src/EnglishForCfo.Data
```
