Commit Graph

1991 Commits

Author SHA1 Message Date
Дмитрий 9bdced8173 docs: два промта следующим сменам — сведение ветки в главную и робот МТС
Accessibility (Pa11y live) / a11y (push) Waiting to run
**Сведение ветки в главную** (`2026-08-10-PROMT-svedenie-vetki-smeny-v-glavnuyu.md`).
Замерено: 262 коммита рабочей ветки против 14 коммитов главной, 735 файлов.
Конфликтов всего три, и все решаются «берём версию ветки» — доказано замером:
по обоим спорным файлам их версия оказалась строгой надстройкой (ноль удалённых
строк). Главное предупреждение не про сведение, а про то, что после: боевой не
равен ни одной ветке, а `routes/web.php` на бою существует в виде, какого нет
нигде в git. Выкат целиком после сведения сотрёт работающее.

**Робот МТС** (`2026-08-07-PROMT-mts-bot-kabinet-otbivaet-brauzer.md`).
Совет из письма-тревоги («нужен другой адрес выхода») ошибочен — доказано тремя
опытами: кабинет отдаёт 403 именно браузеру робота, а обычный запрос с той же
машины, и напрямую, и через прокси, получает нормальный 401. Отдельно вынесен
живой риск: оплаченная кампания идёт, а портал за ней не видит.

Оба написаны по одному правилу: сначала то, что уводит не туда, потом замеры,
потом отдельным разделом «что НЕ доказано» — чтобы догадки не выдавались за факты.
В каждом — раздел граблей, на которые смена наступила сама.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 19:05:54 +03:00
Дмитрий 6201ed59fd chore(сторож секретов): в главную доехали разрешения на рабочие номера дела
Accessibility (Pa11y live) / a11y (push) Waiting to run
SAST — Semgrep / Semgrep SAST scan (push) Waiting to run
Найдено 10.08.2026 при попытке отправить починку разводки лидов: сторож секретов
объявил три находки с пометкой 152-ФЗ и запер отправку. Находки оказались не
новой утечкой, а следствием того, что настройка сторожа в главной отстала.

Что было на самом деле: в этот же день вторая смена внесла в `.gitleaks.toml`
разрешения на рабочие номера дела — по решению владельца. Это номер, С КОТОРОГО
звонит наш обзвон (в человеческой записи и в той, какой его пишет Asterisk), и
пять номеров из прайса оператора. Разрешены ПО ЗНАЧЕНИЮ, а не по файлу: сами
документы остаются под охраной, любой другой настоящий номер в них сторож
поймает по-прежнему.

Эти строки остались на рабочей ветке и в главную не попали. Поэтому ветка,
отведённая от главной, получала сторожа с устаревшим списком разрешённого — он
честно ловил уже разобранные номера и намертво запирал отправку.

Проверено после переноса: `gitleaks detect` с настройкой проекта — 8335
коммитов, «no leaks found».

NB для следующей смены: я сначала решил, будто трёх файлов настроек (.gitleaks.toml,
.gitleaksignore, .lychee.toml) в главной нет вовсе, и чуть не записал это в
историю. Проверка `git cat-file -e ветка:.файл` давала ложный отрицательный ответ
на именах с ведущей точкой. Верный способ — `git ls-tree --name-only ветка`.
Файлы на месте, отстало только содержимое одного из них.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 18:47:59 +03:00
Дмитрий 1c08944bf1 docs: вернулись ещё два документа, поправлена ссылка на исчезнувшую рабочую папку — проверка ссылок стала зелёной
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Продолжение предыдущего коммита. Возвращённые документы сами ссылались на два
файла, которых в git тоже не было: HANDOFF по состоянию клиентской рассылки и
её design-spec от 25.07. Оба лежали только на диске — вернул.

Осталась одна ссылка, которую возвратом не починить: приёмка от 27.07 указывала
на файл внутри временной рабочей папки `.claude/worktrees/client-sms`, а такой
папки давно нет. Переписал на настоящий путь в репозитории — файл на месте,
строка та же.

Итог: `lychee` командой самого хука даёт 0 ошибок (было 20). Отправка на сервер
снова открыта — она была закрыта для ВСЕХ смен, а не только для этой.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:00:50 +03:00
Дмитрий 930e28d2bf docs: возвращены в git 16 документов, на которые главная ссылалась, а их там не было
Найдено 07.08.2026 при попытке отправить починку сторожа пульса: проверка ссылок
падала на 20 битых ссылках, и ни одна не была моей. Оказалось, что закоммиченные
документы ссылаются на файлы, которые лежали только на диске рабочей машины и в
git не попали ни разу. То есть главная не проходила проверку сама по себе — и
отправка была закрыта ДЛЯ ВСЕХ смен, а не только для меня. У соседней смены на
этот момент висело 5 неотправленных коммитов.

Что вернулось: разборы и промты смен по клиентской СМС-рассылке (этапы 1-5,
задачи 5-9, конец июля) и три промта смен 25-26 по кошельку и телеграму от
06.08. Все 16 — ровно те, на которые ссылались уже сохранённые документы, то
есть их отсутствие было пропажей, а не задумкой.

Отбор не на глаз: список получен из вывода lychee, каждый файл проверен на
диске и на отсутствие в git.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 14:54:26 +03:00
Дмитрий 8d96cda70b docs: в отчёт смены вписаны номера обоих коммитов
Чтобы файл читался сам по себе, без обращения к истории.
2026-08-07 10:39:39 +03:00
Дмитрий 171f531b61 docs приёмка: Т-М2 закрыта — живое одобрение МТС с движением денег
07.08 в 10:31 МТС одобрил кампанию №15. Числа сошлись с посчитанными ЗАРАНЕЕ
до копейки: кабинет взял 182.40, наценка 1.4 → списано 255.36, остаток 13.44
отпущен в ту же секунду, баланс 9869.50 → 9614.14, заморожено → 268.80.

Одобрение чуть не потерялось: кабинет написал седьмое слово «Запущена», словарь
робота знал шесть. Снаружи это неотличимо от «вердикта нет» — вскрыли, заглянув
в кабинет разовой пробой на чтение. Чинились ОБЕ половины (разбор и поиск ряда),
как предупреждает комментарий в коде; сторожа на обеих, тесты робота 202 → 206.

Непроверенной во всём блоке осталась одна вещь — живая половина пересдачи Т-М4:
для неё нужен свежий отказ МТС, а кампания одобрена.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 10:39:25 +03:00
Дмитрий 9ba2a6a49b fix(безопасность): за переадресацией не ходим — тайный ключ больше не уезжает чужому
Дверь проверяет адрес из настройки. Если разрешённая машина отвечает «иди на
другой адрес», перевозчик по умолчанию туда идёт и везёт наш заголовок дальше:
при уходе на чужой адрес Guzzle снимает только Authorization и Cookie, а
X-Render-Key и X-Obzvon-Key не из них.

Замерено до правки на подставных машинах: ключ рендера доехал до неразрешённой
машины из ленты Яндекса, из поиска клиентов одиночным запросом и пачкой, из
плитки прокси — и плитка при этом горела зелёным, показывая ЧУЖОЙ IP как свой.
Ключ голосового робота уезжал вместе с заданием.

Поставлен withoutRedirecting в пяти строениях запроса четырёх файлов. У
SelfRenderClient их два: пачка строит запрос сама, и запрет из одиночного пути
туда не доезжает — проверено вырезанием, снятие запрета только с пачки роняет
отдельного сторожа и даёт по утечке на каждый адрес порции.

Новых настроек не заводил: тумблер «сюда переадресовывать можно» и был бы той
дырой, ради которой запрет ставится.

Сторожа: app/tests/Feature/Security/KlyuchNeEdetPoPereadresaciiTest.php, 8
проверок, смотрят на запись переговоров, а не на текст исходника. Каждый показан
красным снятием своего запрета по одному. Отдельная проверка «датчик сам жив»
падает, если подставная сеть перестанет ходить за переадресацией, — иначе
остальные сторожа молча стали бы пустыми.

Отчёт смены: docs/superpowers/priyomka/stroyka-7/otchyot-pomoshchnika-zapret-pereadresacii-2026-08-07.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 10:37:22 +03:00
Дмитрий cc9a1a91a7 docs: заведён отчёт смены по запрету переадресации с тайным ключом
Скелет разделов. Пишется по ходу работы, чтобы не сгорело при обрыве.
2026-08-07 09:38:26 +03:00
Дмитрий 459947f76b Р126 третья дверь: работа оборванного круга сохранена и принята, дыра переадресации найдена
Круг смены 6 оборвали средой, работа помощника лежала в дереве несохранённой и её снёс бы
первый же чужой откат. Замерил целостность, прочёл его отчёт, прогнал своей рукой, вынес
приговор. Заново ничего не переделывал.

