Отменённые и незавершённые операции удаляются из event по raw_tinvest_operation, а не только из текущего окна синка. Бумага, которую MOEX не котирует (структурные ноты, внебиржевые облигации), получает цену из портфеля брокера. Логотип и цвет бренда копируются в instrument (миграция e8b21f6a90c3).
GetOperationsByCursor отдаёт отменённые заявки наравне с исполненными, а отменённая —
это не сделка, которая сорвалась, а сделка, которой не было. Приходит она с
quantity_done = 0, количеством, которое заявка только ПРОСИЛА, в quantity, и без
платежа вообще, — а _operation при нулевом quantity_done откатывался на quantity.
Покупка читалась как бесплатное приобретение: позиция росла, деньги не убывали.
Это и есть четыре из пяти известных расхождений derived с брокерским снапшотом, а не
корпоративные действия, как записано в AGENTS.md: SIBN6P4 +5, HEAD +2, FIVE +2,
MGNT −1. В сырых операциях ровно десять строк с state = OPERATION_STATE_CANCELED, и
разбивка по бумагам сходится с расхождением ровно. Пятое, FIVE→X5, действительно
редомициляция: зачисления X5 нет ни в одной операции ленты, лот невыводим из данных.
Фильтрует только event. Сырые остаются как есть — это журнал того, что отдал источник,
и их отсутствие было бы собственной загадкой. Отсутствие state вообще считается
исполнением: старый payload без поля не должен молча превращаться в отмену.
Перечитывание окна теперь ещё и удаляет отменённую заявку, импортированную до этой
проверки, — иначе плохая строка осталась бы в леджере навсегда.