15.07.2026: Среда доработки

Нейроразминка

Снилась дичь. Запомнилось, как общался с колонкой Алиса (от Яндекса). При том, мысленно. Это было бы очень странно, если бы не вчерашний пост. А так… Так это больше похоже на отсылку.

Кстати об Алисе. Сегодня она заявила, что середина лета приходится на 21 июня. Ну либо на 14-15 июля. В веб-версии, куда я перезашёл после ответа умной колонки, она эту мысль вполне обосновывает. Так что сие не какая-то там придурь или глюк.

А я считаю просто.

  • Беру количество дней календарного лета 30+31+31 = 92.
  • Делю это число пополам 92/2 = 46. Вот 46-день лета и будет его серединой.
  • А дата… 46-30 = 16.

Для меня середина лета это 16 июля. Т.е. завтра. Сегодня я всё ещё нахожусь в первой половине нынешнего лета.

Хмм (h 100px)
Этот эпизод, лично мне, показывает, что рановато современному ИИ интегрироваться в нейроимпланты.

Что на это скажет DeepSeek?

Погоди-погоди! Серьёзно? А если спросим ChatGPT?

Весь в работе (h 100px)
Так-так-так. Очень занятно. А давай заглянем в википедию.

…по традиции астрономии, астрономическое лето — период между летним солнцестоянием и осенним равноденствием. В Северном полушарии оно продолжается с 21 (20) июня по 23 (22) сентября. В Южном полушарии астрономическое лето продолжается с 21 (22) декабря по 20 (21) марта[4][неавторитетный источник]. В разные годы (на Земле) эти астрономические отрезки приходятся на разное время (в пределах указанных суток).

Т.е. Алиса, называя 21 июня серединой лета, мягко говоря, наврала? Или нет? Давай глянем что есть такое Мидсаммер, на который она ссылается?

Мидсаммер или Мидсоммар (Шведский: [ˈmɪˌsmːar] или [ˈmǐːdˌsmːar]) — это праздник лета, который отмечается в день летнего солнцестояния в Северном полушарии или незадолго до него, в самый длинный день в году. Название «середина лета» в основном относится к праздникам летнего солнцестояния европейского происхождения. В этих культурах традиционно считается, что это середина лета, а сезон начинается 1 мая.[9] Хотя в Северном полушарии летнее солнцестояние приходится на 20, 21 или 22 июня, в большей части Европы его традиционно отмечали 23–24 июня. Эти даты были христианизированы и стали кануном и днём святого Иоанна. Обычно его отмечают гуляньями на свежем воздухе, которые включают костры, танцы вокруг майского дерева и застолья.

Вот хоть смейся, хоть плач. Формально, Алиса оказалась права. У шведов середина лета, по каким-то их традициям, и правда приходится на день летнего солнцестояния.

Но есть одна маленькая неувязочка. Я как бы не швед. И не астроном. И даже не агроном. Я программист, тестировщик, обыватель, сотрудник на сорокачасовой рабочей неделе, блогер и т.д. Логично, что в моём контексте правильным ответом было бы 16-е июля. Ну или более близкое, округлённое нежеланием вдаваться в математику, 15-е июля.

Рука-лицо (h 100px)
Но нейросети не видят кто с ними общается. Если бы они знали…

А давай проверим! DeepSeek выдал именно тот ответ, который я ожидал. Спросим у остальных, дав им контекст.

Вот что ответил ChatGPT.

Пишу (h 100px)
Ну… Хуже чем DeepSeek, но приемлемо.

А вот что ответила Алиса.

Рука-лицо (h 250px)

Всё не влезло в скрин, но изначальный вопрос звучал как и у остальных: «Привет. Какого числа середина лета?».

Ну что же. Благодаря этому простому эксперименту я изменил мнение на счёт нейроимплантов. Всё-таки современные ИИ волне годятся, при условии что они погружены в мой контекст, и что туда не попадёт Алиса (от Яндекса), в её теперешнем виде.

