GetInstrumentBy отдаёт общую запись, в которой поля sector нет вовсе — из-за этого
сектор не был заполнен ни у одного инструмента, и аллокация по нему показывала один
бакет unknown на все двадцать. Сектор живёт только в Shares/Bonds/Etfs, поэтому
резолв добивает недостающие поля из потипового справочника: по uid, затем figi, затем
ticker+board. Логика разрешения uid не тронута — одна бумага приезжает под несколькими
instrument_uid, и InstrumentAlias с _match_by_identity остаются единственным местом,
которое это разбирает.
Справочник тянется лениво и один раз на экземпляр клиента, и только для встреченных
типов: это 2000-5000 записей на тип и около 14 секунд на все три.
_backfill_sectors нужен отдельно от резолва: у уже известных бумаг uid не попадает в
missing, и без отдельного прохода они никогда бы не переразрешились.
Пустой сектор остаётся NULL, строка "unknown" не пишется никогда — это литерал самой
аллокации, и данные, притворяющиеся ответом, отличить от отсутствия ответа нельзя.
Из 80 инструментов сектор заполнен у 73. Остальные семь честно пустые: валюта, пять
фондов, у которых поле пусто у самого T-Invest, и внебиржевой структурный продукт.
SDK t_tech.invest импортируется ровно в client.py: остальной код видит обычные
Decimal и dataclass'ы. Операции читаются по курсору GetOperationsByCursor,
снапшоты GetPortfolio/GetPositions складываются в position_snapshot и
cash_snapshot — только для сверки, аналитика их не читает.
mapper.py — явный словарь OperationType -> EventKind на все значения enum SDK,
покрытый тестом: новый тип должен ломать тест, а не молча уезжать в other.
Покупка с привязанной карты помечается meta.card_funded: деньги пришли снаружи,
баланс счёта их не видел, и для доходности это внешний поток, а не внутреннее
движение.