mql5-execution-microstructu.../CHANGELOG.md

575 lines
56 KiB
Markdown

# 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), выгружает период и исходные
окна (`<id>_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 обновлён.