ПРИНЯТО. Третья и последняя дверь с ключом рендера закрыта той же проверенной дверью.
Список разрешённых машин общий с рендером и это доказано работой, а не доводом. Закрытая
дверь красит СЕРЫМ, а не красным, и ключ при этом физически никуда не уходит, замерено мной
двумя случаями по отдельному запуску на каждый.

Помощник сверх задания нашёл и починил ложь, которой никто не искал: подпись плитки называла
серый словами не отвечает, то есть гнала владельца продлевать исправные прокси.

Мои ошибки называю первыми, их три.

Пятьдесят девятая. Я назвал adminDashboardHelpers.ts чужим файлом соседней смены прямо в
промте смене 7, в списке не трогать и в коммит не брать. Взял из головы, не замерив. Вся
правка в этом файле - работа моего же помощника. Исполни следующая смена мой промт дословно,
починка подписи плитки не попала бы в коммит и сгорела.

Шестидесятая. Мой снимок оборванного круга был неполон: записал шесть файлов, их семь.
Перечень собрал командой, но раньше, чем помощник закончил, и не перемерил перед тем, как
назвать его окончательным.

Шестьдесят первая. Мой датчик прогона искал не то слово и я чуть не объявил состоявшийся
прогон несостоявшимся. Спас узкий прогон, которым я прибор перепроверил.

Вырезание второго рода дало дыру. Допущение защиты: дверь проверяет адрес из настройки и
считает, что запрос уйдёт именно туда. Случай мимо: разрешённая машина отвечает иди на другой
адрес. Замерено на двух подставных машинах: тайный ключ уехал на машину, которой в списке
разрешённых НЕТ, а плитка осталась ЗЕЛЁНОЙ и показала чужой адрес как свой. Перемерил на
живой двери боевого Поиска клиентов тем же ножом, отдельным запуском - то же самое. Причина
прочитана в исходнике библиотеки: при уходе на чужой адрес снимаются только два заголовка,
и нашего среди них нет. Вторым прибором замерено, что отключения переадресации нет нигде во
всём боевом коде. Это не отменяет Р126, дверь делает обещанное на своих случаях, но обещание
шире дела и про это не сказано нигде. Отдельным кругом.

Датчики: полный прогон моей рукой на своей базе 5344 проверки, 5340 зелёных, 4 пропущено,
красных 0, арифметика сходится. Проверки интерфейса 3 из 3. Разметка 0 ошибок.
2026-08-07 09:29:23 +03:00
Дмитрий 61182a1c55 docs обзвон: конец смены 6, проверка расписания закрыта живьём, круг 7 оборван
Смену остановил владелец. Довожу до логического конца.

Проверка 1 задачи З-0.10 закрыта ЖИВЬЁМ. Доказать её раньше 02:20 ночи было
нечем, я записал замену и назвал вслух, чего она не доказывает. Дождался и
замерил: 07.08.2026 в 02:20:01 машина робота обошла своих сторожей САМА, без
человека, за две секунды, все три зелёные, итог лёг со своей датой. Уборка
записей чужих голосов перестала зависеть от человеческой памяти, и это замерено,
а не обещано. Журнал того же обхода честно говорит отправка не настроена:
портальная половина не выкачена, и краснота одной проверки из 42 у сторожа обхода
и есть датчик завершённости выката.

Круг 7 оборван на середине. Помощник закрывал третью дверь с тем же тайным ключом
и не успел сохранить работу коммитом. Файлы перечислены поимённо в промте смене 7,
раздел 3.2, вместе с порядком: замерить целостность, прочесть его отчёт, прогнать
своей рукой, вынести приговор, НЕ переделывать заново. Приёмочный лист по этому
кругу не заведён, и это записано.

Итог смены. Задач 54, врезок ПОСТРОЕНО 19, требований 112, решений владельца 127.
Полный прогон 5301 проверка, 5297 зелёных, 4 пропущено, красных 0.

Мои ошибки: их одиннадцать, с 48 по 59, и все одного класса, прибор мерил не то,
о чём я спрашивал. Тяжелейшие три. Пятьдесят пятая: построил главный довод
задания на ложном замере, назвав упоминания зовущими. Пятьдесят восьмая: назвал в
задании одну дверь с тайным ключом, а их оказалось три. Пятьдесят девятая: вынес
владельцу цену решения, взятую из головы, а не из замера.

Правил стало 30, шесть добыты этой сменой.
2026-08-07 08:41:29 +03:00
Дмитрий 0bf43bfd1f docs приёмка: Я3 и Я4 закрыты по сроку — последние комбинации Яндекса 2026-08-07 08:38:44 +03:00
Дмитрий 8167dc7d79 docs приёмка: Я3 и Я4 закрыты по сроку — последние комбинации Яндекса
Срок обеих кампаний истёк 07.08 в 00:00 UTC, портал сам закрыл их и вернул
неоткрученное. Числа сняты с боевой базы, арифметика сходится до копейки:
833.50 - 9.00 = 824.50 и 833.50 - 40.50 = 793.00.

Я-Д5 воспроизвёлся трижды за четыре секунды на разных суммах — возврат по сроку
работает не по случайности.

Предсказание сбылось наполовину: Я4 обещали ~160 показов, вышел 81; Я3 обещали
ноль, вышло 18. Скорость по одному часу для суточного предсказания не годится.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 08:37:58 +03:00
Дмитрий d7b77d25f2 docs обзвон: приговор по восьмёрке в номере, цена решения названа честно
Решение владельца Р127 исполнено коммитом 56ddaa1e. Мой нож замерил: восьмёрка и
семёрка дают теперь ОДИН знак и ОДНО тело, границы держатся, семизначный и
тринадцатизначный номера не тронуты, казахстанский со своим знаком, и правило
устойчиво к повторному приведению.

Моя ошибка первой, пятьдесят девятая. Вынося развилку владельцу, я написал, что у
одиннадцати цифр с восьмёркой второго толкования нет. Я взял это из головы, НЕ
ЗАМЕРИВ. Второе толкование есть: иностранные номера длиной ровно одиннадцать
цифр с кодом на восьмёрку. Большинство дают несуществующий российский номер, но
вьетнамский превращается в живой подмосковный код, и род ошибки меняется с
звонок не состоится на звонок состоится, но не тому человеку.

Правило велит выносить развилку с полным набором дорог. Дороги я вынес полные, а
цену неполную, и владелец решал, не зная её.

Смягчает это одно, и не моя заслуга. Помощник докопал дальше и поправил САМ СЕБЯ:
общий нормализатор телефонов портала живёт в двадцати файлах, включая сам обзвон,
и делает ровно то же самое. Вьетнамский номер портится на входе везде уже
сегодня. Р127 опасности не добавляет, он прекращает расхождение обзвона с
остальным порталом.

Его находка, которую я перемерил своим прибором и подтверждаю: пара из десяти и
одиннадцати цифр даёт ДВА знака на одного человека, и ему позвонят дважды. При
этом общий нормализатор и проверка запрета звонить считают ту же пару ОДНИМ
человеком. То есть беда, ради которой принято Р127, на этой паре жива. Он не стал
чинить и правильно: лечение шире решения, надо сводить три разных канона
телефона, живущих в обзвоне, а один из них сторожит запрет звонить. Вынесено
открытым вопросом первым номером.

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

Датчики: решений 127, разметка 0 ошибок, правописание протокола 0 жалоб.
Прогон 5301 проверка, 5297 зелёных, 4 пропущено, красных 0.
2026-08-07 08:36:21 +03:00
Дмитрий 56ddaa1ed4 fix обзвон: один человек, записанный через 8 и через +7, получал два звонка
Решение владельца Р127. В `odinVidNomera` восьмёрка приводится к семёрке
ТОЛЬКО когда цифр ровно одиннадцать. Короткие и длинные номера не трогаются
вовсе: слить двух разных людей в один знак — ошибка тише и хуже, второму не
позвонили бы никогда и молча.

Замерено до правки: `8 999 000-00-01` и `+7 999 000-00-01` давали два разных
знака и два разных тела. Сторожа смотрят на то, что вправду уехало роботу, и
сравнивают дословно — так же, как сравнивает приёмник.