Кстати (h 100px)
Я намеренно не пишу «не попадут отечественные нейросети». Почему? А потому, что для чистоты опыта задал вопрос ГигаЧату.

Хоть ГигаЧат и прогнал дичи (я о 24 июня), но его основной ответ получился таким как у ChatGPT.

Есть мысль (h 100px)
Так! Мне пожалуйста нейроимплант с DeepSeek.

Мечты-мечты, туды-сюды… Для работы Дипсика нужна коробка, размером с небольшой сейф и по цене небольшого автомобиля. При этом греться она будет как масляный радиатор. Увы, но в ближайшее время рассчитывать на то, что такая хренотень безопасно разместится в черепе можно только в мире, где давно и стабильно освоили пространственную магию, да и то с некоторыми оговорками.

Впрочем, на моей книжной полке стоит книга — Программирование на ЭЦВМ «Минск-2» и «Минск-22». С её издания прошло 55 лет.

photo

Компьютер «Минск-22» (1965)

  • Занимал площадь 50 м²
  • Тактовая частота: 0,25 МГц
  • Операций в секунду: ~6 000
  • Оперативная память: 38 КБ

Микроконтроллер ESP32-C3 (2021)

  • Размером с почтовую марку
  • Тактовая частота: 160 МГц
  • Операций в секунду: до 160 000 000
  • Оперативная память: 400 КБ
Мечты (h 100px)
Т.е. ESP32-C3 (2021) меньше площади, занимаемой компьютером «Минск-22», примерно в миллион раз и мощнее его в  25 000 раз. Так что, если подождать ещё лет 30, может продвинутые ИИ, под руководством людей (или наоборот), и научатся производить маленькие безопасные нейроимпланты.

Доживём — увидим.

Итак, утро началось не только с кофе. Впрочем, сразу после того как убрал ESP32-C3 и отнёс спичечный коробок на кухню, стартовал рабочий день.

Классика джобинга (h 100px)
Среда, кстати, середина рабочей недели. А мне до сих пор не прислали приказ на отпуск. И это держит в тонусе! А то мог был поплыть мечтами…

Ну и раз такое дело, то решил ударными темпами выполнить всю недельную норму, скажем, к середине четверга. Вот только один из руководителей смежного отдела решил попробовать свои силы в автоматизации API-тестов.

Рука-лицо (h 100px)
Зачем, нафига, кто просил? Об этом история умалчивает. Ему разрешили, и он устремился.

В результате, днём сервер помер. Отказала база данных. Чинили её до семи вечера. Ну а я накодил кое-как вслепую, ибо не проверить, да и выкинул из головы всю эту чушь. Пусть сами разбираются, что, почему, у кого и откуда руки растут….

Ну а я, вместе с Эль, отправился в лес погуляти.

Идея (h 100px)
Да. Вот такой вот я… фольклорный персонаж. А то лето завтра перевалит за середину, а я весь негуляный.

Подкроватный сервер и вокальный угар

Есть у меня маленький домашний серверочек, собранный на устаревшем (а потому сильно подешевевшем «железе»). В этом году менял на нём SSD.
Поскольку монитор к нему не подключен, а каждый раз вползать туда по SSH мне лениво, давно сделал для него пингач. Достаточно сказать колонке: «Алиса, пингани сервер», — и из-под стола доносится бодрое «Сервер функционирует, пинг получен».

Не одобряю (h 100px)
Но это не то чтобы речь. Это заранее записанные mp3-файлы проигрываются. Театр одного актёра, не больше.

Сегодня, совершенно случайно, выяснил, что сервер заткнулся и не отвечает, хотя работает. Вроде…

Полез внутрь, ну и заодно, пока не разогнулся, решил допилить нормальный синтез речи, который недоделал несколько лет тому… Разбирался вместе с одним продвинутым ИИ. И вот тут начался спектакль в девяти актах с прологом и хэппи-эндом.

Акт 1: «А он и не был недоделан»

Моя версия: синтез речи я когда-то начал прикручивать, но недокрутил. Там внутри демон на Silero — я его прозвал вокабулятором. Я честно пытался его настроить по разным гайдам, но не преуспел.

