# Changelog ## 2026-09-12 — этап 15 одиннадцатого аудита (fix audit-14) Устранены остаточные расхождения одиннадцатого статического аудита (Git HEAD 9349164): игнорирование отказа снятия checkpoint.marker в основном экспорте, повторная выдача новой сессии каталога с частичным остатком прерванного экспорта (только samples/events) и остаточная принудительная перерисовка при клике по чужому объекту графика внутри открытого измерительного окна. Прежние 126 условий проходят; новая регрессия этапа 15 (SESS-03): RequestLatencyTests PASS=127 FAIL=0 TOTAL=127, сборка 4 exe 0 errors / 0 warnings. - R15-B1 (P1): ExportRun проверяет результат FileDelete при инвалидации checkpoint.marker (как ExportCheckpoint) — при отказе пара samples/events НЕ открывается на перезапись, экспорт повторяется на таймере; результатом удаления является false (MQL5 FileDelete [D1]). - R15-B2 (P1): NewSessionId считает каталог занятым по ЛЮБОМУ известному файлу отчёта сессии (SessionDirUsed: samples/events/schedule/deals/summary/ histogram/offset_signs/comparisons/market_windows/market_ticks/checks/ experiment_manifest), а не по трём служебным именам — частичный остаток прерванного экспорта не маскируется новой сессией. - R15-S1 (P2): клик по чужому объекту графика в OnChartEvent не вызывает принудительную перерисовку внутри открытого окна измерения (тот же безопасный режим, что в ветви занятого Start). ## 2026-09-12 — этап 14 десятого аудита (fix audit-13) Устранены расхождения десятого статического аудита (Git HEAD 148e7a7): повторное использование каталога сессии LOCAL_ONLY, действующий marker после повреждения пары основных файлов экспортом и остаточная принудительная перерисовка внутри отдельных открытых окон. Прежние 123 условия проходят; новые регрессии этапа 14 (SESS-01, SESS-02, WIN-02): RequestLatencyTests PASS=126 FAIL=0 TOTAL=126, сборка 4 exe 0 errors / 0 warnings. - R14-B1 (P1): идентификатор запуска отделён от измерительной шкалы — NewSessionId выдаёт каталог по МОНОТОННОМУ счётчику сессий (курсор не сбрасывается между вызовами) с проверкой существования каталога с данными сессии (intents/manifest/checkpoint.marker): переустановка EA и повтор после отказа первого INTENT получают НОВЫЙ session_id, перезапись прежнего отчёта исключена; при исчерпании кандидатов — ошибка до записи/торговли. - R14-B2 (P1): финальный marker публикуется ТОЛЬКО после полной записи и контрольного чтения всей таблицы экспорта (единый PublishCheckpointMarker); основной экспорт инвалидирует опубликованный marker ДО перезаписи пары samples/events — обрыв между стадиями не оставляет действующий «успех» над повреждённой парой. - R14-S1 (P2): InMeasurementWindow учитывает и активный cleanup (не только основную последовательность); отклонённый клик восстанавливает нажатый вид кнопки БЕЗ принудительной перерисовки внутри открытого окна (ChartRedraw откладывается до паузы). ## 2026-09-12 — этап 13 девятого аудита (fix audit-12) Устранены остаточные расхождения девятого статического аудита (Git HEAD 37b3090): сохранность незавершённого синтетического прогона, единый gate финализации, изоляция окон повторной E3-сессии, проекция состояния панели из контроллера и запрет принудительной перерисовки внутри измерительного окна. Прежние 119 условий проходят; новые регрессии этапа 13 (START-03, START-04, RESTART-01, CHECK-01): RequestLatencyTests PASS=123 FAIL=0 TOTAL=123, сборка 4 exe 0 errors / 0 warnings. - R13-B1 (P1): отказ SyntheticDispatch (durable-запись INTENT/SEND_RETURN) больше НЕ стирает контекст незавершённой сессии — RunSynthetic финализирует её (FINISHED + termination_reason SYNTHETIC_DURABLE_WRITE_FAILED), StartRun возвращает true и направляет вызывающий код в экспорт частичного отчёта (run_status=INCOMPLETE); резерв ДО T0 снимается (ReleaseReservation) — он не является выполненным наблюдением; прерванная после T1 запись сохраняется как DISPATCH_UNCERTAIN; ExportRun/ExportCheckpoint гарантируют каталог сессии (FolderCreate) даже при отказе на первом INTENT. - R13-B2 (P1): финализация — ЕДИНЫЙ проверяемый результат: FinalizeRun() требует успешный финальный checkpoint (ExportCheckpoint(true) возвращает bool и подтверждает marker контрольным чтением) И основной экспорт; повторяется именно неуспешная стадия; FINISHED и разблокировка кнопки только после полного набора. Иные завершения (DriveNext/EndMainCycle) используют ту же финализацию — marker обязателен для любого пилота. - R13-B3 (P1): ResetForRestart и StartRun очищают оконный контекст E3 прежней сессии (m_windows/m_window_count, счётчики и недописанные оконные ссылки) — старые окна не выгружаются в market_windows.csv новой сессии с её session_id. - R13-S1 (P1): панель хранит НАМЕРЕННОЕ состояние кнопки (m_started) и RestoreStartedState() восстанавливает нажатый вид после того, как OBJ_BUTTON сам переключил OBJPROP_STATE при отклонённом клике; терминальный BLOCKED отображается сразу (без зависимости от latch команды) и запрещает торговлю. - R13-S2 (P1): SyncPanelPhase не вызывает ChartRedraw внутри открытого измерительного окна (обновляется только текст панели; отрисовка — в паузе). ## 2026-09-12 — этап 12 восьмого аудита (fix audit-11) Исправлены четыре группы функциональных расхождений восьмого статического аудита (Git HEAD 9465fe6): повторный запуск с накопленными счётчиками/пропуском экспорта, двойной старт одного клика (timer + OBJECT_CLICK), ложный FINISHED при ошибке сохранения и зависимость финального checkpoint от 60-секундного порога. Прежние 117 условий проходят; новые регрессии этапа 12 (RUNN-01, START-02): RequestLatencyTests PASS=119 FAIL=0 TOTAL=119, сборка 4 exe 0 errors / 0 warnings. - R11-B1 (P1): повторный запуск после финализации — независимые счётчики прогона (CExperimentRunner::Init обнуляет MainDispatched/WarmupDispatched/CleanupDispatched/ PrecheckRejected/DispatchUncertain), ExtExportDone сбрасывается перед StartRun; вторая сессия получает полный комплект отчётов (manifest/summary/market_ticks), а не накопленные 400/40. Регрессии RUNN-01, START-02. - R11-B2 (P1): один физический клик = один StartRun — независимый опрос OBJPROP_STATE для запуска убран (источник истины — latch ExtStartPressed, выставленный синхронно в OnChartEvent, потребляется таймером ровно один раз); двойной клик и клики во время прогона игнорируются и не отменяют текущую сессию. - R11-B3 (P1): ошибка экспорта не маскируется под FINISHED — пока отчёт не сохранён, кнопка остаётся нажатой/заблокированной, повторный запуск запрещён, статус EXPORT_FAILED с повторной попыткой на таймере; ResetForRestart разрешён только после успешного экспорта. - R11-S1: финальный checkpoint отделён от периодического — ExportCheckpoint(force) пишет маркер всегда (короткий пилот не зависит от порога 60 с синтетического времени); ошибка SyntheticDispatch (durable-запись) теперь возвращает StartRun=false и состояние READY вместо ложного FINISHED с неотправленными резервами. - Панель: SyncPanelPhase — статус фазы WARMUP/MAIN обновляется со счётчиками диспетчеризации при смене фазы (лёгкая перерисовка только при изменении). ## 2026-09-12 — этап 10 седьмого аудита (fix audit-10) Устранены четыре группы функциональных расхождений седьмого статического аудита (Git HEAD a281c07): потеря ручного Start, неверное восстановление повторного INTENT после отмены, раннее закрытие cleanup без ожидаемых DEAL-callback и повреждённый формат архива тиков E3. Прежние 65 контрольных условий проходят; новые регрессии этапа 10: RequestLatencyTests PASS=117 FAIL=0 TOTAL=117, сборка 4 exe 0 errors / 0 warnings. - R10-B1 (P1): ручной Start захватывается СИНХРОННО в OnChartEvent (latch команды), а не опросом OBJPROP_STATE в OnTimer - клик больше не теряется. Кнопка остаётся нажатой/заблокированной весь прогон (CLatencyPanel::SetStarted), в Status выводятся фаза и итог; после финализации кнопка отпускается и работает повторный запуск (CAppController::ResetForRestart FINISHED->READY, новая сессия) либо ExpertRemove оператором. Терминальный BLOCKED также отпускает кнопку и показывает причину. Регрессия START-01. - R10-B2 (P1): CountUncertainDurableIntents сопоставляет INTENT_CANCELLED РОВНО с одной попыткой того же sequence (хронологическая пара, массив cancel_used): повторный INTENT после отмены без SEND_RETURN остаётся неопределённым (n_dispatch_uncertain+1); прежняя отмена не маскирует новую попытку. Регрессии DURA-09 (cancel->retry->crash => 1) и DURA-10 (cancel->retry->SEND_RETURN => 0). - R10-B3 (P1): DriveCleanup принимает решение о закрытии коллекции cleanup по СВЕЖЕЙ сверке (snapshot + SyncReconcile + CompletedCheck ДО условия закрытия) по единой политике CompletedCheck: измерительные точки полны И полнота DEAL-callback (T4/T5/callback_coverage_complete) подтверждена для операций с ожидаемой сделкой (POSITION_CLOSE); PENDING_DELETE без сделки DEAL не ждёт; неполноту закрывает grace. Вспомогательный предикат CleanupCollectionReady. Регрессия CLN-02. - R10-B4 (P1): FlushWindowTicks пишет market_ticks.csv с ЗАГОЛОВКОМ (session_id,window_id,window_seq,time_msc,bid,ask,flags,volume) при создании/пустом файле; разделитель строк - НАСТОЯЩИЙ CRLF (вместо литерального текста \r\n); точность bid/ask - %.17g (полный round-trip double). Для каждой сессии гарантируется наличие файла с заголовком (EnsureMarketTicksFile в ExportRun); сбой записи - fail-closed. Статические форматтеры MarketTickHeader/FormatMarketTickLine выделены для round-trip теста. Регрессия WINDOW-02. - R10-S1 (P1): SyntheticDispatch формирует СОГЛАСОВАННЫЙ объём DEAL-callback - единственная сделка полного объёма плана (T4=T5); дубль deal с нулевым объёмом не создаёт рассогласование callback_volume/coverage. Локальный прогон пишет устойчивый журнал намерений (INTENT до T0, SEND_RETURN после T1) - intents.csv сессии существует и CountUncertainDurableIntents работает и на LOCAL_ONLY (критерии пилота: intents.csv, checkpoint.marker, market_ticks.csv). - Тесты: TestAudit10Regressions (DURA-09, DURA-10, CLN-02, WINDOW-02, START-01). ## 2026-09-11 — этап 9 шестого аудита (fix audit-9) Устранены функциональные блокеры R9-B1..B4 и существенные ограничения R9-S1..S4 по результатам шестого статического аудита (Git HEAD 4b16006). Повторные 48 контрольных условий аудита 8 на новом коде проходят; основные серии 5x100 разблокированы для пилота. - R9-B1 (P1, E3): отказ по свежести контекста (code 8) БОЛЬШЕ не оставляет неотправленный резерв в tracker — добавлен RequestTracker::ReleaseReservation: удаляется запись без T0, повтор той же sequence слота проходит без дубликата ключа (не code 6), фантомный MAIN в samples не экспортируется (n_attempted растёт только по факту входа в транспорт). Откат выполняется и на pre-T0 отказах journal/durable-INTENT (code 61/63). Регрессия REL-01. - R9-B2 (P1): DriveCleanup закрывает collection по ЕДИНОЙ политике MeasurementPointsComplete (T2 и T3 по операции; REJECTED без ордера освобождает T3) — T2 без T3 больше не завершает наблюдение cleanup раньше времени; неполноту закрывает grace, ноль остатка не подменяет готовность измерения. Регрессия CLN-01. - R9-B3 (P1): ConfirmDurableSendReturns теперь возвращает успех; все вызывающие ветви (CompletedCheck, OnTimer, EndMainCycle, DriveCleanup) ПРЕРЫВАЮТСЯ при сбое durable-flush и НЕ перезаписывают терминальный BLOCKED; SendCleanup имеет собственный durability-gate (code 7) — служебная отправка запрещена при нарушении сохранности; QueueDurableSendReturn при нехватке буфера — fail-closed BLOCKED (а не молчаливый возврат). Регрессия DURA-07 (Directory-as-file отказ). - R9-B4 (P1): checkpoint.marker инвалидируется ДО ЛЮБЫХ перезаписей данных (samples.csv/events.csv), результат FileDelete проверяется; при неуспехе файлы не трогаются и отправки блокируются (CheckpointState=false + BlockRun). Прерывание на любой границе больше не оставляет ложный «успех» старого поколения. - R9-S1 (P1): LoadSamples проверяет ВСЕ 68 имён заголовка (цикл hi<68): подмена market_window_id/market_window_seq больше не принимается молча. Регрессия READER-08 (good=1, bad=-1 code 32). - R9-S2 (P1, E3): поставлена ПОВТОРНАЯ проверка свежести ВЫБРАННОГО контекста (возраст наблюдения И возраст якоря окна относительно текущей котировки) НЕПОСРЕДСТВЕННО перед T0 (после синхронных записей durable-INTENT). При застое durable-INTENT явно отменяется (INTENT_CANCELLED), резерв откатывается (R9-B1), слот ставится в очередь — без фантомного send. CountUncertainDurableIntents учитывает INTENT_CANCELLED (пара = не неопределённость). Регрессия DURA-08. - R9-S3 (P1, E3): Е3-окно не полагается больше на «границы+checksum+CopyTicksRange» — сырые тики окна удерживаются В ПАМЯТИ (ComputeWindowRawTicks) и выгружаются в market_ticks.csv в safe-фазе ПОСЛЕ закрытия окна (синхронная запись внутри измерительной фазы по-прежнему запрещена R8-B3); checksum остаётся проверкой. ExportRun дописывает оставшиеся тики при остановке. Формат описан в CSV_SCHEMA. - R9-S4: новой E3-проверке присвоен отдельный ID REG-02 (не дублирует REG-01). - R9-ДОП (NULL-сессия): guard'ы сессии (InitRun, AppendDurableIntent, FlushPendingSendReturns, FlushWindowTicks) сравнивали m_session_id только с "" — в MQL5 неинициализированная строка равна NULL, условие не срабатывало, и durable-записи уходили в корневой tests\intents.csv вне каталога сессии; когда этот путь занимал каталог (остаток Directory-инъекции DURA-07), flush падал с code 66 «durable line open failed». Все 4 guard'а переведены на NULL||"": сессия гарантированно создаётся в InitRun, каталог сессии используется по назначению. Регрессия DURA-03 (before=2 flush=1 load=1 pend=0 err=0, sess =tests_E1_S01_*). Валидация: 4 exe 0 errors/0 warnings (MetaEditor 6191 avx2); RequestLatencyTests PASS=112 FAIL=0 TOTAL=112 (5 новых проверок R9); EOL CRLF (bareLF=0 по 6 файлам); CSV_SCHEMA.md обновлён (market_ticks.csv). Ограничение тестирования, закрытое вручную: ветвь ReleaseReservation готова и покрыта регрессией; ветви E3ContextStale по якорю окна и реально затянутого durable-INTENT требуют живого терминала/диска — закрыты код-ревью и контрольными пробами аудита (stale->refresh->retry->1 SEND). ## 2026-09-11 — этап 8 пятого аудита (fix audit-8) Устранены функциональные блокеры R8-B1..B4 и существенные ограничения R8-S1/S2/S3 по результатам пятого статического аудита (Git HEAD 22ce0ff): - R8-B1 (P0, E3): после терминальной остановки E3_WINDOW_CAPACITY_EXCEEDED / E3_WINDOW_STORAGE_FAILED новая отправка недостижима: UpdateMarketRegime при переполнении/ошибке хранения окна НЕ выводит режим (regime=UNKNOWN, m_last_regime сбрасывается) и останавливает; DriveNext повторно проверяет состояние после UpdateMarketRegime; в PrepareAndDispatch добавлен гейт code 7 перед транспортом для FINISHED/BLOCKED. Регрессия REG-01. - R8-B2 (P1): единая политика полноты измерительных точек CollectionCloseAllowed (REQUEST T2; ORDER_ADD T3 по операции, кроме однозначного отказа без ордера) применяется в CompletedCheck, пост-T6 ветви OnTimer и cleanup: одинаковое событие «callback-покрытие полное» больше не закрывает коллекцию раньше T2/T3 (grace закрывает позже). Регрессия T2-01. - R8-B3 (P1): SEND_RETURN durable больше не пишется между T1 и обработкой callbacks — факт возврата буферизуется (QueueDurableSendReturn) и дописывается в safe-фазе после закрытия окна (FlushPendingSendReturns; вызовы после каждого CloseCollection и в ExportRun); сбой дописывания — fail-closed (BLOCKED). Регрессия DURA-03. - R8-B4 (P1): CountUncertainDurableIntents — подтверждённые sequence собираются динамически (без cap 256): парный журнал 440/1000 попыток даёт 0 неопределённых; FileOpen INVALID_HANDLE различает отсутствие (0) и недоступность существующего файла (sentinel ULONG_MAX); короткое чтение FileReadArray и сбой ArrayResize — sentinel, а не частичный разбор; LoadDurableContent проверяет прочитанные байты. Регрессии DURA-04/05/06. - R8-S1 (P1): общий quote-aware счётчик логических записей CCsv::CountCsvRecords использован и в ReadBackVerifyFile (multiline-экспорт не отвергает сам себя); capacity в LoadSamples — число НАБЛЮДЕНИЙ (заголовок не расходует); ParseRow отклоняет незакрытую кавычку; ParseCsvUlong проверяет диапазон 20 знаков; LoadUtf8 проверяет число прочитанных байт (FileReadArray возвращает uint [D3]). Регрессии READER-05/06/07. - R8-S2 (P1, E3): в UpdateMarketRegime сначала фиксируется факт РЕАЛЬНО нового тика (монотонный time_msc), затем проверяется возраст — polling-путь восстанавливает контекст после паузы; перед T0 возраст контекста перепроверяется (отказ code 8 без durable-INTENT); в samples добавлены market_window_id/market_window_seq (68 колонок), в market_windows — ticks_checksum (FNV-1a 64 по time_msc/bid/ask валидных тиков) — набор тиков воспроизводится CopyTicksRange(from_msc,to_msc) и сверяется суммой; сырые тики в send-пути на диск не пишутся (синхронная запись внутри измерения запрещена по R8-B3). Регрессия WINDOW-01. - R8-S3: FinalizeTransaction пишет ЕДИНОЕ exit_us один раз (без повторного SetExitTime); инструментальная граница длины обработчика описана честно (хвост финализации не включён); checkpoint.marker содержит поколение и удаляется до перезаписи файлов. Валидация: 4 exe 0 errors/0 warnings (MetaEditor 6191 avx2); RequestLatencyTests PASS=107 FAIL=0 TOTAL=107 (10 новых проверок R8); EOL CRLF (bareLF=0 по 8 файлам); CSV_SCHEMA.md обновлён (68 колонок samples, ticks_checksum, read-back, intents). Ограничение, оставшееся осознанно: недоступность durable-журнала (sentinel ULONG_MAX) не инъецируется в песочнице MQL5 (блокировка файла средствами языка невозможна) — ветвь покрыта регрессией только до границы «существует/пуст», а недоступные ветви — код-ревью и manual-тестом на реальном диске. ## 2026-09-11 — этап 7 четвёртого аудита (fix audit-7) Блокирующие расхождения R7 устранены (демо-пилот и основные серии 5x100 — только после повторного статического аудита; см. также следующий контрольный запуск): - R7-B1 — устойчивый журнал намерений: `AppendDurableLine` пишет ровно n-1 полезных байт с индекса 0 (`FileWriteArray(handle,array,start,count)`; `StringToCharArray` с WHOLE_ARRAY копирует завершающий ноль — прежний вызов писал с последнего элемента и блокировал торговую отправку до T0). Настоящий файловый round-trip INTENT/SEND_RETURN без NUL и отказ записи — DURA-01/02. - R7-B2 — сборка callback-меток: раннее закрытие collection — только при подтверждённой полноте ожидаемых точек T4/T5 (`callback_coverage_complete`), а не по объёму из истории (`snap.coverage_complete`); снимок с `history_scan_failed` полноту T5 по подмножеству тикетов НЕ повышает (SyncReconcile); при доказанном покрытии после T6 коллекция закрывается в OnTimer, запоздавшие в окне DEAL_ADD вносят исходные метки без пересчёта финального исхода. - R7-B3 — прогрев: квота — только по фактическим отправкам (`WarmupQuotaMet`); расписание, исчерпанное с недобором фактических отправок (систематический precheck-отказ), — терминальный `WARMUP_INSUFFICIENT_DATA` на ВСЕХ переходах в MAIN (единый `ReturnToSchedule`), а не только в ветви DriveNext(WARMUP). - R7-B4 — CSV-reader: деление на ЛОГИЧЕСКИЕ записи (кавычки/встроенные переводы строк/CRLF), терминатор снимается один раз; пустые числовые ячейки сверяются с `present_mask` (несоответствие — отказ code 40); `offset_signs_rebuilt` — схема 10 колонок как онлайн; `histogram_rebuilt`/`offset_signs_rebuilt` строят группы условий ИЗ ДАННЫХ + combined (одинаковые данные — одинаковая схема таблиц онлайн/rebuild). - R7-B5 — свежесть котировки: `NoteQuoteObserved(quote.time_msc)` обновляет время наблюдения ТОЛЬКО при новом тике Рабочего символа (InpSymbol); повторное чтение прежней котировки застой не маскирует; OnTick опрашивает рабочий символ, а не символ графика; UpdateMarketRegime требует монотонного роста time_msc. - R7-B6 — E4: обычный анализ принимает ТОЛЬКО допустимое экспериментальное происхождение (по умолчанию `DEMO`; `SYNTHETIC` — отдельный синтетический режим проверки отчёта, code 41); `data_origin` переносится во все производные файлы; конфигурация СТРОК сверяется с manifest серии (code 42); в `summary_rebuilt_e4.csv` добавлены показатели полноты (n_attempted/n_applicable/ отказы/пропуски/deadline) по сериям и pooled. - R7-S1 — применимость метрик: неустановленный исход без сделки — отдельная UNKNOWN-категория (не APPLICABLE/MISSING); доказанное отсутствие исполнения (CANCELED_NO_FILL/EXPIRED_NO_FILL/PENDING_DELETED) — NOT_APPLICABLE, а не «потеря callback»; CONFLICT/INTERRUPTED учитываются в summary ДО проверки has_value (конфликт без числа не засчитывается MISSING). - R7-S2 — comparisons: delta = B−A и относительное изменение (B−A)/A для mean/median/p95 (ТЗ §7, стр.419); единая схема online и rebuild. - R7-S3 — сохранность: cleanup-отправки тоже пишутся в intents.csv (INTENT до T0, SEND_RETURN после T1); SEND_RETURN durable перенесён ВНЕ измеряемой фазы; нечитаемость/повреждение durable-журнала даёт sentinel-неопределённость (не 0); исчерпание протокола окон E3 — обязательная остановка `E3_WINDOW_CAPACITY_EXCEEDED`. - R7-S4 — единая метка выхода обработчика для events и metadata (одно exit_us); переполнение реестра сделок блокирует дальнейшие отправки сразу (OnTransaction, CheckIntegrity code 68), а не только итоговой RUN-DEAL-02; RegisterHistoryDeal учитывает потери аналогично MarkDealAdd. Регрессии: 97 проверок RequestLatencyTests (14 новых R7: DURA-01/02, WARM-02/03, T5-03, DL-05, READER-03/04, CMP-02, EVAL-08/09/10, QUOTE-01, E4-03). Компиляция 4 exe 0 errors/0 warnings (MetaEditor 6191 avx2). EOL CRLF. ## 2026-09-11 — этап 6 третьего аудита (fix audit-6) Блокирующие расхождения R6 устранены (полное соответствие ТЗ проверяется демо-пилотом после контрольной сборки; основные серии 5x100 не запускать): - R6-B1 — сквозная достоверность T5: вид сверки определяется ЯВНЫМ признаком `ConfirmationSnapshot.light_snapshot`, а не числом сделок (световой снимок с count>0 и обнулёнными тикетами больше не бьёт по нулевым тикетам в SyncReconcile); первый реальный callback ПОСЛЕ history-регистрации учитывается ровно один раз (deal_count/callback_volume не теряются); `RegisterHistoryDeal` дополняет уже известную callback-сделку историческими атрибутами без потери происхождения; history_volume наполняется только полным сканом; сверка полноты callback-меток выполняется и после установки T6 (CheckTriggered/OnTimer) без переписывания исхода/T6. - R6-B2 — единая аналитическая семантика online/offline: rebuild-путь восстанавливает RequestMetadata и считает метрики той же `CRequestTracker::EvaluateMetric` (все категории/применимость/срок), а не второй реализацией; WARMUP исключается одинаково; histogram/offset_signs/ comparisons/E4 используют ту же валидность; deadline-счётчики (n_deadline, denominator, n_timestamp_missing_at_deadline) идентичны онлайну; `source_set_id`/population/observation_unit одинаковы. - R6-B3 — своевременность знаковой T2-T4 по ОБЕИМ точкам: max(T2,T4)<=deadline (поздняя T2 при ранней T4 — LATE, и наоборот); `SetFinal` фиксирует `deadline_exceeded` при поздней фактической T6 независимо от порядка callback и таймера (sticky); общий флаг не переносится в пригодность остальных метрик. - R6-B4 — планировщик: `MainComplete` — по фактическим отправкам и терминальным состояниям слотов, а не high-watermark индекса (E3 не завершается при неотправленной второй ветви); блоки формируются ДО перемешивания (каждый из 10 блоков: 10A+10B, 5Buy+5Sell на ветвь); прогрев учитывается по фактическим отправкам (warmup-only жизненный цикл статусов, requeue/отказы), при систематическом отказе подготовки запуск завершается неполным статусом WARMUP_INSUFFICIENT_DATA. - R6-B5 — согласование CompletionPolicy/контроллер: `PENDING_DELETED` не подтверждается при `history_scan_failed`; доказанный исход без права установить T6 (UNEXPECTED_ACTIVATION) сохраняется через `RecordOutcome`, а остаточная позиция закрывается адресно; определённый REJECT без ордера трактуется как известное состояние (нет экспозиции); cleanup UNKNOWN после grace завершается конечным BLOCKED, а не бесконечным DRAINING. - R6-B6 — сохранность: тяжёлый checkpoint выполняется ТОЛЬКО в безопасной фазе (`CanCheckpoint`: нет активной записи и cleanup), результат записи проверяется и при ошибке останавливает новые отправки (BLOCKED), маркер `checkpoint.marker` пишется последним; добавлен устойчивый журнал намерений `intents.csv` (INTENT до T0, SEND_RETURN после T1); INTENT без SEND_RETURN учитывается как неопределённая отправка в manifest (CountUncertainDurableIntents). - R6-B7 — E4: пять источников должны иметь manifest (отсутствие = отказ), run_status=FINISHED и n_main_dispatched>=квоты; нормализованная конфигурация (configuration_id) и символ равны МЕЖДУ всеми пятью сериями; каждая строка принадлежит сессии серии; ключи sequence уникальны внутри файла. Существенные (R6): S1 — CSV-reader проверяет полный заголовок из 66 имён, числовые поля и уникальность sequence; S2 — монотонный возраст последнего наблюдённого обновления котировки (застой рынка TimeCurrent не обнаруживает); S3 — handler_exit_us и длительность снимаются ПОСЛЕ SetExitTime (включая поиск события журнала); S4 — переполнение реестра сделок — явный отказ со счётчиком потерь и проверкой RUN-DEAL-02. Регрессии в RequestLatencyTests (TestAudit6Regressions): EVAL-05/06/07, DL-01..04, OFF-01/02, E3-02, BLOCK-01, WARM-01, PDEL-04, PEND-04, READER-01/02, E4-02. ## 2026-09-11 — этап 5 повторного аудита (fix audit-5) Блокирующие расхождения R5 (полное соответствие ТЗ не подтверждено до контрольной сборки; торговые серии 5x100 не запускать): - R5-B1 (P0) — автомат WARMUP->MAIN->CLEANUP->MAIN замкнут: EndMainCycle больше не переводит в MAIN при `m_cleanup_in_flight` (единственный владелец перехода — DriveCleanup после подтверждения нулевой остаточной экспозиции); прогрев строго последователен (одна операция в работе, пауза); закрытие collection для cleanup не зависит от наличия T6 (поздний REQUEST и grace закрывают коллекцию); раннее закрытие в CompletedCheck ждёт ВСЕ ожидаемые точки (T2 всегда, T3 для операций с ордерной точкой); `ReturnToSchedule()` выбирает WARMUP/MAIN по фазе расписания. - R5-B2 — финализация/журнал/запись: intent проверяется ДО OrderSend* (переполнение журнала -> BLOCKED, слот в очередь); FINISHED повторяет экспорт до первого успеха; штатное завершение переводит контроллер в FINISHED (manifest run_status=FINISHED) только без незавершённого cleanup; OnDeinit экспортирует журнал/записи; добавлен периодический checkpoint (60 с) samples/events вне callbacks. - R5-B3 — категория LATE по фактическому концу метрики против `observation_deadline_us` (online и offline одинаково): ранние T4 остаются VALID без T6; поздние T2/T6 — LATE независимо от порядка callbacks/таймера; флаг `deadline_exceeded` остаётся информационным. - R5-B4 — раздельные признаки: `callback_coverage_complete` (полнота локальных DEAL_ADD callbacks) и `deal_coverage_complete` (торговый результат); T5-метрика использует callback-покрытие; сделки из истории регистрируются в реестр (deals.csv) с происхождением через `SyncRecoveredDeals`; результаты каждой проверки переносятся в metadata (executed_volume/покрытия) — событийный full-fill больше не остаётся с нулевым executed_volume. - R5-B5 — RebuildReport: единая 41-колоночная схема summary_rebuilt (как онлайн); устранены дублирующиеся ключи (c-loop 0..1 + combined); контрольное чтение — от реально созданной таблицы (не константа 25); LoadSamples проверяет заголовок, полную схему (66 колонок) и ёмкость — повреждённый набор отвергается; n=1 допустим (stddev пуст). - R5-B6 — E3: возраст признаков на ОДНОЙ календарной шкале (TimeCurrent vs quote.time_msc; GetMicrosecondCount не смешивается), контроль устаревания якоря после CopyTicksRange; режим/окно/calibration_id закрепляются за записью при отправке (не при late callback); калибратор добирает >=5 сессий (ёмкость 20000), не сохраняет невалидный набор (INSUFFICIENT_DATA), выгружает период и исходные окна (`_windows.csv`); TryDispatchByRegime выбирает первую подходящую возможность нужной ветви (слот другой ветви не блокирует). - R5-B7 — RebuildE4: 5 РАЗНЫХ каталогов, уникальные source session_id, ровно `expected_main` MAIN B-ASYNC на серию (вход `InpE4ExpectedMainPerSeries`), статус исходных запусков из manifest (INCOMPLETE/BLOCKED отвергаются), единый символ; warmup/PILOT/SYNTHETIC исключаются. - R5-B8 — CompletionPolicy: FILLED/EXPIRED не подтверждают удаление (PENDING_DELETED только CANCELED+нет активного+0 объёма; FILLED с нулевым объёмом — противоречивый снимок; EXPIRED — не команда отмены); PARTIAL_CANCELED/EXPIRED подтверждаются по отсутствию активного остатка (исторический неисполненный объём не смешивается с активным); pending-create требует точного `expected_order_type`. Существенные замечания R5-S1..S6: - R5-S1 — универсальные построители расписания: малые чётные пилоты (per_condition=4/10/40) дают валидные слоты без планов-пустышек; нечётные/нулевые значения отвергаются в Init. - R5-S2 — нулевые enum (ORDER_TYPE_BUY=0, ORDER_FILLING_FOK=0) пишутся как `0` (признак `actual_known`); configuration_id переносится из Preflight в экспорт. - R5-S3 — первичный журнал фиксирует SEND_START/SEND_RETURN MAIN с фактическими данными (action/symbol/volume/type, retcode/request_id/order/deal). - R5-S4 — CollectDealsByOrder с ограничением буфера и явным неполным исходом (truncated -> history_scan_failed), бюджет сканирования не выдаётся за полноту. - R5-S5 — группы исходов ALL/SUCCESS/REJECTED; n=1 допустим в summary (stddev пуст). - R5-S6 — handler_exit_us штампуется в конце FinalizeTransaction (длительность охватывает весь путь включая поиск записи журнала). Регрессии в RequestLatencyTests.mq5: EVAL-01..04 (LATE по концу метрики), T5-01/02 (callback vs trade coverage), PDEL-02/03, PART-01, PEND-03, PILOT-01, ENUM-01, REBUILD-01 (сквозной tracker->samples->RebuildReport->73 строки), E4-01 (повтор каталога отвергается). Сборка MetaEditor 6182 avx2: 0/0 для всех 4 exe (RequestLatencyLab, RequestLatencyTests, LatencyReport, MarketCalibration). ## 2026-09-10 — этап 4 повторного аудита (fix audit-4) ### Блокеры - R4-B1: cleanup — в RequestPlan сохраняется полный фактический контракт (volume/type/filling/deviation/price-тикет/comment); потеря записи cleanup и неопределённое состояние DriveCleanup -> BLOCKED; остаточная экспозиция не разрешает следующий MAIN. - R4-B2: событийная сверка — callback volume (лоты) конвертируется в units один раз на границе tracker/snapshot (CStateReader::LotsToUnits); regression UNITS-01..03. - R4-B3: закрытие коллекции ждёт T2 (REQUEST) для всех операций; поздний REQUEST сохраняет метку после T6/закрытия; CORRELATION_LINK фиксирует deferred-привязку. - R4-B4: MarketCalibration считает количество отдельных торговых сессий (уникальные даты валидных окон); generate->save->load->valid покрыт CAL-01/02. - R4-B5: полные t.bid/t.ask (флаги не обнуляют вторую сторону); единое окно [anchor-60000, anchor-1]; anchor = quote.time_msc до T0; контроль возраста признаков (feature_max_age_ms); window/sequence/calibration/dataset трассировка. - R4-B6: E4 — report-only workflow (LatencyReport InpE4Mode): ровно 5 E1 ASYNC datasets, проверка совместимости, pooled-статистика из 500 первичных записей + per-series таблица со ссылками на исходные session_id (без копирования samples). - R4-B7: WAIT/precheck-reject возвращают слот в очередь (не расходуют квоту); DISPATCHED/квота E3 — только после фактического OrderSend/OrderSendAsync; недобор фактических send -> INSUFFICIENT_DATA (run_status=INCOMPLETE). - R4-B8: samples.csv — пустые поля для отсутствующих значений; actual_type/actual_filling/request_price фактического запроса; SyncReconcile объёмов после полной сверки; T6 evidence (order state, объёмы, активный остаток, позиция); summary: исключение CLEANUP, outcome_group ALL/REJECTED, combined A+B, EvaluateMetric-семантика применимости; histogram без знаковой метрики; offset_signs.csv и comparisons.csv экспортируются; rebuilt-зеркало в ReportBuilder. ### Существенные - R4-S1: pending-delete — отсутствие активного ордера только при LAB_READ_ABSENT_CONFIRMED. - R4-S2: pending-create — подтверждение размещения со сверкой symbol/type/magic/volume/price ожидаемого контракта. - R4-S3: initial/remaining_volume_units в снапшоте конвертируются в units. - R4-S4: handler exit фиксируется в журнале и для unresolved (seq==0). - R4-S5: StartRun проверяет init journal/tracker/runner; экспорт fail-closed (read-back участвует в статусе, повторная попытка); run_status=INCOMPLETE при stop_reason. ### Регрессии Tests (>50 проверок) UNITS-01/02/03, COLL-03, CAL-01/02, VOLU-01, QUOTA-01/02, PEND-01/02, PDEL-01, CSV-03, HIST-02, CMP-01 (плюс предыдущие). ## 2026-09-10 — этап 3 повторного аудита (fix audit-3) Устранение блокеров B1-B10 и существенных S1-S6 третьего аудита. ### Блокеры (10) - B1: cleanup переведён в полноценную запись tracker с role=CLEANUP: отдельный lifecycle (precheck -> reserve -> T0/T1 -> correlation -> T6 -> подтверждение нулевой экспозиции -> пауза -> следующий MAIN); DriveCleanup в OnTimer; однократный учёт dispatch; отказ/остаток -> BLOCKED (безопасность). - B2: отложенная корреляция ранних ORDER_ADD/DEAL_ADD — буфер PushDeferred с исходной callback-меткой; ReconcileDeferred после появления точного моста заполняет T3/T4 исходными временами. - B3: коллекция не закрывается до собранного ожидаемого REQUEST (T2) для market; поздний REQUEST после T6 не теряет T2-T4. - B4: 4754 = «ордер не найден» -> ABSENT_CONFIRMED; 4756 и пр. остаются FAILED; no_active исключает FAILED; коды ошибок сохранены в snapshot. - B5: событийная сверка адресная и короткая (light, объём из callback); полный История-скан вынесен в таймер/DriveCleanup. - B6: проверка bool HistorySelect и HistoryDealsTotal; history_scan_budget вместо жёстких 100000; сбой выборки -> не «нет сделок». - B7: однозначный финальный reject (IsFinalRejection) подключён к T6; неоднозн. TIMEOUT/CONNECTION/LOCKED/ERROR не превращаются в reject. - B8: E4 запрещён для торгового runtime (PREFLIGHT/StartRun); reuse=1 в experiment_manifest (анализ 5 серий E1 без повторной торговли). - B9: статусы PLANNED->INTENT_SAVED->DISPATCHED; PRECHECK_REJECTED/WAIT отдельно; счётчик фактических вызовов растёт только после OrderSend*; убран двойной MarkPrecheckRejected. - B10: проверка результатов SaveUtf8 в ExportRun, EventSetMillisecondTimer, integrity-блок при потере журнала (records_lost -> BLOCKED). ### Существенные (6) - S1: фактическое deviation/comment из настроек в запросе; поля в RequestPlan. - S2: рыночный контекст (bid/ask/spread/tick_time_msc) фиксируется при отправке и экспортируется в samples.csv (+ actual_type/filling/deviation/comment). - S3: пустые статистики summary при n<2 (пустые вместо нулей/stddev=0). - S4: LatencyReport повторно строит и histogram_rebuilt.csv; experiment_id и series_id заполняются из выборки. - S5: калибровка E3 требует совпадения символа, >=5 отдельных торговых сессий (trading_session_count); MarketCalibration считает число сессий. - S6: market cleanup заполняет type_filling/deviation и проходит PreCheck. ## 1.00 (черновик, 2026-09-08) Первая рабочая структура кода RequestLatencyLab по ТЗ (черновик). ### Добавлено - Основной советник `RequestLatencyLab.mq5` с автоматом IDLE→PREFLIGHT→READY→WARMUP→MAIN→DRAINING→EXPORTING→FINISHED и режимами LOCAL_ONLY / PENDING_CREATE_DELETE / MARKET_ORDER. - Модули `Include/RequestLatencyLab/*`: Models, Configuration, TimeSource, Statistics, EventJournal, MarketRegime, StateReader, CompletionPolicy, RequestTracker, ExperimentRunner, CsvStorage, ReportBuilder, LatencyPanel, AppController. - Legacy-модули (адаптация статьи 1): `Legacy/BenchmarkStatistics.mqh`, `Legacy/TradeRequestTools.mqh`, `Legacy/LifecycleAdapter.mqh`. - Исходники статьи 1 (SHA-256 совпадают с ТЗ) используются по ссылке из соседнего каталога `mql5-execution-microstructure`; каталог `Dependencies` исключён (снимки не копируются). - Скрипты: `MarketCalibration.mq5`, `LatencyReport.mq5`. - Автотесты: `Tests/RequestLatencyTests.mq5` (LOCAL_ONLY, пишет checks.csv). - Документация: README, CHANGELOG, CSV_SCHEMA, Docs/DependencyChanges, Docs/RequestLatencyLab_TZ_RU.md, dependencies.lock.json. ### Ключевые решения - `LatencySample` сохранена без изменений (10 редакторских полей, порядок/типы неизменны). - T0–T6 по `GetMicrosecondCount`; только REQUEST задаёт `retcode` структуры; код RETURN хранится в `send_retcode`. - Единый последовательный протокол: один запрос в работе, пауза ≥1000 мс, резервный таймер 20 мс, сроки [T0, T0+5000 мс] / +1000 мс. - Севдофиксация конфигурации через `configuration_id` (без дат и случайности). - Park–Miller (seed) + Fisher–Yates; прогрев на отдельном состоянии PRNG. ### Известные ограничения (следующие шаги) - CLEANUP-записи в live-цикле журналируются событиями и счётчиком; полная отдельная LatencySample-строка для CLEANUP — предмет пилота (ДЕМО). - Реглом-гейтинг E3 (`TryDispatchByRegime`) реализован, но приоритетный диспетчер MAIN использует последовательные слоты; E3-сбор подтверждается пилотом. - Проверки, требующие DEMO_PILOT / AFTER_PUBLICATION — NOT_RUN до проведения. - Публикация на MQL5 Forge не выполнялась (см. Docs/RequestLatencyLab_TZ_RU.md §10). Сборка зависит от абсолютного пути к соседнему каталогу mql5-execution-microstructure. ## 2026-09-10 — повторный аудит (fix audit-2) - B1: детерминированный HistorySelect перед CollectDealsByOrder (StateReader). - B2: неизвестный REQUEST больше не получает fallback-привязку (0 + unresolved). - B3: collection_closed реально управляет cleanup: разделение T6 и закрытия, grace-период. - B4: событийная адресная сверка T6 в OnTransaction (HISTORY_ADD/ORDER_DELETE/DEAL_ADD); таймер - watchdog. - S5: E3 формально завершается INSUFFICIENT_DATA (лимит окна кампании InpE3CampaignLimitMin). - S6: preflight проверяет чистоту символа (позиции/ордера). - S7: привязка позиции через trans.position/DEAL_POSITION_ID вместо PositionGetTicket(0). - S8: RUN-T6-01 проверяет completed=>T6; отсутствие T6 у incomplete не ошибка. - S9: регрессии CORR-09, COLL-01/02, POS-01, UNRES-01; CORR-07 обновлён.