Сторожа показаны красными тремя сломами: без починки, без проверки длины и с
приведением к восьмёрке вместо семёрки. Возврат доказан слепком файла.

Названная владельцу цена: иностранные одиннадцатизначные номера с кодом на
восьмёрку это правило портит. Вьетнамские `8496…`/`8497…`/`8498…` станут
похожи на живые коды Московской области — робот позвонит чужому человеку.
Лечится чисткой номеров на входе, это отдельная задача. Подробности и
незакрытые хвосты — в отчёте.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 08:25:28 +03:00
Дмитрий 09ed5e1b31 docs обзвон: приговор по двери боевого рендера, дверей оказалось три
Решение владельца Р126 исполнено коммитом 92472816, и исполнено ШИРЕ, чем я
заказал.

Моя ошибка первой, пятьдесят восьмая. Я назвал в задании ОДНУ дверь, через
которую уходит тайный ключ боевого Поиска клиентов. Помощник замерил: дверей
ДВЕ, и вторая шлёт тот же ключ по той же настройке. Перепроверил вторым прибором
на версии до его правки: у второй двери был ровно тот же вид проверки и тот же
заголовок с ключом. Почини он только названный мной файл, решение владельца
осталось бы невыполненным, а дыра открытой. Отсюда правило 29: одно найденное
место это находка, а не перечень.

И третья дверь нашлась потом: та же тайна уходит из плитки срока прокси по
другой настройке. Помощник назвал её и НЕ тронул, правильно. Перемерил сам,
вынес владельцу, закрыто отдельным заходом.

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

Помощник назвал свою ошибку первой, и она новая для этого проекта: он запустил
полный прогон раньше, чем закончил правку стиля, и через четыре минуты форматтер
переписал два его файла прямо во время прогона. Зелёный цвет такого прогона не
доказывает ничего. Отсюда правило 30.

Вторая его ошибка честнее первой: проверка покраснела на его же оплошности, и
первым побуждением было подогнать код под ошибку. Поправил проверку.

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

Датчики: разметка 0 ошибок, ссылки живые.
2026-08-07 08:14:19 +03:00
Дмитрий c2b3fe47fc docs: промт-передача следующей сессии по вкладке «Активность» 2026-08-07 08:12:50 +03:00
Дмитрий 0181f2e3e7 docs: промт-передача следующей сессии по вкладке «Активность»
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 08:12:36 +03:00
Дмитрий e4a4766c50 docs: план переделки вкладки «Активность» под вопрос «жив ли клиент» 2026-08-07 08:05:53 +03:00
Дмитрий 16d8191d08 docs: план переделки вкладки «Активность» под вопрос «жив ли клиент»
11 задач по TDD: два сервиса на бэкенде (вердикт с полоской и лента дел из
пяти источников), ручка подгрузки, живая сортировка списка клиентов, типы и
маппер, русские фразы, панель Vue, точка состояния в списке, полный прогон,
приёмка глазами.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 08:05:43 +03:00
Дмитрий 9247281688 fix поиск клиентов: дверь к рендер-виртуалке — разрешённые машины и обязательное шифрование, Р126
Тайный ключ SELF_RENDER_KEY уходил заголовком X-Render-Key на любой адрес, какой окажется
в настройке. Проверялось ровно одно: адрес не пуст и ключ не пуст. Отсюда две молчаливые беды:
опечатка в SELF_RENDER_ENDPOINT увела бы ключ чужому человеку навсегда и без признаков,
а http:// увёз бы его открытым текстом.

Дверь повторяет проверенное устройство Р123 от голосового робота: своя причина на пустой
адрес и на пустой ключ, список разрешённых машин с пустым списком как «закрыто всё»,
обязательное https кроме своей машины, а «своя машина» — два независимых ответа: окружение
из положительного списка И двоичная проверка петли 127.0.0.0/8, ::1, localhost по RFC 6761.
Закрытая дверь = мягкая деградация: наружу не ходим, отдаём пусто, причина в журнал уровнем
warning, потому что на боевом всё ниже не доезжает.

Тумблера «можно без шифра» нет намеренно: он и был бы той самой опечаткой.

Дыр было ДВЕ, а не одна. Тот же ключ и тот же SELF_RENDER_ENDPOINT уходят из
RenderServiceYandexListSource — лента Яндекс.Карт. Починка только названного файла оставила
бы дыру открытой, поэтому дверь общая на обе.

Боевой поиск не сломается: умолчание списка НЕ пустое и содержит замеренный боевой адрес
виртуалки 51-250-1-97.sslip.io — пустое умолчание остановило бы поиск в момент выката.
Набор тот же, что владелец уже принял для OBZVON_ALLOWED_HOSTS: это одна и та же машина.
Прогнаны все формы адреса, какие могут стоять в боевой настройке, в окружении production.

Проверок 37, сторожа показаны красными пятью отдельными сломами, возврат доказан слепками.
Larastan 0, Pint чисто.

Не закрыто и ждёт слова владельца: ProxyMarketProbe шлёт тот же ключ на другую настройку
без двери; боевое значение SELF_RENDER_ENDPOINT не замерено, на боевой не ходил.

Отчёт: docs/superpowers/priyomka/stroyka-6/otchyot-pomoshchnika-r126-dver-rendera-2026-08-07.md
2026-08-07 08:04:35 +03:00
Дмитрий 475e2d6245 docs обзвон: знак и тело больше не расходятся, промт смене 7 написан
Портальная причина дыры закрыта коммитом a4ff69aea. Помощник выбрал путь, где
портал считает опознавательный знак задания САМ внутри вызова, а наружу
принимает то, из чего знак складывается. Рассогласовать стало нечего.

Довод, которого не было в моём задании и который решил дело: второй путь всё
равно потребовал бы сменить подпись, потому что для сверки знак надо
пересчитать. То есть он платит ту же цену, а взамен даёт лишний довод, который
может быть только неверным, и новый исход дверь закрыта. А чем кончается
закрытая дверь? Человеку не позвонили. Второй путь не убирает вред, а делает его
громким.

Мой нож мерил не текст, а то, что вправду уезжает роботу. Один человек в двух
записях даёт один знак И одно тело. Строка без цифр закрывает дверь, наружу не
уходит ничего. Вторая попытка и другой клиент дают другой знак.

И мой нож замерил цену того, что помощник НЕ стал чинить осознанно: человек,
записанный восьмёркой и семёркой, считается двумя разными, и ему позвонят
дважды. Он нашёл это сам и вынес владельцу, потому что ошибка в обратную сторону
тише и хуже: слияние двух разных людей означало бы, что второму не позвонят
никогда и молча. Владелец закрыл это решением Р127: восьмёрку приводим к
семёрке только у одиннадцатизначных номеров.

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

Промт смене 7 написан: docs/superpowers/2026-08-10-PROMT-obzvon-stroyka-4.md.
В нём правила стройки вперёд всего, 57 ошибок надзирателя, 28 правил, числа
собраны командой, порядок работ и три ловушки, которые выглядят правильными.
В промте смены 6 поставлен указатель, что он отработан.

Датчики: задач 54, врезок ПОСТРОЕНО 19, требований 112, решений 127.
Разметка 0 ошибок, правописание протокола 0 жалоб, все ссылки промта ведут к
живым файлам.
2026-08-07 07:53:48 +03:00
Дмитрий c298789eef docs: спека переделки вкладки «Активность» под вопрос «жив ли клиент» 2026-08-07 07:49:07 +03:00
Дмитрий c9daf48bdc docs: спека переделки вкладки «Активность» под вопрос «жив ли клиент»
Замерено на боевом: вкладка читает журнал сделок, где 364 из 419 строк —
системные «робот залил лид». Данные про входы и про дела клиента лежат в
двух других журналах и на вкладку не попадают вовсе.

Решения владельца: вердикт + полоска 90 дней + лента только дел, пороги
3 и 14 суток, входы только сверху, заодно чиним мёртвую сортировку списка
клиентов по последней активности.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 07:48:57 +03:00
Дмитрий a4ff69aea3 fix обзвон: знак задания и номер в теле больше не могут разойтись
Портальный клиент голосового робота считал опознавательный знак задания от
ОДНИХ ЦИФР телефона, а в тело задания клал номер КАК ЕСТЬ. Один и тот же
человек, записанный `+7 999 000-00-01` и `79990000001`, давал ОДИН знак и
РАЗНЫЕ тела. Приёмник робота сравнивает тело дословно и на такую пару
отвечает отказом — то есть честный повтор получал отказ вместо звонка.

