diff --git a/doc/call_audit_findings.txt b/doc/call_audit_findings.txt index 9c207c8e..04427910 100644 --- a/doc/call_audit_findings.txt +++ b/doc/call_audit_findings.txt @@ -1,7 +1,8 @@ Аудит src/call — 26.10.2026, начат с голосовых вызовов -Статус: подтверждён дефект допуска второго исходящего звонка. Реализация не -менялась; аудит остановлен перед её исправлением по правилу AGENTS.md. +Текущий статус: дефект допуска второго исходящего звонка исправлен после +согласования. Штатная регрессия и четыре C++ voice-набора PASS; полный check +выполняется. Разделы1–4 сохраняют историю диагностики, внедрение — в разделе5. Полная проверка аудио, видео и платформенных разделов не завершена. База проверки: f79b9261, чистое рабочее дерево после предыдущего push stream. @@ -118,3 +119,71 @@ FAIL ожидаемо. C/C++ реализации и штатные тесты Неизменность C-токенов всех21 call-заголовков относительно начала аудита, отсутствие правок C/C++ реализаций/lib/tests от f79b9261, diff --check и итоговые отметки чек-листа PASS: /tmp/call-audit-contract-check.log. + +5. Исправление допуска и штатная регрессия — 26.10.2026 + +call_start до создания session, CM и INVITE проверяет: +- ненулевые peer/id и остальные обязательные аргументы, с ERROR контекста; +- уже зарегистрированный ID, включая ENDED: WARN без событий/изменений записи; +- любую обычную сессию state!=ENDED: ENDED/BUSY только для нового ID, INFO + с requested/busy ID, исходным ch, peer и состоянием занятого звонка; +- прежнюю pending radio invitation — по существующему правилу. + +Для проверки обычной занятости используется тот же предикат, что в call_busy +и входящем INVITE. Один проход даёт также запись/состояние для точного лога; +дополнительного boolean-прохода и нового API поиска не добавлено. Всё выполняется +в одном uasync-потоке до первого изменения состояния, межпоточной гонки допуска нет. +Завершённые записи с таймерами END_ACK не блокируют новый уникальный ID. +Не изменены wire, таймеры/состояния, входящая политика и аудиопроцессинг. + +Добавлен tests/test_call_admission.c и цель Autotools, включённая в общий check. +Fixture test_call используется в отдельном процессе: два реальных ядра, +CHAT/Merkle/BGP/ETCP/router/CM и DM. Для проверки рации дополнены настоящие +join/update/tree подписи участников через member_sync, без прямого изменения БД. +Тест получает все состояния штатным сигналингом, вручную их не присваивает. +Observers --wrap=conn_mgr_open/etcp_route_send считают реальные вызовы и передают +их исходным функциям; только END_ACK намеренно удерживается для проверки ENDED. + +Покрыты caller OUTGOING и обе роли RINGING/ACTIVE/WAIT_DECISION (7 сочетаний): +повтор собственного ID, коллизия того же ID с другим tuple, новый ID через CHAT/DM +и другой ch/peer до проверки его доступности. Вторую существующую CHAT-группу +и третье физическое ядро тест не создаёт: проверяется общий допуск instance +до поиска группы/пира, а не маршрутизация к этим дополнительным назначениям. + +Во всех отказах проверяются отсутствие новых session/CM/INVITE и started, +сохранение исходного состояния/роли/CM/очереди/таймеров/seq. BUSY приходит ровно +для нового ID; дубликат не даёт событий. Дополнительно проверены: +- нулевые peer/id без создания записей и ложных событий; +- двусторонние закодированные Opus-кадры после всех ACTIVE-отказов через реальный + router, прежний ETCP остаётся UP; это не запуск микрофона/PCM-вывода; +- повтор старого ID после ENDED без ложного события; новый звонок при ещё живом + старом tombstone, с последующим PHONE_BUSY/CONTINUE той же попытки; +- рация отклоняется при обычном звонке, обычный звонок — при pending radio invitation; +- нормальный новый звонок/decline после завершения приглашения и полная очистка. + +Финальная регрессия:547 assertions,22 BUSY,18 отказов без события, +audio_RX1/1, allocations0->0, exit0. Лог /tmp/call-admission-fix-regression.log. +Сборка ./build.sh --no-gui -j4 PASS: /tmp/call-admission-fix-build.log; +после уточнения fixture целевая сборка PASS: /tmp/call-admission-regression-build.log. +Первый прогон остановился на рации: старый fixture не имел tree-подписей; +radio=info показал rc_group invalid member и UNAVAILABLE. Исправлен только +fixture, требования проверки членства в production не ослаблялись. + +Первоначальный диагностический стенд пересобран с исправленной штатной libutun: +те же5 сценариев теперь PASS, exit0, live1->1, second_created0/CM0, +исходная сессия сохранена, started не меняется, allocations0->0. +Логи /tmp/call-admission-original-{outgoing,ringing,active,incoming,wait_decision}.log, +сборка /tmp/call-admission-original-build.log. Логи прочитаны полностью. + +Отдельная штатная CMake-сборка /tmp/utun4-call-admission-gui: +test_call_jitter, test_call_delay, test_call_timeline и test_voice_tx4/4 PASS. +Это реальные Opus/SoundTouch/voice-компоненты с существующими тестовыми +обвязками, без аппаратного GUI/Android-звонка. Configure/build: +/tmp/call-admission-gui-configure.log, /tmp/call-admission-gui-build.log; +ctest: /tmp/call-admission-voice-tests.log (3,01с). + +Полный check.sh запущен от user в отдельном IPv6 network namespace: +/tmp/call-admission-full-check.log и /tmp/call-admission-netns.log. +Настройки сети хоста не меняются. Итог будет записан после завершения. +Исправление285a60bf; тестcfc8d801 и уточнение fixture8eb3d102. +Полнота аудита пока прежняя:0[V]/4[~]/17[ ], архитектурный документ[~]. diff --git a/doc/chat_call_arch.md b/doc/chat_call_arch.md index bc175ab9..ee4b5df2 100644 --- a/doc/chat_call_arch.md +++ b/doc/chat_call_arch.md @@ -3,10 +3,12 @@ Статус: реализовано. Звонок использует роутер, CM подготавливает оптимальный путь. Статус аудита 26.10.2026: проверка начата с голосовой сигнализации, call.c прочитан целиком. -Подтверждён дефект исходящего допуска: call_start не проверяет call_busy и при существующем -OUTGOING/RINGING/ACTIVE/WAIT_DECISION создаёт вторую незавершённую сессию и CM handle. -Воспроизведено на двух настоящих ядрах в пяти сценариях, включая входящий RINGING. -Реализация ещё не исправлена; аудит остановлен по AGENTS.md перед изменением кода. +Выявленный дефект исходящего допуска исправлен: call_start отклоняет новую попытку при любой +незавершённой обычной сессии или приглашении рации до создания session/CM/INVITE. +Новый ID получает ENDED/BUSY; уже зарегистрированный ID, включая ENDED до очистки, +отклоняется без событий, чтобы отказ не завершил прежний звонок. Новый уникальный ID после ENDED разрешён. +Штатный test_call_admission на двух настоящих ядрах проверяет состояния обеих сторон, +повторы ID, CHAT/DM, сохранение первого звонка/аудиоприёма, ENDED и взаимодействие с рацией. Полная сверка аудиостека, видео и платформенных разделов не завершена. Доказательства и вариант исправления: [call_audit_findings.txt](call_audit_findings.txt).