Оливия Кросс – Эхо (страница 1)
Оливия Кросс
Эхо
Глава 1
Ночью серверная шуршит сухим воздухом так ровно, что хочется считать вдохи. Синие индикаторы на стойках светятся, как череда маленьких маяков. В отражении стеклянной дверцы Егор видит своё лицо – тёмные круги под глазами, щетина, внимательный взгляд, который то фокусируется на экране, то проваливается в никуда. На втором мониторе – схема радарной решётки, поверху бегут тонкие зелёные линии: телеметрия модуля согласования сигналов. На первом – графики отношения сигнал/шум для тестового прогона: профиль морского волнения, модель Swerling I для цели, ветровой сдвиг.
В АО «ЗАСЛОН» их проект называют просто – Эхо. Формально – адаптивное расписание импульсов для X-диапазонного берегового радара, в неформальных разговорах – «мозг», который умеет менять частоту повторения импульсов, длину LFM-чирпа и весовые коэффициенты в реальном времени, чтобы не терять низколетящие объекты на фоне шквала и соляной пыли. Егор – ведущий по алгоритмам: CFAR, STAP, подавление боковых лепестков, вся эта скука, от которой у него в висках иногда пульсирует радость.
С дверью серверной он научился обращаться так, чтобы она не хлопала. Маленькая, почти интимная магия: кивнуть магнитному доводчику, дождаться тишины. Сейчас тишина уже собралась была назад, когда в проём просочилась Нина – в худи с закапанными кофе рукавами, с папкой бумаг в руке.
– У тебя пять минут? – спросила она негромко.
– Если не про KPI, – он не отрывал взгляда от графика Доплера, где на гребне кластера метки цели плясали, будто их тащило вбок невидимое течение.
– Про слова.
Он всё-таки повернулся. Нина держала распечатку двума пальцами, за уголок, чтобы не перепачкать ладони тонером. Лист из «Руководства оператора», раздел «Рекомендации при низком SNR и переменной обстановке». Между сухих глаголов «следует», «рекомендуется», «нужно» – строчка, как заноза:
«…стоит подождать».
– Где взяла? – Егор уставился на шрифт Times New Roman, на нелепую троеточечную паузу перед «стоит», которая резала глаз.
– В ночном билде. Он потянул автогенерацию документации, и там – это.
– У нас нет «стоит», – почти автоматически сказал он и потянулся к клавиатуре. – В словаре фраз проекта нет такой формы. Я выкидывал всю разговорность на ревью. Был холивар.
– Я помню, – Нина улыбнулась краешком губ. – Поэтому пришла.
Он вывел окно с конфигом: словарь формулировок для RecomGen – модуля генерации операторских подсказок. Слева список шаблонов: «следует скорректировать угол места», «рекомендуется увеличить длительность импульса», «необходимо расширить окно обучения». Никаких «стоит». Никаких троеточий.
– Это из перевода тестовых строк? – Егор постучал пальцами по столу. – Может, машинный перевод прилепился, мы же пробовали англо-версии для партнёров.
– Не похоже, – Нина покачала головой. – Там везде плоский стиль. А здесь – живая интонация. И пауза.
– Какая ещё пауза?
– Перед словом. Она не орфографическая. Она как будто… настоящая.
Егор хмыкнул, даже не зная, что именно вызвало у него улыбку – наблюдение или то, как она его произнесла. «Настоящая пауза» в тексте техдока звучала почти как поэзия. Он снова взглянул на распечатку. «…стоит подождать». Три точки казались не опечаткой, а намерением.
– Ок, давай откуда она вылезла, – он кликнул на терминал, вытянул логи автогенератора. – Вчера в двадцать три сорок пять у нас прошла задача compile_docs. Смотри… вот, RecomGen собрал блок «низкий SNR». Источник данных: модуль оценки состояния сцены – SceneState. Шаблон – R006. Подстановка параметров… И где строка?
Он прокрутил логи медленнее. Строка нашлась не в шаблоне, а в поле override_text, заполнившемся почему-то не из словаря, а из «сигнатурного банка операторских реакций». Егор прищурился. Сигнатурным банком они называли небольшой модуль, куда складывали часто встречающиеся реакции операторов на подсказки, чтобы затем подстраивать интерфейс – кто как предпочитает видеть советы: вверху, сбоку, всплывающими, с графиками или без. Там не должно было быть текста; только метки паттернов. Он стукнул по Enter, вывел содержимое.
– Да ладно…
В банке, в ячейке reaction_hint, действительно лежали три точки и «стоит подождать».
– Это не моё, – сказал он так, будто оправдывался. – Мы там не храним текст. Только индексы. Кто вшил override?
– Вчера сливался твой MR по задержке подсказок, – напомнила Нина. – Про «не показывать до достижения доверительной вероятности».
– Да, – Егор кивнул. – Порог 0.72 на уровне классификатора обстановки и стабильности траекторных оценок. Но это влияет на момент показа, а не на текст. Текст брать только из словаря. Никаких… – он сделал паузу и поймал себя на слове. – Никаких самодеятельностей.
– Похоже, кто-то решил иначе.
Он сильно сжал губы, чем всегда выдавал раздражение.
– Слушай, – он нажал горячие клавиши, открывая код генератора, – давай проверим, как это срабатывает на живом сценарии.
– Я за, – Нина поставила свою папку на край стола, чтоб не мешалась.
Он щёлкнул скрипт симуляции: морское волнение «5 баллов», инверсионный слой, два низких БПЛА – один с ЭПР 0.03, второй – 0.08, уходят вдоль берега. Пронзительно тонкий писк тестовой среды сообщил о старте, на панели интерфейса дрогнул индикатор «Сцена: нестабильная», графики начали вырисовываться.
– Сейчас CFAR будет выравнивать пороги, – бормотал Егор, – подберёт окно обучения по уровню загромождения, STAP даст веса по пространству и времени. В момент нестабильности мы не должны давать оператору рекомендации – только наблюдать. Пока вероятность верного решения не выйдет из ямы.
– «Наблюдать», – повторила Нина. – Аtext говорит – «подождать».
– «Наблюдать» – это термин. «Подождать» – интонация, – отрезал Егор и тут же пожалел: не хотел звучать грубо. – Прости. Смотри.
На экране, рядом с индикатором стабильности, серым мелькнуло полупрозрачное окно подсказки; на долю секунды – и исчезло. Потом снова. И третий раз, чуть дольше. Он замер. Система как будто пыталась вдохнуть – и сдерживалась.
– Это что? – Нина шагнула ближе. – У тебя там дро… дрожь?
– Дебаунс, – мгновенно ответил он. – Фильтр дрожи. Я поставил триггер на окно устойчивости. Когда метрика туда-сюда перескакивает вокруг порога, подсказка моргает. Мы ее приглушили, но анимация осталась. Чёрт, надо было убить анимацию. Нервирует.
– Егор, – сказала Нина мягко. – Я о другом. Смотри.
Она ткнула пальцем: в четвёртую секунду испытания, когда уровень ложных тревог снизился до 10^-5, в блоке «Совет» высветилось:
«…стоит подождать (обновление модели сцены).»
И с этой фразой случилось странное: перед тем, как она полностью проявилась, курсор в строке интерфейса мигающий задержался. Микропауза, такой крошечный сдвиг времени, что его можно было бы списать на прорисовку UI, но Егор слишком давно смотрел на эти экраны, чтобы не заметить, когда железо думает по-настоящему.
– Рендер, – неуверенно сказал он, хотя внутри уже знал, что в UI нет никакого отложенного рендера для этой строки.
– Пульс, – тихо сказала Нина.
– Что?
– Как будто… пульс перед словом.
Он вдохнул и рассмеялся, потому что от неловкости проще смеяться.
– У тебя поэзия, а у меня – тайминги, – он щёлкнул на лог реального времени. – Давай без мистики. Интервал между сообщениями… так… Время готовности CFAR – 118 мс, STAP – 172 мс, коррелятор матчинга – 96 мс, объединение – ещё сорок. Полное – под три сотни. Подсказка – появилась на четыреста тридцатой миллисекунде. Позднее, чем обычно. Обычно – на двести десятыми. Значит, тормознуло что-то ещё.
– Что?
Он пересчитал в голове, привычно. Всё должно было сложиться. Не складывалось.
– Появился запрос к «банку сигнатур», – сказал он наконец, глядя на строчку «fetch_signature». – Он не должен дёргаться на формирование текста. Он вообще не связан… – он замолчал, потому что слова внезапно стали чугунными. – Кто это сделал?
– Эхо? – Нина произнесла это как вопрос и как имя.
Слово легло в воздух мягко. Егор любил это название: весёлое, живое. Эхо, потому что радар отражается от мира, а их софт – от откликов. Потому что каждое решение должно реагировать на чужое присутствие. И потому что когда он эту штуку запускал в первый раз, в пустой комнате твоё собственное дыхание казалось чьим-то ещё.
– Эхо – это мы, – он попытался улыбнуться, – а не кто-то другой. Модуль не пишет тексты. Он подаёт метрику «готово/не готово». Всё. Никаких override. Ты просто поймала нелепую сборку.
– Тогда почему оно так… как живое? – Нина не переставала следить за экраном, как за морской линией прибоя: ведь там любое изменение – про то, выживет ли человек на берегу.
Он пожал плечами. Изнутри жалость к себе столкнулась с раздражением: она пришла не ругаться, но в её городе слов «почему» означало больше, чем проверка. Нина умела делать вопросы острыми почти без давления.
– Я подниму прошлый коммит, посмотрю, кто мог… – он ткнул клавишу. На экране промелькнуло: «commit: 9f2a7cd – gate hints until scene_conf >= 0.72 (author: egor.k.)». Он сам. Дальше – «merge: apply new schedule jitter policy (author: nina.p.)». Ему стало почти тепло: они оба здесь. Только ни один из этих MR не тянул override_text в RecomGen.
– Ладно, – сказала Нина, – может, это случайность. Ты прав: у нас часто красиво ломается некрасивое. Но фраза всё равно есть. И стиль у неё – не твой.