Вторая половина той же беды: знак и телефон приходили в `pozvonit` ДВУМЯ
независимыми доводами, и ничто не заставляло их сойтись. Работник очереди,
посчитавший знак один раз и перебирающий номера, отправил бы роботу
рассогласованную пару, и человеку не позвонили бы молча.

Что сделано:

- заведено ОДНО место приведения номера — `ObzvonClient::odinVidNomera`;
  оба потребителя берут номер оттуда: и знак, и тело задания;
- `pozvonit` больше НЕ принимает знак снаружи. Он принимает то, из чего знак
  складывается — арендатор, кампания, номер, попытка, — и складывает знак сам.
  Рассогласовать нечего: второго номера в клиенте не существует;
- отказ по номеру теперь считается по признаку "в номере ноль цифр", а не по
  `trim`. Раньше строка вроде "абв" проходила дальше и давала ОДИН И ТОТ ЖЕ
  знак на все такие задания — два разных задания столкнулись бы знаками у
  робота, и одному из людей не позвонили бы вовсе;
- в докблоке `pozvonit` вслух записано следствие решения владельца Р124:
  номер попытки нельзя прибавлять на исходе, где звонок МОГ состояться, —
  иначе знак станет другим и защита не сработает именно в том случае, ради
  которого заведена.

Разбор ответа робота, пределы времени, предел одновременных и проверка
шифрования Р123 не тронуты.

Мерки. Сторожа роняли работой, а не текстом: возвращали беду в код и
смотрели на то, что уходит подставному роботу.

- вернул в тело номер "как есть" — 4 красных из 55;
- вернул знак доводом снаружи — 1 красный из 55, сторож читает доводный ряд
  метода через `ReflectionMethod`, а не текст файла;
- возврат доказан слепком со снятием невидимых знаков конца строки,
  после возврата 55 из 55 зелёных;
- полный прогон на своей базе: 5293 проверки, 5289 зелёных, красных 0,
  ошибок 0, пропущено 4; арифметика сходится;
- `composer stan` — 0 ошибок, `pint --test` — passed.

Открытым оставлено и названо в отчёте: `8...` и `+7...` сегодня разные люди
для портала; `dopolnitelno` обязано быть одинаковым у повтора; правило счёта
попыток не назначено.

Отчёт: docs/superpowers/priyomka/stroyka-6/otchyot-pomoshchnika-znak-tela-2026-08-07.md
2026-08-07 07:43:34 +03:00
Дмитрий 4513fe1a58 docs приёмка: дефект М-1 выкачен на боевой и доказан живыми данными 2026-08-07 07:34:28 +03:00
Дмитрий a0c660704c docs приёмка: дефект М-1 выкачен на боевой и доказан живыми данными
Задание 88 закончилось после выката и принесло ту же дату старта, а время
изменения кампании №15 осталось от прошлого задания. Раньше совпадало с концом
каждого задания до секунды — значит строку больше не трогают и счётчик 48 часов
пошёл по-настоящему.

Никого не стёрли: перепись боевого 1031 файл до и после, боевая копия файла до
выката побайтово равна прежней версии, после — новой.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 07:33:36 +03:00
Дмитрий 9eba348ee8 fix телеграм: счётчик зависшей модерации сбрасывался каждой проверкой робота 2026-08-07 07:19:00 +03:00
Дмитрий 1464fd5c3f fix телеграм: счётчик зависшей модерации сбрасывался каждой проверкой робота
Кампания, застрявшая на модерации дольше 48 часов, обязана уйти в ручной
разбор — иначе висит вечно с замороженными деньгами клиента и молча.
Срок считается по времени изменения строки, а вчерашняя правка «день начала
показов» писала дату при КАЖДОЙ проверке робота массовым обновлением, которое
всегда двигает updated_at. Робот ходит раз в четверть часа — счётчик не
досчитал бы никогда. Защита была цела на вид и мертва на деле.

Улика с боевого: у кампании №15 время изменения строки совпадало с концом
последнего задания робота до секунды, при том что вердикта не было третьи сутки.

Пишем дату, только если она вправду изменилась. Сравнение сырых значений мимо
приведения типов: starts_on это date:Y-m-d, сравнение с Carbon разошлось бы молча.

Сторожа SchyotchikZavisshejModeraciiTest (3 шт) видены красными до правки.
Блок телеграма 381 зелёный на своей базе, статанализ 0, pint чисто.
На боевой НЕ выкачено.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 07:18:27 +03:00
Дмитрий 30424a4b52 fix телеграм: счётчик зависшей модерации сбрасывался каждой проверкой робота 2026-08-07 07:18:03 +03:00
Дмитрий d3f190806a @' 2026-08-07 07:04:13 +03:00
Дмитрий b522d98afe @
fix: письма о недоливе — одна сводка в сутки вместо потока на каждом прогоне

Сверка с поставщиком шла каждые 30 минут и на каждом прогоне слала письмо
на КАЖДУЮ пару (тенант, дата) с недоливом больше 20%. Вчерашняя дата остаётся
в окне сверки, поэтому поток рос день ото дня: 144 письма 27.07 → 510 за 06.08,
около 3000 за 12 дней на ops@liderra.ru.

Теперь пары собираются в один список и уходят одной сводкой раз в сутки
(отсечка по московской дате в redis; гонки нет — handle держит общий lock).
Частоту самой сверки не трогал.

Поштучный TenantBusinessDriftAlertMail с шаблоном удалён — стал мёртвым.

Тесты: сводка собирает все пары в одно письмо, второй прогон в те же сутки
молчит, в новые сутки письмо уходит снова. Красными их видел.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@
2026-08-07 07:02:45 +03:00
Дмитрий 575b6d6491 docs обзвон: приняты З-0.3, З-3.1 и половина З-0.6, в плане нашлась дыра
Три приговора вынесены своей рукой. Плюс в план заведена новая задача по
решению владельца и записаны четыре его решения.

З-0.3 принята, коммиты 18f933550 и dd3b6fb4b. Портальная половина шва: клиент
умеет позвать робота, спросить состояние, остановить, мягко деградировать и
требовать шифрования. Мой нож проверил восемь форм адреса на боевом окружении:
большие буквы, порт и пробелы проходят, четыре опасные формы закрыты, каждая со
своей причиной словами.

З-3.1 принята, коммит 5dfe32dc9. Ловушка решения Р115 закрыта и проверена моим
ножом на каждом часе суток: менеджер в Москве с 14 до 18 и получатель во
Владивостоке дают ноль общих часов, а менеджер с 10 до 18 даёт ровно три, и
арифметика сходится знак в знак. Что живая рассылка клиентов не изменилась,
помощник доказал не тестами, а вычитанием: 144 816 сверок, ноль расхождений,
прибор показан красным подложенной поломкой.

З-0.6 принята КАК ПОЛОВИНА и половина честная: из восьми проверок задачи закрыта
одна, две частично, пять не закрыты. Построен приёмник заданий с памятью знаков
на сутки по решению Р124. Мой нож нашёл дыру: тот же знак с другим телефоном
приёмник считал повтором, молча не звонил второму человеку и отдавал порталу
номер звонка первого. Закрыто доделкой, теперь громкий отказ.

Главная находка смены крупнее всех задач. Помощник разобрал моё задание и
сказал, что между принять задание и отчитаться лежит САМ НАБОР НОМЕРА, а его нет
нигде в плане. Проверил вторым прибором, перебрав все 53 задачи поимённо: он
прав. Диалплан набирать умеет, а начать звонок некому. Владелец решил завести
отдельную задачу, она заведена как З-0.12 и стоит сразу за швом.

Мои ошибки, их четыре за эти круги, и все одного класса.

Пятьдесят третья. Завёл приёмочный лист ПОСЛЕ отправки задания, а не до. Ровно
на этом месте метод и рассыпается: лист, написанный после, подгоняется под то,
что вышло.

Пятьдесят пятая, самая тяжёлая. Я построил главный довод задания на ложном
замере. Написал, что правило часов зовут двенадцать файлов живого модуля, что
обзвон уже читает его через тарификатор и что у проверки часа двенадцать мест
боевого кода. Все три неверны: зовущих пять, тарификатор правило не читает
вовсе, у проверки часа один боевой зовущий. Помощник разбил все три, я перемерил
и подтвердил. Перечень я собрал командой, как велит правило, но команда считала
УПОМИНАНИЯ, а я назвал их зовущими.