Ассистент полез в старый лог демона и вернулся с фактами: 66 принятых соединений, каждое закрыто штатным «Иду на новый круг», плюс 42 записи от torch о реальном прогоне модели. Ни одной ошибки.

То есть вокабулятор был доделан. Работал. Говорил. Просто я этого не заметил почему-то.

Рука-лицо (h 100px)
Неловко получилось.

Акт 2: Сервер, которого больше нет

Дальше выяснилась деталь, которая объяснила вообще всё. В апреле я переустановил сервер с нуля (когда менял SSD). Данные уцелели: код на месте, mp3 на месте, 60 мегабайт модели Silero на месте. Всё выглядит живым.

Ну вот так (h 100px)
А рантайма нет. Товарищи mpg123, torch и sounddevice пропали с концами.

И вот в чём коварство. PHP вызывает mpg123 через exec(). Программы нет — exec() молча возвращает «command not found». Никакой ошибки, никакого лога. Просто тишина. Код на диске выглядит идеально рабочим и врёт мне в лицо.

Весь в работе (h 100px)
Мораль: если что-то работало и перестало, проверяй не конфиги, а наличие пакетов.

Акт 3: Самострел

Копнули глубже — и стало ещё веселее. Мой старый код проигрывал звук так:

pulseaudio -D && mpg123 -o pulse файл && pulseaudio -k

Видите последнее? Каждый пинг ПОДНИМАЛ PulseAudio, играл, а потом УБИВАЛ его. Тот самый PulseAudio, через который вокабулятор держал звуковой поток. То есть каждое «Пинг получен» ломало синтез речи. Годами. Но регулярно.

Хмм (h 100px)
Ассистент предложил выкинуть PulseAudio целиком: он сессионный, а звук у меня дёргает веб-сервер, у которого никакой сессии нет. Отсюда все мои старые мучения с правами — я их даже нашёл в комментариях к собственным скриптам двухлетней давности. Именно с этим любился я из прошлого, и в итоге забил болт.

Перешли на ALSA напрямую. Заодно оказалось, что пользователь веб-сервера вообще не состоял в группе audio — то есть до звуковой карты не дотягивался в принципе. Бедняга даже не знал, что у него есть динамик.

Акт 4: Сервис-призрак

Почему демон не переживал перезагрузки? Я был уверен, что сделал systemd-сервис. У меня даже readme лежит с командами:

systemctl enable vocabulater.service
systemctl start vocabulater.service

А сервиса не существовало. Никогда. Это была не документация, а список намерений. Я написал себе инструкцию и не выполнил её. Демон запускался руками и умирал с каждым ребутом, а я каждый раз думал, что «что-то опять отвалилось».

В общем, сделали сервис. Перезагрузил сервер. И через минуту он сам, без единой команды, сказал в темноту: «Стартую вокабулятор».

Мечты (h 100px)
Вот это был момент. Железяка заговорила сама. Осталось только аплодисменты записать.

Интерлюдия: Ударение

Первая же фраза прозвучала с ударением «проверка связИ», и где-то в закоулках моей души шевельнулся… француз. Оказалось, Silero умеет в ударения — знаком «+» перед ударной гласной. Написал «св+язи», и говорилка исправилась.

Злобные планы (h 100px)
Приятно, когда машина слушается. Водилы подтвердят.

Акт 5: Кроличья нора

Звук починили. Пинг работает. Локально. А из Home Assistant — нет. Потому что он ходит по HTTPS, а у меня истекли сертификаты. Все одиннадцать. В один день.

Бомбит (h 100px)
«Какого лешего у вас тут происходит!??»

Оказалось — не совпадение: их выпустили пачкой при апрельской переустановке, Let’s Encrypt живёт 90 дней. Так общий день рождения дал общий день смерти. Помянем.

Почему не продлились? А потому что в коде панели управления сервером (не надо на меня так смотреть, это другие разрабы постарались) была синтаксическая ошибка. Крон исправно запускался каждую ночь в три часа, падал на импорте и умирал. Три месяца. Каждую ночь. В три часа. А сообщения об ошибках он отправлял письмами локальному root — в почтовый ящик, которого нет.