Пятьдесят седьмая. Моя подсказка к решению Р123 привела бы к негодной починке:
сторожа были бы зелёными при живой дыре. Помощник показал это замером.

И четыре раза за смену мой собственный прибор мерил не то, о чём я его
спрашивал: подставной робот протекал между случаями, заголовок я спрашивал по
выдуманному имени, устройство памяти предположил вместо того, чтобы посмотреть,
подписи нового кода выдумал.

Решения владельца, закрытые 07.08.2026: Р122 подпись письма вместо слова в
адресе, Р123 шифрование к роботу кроме своей машины, Р124 робот помнит знаки
сутки, Р125 номер без общего окна не набираем и говорим клиенту до запуска,
Р126 дверь боевого Поиска клиентов чинится отдельным заходом.

Датчики: задач 54, врезок ПОСТРОЕНО 19, требований 112, решений 126.
Разметка 0 ошибок, правописание протокола 0 жалоб.
2026-08-07 06:47:54 +03:00
Дмитрий dd3b6fb4b5 fix обзвон: к роботу только по шифрованной дороге, кроме своей машины — Р123
Дверь пускала http к разрешённому хосту, и тайный ключ уезжал заголовком
открытым текстом — молча, без единого признака. Одной опечатки в OBZVON_ENDPOINT
хватало. Теперь адрес без шифрования портал не принимает: дверь закрыта, звонка
нет, причина сказана словами и лежит в журнале уровнем предупреждения.

Исключение ровно одно — разработчик на своём компьютере — и устроено оно ДВУМЯ
независимыми ответами, чтобы одной перепутанной настройки на боевом для утечки
не хватило:

1. приложение само говорит, где живёт: спрашиваем Laravel, а не список слов.
   Список окружений положительный, а не «всё кроме боевого»: любое неназванное
   окружение обязано шифрование.
2. робот стоит на ЭТОЙ ЖЕ машине: адрес ведёт на петлю — вся сеть 127.0.0.0/8,
   ::1, ::ffff:127.x.x.x, имена localhost и *.localhost по RFC 6761. Определяется
   двоичным сравнением адреса, а не совпадением слов. Резолвер имён не зовём
   намеренно: он вносит в проверку безопасности неопределённость и щель между
   «проверили» и «пошли».

Именно второй ответ и закрывает то, что владелец назвал незакрытым: одной
ошибки в APP_ENV на боевом теперь мало — боевой робот петлёй не станет. На это
стоит именной сторож.

Тумблера «можно без шифра» нет намеренно: он и был бы той опечаткой, ради
которой Р123 принято.

12 новых сторожей: четыре случая ножа приёмки ж, з, и, к; сторож на само
исключение; сторож против совпадения слов вместо петли; сторож на подложное
шифрование, когда проверку чужого удостоверения снимают. Каждый показан
красным — починка ронялась четырьмя разными способами, и каждый раз краснело
именно то, что этот способ ломает. Возврат доказан слепком со снятием невидимых
знаков конца строки.

Моя ошибка первой: первый сторож про журнал зеленел не по той причине — любая
строка предупреждения его устраивала. Нашёлся только арифметикой прогона, потому
что упал в поле ошибок, а не провалов. Переписан.

Найдено и НЕ тронуто второе место того же класса: services.self_render шлёт
секрет заголовком, и его дверь не проверяет ни схему, ни хост вовсе. Путь живой,
боевой. Вынесено решением владельцу отдельно.

Отчёт: docs/superpowers/priyomka/stroyka-6/otchyot-pomoshchnika-r123-shifrovanie-2026-08-07.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 06:31:35 +03:00
Дмитрий f671e21d01 fix обзвон: знак тот же, а тело задания другое — второму человеку не звонили молча
Замерено владельцем на приёмнике заданий: знак задания тот же, телефон в теле
другой. Приёмник считал это повтором, второму человеку не звонил вовсе и отдавал
порталу номер звонка ПЕРВОГО задания — портал привязал бы итог чужого разговора
к другому человеку.

Теперь вместе со знаком запоминается отпечаток тела задания. Тот же отпечаток —
вправду повтор, ведём себя как прежде. Другой — не повтор, а ошибка портала:
отвечаем 422, набора нет, чужой номер звонка не отдаём, память первого задания
не трогаем.

Почему 4xx, а не 5xx: по второму телу мы не набирали ничего, и это правда. 5xx
сказало бы «звонок мог состояться», портал пометил бы человека как «может быть,
звонили» и не позвонил бы ему никогда — та же беда, только навсегда.

Отпечаток считается вычитанием, а не перечислением: вычтен один знак задания,
всё остальное — включая поле, которое заведут завтра, — под защитой. Снят под
тайным ключом, поэтому персональных данных в открытом виде в памяти нет.

Проба приёмника: было 81 проверка, стало 108. До починки 7 красных, после 0.
Починку ломал тремя разными ломами, все три покраснели; слепок приёмника после
возврата совпал знак в знак.

Портальная сторона не изменена ни строкой. Причина беды — там: портал даёт
передавать знак и телефон врозь. Вынесено владельцу отдельным пунктом отчёта.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 06:23:47 +03:00
Дмитрий 5dfe32dc91 feat: окно часов обзвона — общая рамка и своё окно клиента, З-3.1
Правило часов остаётся ОДНО и живёт в боевом SmsQuietHours — решение
владельца Р76. Обзвон получает не копию правила, а тонкую обёртку
ObzvonOknoChasov со своими числами: Р76 отдал в общее пользование
ПРАВИЛО, а не ГРАНИЦЫ. Админ, поправив окно рассылок, окно обзвона
не двигает.

Два окна живут в разных часах, и рамка — их пересечение, Р115. Часы
менеджера приходят вместе со СВОИМ смещением, LocalHoursWindow, и
меряются им, а не смещением получателя. Иначе московские 14:00-18:00
были бы прочитаны как владивостокские, робот перевёл бы звонок на
спящего менеджера, а на экране и в журнале всё бы сошлось.

Окно клиента только сужает рамку, Р64: 09:00-22:00 принимается как
10:00-20:00. Часы целиком вне рамки и непересекающиеся из-за поясов
окна дают пустой ответ «звонков не будет» — это ответ, а не молчание.

Входящие окном не ограничены, Р35: спросить обёртку про приём звонка
физически нечем, и на это стоит сторож.

Живая рассылка СМС не изменилась ни на один час — доказано вычитанием
против старого правила из git HEAD: 144 816 сверок на 13 поясах, всех
1440 минутах суток и 7 наборах границ, расхождений 0. Прибор показан
красным: подложенная поломка в один знак дала 6049 расхождений.

Подпись canSendNow не менялась — новое условие вошло третьим
необязательным доводом с умолчанием. nextWindowOpensAt, earliestOpening
и isValidWindow не тронуты вовсе. Границы читаются один раз на объект:
20 000 номеров — ровно один запрос к базе.

Сторожа показаны красными пятью врезами; дословные сообщения, разбор
задания и незакрытые хвосты — в отчёте
docs/superpowers/priyomka/stroyka-6/otchyot-pomoshchnika-z-3-1-okno-chasov-2026-08-07.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 05:58:59 +03:00
Дмитрий f409f8746b feat обзвон: робот принимает задание от портала — роботная половина шва З-0.6
Портальная половина шва построена 06.08.2026, а на роботной стороне не было
никого: приёмника заданий не существовало. Теперь есть.

Что построено

- bots/lena-golos/priyomnik.py — три ручки pozvonit, sostoyanie, ostanovit;
  память опознавательных знаков на сутки по решению владельца Р124; проверка
  тайного ключа; набор номера вынесен сменной деталью.
- bots/lena-golos/proba-priyomnika.py — проба без звонка, 81 проверка.
  Подставной набор номеров не набирает, а считает, сколько раз его позвали:
  "человеку позвонили дважды" выглядит здесь как "набор позвали два раза".
- bots/lena-golos/lena-priyomnik.service — эталон службы. На сервере его нет.
- bots/lena-golos/README.md — свой раздел: устройство, кто кого зовёт, цена по
  Р84, порядок выката, открытые хвосты.
- docs/superpowers/priyomka/stroyka-6/otchyot-pomoshchnika-z-0-6-priyomnik-2026-08-07.md

Главное, ради чего всё это

Портал читает 4xx как "звонка не было" и вправе повторить. Значит 4xx после
начала набора стоит второго звонка живому человеку. В приёмнике каждый 4xx на
ручке звонка стоит строго до обращения к набору; единственное исключение — когда
сам набор отдельным полем поклялся, что не начинался.

Память знаков лежит файлом на диске и переживает перезапуск робота, и не в /tmp:
эта папка вычищается целиком при каждой перезагрузке машины, и защита умирала бы
молча именно в день перезагрузки.

Два одинаковых знака почти одновременно: знак резервируется до набора одной
неделимой записью, проигравший не набирает и получает 5xx. Ни 4xx, ни выдуманный
номер звонка — оба были бы ложью.

Память знаков применяется только к ручке звонка. Портал шлёт Idempotency-Key на
всех трёх ручках, но на двух других кладёт туда номер звонка, а не знак задания.
Прими мы его за ключ памяти везде — второй вопрос о состоянии отдавал бы
запомненный ответ, и разговор вечно числился бы идущим.

Приёмник сегодня звонить не умеет и говорит об этом честно

Набора номера нет ни в первой половине З-0.6, ни во второй — это третий кусок,
и в плане он не назван. Пока его нет, на ручке звонка стоит NabornikNeNastroen,
и приёмник отвечает 4xx "набор не настроен", то есть говорит порталу правду:
звонка не было. Ответить "принял", не имея чем звонить, значило бы наполнить
отчёты звонками, которых нет.

Р84 замерено, а не оценено на глаз

Сторонних библиотек ноль — только http.server, sqlite3, hmac, json, threading из
самого Python. Пик памяти на 200 заданиях подряд 0,17 МБ, обращений к базе на
задание 7, один процесс, потолок 8 одновременных запросов, тело не длиннее
64 КБ. Служба понижена Nice=10 и IOSchedulingClass=idle.

Личные данные

В журнал не попадает ни телефон, ни имя, ни текст скрипта, ни тайный ключ —
тела запроса там нет вовсе. Журнал идёт в journald, а не в свой файл: свой файл
стал бы пятым местом текстового следа без срока и без уборки.

Сторож показан красным пять раз

Ронялки: приёмник забыл знак — 13 красных; 4xx при гонке вместо 5xx — 2 красных;
обычное равенство вместо hmac.compare_digest — 1 красный; телефон в журнал —
2 красных; память в /tmp — 1 красный. Две самые важные повторены на итоговом
слепке файла.

Моя ошибка, называю первой: первая редакция сторожа постоянного времени искала
слово compare_digest по ТЕКСТУ файла и нашла его в моём же комментарии — проба
осталась зелёной на сломанном коде. Починено: смотрю в co_names скомпилированной
функции.

На машину робота не ходил, ничего там не менял, в app/ не менял ничего.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 05:45:40 +03:00
Дмитрий b5ea25f2a1 docs обзвон: приговор по З-0.3 и лист З-3.1, заведённый до работы
Приговор по З-0.3 вынесен своей рукой. Портальная половина шва принята: клиент
умеет позвать робота, спросить состояние и остановить. Резал своим ножом семь
случаев, каждый отдельным запуском. Главное различение сделано правильно и
проверено не текстом, а тем признаком, по которому будет решать будущий работник
очереди: дверь закрыта и отказ означают, что звонка НЕ было и повторять можно,
а не знаю означает, что звонок МОГ состояться и вслепую повторять нельзя.

Мои ошибки называю первыми, их три.

Пятидесятая. Я вложил в задание собственное противоречие: велел считать ответ
двести и мусор отказом, и тем же заданием пунктом выше объяснял, что молчание
ещё не значит отсутствие звонка. Буквальное исполнение моей строки вернуло бы
ровно ту дыру, которую задание закрывало, и живому человеку позвонили бы дважды.
Помощник поступил правильно, а не послушно.

Пятьдесят первая. Мой собственный прибор соврал дважды за круг, обоими разами
одинаково: мерил не то, о чём я его спрашивал. Подставной робот протёк из одного
случая в следующие, и спрашивал я про заголовок по выдуманному имени. Перемерил
каждый случай отдельным запуском, выводы поменялись.

Пятьдесят вторая. Оставил в тексте плана посторонний иероглиф. Проверка образцом
пометила весь файл подряд, то есть прибор снова был негодный; перемерил поиском
по самому знаку.

Вырезание второго рода дало три находки. Знак задания не различает перезапуск
кампании: через месяц у тех же номеров он тот же, и робот может отказать
законному звонку. Ключ уезжает открытым текстом, если адрес записан без
шифрования. И предел одновременных считает обращения, а не разговоры, тогда как
машину грузят именно разговоры, значит решение владельца Р84 этим пределом не
закрыто и портал не может закрыть его в одиночку.

Помощник возразил трижды и трижды был прав, а свою ошибку назвал первой: его
прибор показывал ноль красных при красном стороже, потому что проверка журнала
падает в поле ошибок, а не провалов. Поймала арифметика.

Лист по З-3.1 заведён ДО работы, как требует метод. Разведка собрана командой:
правило часов зовут двенадцать файлов живого модуля рассылки, час берётся одним
смещением получателя, и в этом вся ловушка. Ловушка названа заранее вместе с
пятью другими допущениями.

Полный прогон своей рукой: 5207 проверок, 5203 зелёных, 4 пропущено, красных 0.
Разметка 0 ошибок.
2026-08-07 05:06:11 +03:00
Дмитрий c7ae012f48 docs обзвон: З-0.10 принята, дыра в двери закрыта, три решения владельца
Приговор по З-0.10 вынесен сменой 6 через сутки после работы — то есть отчёт
помощника доказательством не служил вовсе, все десять замеров сделаны заново
своей рукой. Шесть проверок плана закрыты, из них три главные живым действием:
подставил итогу дату 78 часов назад и УВИДЕЛ письмо на ops@liderra.ru, хотя
внутри итога всё зелено; подставил красного сторожа и увидел, что письмо
назвало его поимённо; на здоровом итоге писем ноль.

Вырезанием второго рода нашёл дыру: дверь принимала итог ЗЕЛЁНЫМ, когда тело
само говорило "красных 2", а в списке лежал один зелёный. Длина списка нигде не
сверялась с объявленным числом, а поле с числом красных не читалось вовсе.
Замерено прибором вне хранилища на настоящей двери. Закрыто доделкой c351b0b6,
и тот же мой нож теперь краснеет и называет обе беды раздельно.

Помощник доделки возразил мне по существу и был прав: мой довод про подделку
завышен. У того, кто владеет тайным словом, нет причины слать обрезанный список,
он пришлёт связный зелёный. Порог для подделки эта работа не подняла ни на
сколько, её честная цена другая — защита от случайной порчи и от будущих правок
обхода. Довод снят, это моя ошибка 49.

Своим ножом резал и саму доделку. Новая строгость к незнакомым полям имеет цену:
прибавят в итог безобидное поле — письмо пойдёт каждый день, а это воюет с
проверкой 5 той же задачи. Приговор: строгость оправдана, вред от мягкости
больше, и цена названа честно в описании машины там, где её увидят.

Проверка 1 задачи живьём НЕ доказана и раньше 07.08 доказана быть не может:
итог собран рукой, расписание сработает впервые ночью. Замерено вместо неё, что
файл расписания принят по всем формальным признакам. Датчик для следующей смены
записан.

Мои ошибки. Первой — 48: в сообщении собственного коммита e37780920 написал, что
файлы задачи лежат несохранёнными. Неправда, они были в коммите 67195f0b, я это
сам замерил и поправил промт, но сообщение коммита не перечитал. Отсюда правило
25: поправил бумагу — перечитай и то, что уже ушло в сообщение.

Владелец закрыл три развилки 07.08.2026, все с полным набором дорог:
Р122 машина стучится подписью письма, а не словом в адресе;
Р123 к роботу только по шифрованной дороге, кроме своей машины;
Р124 робот помнит опознавательные знаки заданий сутки.

Датчики: задач 53, врезок ПОСТРОЕНО 17, требований 112, решений 124.
Полный прогон своей рукой на своей базе: 5207 проверок, 5203 зелёных,
4 пропущено, красных 0. Арифметика сходится. Разметка 0 ошибок.
2026-08-07 04:59:37 +03:00
Дмитрий 872cc4147b docs обзвон: в отчёт З-0.3 дописана проверка, что мои сторожа вправду в прогоне
Соседняя смена в своём отчёте назвала ровно те же числа полного прогона
5207 / 5203 / 0 / 0 / 4. Это выглядело так, будто мои 35 сторожей в прогон не
попали, а число досталось мне от чужого замера. Проверено командой, а не на
слово: сбор проверок даёт 5207, из них 35 моих. Мои внутри; у соседа своя основа
была 5172, он гонял уже после того, как мой файл лёг в дерево.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 00:04:48 +03:00
Дмитрий 18f933550e feat обзвон: портал умеет позвать голосового робота — портальная половина шва З-0.3
Модуль «Обзвон» построен на 17 задач из 53 и при этом не мог позвонить ни разу:
между порталом и роботом не было шва. Эта половина его закрывает — робот живёт
на отдельной машине, портал теперь умеет сказать «позвони», спросить «что с
разговором» и сказать «останови».