Классика джобинга (h 100px)
Это даже звучит жутко.

Ошибку я поправил. Однако, сертификаты не выпустились. Здравствуй, акт шестой.

Акт 6: Шесть версий, шесть промахов

Дальше был час, за который ассистент выдвинул и похоронил шесть гипотез:

  1. Гипотеза: Крон не работает. Оказалось: работает, задача на месте
  2. Гипотеза: Порт 80 закрыт снаружи. Оказалось: открыт, 12 стран из 12 достучались
  3. Гипотеза: Мёртвый домен топит пачку. Оказалось: все домены смотрят куда надо
  4. Гипотеза: fail2ban банит проверяющих. Оказалось: ни одного бана, там одни боты с /wp-admin/
  5. Гипотеза: Проблема в IPv6. Оказалось: нет никаких IPv6-записей
  6. Гипотеза: Асимметричная маршрутизация. Оказалось: это противоречит настройкам роутера

Отдельно отмечу лучший момент. Ассистент бодро заявил: «Порт 80 открыт снаружи, проверено!» — а проверял он с моего же компьютера. Из моей же локальной сети. Запрос развернулся на роутере и наружу вообще не вышел. Он это сам поймал и честно признал. Уважаю. Но осадочек остался.

Не одобряю (h 100px)
Проверять внешнюю доступность изнутри своей сети — всё равно что проверять, слышно ли тебя на улице, крича в подушку.

Акт 7: Роутер ни у чём не виноват

Настоящая причина оказалась красивой. У меня на роутере был поднят КВН, но для конкретных адресов — прописан списком статических маршрутов. Сервер при этом честно сидит на политике «Прямое подключение», а потому КВН к нему никак не относится.

Рука-лицо (h 100px)
Так я думал. Это же логично следовало из настроек. Но… У разрабов ПО для роутера руки росли из ж… было иное мнение.

Статические маршруты в роутере оказались… глобальными. Они кроют политики приоритетов подключений, как… Впрочем, не будем о животноводстве. Приоритеты подключений задают, каким каналом устройство ВЫХОДИТ в интернет. А маршрут — правило уровнем ниже, и оно срабатывает первым.

И вот что происходит. Проверяющий Let’s Encrypt стучится ко мне на порт 80. Доходит. Сервер отвечает. Роутер смотрит на пакет и видит только «куда» — адрес получателя. А тот случайно попал в мой КВН-список. Для роутера нет разницы между «я иду на этот адрес» и «я отвечаю на входящий с этого адреса». Ответ уходит в туннель и вылезает наружу совсем с другого IP. Проверяющий ждёт ответ от одного адреса, получает от другого, крути пальцем у виска и пишет: «Timeout during connect».

Доказали трассировкой: для одних адресов второй хоп — мой провайдер, 0.6 мс. Для других — приватный адрес и скачок задержки до 89 мс. Туннель.

Идея (h 100px)
Я проверил руками: выключил КВН, и сертификат выпустился. Включил — словил ошибку. Выключил — снова выпустился. Дважды. Роутер всё это время делал ровно не то, что я ему велел, но строго по своему алгоритму.

Акт 8: Мина

Выключил КВН, пошли выпускать сертификаты. Выпустились. А сайты по HTTPS всё равно отдают чужую просрочку.

Полезли смотреть, почему nginx не подхватил новые файлы. И нашли вот это:

include /www/server/panel/vhost/nginx/*.conf;
} ← закрылся блок http
listen [::]:80 ipv6only=off; ← а это висит снаружи, вне каких-либо блоков.
Абсурдное кстати (h 100px)
Внеблоковый статус, это только звучит гордо, а на деле тот ещё геморрой.

Одна лишняя строка. Панель дописала директиву не туда. Конфиг не проходил проверку. Работающий nginx жил на СТАРОМ конфиге, загруженном в память при последнем запуске. Перечитать себя он не мог. А значит: новые сертификаты не применялись, панель молча откатывала правки.

Это к тому, что при первой же перезагрузке сервера, nginx бы просто НЕ ПОДНЯЛСЯ. А с ним полегли бы и все одиннадцать сайтов. Разом. Без предупреждения.

Рука-лицо (h 100px)
То есть я весь вечер ходил вокруг мины и не знал. И нашёл её не потому, что искал — а потому что чинил сертификаты.

Удалили строку. Проверка прошла. Сертификаты применились. Семнадцать доменов (нашлись ещё и кириллические, о которых я забыл) получили новенькие сертификаты до октября. И сервер, наконец, сказал «Пинг получен» в ответ на запрос из Home Assistant. Через HTTPS. Как и было задумано в 2023 году.

Акт 9: Сторож, который говорит

Раз уж сервер теперь умеет говорить — пусть говорит по делу. Попросил у ИИ помочь написать скрипт, который раз в день проверяет сертификаты и, если что-то не так, объявит вслух, какие домены пострадали.

Ещё одно применение вокабулятора для дела. Взрослеем. Умнеем.

Одобряю (h 100px)
Ай, захвалили))

Первая версия проверяла файлы на диске. Отрапортовала: всё годно. А один сайт при этом не работал. Потому что годный файл на диске ничего не значит, если он не прописан в конфиге. nginx в таком случае молча берёт сертификат от первого попавшегося соседа. Браузер получает подлинный пропуск, но на чужое имя. Это как предъявить настоящий паспорт, но не свой.

Переписали: теперь скрипт спрашивает у nginx, что тот РЕАЛЬНО отдаёт в эфир для каждого домена, и сверяет имя. Первый же запуск новой версии обнаружил проблему и торжественно сообщил вслух:

«Внимание. Проблема с сертификатами. Пострадал 1 домен. 127 точка 0 точка 0 точка 1 — чужой сертификат»

Рука-лицо (h 100px)
Он требовал сертификат для локалхоста. Пришлось объяснить, что это лишнее.

Сторож поправил очки, покряхтел, но согласился.

Что в итоге

Сервер говорит. Сам поднимается после перезагрузки. Произносит любой текст живым голосом, с ударениями. Пинг из Home Assistant отвечает быстро. Сторож следит за сертификатами и докладывает голосом. Сертификаты можно не трогать до октября.

Корневую причину — маршруты на роутере — я тупо вырубил.

Есть мысль (h 100px)
Можно конечно перевести проверку на DNS, чтобы Let’s Encrypt вообще ко мне не ходил, но не хочется заморачиваться.

Вот так оно и бывает. Исходная задача звучит как «научить сервер говорить». Потом выясняется, что он как бы умел, всё это время, но не мог. А потому что в апреле, по ходу замены SSD, из под него вынесло всё, на чём он стоял, а я потом удивлялся тишине, когда заметил, спустя 3 месяца.

Что я запомнил

  • exec() молчит, когда программы нет. Тишина — это тоже ошибка.
  • Код на диске не доказывает, что оно работает. Проверяй пакеты.
  • Readme с командами — это не «сделано». Это может оказаться список намерений, или вовсе мечты-мечты.
  • Проверять внешнюю доступность изнутри своей сети — всё равно что закрыть глаза ладошками, и думать, что «сделал темно» всему миру.
  • Шесть красивых гипотез не стоят одной трассировки.
  • Мониторинг, проверяющий файл вместо реального результата, врёт, но врёт успокаивающе.
  • Если что-то падает каждую ночь в три часа и никто не жалуется — возможно, жалобы уходят в почтовый ящик, которого нет.
  • Иногда чинишь одно, а находишь мину под другим. Это и есть лучшая часть. Так что поосторожнее с минами.

Тем временем вечер закончился. И это было даже весело. Словно смотрел черно-белый детектив из 60-х.

Напишите комментарий

Введите имя

Введите адрес электронной почты

Введите адрес вашего сайта

Нажмите эту кнопку, чтобы отправить комментарий.

Введите текст комментария