Что сделано:
- блок services.obzvon: адрес, тайный ключ, предел одновременных обращений,
  ожидание места, ДВА предела времени, список разрешённых хостов. Всё через env,
  ни одного секрета в коде;
- ObzvonClient — три умения плюс опознавательный знак задания;
- ObzvonOtvet и IskhodObrashcheniya — пять исходов вместо «вышло / не вышло»;
- .env.example — семь настроек с пустыми значениями и пояснениями;
- 35 сторожей.

Главное решение. Ответ клиента НЕ булев. «Портал не получил ответа» — это не
«звонка не было»: робот мог принять задание и уже звонить, пока ответ терялся по
дороге. Слейся эти две правды — работник очереди повторил бы вслепую, и живому
человеку позвонили бы дважды, а с кошелька клиента списали бы вторую трубку.
Поэтому «не знаю» отделено от «точно не было», и у задания есть устойчивый
опознавательный знак, одинаковый у всех повторов одной попытки.

Решение владельца Р84: робот делит железо с боевым рендером «Поиска клиентов».
Предел одновременных взят замками общего кэша, а не числом в памяти процесса —
иначе два работника очереди дали бы двойную нагрузку. Что он ограничивает и чего
НЕ ограничивает, сказано прямо в шапке клиента.

Урок соседнего шва self_render взят дословно: успех — только по условленному
слову робота. Ответ 200 с мусором успехом не считается. В отличие от задания,
мусор записан не в «отказ», а в «не знаю» — иначе вернулась бы дыра с двойным
звонком. Клиент, в отличие от SelfRenderClient, не повторяет запрос сам никогда.

Журнал — только от «предупреждения» и выше: на бою LOG_LEVEL=warning.

Незакрытое названо в отчёте: защита от двойного звонка ЗАЯВЛЕНА, но не замкнута,
пока нет приёмника на машине робота З-0.6; настоящие пределы времени и предел
одновременных на живой нагрузке не мерены; ключ едет открытым заголовком.

Отчёт: docs/superpowers/priyomka/stroyka-6/otchyot-pomoshchnika-z-0-3-2026-08-06.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 00:01:50 +03:00
Дмитрий c351b0b6f5 fix обзвон: дверь итога сторожей проверяет связность того, что приняла
Дверь принимала итог, который сам себе противоречил, и записывала «всё
хорошо». Годный по форме случай: тело говорит «сторожей 3, красных 2», а в
списке лежит одна зелёная строка — двое сторожей исчезали молча.

Дыры было две:
- длина списка storozha ни с чем не сверялась;
- поле storozhey_krasnyh не читалось вовсе — машина присылала своё
  показание, а дверь его выбрасывала.

Теперь сверяются три показания о числе сторожей — настройка, объявленное
число и длина списка — плюс объявленное число красных против нашего
подсчёта по строкам. Красных считаем ровно по машинному правилу: код не
ноль или провалов не ноль. Иначе зелёный сторож с нулём проверок давал бы
ложную тревогу, потому что портал ругается на такого, а машина его красным
не считает.

Сверх заказанного закрыты два места того же рода. Поля, которых дверь не
знает, ищутся вычитанием, а не перечислением — и в итоге, и в строке
сторожа: тогда забытое поле оказывается под защитой, а не мимо неё. И
ловится список нужной длины, набитый повторами одного имени: числа при этом
сходятся все до одного, а гоняли одного сторожа трижды.

Каждая новая проверка показана красной вырезанием своего куска по одному за
раз. Без чтения storozhey_krasnyh случай с объявленной краснотой при трёх
зелёных строках не ловит ничто — список бед выходит пустым.

Машину не трогал, схему не трогал, остальную дверь не переписывал.

Полный прогон: всего 5207, зелёных 5203, красных 0, ошибок 0, пропущено 4.
2026-08-06 23:53:05 +03:00
Дмитрий c61178ab26 docs телеграм: снят неверный вывод о причине закрытия окна входа 2026-08-06 22:59:33 +03:00
Дмитрий 9c0e0503d5 docs телеграм: снят неверный вывод о причине закрытия окна входа
Проверка на второй заход опровергла мой же разбор. На СТАРОМ коде служба
отступала пять раз подряд, пока окно владельца было открыто, и вернулась к
работе ровно в минуту закрытия — защита работала. Довод «в журнале нет ни
одной строки ПРОПУСК» был замером через полминуты после открытия окна:
пустой журнал доказывал лишь, что окно ещё не дожило до проверки.

Причина закрытия окна НЕ установлена — записано открытым, с рабочим обходом.
Починка сравнения путей остаётся как укрепление: старая проверка держалась
на случайном вспомогательном процессе, слепом первые секунды.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 22:58:52 +03:00
Дмитрий fc07935f28 docs телеграм: вход в кабинет МТС восстановлен — служба лезла поверх окна владельца 2026-08-06 22:41:51 +03:00
Дмитрий 0bbe4ce1c7 docs телеграм: вход в кабинет МТС восстановлен — служба лезла поверх окна владельца
Владелец не мог войти руками: окно закрывалось раньше, чем он успевал.
Защита службы «профиль занят» сравнивала путь буква в букву и искала обратные
косые черты, а браузер подписывается прямыми — совпадения не было никогда.
Улика: за всю жизнь службы в журнале ноль строк «ПРОПУСК: профиль занят».

Починка живёт вне git (C:\liderra\mts-telegram-robot): сравнение вынесено в
etoNashProfil под 5 сторожей, тесты робота 197 -> 202. Проверено живьём:
вход сохранён, сторож ALIVE, задание 52 ok=true, служба дважды отступила
при занятом профиле.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 22:41:42 +03:00
Дмитрий e377809205 docs обзвон: З-2.4 принята, волна 2 закрыта, промт смене 6 написан
Конец смены 5. Здесь приговор по последнему кругу, врезка в план и передача
следующей смене.

З-2.4 принята, коммиты bde377a11, df8c4720c и 6e775055. Этой задачей ЗАКРЫТА
ВОЛНА 2 целиком. Замерено надзирателем: чистый полный прогон 5166 проверок,
5162 зелёных, 4 пропущено, красных 0, выход 0, арифметика сходится. Обзвон и
сделки 447 из 446. Ноль удалённых строк в кодовом коммите.

🔴 Главное в круге — дыра, найденную моим ножом. Я назвал вслух допущение новой
защиты: у всякой записи мимо двери есть в выражении имя класса или имя таблицы.
Случай мимо — правка через связь: ни того, ни другого имени там нет вовсе.
Замерено подставным пробником: 8 из 8 зелёных при живой дыре.

Помощник закрыл её НЕ текстом и оказался правее меня дважды. Мою зацепку по
столбцу он забраковал: подстрока совпадает с соседним столбцом, и ключ уникален
в схеме, но не в коде — он написан в пояснении к самой двери как образец
запрещённого, так что обход по тексту покраснел бы НА ДВЕРИ. Завёл свой
построитель, ловящий на самой записи все три формы разом. Перепроверил тем же
ножом: файл, дававший 8 из 8 зелёных, теперь роняет сторожа и называет строку
21. Пробник убран, дерево чисто.

🪤 Мои ошибки смены, их двенадцать, 36-47, и все одного класса: прибор мерил не
то, о чём я спрашивал, и отвечал осмысленно на вид. Тяжелейшая — 43: вынес
владельцу развилку с НЕПОЛНЫМ набором дорог, четвёртая и лучшая нашлась уже
после его решения. Из 46 и 47 добыты два правила: датчик прогона это число
проверок, а не код возврата; и своя база на каждый прогон, а не на смену.

Промт смене 6 написан: docs/superpowers/2026-08-09-PROMT-obzvon-stroyka-3.md,
713 строк. В нём правила стройки вперёд всего, 47 ошибок, 24 правила, числа
собраны командой, порядок работ и две ловушки, которые выглядят правильными.
В старом промте поставлен указатель, что он отработан.

🔴 Честно записано в промте: З-0.10 осталась В РАБОТЕ, приговор ей не вынесен,
её файлы лежат в дереве несохранёнными и перечислены поимённо. Первое дело
смены 6 — замерить, что цело, прогнать самой и вынести приговор по уже
заведённому листу, а не переделывать заново.

Датчики: задач 53, врезок ПОСТРОЕНО 16, требований 112, решений 121, листов
смены 5 восемь. Разметка 0 ошибок, все ссылки промта ведут к живым файлам.
2026-08-06 22:39:59 +03:00
Дмитрий 67195f0bf8 feat обзвон: машина робота проверяет себя сама, портал следит за свежестью
Сторожа уборки записей телефонных разговоров запускал только человек, который
про них помнил. Уборка могла умереть молча, и голоса чужих людей копились бы
месяцами при обещанном сроке хранения.

Теперь машина раз в сутки гоняет своих сторожей сама и стучится в портал с
итогом. Портал хранит итог вместе с ЕГО СОБСТВЕННОЙ датой и шлёт письмо, когда
итог красный ИЛИ протух. Зелёный итог недельной давности хуже красного
сегодняшнего, поэтому возраст проверяется всегда.

Решение владельца Р116: стучится машина, портал на машину не ходит — ключа от
машины с голосами живых людей у боевого портала быть не должно.
Решение владельца Р117: адрес письма из настройки MONITORING_ALERT_EMAIL, а не
вписанный в код.

На машине
- суточный обход и его расписание, 05:20 МСК, под flock, от ubuntu
- машинная копия 12 эталонов: своего ssh-ключа у машины нет и не будет
- у сторожей появилась вторая створка двери LENA_MESTNAYA=1 — работа без ssh

В портале
- приём итога: подпись тела, без слова в адресе. Адреса текут в журналы nginx
- ежедневная проверка свежести и красноты, письмо только когда плохо
- итог лежит в scheduler_heartbeats, схема базы не тронута
- сама проверка записана в EXPECTED_INTERVALS: присмотр без присмотра не жил бы

Сторож нового обхода ходит с рабочего места по ssh и сверяет машинную копию с
хранилищем побайтово — обход на машине сравнил бы копию сам с собой.

Попутно закрыто: копия моста и журнал обхода стали новыми местами, где ложится
похожее на речь. Разобраны поимённо, журнал обнуляется каждым прогоном.

Замеры: сторожа 26/46/27 не изменились, обход 2,2 с под нагрузкой nice,
проверок в портале 21 из 21, полный прогон 5161 при одной чужой красной.
Три ножа показаны красными; один мой сторож при этом оказался ложно зелёным и
переписан.

Не выкачено: портальная половина не на бою, дорога с машины не настроена.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 22:31:13 +03:00
Дмитрий 6e775055d9 feat обзвон: закрыта запись исхода через связь — третий пол и якорь по столбцу
Нож надзирателя пробил обе прежние половины. Случай: запись через связь,
одной строкой, где нет ни имени класса, ни имени таблицы. Пол в модели молчал,
потому что это построитель, а не объект; обход кода не начинался, потому что
искал имена, которых в выражении нет. Проверил своим ножом: сторож дал восемь
из восьми зелёных при живой дыре.

Закрыто двумя вещами, и первая — не то, о чём просили.

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

Третий якорь в обходе кода — сам столбец. Замер надзирателя перемерил своей
рукой и подтвердил: столбец ровно outcome есть во всём каноне схемы у одной
таблицы, в миграциях его нет вовсе, у соседней таблицы он зовётся иначе.

Но якорь в предложенном виде дал бы ложную красноту, и я его поправил дважды.
Подстрока без кавычек совпала бы с именем столбца соседней таблицы — беру ключ
в кавычках. И главное: ключ уникален в схеме, но НЕ уникален в коде — он есть
ещё в пяти местах, и одно из них пояснение в шапке самой двери, где дословно
написан образец запрещённого. Обход по тексту покраснел бы на самой двери.
Поэтому комментарии убираются разбором PHP, а не вычёркиванием по образцу:
разборщик отличает комментарий от такой же строки внутри кавычек. Ложная
краснота хуже дыры: она приучает не смотреть.

Список исходов про номер считается вычитанием из восьми, а не вторым списком:
допишут девятый и забудут разложить — он окажется под защитой, а не мимо неё.

Белого списка нет ни в одной из трёх половин. Исключений в обходе ровно два и
оба по устройству: файлы, где полы и стоят.

Чего не ловит и этот якорь, названо и в отчёте, и в подписи к сторожу: правку
прямым SQL мимо портала, ключ и имя таблицы, собранные из кусков, столбец,
переименованный в будущем, и код вне папки приложения. Полную защиту даст
только замок в самой базе — это вопрос владельцу, схему не трогал.

Новая половина показана красной ножом надзирателя: сторож назвал файл, строку
и само выражение. Возврат доказан пустым состоянием дерева и слепками.

Прогоны: полный 5166, зелёных 5162, красных ноль, ошибок ноль, арифметика
сходится. Обзвон и сделки 447. Сторож мимо-двери 13 из 13. Статанализ ноль,
deptrac ноль.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 22:24:16 +03:00
Дмитрий 6d97a9691a docs обзвон: отчёт З-2.4 — восстановлен стёртый мной же раздел и числа чистого прогона
Три вещи в отчёт.

Первое: раздел про голый шов я СТЁР сам, заменяя соседний кусок по границам «от
заголовка до заголовка» — он лежал между ними и ушёл молча, вместе с коммитом.
Восстановлен целиком. Поймал перечнем заголовков, а не памятью.

Второе: моя ошибка в прогоне. Первый полный прогон круга 2 дал 44 ошибки «таблицы
не существует». Причина не в коде и не в среде, а во мне: сборка тестовой базы
идёт в начале КАЖДОГО прогона, поэтому второй прогон сносит таблицы под первым, а
я запустил короткую проверку на своей же базе, пока на ней шёл мой полный прогон.
Уронил сам себя ровно тем способом, от которого сам же предостерегал строкой выше
в этом отчёте. Урок шире, чем «своя база на смену»: своя база на ПРОГОН.

Третье: датчик снова врал. В сводке стояло «красных ноль», и по этому числу
прогон читался зелёным, а настоящий счёт лежал в другом ключе и выход был два.
Поймал сложением. Годная проверка прогона — не одно число и не код возврата, а
сходится ли арифметика: всего равно зелёные плюс красные плюс ошибки плюс
пропущенные.

Чистый полный прогон: всего 5140, зелёных 5136, красных ноль, ошибок ноль,
пропущено 4, утверждений 16188, выход ноль. Арифметика сходится.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 21:38:41 +03:00
Дмитрий c27488d668 docs лендинг: в промт добавлены планка, режим смены и запрет срезать углы
Владелец прочитал промт и указал, чего в нём не хватало.

Новое в начале промта, до всего остального:
· ПЛАНКА — это не задача сделать сайт, это задача произвести впечатление.
  «Шокировать, но не кислотой, а дороговизной, технологичностью и
  элегантностью». Таблица «чем шокируем / чем НЕ шокируем». Вау-эффект
  безоговорочно; сравнение не с прошлым лендингом, а вровень с эталоном.
· НИКАКОЙ ПЛОСКОСТИ — основа видео-эталон; плоская вёрстка это не упрощение,
  а другая работа.
· ТОКЕНЫ НЕ ЭКОНОМИМ, УГЛЫ НЕ СРЕЗАЕМ — с расшифровкой, что именно это
  значит: не «пока попроще», не подменять проверку рассуждением, не выдавать
  первый вариант за найденный, переделывать столько раз, сколько нужно.
· РЕЖИМ СМЕНЫ — не больше 200-300 тысяч токенов, останавливаться в логичных
  и законченных местах, перед остановкой записывать состояние на диск,
  усталость называть вслух и просить компакт. Не тянуть до последнего:
  качество падает раньше, чем кончается место.

Прочее в промте:
· разделение источников таблицей — видео даёт устройство и планку, картинка
  содержание и палитру; при расхождении побеждает видео;
· три вопроса себе вместо одного: мир или подложка · выдержит ли сравнение
  с эталоном · тут вау или просто аккуратно;
· оговорка, что landing-3d это заготовки, а не образец вкуса.

В цепочке вкуса: мерило из трёх вопросов (дорого? технологично? элегантно?),
к которому сводятся все двенадцать звеньев, и последняя проверка перед
показом — «ого» или «аккуратно».

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 21:16:37 +03:00