Commit Graph

4196 Commits

Author SHA1 Message Date
Дмитрий a709efdee4 feat(кошелёк): две колонки, период, разрез по кампаниям, расшифровка заморозки
Владелец 06.08: "кошелёк убогий и неинформативный". Отметил пять слабых мест
из шести. Не отметил только прогноз "надолго ли хватит" - он пополняет по
факту, а не по остатку.

Что теперь на экране:
- слева липкая колонка денег: свободно крупно, и под ней РАСШИФРОВКА
  заморозки - какая кампания, сколько заперто, когда вернётся. Раньше стояло
  голое "Заморожено 2 507 руб" без единого слова, под что;
- период: сегодня / вчера / 7 дней / 30 дней / свои даты, живёт в адресе
  страницы;
- столбики расхода по дням, цвет по каналу, своим CSS без библиотеки;
- таблица "Куда ушли" - строка на кампанию с суммой и долей, клик отбирает
  ленту;
- закладки по каналам сохранены, но теперь считаются за выбранный период;
- лента разбита по дням с итогом за день и постраничной догрузкой.

Сервер: две новые сборки RaskryitieZamorozki и OtchyotKoshelka, новая ручка
/api/advertising/wallet/report, лента получила отбор по датам, каналу и
кампании и листание по ключу вместо смещения. Расчёт списаний, заморозки и
возврата по сроку НЕ тронут - правка только про показ.

Найдено по дороге и закрыто:
- чтение отчёта обёрнуто контекстом построчной защиты. Без этого на боевом
  запрос вернул бы НОЛЬ строк молча: местная база под суперпользователем
  защиту обходит, и мы бы увидели это только у клиента;
- сторож на число запросов мог зеленеть БЕЗ самой ручки - на любой неизвестный
  путь портал отвечает страницей с кодом 200. Усилен и проверен вырезанием
  маршрута;
- общий форматтер срезал хвостовой ноль: "833,50" превращалось в "833,5". На
  это независимо наступили три правки подряд, каждая завела свою копию.
  Сведено в formatExact.

Границы суток и группировка по дням считаются ПО МОСКВЕ, а не по Гринвичу.
Сторож взят с живого боевого: запись 69, 2026-08-05 21:00:24 UTC - для
человека это 6 августа. Наивные версии всех трёх мест были написаны нарочно
и увидены красными, прежде чем чинились.

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

Проверено: 461 сторож сервера, 2135 сторожей экрана, контроль типов ноль,
статанализ ноль, форматтер чисто, сборка фронта проходит.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 11:18:26 +03:00
Дмитрий 6c01d3e08c обзвон З-2.1: заведено хранилище записей разговоров и переезд звука в него
Портал давал человеку два обещания про запись его разговора — «живёт месяц и
стирается сама» и «потребуешь удалить свои данные — удалим и голос». Обе чистки
были построены и обе ходили в хранилище с именем obzvon_zapisi, которого в
настройках НЕ СУЩЕСТВОВАЛО. Врать они не врали — честно отвечали «не смог
удалить файл», — но удалять им было нечего. Оба обещания были бумажными.

Построено:
  • config/filesystems.php — диск obzvon_zapisi. Драйвер переключается одной
    переменной окружения OBZVON_ZAPISI_DRIVER: в день покупки объектного
    хранилища меняется настройка, а не код;
  • ObzvonZapisHranilishche — единственная дверь к звуку. Приём с проверкой,
    открытие ПОТОКОМ со следом в журнале ПДн ДО чтения, ссылка со сроком в час
    там, где хранилище её умеет, и NULL там, где не умеет;
  • PereveztiZapisJob — переезд записи с сервера робота. Не воскрешает стёртый
    голос, не создаёт вторую копию, не оставляет сироты при проигранной гонке;
  • ZvukovoyFayl — одно место, где живёт знание «что такое запись разговора»:
    расширения, подписи форматов, граница пустой записи в 44 байта.

Три замка изоляции, и все три нужны: RLS на строке, явная сверка клиента и
сверка САМОГО ПУТИ — recording_path заполняет чужая машина, и путь вида
7/../8/golos.wav увёл бы в папку другого клиента при законной сверке клиента.

Исправлена ложь в бумаге. В комментарии диска obzvon_materialy было написано,
что вызов url на закрытом диске бросит исключение и публичной ссылки не
появится. Замерено живым запуском: у местного драйвера url не бросает НИКОГДА,
а молча отдаёт /storage/путь. Ссылка ведёт в папку публичного диска, где записи
нет, — вреда нет, но и обещанной защиты нет. Настоящая защита в том, что url не
зовёт никто.

Ловушка круга: проверка З-2.2 утверждала, что хранилища нет, и покраснела бы от
самой постройки. Вычеркнута не была — переписана. Она стерегла живое: пометить
строку стёртой при живом файле значит выкинуть её из указателя под чистку
навсегда. Теперь «файл жив, а убрать не вышло» строится честно — подставлено
хранилище, у которого delete отвечает отказом.

22 новых сторожа, каждый показан красным в пять заходов. Убрана подмена
настроек в заготовке z22DiskZapisey — пять сторожей З-2.2 теперь охраняют и
наличие хранилища тоже.

Прогон обзвона 212 из 212, статанализ 0 ошибок.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 11:02:17 +03:00
Дмитрий 6d9bb7f65d docs обзвон З-2.1: заведён отчёт круга до разведки
Пустой скелет разделов, чтобы обрыв сессии не съел собранное.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 10:06:03 +03:00
Дмитрий e47bc34714 docs обзвон: промт переписан для смены 4
Смена 3 закрыла три работы, которые владелец поставил первыми, и промт
переписан под то, что открылось.

Главное, что унесено отдельным правилом: "построено" вчера означало "лежит в
хранилище", а не "работает". Уборка записей была написана и проверена 27
сторожами, а на самой машине её не было вовсе. Отсюда правило 13 — спрашивать
третье: доехало ли до жизни.

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

Числа собраны заново командой: план 3811 строк и 12 построенных задач,
решений владельца 104, прогон 5014 проверок при нуле красных.

Отдельно записано честно то, чего смена не смогла: датчик "прирост равен числу
сторожей" на движущемся дереве не работает, и объяснить прирост не вышло —
соседняя смена писала новые файлы проверок прямо во время прогона.

Заведён раздел с вопросами, висящими на владельце, — их шесть, и ни один не
закрыт самовольно.
2026-08-06 09:15:14 +03:00
Дмитрий c3c1473455 docs приёмка: работа 3 принята — канон говорит правду и стережётся
Приговор вынесен своей рукой. Круг шёл в четыре захода, принят с пятью
оговорками.

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

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

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

Сторож поймал собственного автора через час после написания.
2026-08-06 08:48:36 +03:00
Дмитрий 2ea204e3b3 docs схема: сторож видит имя по пути, а не по окончанию
Прежде имя опознавалось только по окончанию, и сторож был слеп к
App\Services\Db\GrantsConsistencyChecker в db/02_grants.sql. Одна и та же
ложь, в одном месте, ловилась или нет по последнему слову. Скверно
вдвойне: чем незнакомее окончание, тем вероятнее, что класса и правда
нет.

Теперь имя с путём считается именем независимо от окончания. Выбор
доказан замером четырёх правил: 17, 35, 40 и 348 срабатываний. Любое
слово-верблюд отпадает по числу — в шум идут PostgreSQL, SaaS и имена
тестов.

Список окончаний для голых имён расширен: цена — одно лишнее имя в
долге, находка — два имени в самом db/schema.sql, которых прежний
список не видел. Известная граница названа вслух внутри сторожа: голое
имя с незнакомым окончанием он не увидит, лечится привычкой писать имя
с путём.

Починил заодно две свои ошибки того же рода. Правило про запрет
обработки работало по окну в восемь строк и давало ложное красное на
десятке посторонних имён — сведено к тому же понятию куска, мерка в
стороже теперь одна на всё. И существующими считались классы только из
app/app: собственные проверки проекта сторож посчитал бы
несуществующими. Добавлены app/tests и app/database.

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

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

Полный прогон: 5011 проверок, красных 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 08:42:18 +03:00
Дмитрий 26746ec1de docs приёмка: З-0.8 принята — текстовый след разговора закрыт
Приговор вынесен своей рукой. Задача З-0.8 принята с четырьмя оговорками.

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

Вторая моя ошибка: сказал, что мест четыре. Помощник нашёл то, о чём я не
подумал вовсе, — имя человека, оно писалось и отдельной строкой, и внутри
речи Лены, 64 строки из 242.

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

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

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

Записанные ранее слова не стёрты: в журнале по-прежнему 128 дословных реплик,
уйдут вращением за 90 дней. Течь остановлена, лужа остаётся.
2026-08-06 08:34:16 +03:00
Дмитрий 76944fb46f docs: описан текстовый след разговоров и как проверить, что уборка жива
README Лены: новый раздел про текстовый след - четыре места, что сделано у
источника, почему живой журнал вращается, а законченная выжимка удаляется
по возрасту, где что лежит на сервере и чем всё это проверить.

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

Отчёт круга дописан целиком: замеры, семь ножей, разбор задания.
2026-08-06 08:21:37 +03:00
Дмитрий fa87a6cc3a docs(кошелёк): замысел переделки экрана - две колонки, период, разрез по кампаниям
Владелец 06.08: кошелёк убогий и неинформативный. Прошёлся по нынешнему
экрану и отметил пять слабых мест из шести. Не отметил единственное -
прогноз "надолго ли хватит денег": он пополняет по факту, а не по остатку.

Отмечено: не видно расхода во времени; не видно, сколько съела каждая
кампания; "Заморожено 2 507 руб" без единого слова, под что и когда
вернётся; лента без итогов и без отбора по датам; выглядит бедно.

Выбранное направление - две колонки. Слева липкая колонка денег с
расшифровкой заморозки по кампаниям и датой возврата, справа период
(сегодня / вчера / 7 / 30 / свои даты), столбики по дням, таблица
"Куда ушли" и лента, разбитая по дням с итогом за день.

Проверено на боевом только чтением: данных хватает, новых таблиц не
нужно. Сумма активных заморозок в ad_wallet_holds сошлась с frozen_rub
кошелька копейка в копейку - 2 507,00 руб на три кампании.

Записан главный подводный камень: пояс приложения UTC, а кабинет
показывает московское время. Границы суток и группировку по дням считать
по Москве, иначе "сегодня" начнётся в три часа ночи. Сторож на это
заведён отдельным пунктом и обязан быть красным до правки.

Скилы: superpowers:brainstorming (процесс) + frontend-design (облик,
инструмент 30 тулчейна); список примет убожества сверен по стороннему
redesign-existing-projects как по справочнику, не как по решале.

Кода эта запись не меняет - только замысел.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 08:20:40 +03:00
Дмитрий 53288b5cfd feat: убран текстовый след разговоров и назначен срок хранения три месяца
Мост писал в журнал дословные слова человека и его имя. Журнал живёт не во
временной папке, его не чистит даже перезагрузка, и срока хранения у него
не было никакого - слова человека лежали дольше его же голоса.

Что сделано:
- most.py пишет меру реплики вместо самой реплики: когда заговорил, сколько
  сказал, на каком языке расслышали. Имя человека спрятано и в строке
  "кому звоним", и внутри речи Лены. Накопитель дословных слов в памяти
  службы убран - его никто не читал;
- tekstovyy-sled.logrotate - вращение журналов моста и летописи звонков,
  срок 90 суток, решение владельца Р104. Вращение, а не удаление по
  возрасту: живой журнал по возрасту не стареет никогда;
- chistka-sleda-prob.sh и chistka-sleda-prob.cron - уборка выжимок проб
  по тому же сроку;
- proba-mosta-bez-zvonka.py - проба моста подставными посылками Inworld,
  без живого звонка;
- proverka-tekstovogo-sleda.sh - сторож по каждому из четырёх мест отдельно.

Чужие файлы не тронуты. Оба чужих сторожа зелёные.
2026-08-06 07:57:09 +03:00
Дмитрий 82503073cc docs схема: сторож стережёт все бумаги про базу, а не одну
Прежняя версия читала один db/schema.sql. Дыра хуже, чем пропущенный
файл: два из семи мест лжи, которые эта же работа и чинила, жили в
db/CHANGELOG_schema.md. Сторож берёг ту бумагу, где ложь уже поправлена,
и не берёг ту, где она жила.

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

Журнал схемы помнит прошлое, и первая версия правила покраснела на моей
же честной записи v9.71. Глушить сторожа не стал: правило простое и
проверяемое — кто называет несуществующее имя, тот пишет НЕ СУЩЕСТВУЕТ
тем же куском текста. В SQL кусок это подряд идущие комментарии, в
разметке абзац, причём строка таблицы стоит сама за себя. Запись v9.71
переписана по этому правилу.

Имена кусков кода теперь ищутся не только в app/app, но и по карте
классов Composer. Без неё QueryException из фреймворка попадал в наш
долг, то есть сторож врал про чужой класс.

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

Показан красным пятью ножами: schema_modules, журнал схемы, сырая
миграция, schema.sql и отдельно снятие пометки с моей честной строки.
Отдельно назвал границу мерки: ложь ВНУТРИ честного куска проходит
зелёным, и это выбрано сознательно.

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

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 07:48:47 +03:00
Дмитрий ddf58fe025 docs: заведён скелет отчёта работы 2 по текстовому следу разговоров
Отчёт пишется по ходу работы, а не в конце.
2026-08-06 07:30:46 +03:00
Дмитрий a8481b68c0 docs схема: седьмое место лжи и живой сторож канона
Седьмое место — шапка столбца sso_provider у таблицы админов. Там стояло
голое обещание «Логика guard'ов — в SaasAdminAuthService», без единой
оговорки. Класса нет. Место опаснее прочих шести: речь об аварийном
входе, который нарочно обходит единый вход. Ни SSO, ни обязательный
второй ключ, ни ограничение аварийного входа кодом не проверяются.

Сторож заведён отдельной новой проверкой портала:
app/tests/Unit/Schema/KanonNeObeshchaetOhrannikaTest.php. Общих файлов
не трогает, базы не требует, ходит сам при каждом полном прогоне.
Краснеет, когда канон называет поимённо кусок кода портала, которого
нет в проекте, а рядом не сказано, что его нет.

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

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

Полный прогон: 5011 проверок, красных 0, ровно плюс две мои.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 07:08:02 +03:00
Дмитрий a69df6a12e docs приёмка: работа 1 принята — уборка на машине робота вправду живёт
Приговор вынесен своей рукой. Круг принят с тремя оговорками.

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

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

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

Живых записей было 86 и осталось 86. Оба надреза возвращены, слепки совпали
знак в знак. Прогон своей рукой 5009 проверок, красных ноль.
2026-08-06 06:47:54 +03:00
Дмитрий 8df431a4ea fix: две беды по приговору — слепая проверка расписания и права папки после перезагрузки
Беда 1. Проверка «расписание зовёт chistka-zapisey.sh» считала совпадения по
всему файлу вместе с пояснениями и удовлетворялась собственным комментарием:
подмени строку запуска на вызов несуществующего файла — проверка оставалась
зелёной. Заменена на четыре зрячие: сторож берёт саму строку запуска, достаёт
из неё пользователя и путь и спрашивает, существует ли то, что расписание
вправду зовёт, и тот ли это скрипт.

Беда 2. Доказательство «ubuntu удаляет файлы asterisk» было сделано на здоровом
случае. Папка живёт в /tmp и исчезает при перезагрузке, дальше её создаёт заново
демон Asterisk. Замерил его umask — 0022, значит папка возродится с правами 0755,
и уборка не удалила бы НИ ОДНОГО файла, оставаясь на вид живой. В приговоре было
0775, на деле хуже: 0755. Проверено с контролем «файл вправду существует».

Лечение: правило /etc/tmpfiles.d/lena-inworld.conf, которое воссоздаёт папку при
каждой загрузке с явными правами 0775 asterisk:ubuntu. Эталон положен в
хранилище как lena-inworld.conf, слепки сходятся побайтово. Не root — root в
папке, открытой всем, хуже лечимой беды, и журнал стал бы его. Не общая группа —
после перезагрузки права всё равно 0755, группе там писать нечем.

Сторож вырос с 17 до 26 проверок. Главная новая — замером, а не рассуждением:
кладёт подставной файл от asterisk и пробует удалить его от того пользователя,
который взят из самой строки расписания, потом убирает за собой.

Каждая из девяти новых проверок показана красной восемью ножами, включая нож
надзирателя и нож приговора. Нож B нарочно отделяет «зовёт не тот скрипт» от
«зовёт то, чего нет» — проверки независимы.

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

Записей было 86 и осталось 86, слепок списка совпал с началом смены байт в байт.
Мусора на машине не осталось, проверено командой.
2026-08-06 06:38:18 +03:00
Дмитрий 4a993f8575 feat(кошелёк): видно, за что списали и сколько уходит на каждый канал
Три правки по замечаниям владельца от 06.08.2026.

1. Кошелёк переехал из «Рекламных возможностей» в «Финансы», рядом с
   «Биллингом» — это деньги, а не рекламный канал. Перенесён в обоих меню:
   боковая панель и мобильное «Ещё».

2. Каждое списание теперь называет канал, номер и название кампании:
   «Яндекс Аудитория · кампания №21 «Я4 приёмка — впритык…»». Раньше все до
   одного писались немой фразой «Списание за рекламу (факт)». Подпись
   собирается при показе, поэтому заговорили и уже записанные строки —
   летопись задним числом не переписывается, это финансовый документ.

   Попутно закрыта ловушка: номера кампаний у Яндекса и у СМС идут по разным
   счётчикам и совпадают. В боевой летописи есть и «кампания №4» от СМС, и
   рекламные — различить их было нечем. Теперь разводит канал в подписи.
   Поправлен падеж: было «Заморозка снята — кампанию №13».

3. Закладки по каналам с суммой трат прямо на закладке: Всё 157,74,
   Яндекс Аудитория 130,74, Рассылка СМС 27,00. Тратой считается только
   списание — заморозку ещё можно вернуть, что и случилось с 724 руб.

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

Сторожа: 6 на сервере, 5 на экране, каждый сначала увиден красным.
Рекламный блок 441 зелёный, фронт 2108 зелёных, статанализ ноль, типы чистые.
2026-08-06 06:35:55 +03:00
Дмитрий e54be8adfc docs приёмка: отчёт работы 3 дописан — прогон, сторож, разбор задания
Полный прогон проверок портала на своей базе liderra_testing_kanon:
5009 проверок, 5005 прошли, красных 0, код возврата 0.

Тестовая база собрана с нуля из поправленного канона: 192 миграции при
192 файлах, новая подпись доехала до базы дословно. Значит правка внутри
COMMENT ON COLUMN исполняемый текст не сломала.

Счётчики шапки канона не изменились: таблиц 99, указателей 144,
политик 48, функций 5, триггеров 15 — до и после одинаково.

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

Временная база снесена, снос проверен командой.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 06:14:41 +03:00
Дмитрий f4c3220ffd fix: уборка записей Лены заведена на самой машине робота, а не только на бумаге
Была беда: скрипт уборки жил только в хранилище. На машине робота не было ни
файла, ни расписания — замерено тремя приборами. Значит голоса людей копились
бы бессрочно, хотя владелец обещал месяц, решение Р95.

Что сделано на машине 51.250.1.97:
- скрипт положен в /home/ubuntu/lena-inworld/chistka-zapisey.sh, слепок сходится
  с хранилищем побайтово, содержимое не правил ни на букву;
- расписание /etc/cron.d/lena-chistka-zapisey — раз в сутки 01:40 по времени
  сервера, это 04:40 по Москве, от пользователя ubuntu;
- рядом положен сторож скрипта proverka-chistki.sh, 27 проверок, зелёный там же.

Что добавлено в хранилище:
- bots/lena-golos/chistka-zapisey.cron — эталон расписания. На сервере имя без
  точки: файл с точкой в имени cron молча пропускает;
- bots/lena-golos/proverka-raspisaniya.sh — новый сторож на 17 проверок. Он
  проверяет не скрипт, а живёт ли уборка на машине;
- README.md — раздел про уборку на сервере.

Доказано замерами, не рассуждением:
- уборка удаляет файл, принадлежащий asterisk, запускаясь от ubuntu — подставной
  состаренный файл, в журнале «удалено 1»;
- заготовки chelovek, imya.txt и подпапки не тронуты, хотя старше срока;
- проход по расписанию оставил строку, которой рука не писала;
- пустой проход тоже оставляет след «удалено 0»;
- живых записей было 86 и осталось 86 — слепок списка совпал побайтово;
- текст расписания на сервере и в хранилище один и тот же.

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

Осталось открытым: сторожа никто не зовёт сам; расшифровки разговоров в
most.log уборка не касается — это следующий круг.
2026-08-06 06:04:11 +03:00
Дмитрий b04c3e92d2 docs схема: канон перестал обещать охранника, которого нет
Решение владельца Р103 от 06.08.2026 — лечим бумагу, охранника не строим.

Поле pd_subject_requests.processing_restricted существует, а обещанного
каноном охранника App\Services\Pd\ProcessingRestrictionGuard и исключения
App\Exceptions\Pd\ProcessingRestrictedException в проекте нет вовсе.
Портал по этому флагу не запрещает ничего.

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

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

db/schema.sql — 4 места: шапка pd_subject_requests, COMMENT ON COLUMN,
пункт Ю-9 в списке решений v8.5, impersonation_tokens.second_approver_id.
db/CHANGELOG_schema.md — 2 пометки в старых разделах + новая датированная
запись v9.71 со ссылкой на Р103.

Боевая база не тронута: подпись к столбцу там прежняя, менять только
с отдельного разрешения владельца.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 06:01:56 +03:00
Дмитрий 5fa17edc86 docs обзвон: решение владельца Р104 — текстовый след храним три месяца
Владелец закрыл развилку, которая висела без ответа: срок хранения текстового
следа разговора. Р95 назначал месяц только для звука, на дословные слова и
телефоны звонивших срока не было никакого.

Решение: три месяца, столько же, сколько портал хранит расшифровку. Срок один
и для слов, и для телефонов.

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

Записано и то, чего решение НЕ закрывает: текст переживёт голос на два месяца,
и человеку это придётся объяснять; срок не отменяет обезличивания журнала
и не назначает того, кто будет чистку звать.

Протокол вырос до 104 решений.
2026-08-06 05:51:06 +03:00
Дмитрий 1e8c127bb7 docs обзвон: лист работы 2 заведён до работы, вырезание нашло четвёртое место
Приёмочный лист задачи З-0.8, решение владельца Р99. Заведён ДО работы.

Все три места, названные планом, перемерены командой и подтверждены:
дословных реплик 128 и 126 в двух журналах моста, 165 строк летописи
звонков с телефонами с 23 июля, правило вращения на летопись не наводится.

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

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

Открытая развилка записана и не закрыта самовольно: срок хранения ТЕКСТА
владелец не назначал, Р95 назначил месяц только для звука.
2026-08-06 05:42:42 +03:00
Дмитрий 2bdb7a1f25 docs: заведён скелет отчёта работы 3 — правда про прекращение обработки
Скелет разделов заводится до разведки, чтобы наработки не пропали
при обрыве разговора по длине.
2026-08-06 05:37:06 +03:00
Дмитрий 9e57a944f8 docs: заведён отчёт работы 1 — уборка записей на машине робота
Скелет разделов. Пишется по ходу работы, а не в конце.
2026-08-06 05:35:56 +03:00
Дмитрий edd27baea4 docs обзвон: приёмочные листы смены 3 заведены до работы
Два листа заведены ДО начала работ, как требует метод.

Работа 1 — уборка записей на сервере робота, решение владельца Р98.
Разведка тремя приборами вскрыла мою собственную ошибку: промт утверждал,
что не хватает только расписания, а на машине нет и самого скрипта уборки.
Замер: 86 записей, 62,4 МБ, старше месяца ноль — уборка, заведённая сегодня,
удалит сегодня ровно ноль, первое настоящее удаление около 01.09.2026.

Работа 3 — ложь канона про охранника, решение владельца Р103.
Разведка вскрыла вторую мою ошибку: мест лжи не одно, а четыре, и два из них
в журнале схемы, где несуществующий класс расписан как готовое устройство.
Заодно перемерено моё же утверждение "читает только обзвон" — оказалось
неточным.
2026-08-06 05:32:39 +03:00
Дмитрий 3c0a01699b docs,обзвон: владелец закрыл все восемь висевших вопросов — решения Р97-Р103
Протокол вырос с 96 решений до 103, промт переставил из-за них порядок работ.
Разрез, по которому лёг новый порядок: сперва идущий вред, потом заряженный. На
сервере робота голоса и телефоны живых людей копятся с 23 июля и не убираются
ничем; в портале записей обзвона нет ни одной.

Поэтому первой работой смены 3 идёт не задача плана, а завести уборку записей на
сервере робота — она построена и проверена 27 сторожами, но её не зовёт никто.
Второй З-0.8, текстовый след разговора: там дословные расшифровки речи и телефон
каждого звонившего, и бумага от 3 августа утверждала, что личных данных там нет,
а это оказалось неправдой. Третьей маленькая правка текста канона схемы. И только
четвёртой и пятой остаток волны 2.

Что решено против плана: стоп-листы при стирании по требованию не вычёркиваем.
Довод владельца принят — стерев человека из списка «этому не писать», портал
снова начнёт ему слать, и требование «удалите меня» обернётся возобновлением
рассылки. План в задаче З-2.5 велит обратное, верно решение.

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

У каждого решения записаны отрезанные ветки и строка «чего это не закрывает».
Разметка ноль ошибок, все ссылки промта проверены на существование.
2026-08-06 05:16:33 +03:00
Дмитрий a89e0b1595 docs(приёмка Яндекса): последняя карточка закрыта — 29 из 29, возврат по сроку пойман
Я-Д5, вторая половина: release +724,00 руб по кампании 13 в 00:00:16 шестого
августа. Смета 850,00 минус откручено 126,00 — копейка в копейку. Кампания
стала completed, Яндекс говорит ENDED. Возврат ровно один, списаний после
закрытия нет, кошелёк сходится: заперто 2512,50.

Час предсказан накануне и совпал: закрытие по сроку живёт внутри часового
обхода списаний, а часовой пояс приложения UTC — значит «завтра» наступает
в 00:00 UTC, в три ночи по Москве.

Вторая половина предсказания провалилась: после смерти #13 поехала не та
кампания. #21 набрала 7 показов за час, а #16 с вдвое более щедрой частотой
стоит на месте. Порядок предсказан неверно, записано как есть.

Я3 и Я4 своего не доберут: #21 нужно 834 показа при восьми, #19 нужно 1667
при нуле, срок у обеих кончается сегодня. Пишем недостигнутыми по решению
владельца.
2026-08-06 05:07:34 +03:00
Дмитрий 9585a120a0 docs,обзвон: промт переписан для смены 3 — волна 2 закрыта на три четверти
Смена 2 закрыла два круга: З-2.5 стирание по требованию и З-2.2 чистка по срокам.
Осталось две задачи волны 2, и порядок переставлен замером: первой идёт З-2.1, а
не З-2.4. Довод записан в промте — З-2.4 это удобство на экране, а З-2.1 держит
два уже построенных обещания: обе чистки умеют убрать строку и обе честно кричат,
что файл убрать нечем, потому что хранилища записей в портале нет и заводит его
именно З-2.1.

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

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

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

Все числа собраны командой заново, все десять ссылок проверены на существование,
разметка ноль ошибок.
2026-08-06 02:16:47 +03:00
Дмитрий 9ac09fb1c1 docs,обзвон: приговор по кругу З-2.2 — своя ошибка была не пропуском, а подсказкой в неверную сторону
Своих ошибок две, называю первыми. Пятнадцатая: я не просто пропустил ловушку, я
на неё указал. В задании написал «ищи просроченные по этим указателям» и
перечислил их поимённо, а указатель отбирает строки, не спрашивая, было ли
содержимое вообще. Чистка по моему совету поставила бы след «расшифровка удалена
по сроку» строкам, у которых расшифровки не было никогда, а у записей, которые
приносит клиент, соврала бы про все разом: расшифровщик живёт в четвёртой волне,
текста нет ни у одной. Замки базы такого не ловят. Своя ошибка, вложенная в
поручение, становится ошибкой помощника — здесь спас несогласный исполнитель.

Шестнадцатая: ложный совет, повторённый за планом. Написал «пустой прогон обязан
быть виден в журнале», а на боевом журнал глотает всё ниже предупреждения. Это
записано в памяти проекта отдельной находкой, и я всё равно не сверил. Тот же
класс, что ошибка двенадцатая прошлой смены: совет, который я не запустил.

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

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

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

Круг ПРИНЯТ с двумя оговорками: стирание звука работает на бумаге, хранилища ещё
нет, и команда об этом честно кричит; расписание на живой машине не заведено —
решение владельца не принято.

Прогон своей рукой: 4998 проверок, красных ноль, прирост ровно плюс двадцать пять
при двадцати пяти новых сторожах. Датчик бумаг сходится: одиннадцать отметок при
одиннадцати закрытых задачах.
2026-08-06 02:09:41 +03:00
Дмитрий 9b66c7cd71 test обзвон: шесть сторожей по дырам приёмки — настройка, повтор, объём
Приёмка нашла три дыры, все в сторожах, а не в коде. Код не тронут ни одной
строкой: сверено пустым git diff по всем моим файлам.

Дыра 1 — срок можно было зашить в код, и никто бы не заметил. Прежний сторож
проверял, что строки настроек ЗАВЕДЕНЫ, а не что их ЧИТАЮТ. Заведены два
сторожа поведения: настройка, отличная от умолчания, обязана менять судьбу
записи. У материалов клиента этой дыры нет — чистка там настроек не читает,
а читатель настроек накрыт чужим сторожем круга З-2.3, проверено тем же ножом.

Дыра 2 — повторный запуск. Два сторожа: второй заход не падает, строку не
переписывает и не дописывает в журнал ПДн лишнюю запись об уже стёртом.
Половина сторожа, сравнивавшая столбцы, обманывалась одной секундой —
добавлен ctid, прибор «трогали ли строку вообще».

Дыра 3 — объём. Мерка построена другая, чем просила приёмка, и в отчёте
объяснено почему: запросы обязаны расти с числом строк, иначе придётся
отказаться от правила «не стёрся файл — строку не трогаем». Ловим лишний
запрос в переборе: цена строки прибита к четырём и обязана совпадать на
двух объёмах. Плюс сторож на потолок за заход — его не было вовсе, а именно
он защищает ночь от полумиллиона просроченных строк.

Полный прогон: 4992 на входе, 4998 на выходе, красных ноль.
2026-08-06 01:47:27 +03:00
Дмитрий 9436134adf docs обзвон: в отчёт смены З-2-2 вписаны номера коммитов 2026-08-06 00:49:11 +03:00
Дмитрий cec731b17c feat обзвон: чистка записей по сроку хранения — три ступени и чужие голоса
Записи разговоров и записи, которые клиент приносит для обучения робота,
умели приниматься и получать дату истечения — а стирать по этой дате не умел
никто. Любая попавшая к нам запись лежала бы вечно при обещанном сроке.

Построено:
- obzvon:chistka — три ступени по одной строке звонка: месяц звук, три месяца
  расшифровка, дальше ничего. Строку не удаляет никогда: вместе с ней ушли бы
  деньги, и клиент не смог бы спросить «за что вы с меня взяли».
- obzvon:chistka-materialov — чужие голоса: звук 30 дней, расшифровка полгода,
  два срока врозь. Кроме этой команды их не убирает ничто.
- SrokiZvonka — правило срока в одном месте: им пользуется чистка и им же
  обязана пользоваться звонилка волны 3, когда будет проставлять срок.
- Два ключа сроков звонков в system_settings. Новых таблиц нет.
- Обе команды в расписании и в списке сторожа пульса: команду, которой в
  списке нет, scheduler:check-heartbeats не проверяет вовсе.

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

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

19 сторожей, каждый показан красным. Полный прогон свой рукой.
2026-08-06 00:47:47 +03:00
Дмитрий 6c8d133421 docs обзвон: скелет отчёта смены З-2-2 по чистке записей
Отчёт заводится до разведки и пишется по ходу работы.
2026-08-05 23:58:12 +03:00
Дмитрий c88a14b163 docs,обзвон: приёмочный лист круга З-2.2 заведён ДО работы
Разведка до задания дала три расхождения. Главное: у строки звонка даты
истечения могут быть пустыми, тогда как у материалов клиента обе обязательны, и
канон прямо объясняет почему — строка без даты истечения это голос человека,
которого не найдёт ни одна чистка. Значит звонок с непроставленным сроком не
будет вычищен никогда, а проставлять эти даты сегодня некому: строки звонков не
пишет ни один сервис. Вопрос решается сейчас, иначе первая партия боевых звонков
ляжет вечным грузом.

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

Третье: проверку «карточка говорит словами» исполнить нечем — экрана нет, его
строит волна 4. Вместо неё засчитаю признак в данных, из которого надпись
рисуется.

Попутно: порядок «третий заход в расписание после З-1.6» неисполним буквально —
ни З-0.7, ни З-1.6 не построены, горло свободно и я иду первым.
2026-08-05 23:55:08 +03:00
Дмитрий f7c59ad747 docs,обзвон: приговор по кругу З-2.5 — вырезание нашло невод, который ловит ноль
Своя ошибка названа первой и она четырнадцатая. Перечень мест, где живёт человек,
я собрал глазами по одной таблице, а не командой по всем. В задании назвал звук и
расшифровку, а мест оказалось четыре: телефон в строке звонка и, тяжелее, телефон
в списке, из которого робот набирает. Имя той таблицы я в разведке видел, но
внутрь не заглянул. Оставь мы там номер, и человеку позвонили бы снова после
отчёта «выполнено»: лежащий голос он не услышит, а звонок услышит ухом. Нашёл не
я, а несогласный исполнитель — десятый раз из четырнадцати.

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

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

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

Круг ПРИНЯТ с тремя оговорками: стирание в чужих материалах остаётся частичным и
портал говорит это вслух; у читателя запрета зовущего в бою нет, звонилка не
построена; канон схемы продолжает утверждать несуществующего охранника.

Прогон своей рукой: сервер 4973 проверки, красных ноль, прирост ровно плюс
девятнадцать при девятнадцати новых сторожах. Интерфейс 2103, красных ноль.
Датчик бумаг сходится: десять отметок при десяти закрытых задачах.
2026-08-05 23:50:44 +03:00
Дмитрий 1f260c0b97 fix/обзвон: честный отчёт о стирании доходит до оператора - З-2.5, второй заход
Приёмка вскрыла, что первый заход воспроизвёл ту же беду на другом основании.

1. Невод по тексту не мог найти НИЧЕГО по построению.
   `obzvon_materialy_klienta.transcript` не пишет никто: расшифровщик живёт в
   З-4.2, волна 4. Значит сводка честно говорила "материалы клиента=0", пока
   голос человека лежал на диске 30 дней. Теперь портал считает отдельным числом
   записи, которые проверить НЕЧЕМ - звук жив, расшифровки нет и не было, - и
   говорит это тревожной строкой.
   🔴 Условие уточнено против предложенного: добавлено transcript_deleted_at IS
   NULL. Без него строка, у которой расшифровку стёрли мы сами, а файл убрать не
   смогли, попадала бы в оба числа сразу. Доказано надрезом.

2. Изоляция клиентов не сторожилась ничем. Соединение обходит защиту строк, значит
   отбор по клиенту в коде - ЕДИНСТВЕННЫЙ замок. Сняв его, приёмщик оставил все
   13 сторожей зелёными. Заведены сторожа на все три таблицы.

3. Своя находка того же класса: читатель флага сверял телефон точными написаниями
   с колонкой, которую заполняет ЧЕЛОВЕК руками. На записи "8 (900) 123-45-67"
   он молча отвечал "звонить можно" тому, кто потребовал прекратить обработку.
   Сверка переведена на хвост из десяти цифр - и там, и в переходнике.

4. Экран админки показывал зелёную галочку "выполнено" и пустое поле
   "Webhook-логов", а про обзвон и про нестёртые файлы молчал. Это видимая
   половина той же неправды: тот, кто жмёт кнопку, и есть тот, кто обязан пойти
   проверить руками. Экран называет обзвон поимённо, при нестёртых файлах и
   непроверяемых записях галочки нет вовсе - вместо неё тревога. Мёртвое поле
   убрано вместе с полем в типе ответа.

Сторожа: 13 -> 19 на сервере, плюс 5 экранных. Каждый показан красным семью
надрезами по коду.

Отчёт: docs/superpowers/priyomka/stroyka-2/z-2-5-otchyot-2026-08-05.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 23:26:49 +03:00
Дмитрий b0025f8f90 docs: отчёт З-2.5 - номера коммитов и состав выката
Дописан раздел "Что построено": оба коммита названы, проверено git show --stat,
что чужие куски из индекса в коммит не попали.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 22:27:48 +03:00
Дмитрий cfbe9d51c2 feat/обзвон: требование "удалите мои данные" доходит до обзвона - З-2.5
Портал ставил обращению отметку "выполнено", а голос человека оставался лежать:
наша запись месяц, наша расшифровка три месяца, чужая расшифровка полгода.
Это не недоделка, а машинный ложный отчёт - портал утверждал обратное сделанному.
Бьёт по самым беззащитным: люди на чужих учебных записях согласия нам не давали.

Построено:
- App\Services\Obzvon\ObzvonErasureAdapter - стирает звук, расшифровку и телефон
  в obzvon_calls, телефон в obzvon_number_results, расшифровку и звук в
  obzvon_materialy_klienta. Строку звонка НЕ удаляет: вместе с ней ушли бы деньги.
- App\Services\Obzvon\ObzvonZapretObrabotki - первый в портале читатель флага
  processing_restricted. Отвечает "звонить можно/нельзя" и называет причину словами.
- tests/Feature/Obzvon/ObzvonStiraniePoTrebovaniyuTest.php - 13 сторожей,
  каждый показан красным девятью надрезами по коду.

Правлено точечно: PdErasureService зовёт переходник внутри той же транзакции и
включает его числа в сводку обращения.

Сверх задания, названо в отчёте:
- стирается сам телефон в obzvon_calls, а не только звук с расшифровкой;
- стирается номер в obzvon_number_results - это список, ИЗ КОТОРОГО РОБОТ
  НАБИРАЕТ. Оставить там номер значило бы позвонить человеку снова после того,
  как портал отчитался "выполнено";
- поиск в чужих материалах идёт по нескольким написаниям телефона, а не по
  одному точному: в портале номера лежат и с плюсом, и без.

Границы соблюдены: стоп-листы не тронуты, новых таблиц и миграций нет, боевого
сервера не касался.

Отчёт: docs/superpowers/priyomka/stroyka-2/z-2-5-otchyot-2026-08-05.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 22:25:49 +03:00
Дмитрий 04aa2b863e docs: скелет отчёта З-2.5 - стирание по требованию доходит до обзвона
Пустой каркас разделов, чтобы писать по ходу работы, а не в конце.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 21:27:56 +03:00
Дмитрий 4993cf1223 docs,обзвон: приёмочный лист круга З-2.5 заведён ДО работы
Смена 2, круг первый. Разведка сделана до задания и дала три расхождения плана
с делом. Первое: план велит стиранию доставать до расшифровок чужих записей, а в
таблице материалов клиента нет ни телефона, ни имени — единственная дорога до
человека это поиск по тексту расшифровки, и план способа не назвал. Второе:
канон схемы утверждает, что при поднятом флаге запрета обработки сервисы
поднимают исключение через класс-охранник, а такого класса в проекте нет ни
одного упоминания — бумага описывает защиту, которой не существует. Третье:
сроков не два, а четыре, и самый долгий шесть месяцев, тогда как план называет
трёхмесячную чистку как единственную.

Отдельно поднимаю возражение самому плану: он велит стиранию чистить стоп-листы,
а это вредно. Стерев человека из списка «не писать», мы снова начнём ему писать,
и требование «удалите мои данные» обернётся возобновлением рассылки. В круг не
беру, выношу владельцу вопросом.

Заранее названа больная точка приговора: у читателя флага зовущего в бою не
будет, звонилка живёт в волне 3. Сказано до работы, чтобы не обнаружилось потом.
2026-08-05 21:23:47 +03:00
Дмитрий 7d8551c38c docs,обзвон: промт обновлён — порядок работ переставлен находкой круга З-2.3
Круг З-2.3 принят, приговор дописан: полный прогон своей рукой дал 4954 проверки,
4950 зелёных, четыре пропущено, красных ноль, код возврата ноль. Прирост ровно
плюс двадцать четыре — столько же, сколько новых сторожей завёл круг. Совпадение и
есть доказательство, что чужих проверок никто не тронул.

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

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

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

Все числа собраны командой заново и каждое сверено с делом. Одно не сошлось и
исправлено до коммита: чужих коммитов за сутки восемнадцать, а не десять — я
написал по памяти. Оговорка про это оставлена в самом промте.
2026-08-05 21:07:13 +03:00
Дмитрий 80d4fa2cfa docs,обзвон: приговор по кругу З-2.3 — вырезание нашло ложный отчёт о стирании
Своя ошибка названа первой и она шестая за смену. Я разрешил помощнику построить
ручку приёма и назвал папку, куда её класть. Класть было некуда: файла маршрутов
в проекте не существует вовсе. Класс тот же, что у пяти предыдущих: утверждение о
коде без замера. Я перемерил пять утверждений плана и не перемерил своё
собственное. Побочная цена: у построенного ноль зовущих в бою, дорогу кладут
задачи волны 4.

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

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

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

Врезка вписана в задачу З-2.5, её вес меняется: она обязана закрыться до первого
живого обзвона. Врезка ПОСТРОЕНО вписана в З-2.3 с шестью расхождениями. Датчик
бумаг сходится: девять отметок при девяти закрытых задачах.
2026-08-05 20:53:58 +03:00
Дмитрий efd08a82e8 docs: отчёт З-2.3 — названа своя небрежность порядка
Ножи 8-12 резались параллельно идущему полному прогону, и правились те же
файлы. Прогон рвал бы только мои же проверки, и они зелёные, но число
«красных 0» получено на шевелящемся дереве.

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

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 20:39:45 +03:00
Дмитрий b32626f232 docs: отчёт круга З-2.3 — приём материалов клиента
Четыре мерки с числами, семь ножей со слепками до и после, разбор задания
и шесть расхождений задания с делом.

Свои ошибки названы первыми: правка через оболочку вопреки правилу, 38 чужих
моделей, тронутых ключом -M у ide-helper и возвращённых, и два незаслуженно
зелёных сторожа.

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

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 20:37:13 +03:00
Дмитрий 2b401298d8 feat: приём записей клиента для обучения робота обзвона — З-2.3
Клиент отдаёт нам записи СВОИХ холодных разговоров. Это голоса живых людей,
которые об этом не знают и согласия нам не давали. До этой правки принять их
было негде и нечем: положить так, чтобы клиент А не открыл запись клиента Б,
было некуда; срока жизни у записей не было; обращение к чужому голосу не
оставляло следа.

Что заведено:

- таблица obzvon_materialy_klienta — канон в db/schema_modules.sql раздел 24,
  журнал схемы v9.70. Изоляция клиентов защитой по строкам: ENABLE + FORCE,
  политика с USING и WITH CHECK. DELETE не выдан никому — строка остаётся
  носителем надписи «удалены по сроку хранения»;
- ДВА срока, а не один — решение владельца Р82: звук 30 дней, расшифровка
  шесть месяцев. Обе даты истечения NOT NULL: строка без даты означает голос,
  которого не найдёт ни одна чистка. Сами сроки — в настройках портала,
  не в коде;
- два следа удаления врозь: команда чистки из З-2.2 обязана уметь стереть
  звук, не тронув текст. Два замка не дают строке врать «стёрто», пока файл жив;
- закрытое хранилище obzvon_materialy: без ключа url и с serve=false, корень
  под storage/app/private. Публичной ссылки на чужой голос не появится даже
  по ошибке;
- служба MaterialyKlientaService: приём с отклонением чужого формата и битого
  файла, открытие с явной сверкой клиента поверх защиты по строкам, счёт
  записей без нижней границы — три берём, двадцать берём, ноль пускаем
  вторым путём;
- отказ MaterialNePrinyat отделяет наш сочинённый текст от дословного
  показания системы видимой границей. Настоящая причина не выбрасывается;
- след в журнале ПДн pd_processing_log готовым сервисом PdAuditLogger —
  на приём и на каждое открытие.

Стирает НЕ эта правка, а З-2.2, и она не построена. До её постройки материалы
не исчезнут — это известно и так задумано.

При накатке на боевой ОБЯЗАТЕЛЕН перезапуск db/03_service_bypass_policies.sql:
новой RLS-таблице мало политики и прав, иначе служебная роль молча правит
НОЛЬ строк.

Тронут один чужой сторож: SchemaDeltaTest, счётчик таблиц канона модулей
42 в 43. Так же его правили соседи на З-1.1 и З-1.3 — счётчик обязан расти
вместе с каноном, иначе прогон красный у всех.

Осталось открытым: от какой даты считать полгода — считаем от загрузки,
столбец recorded_at заведён под будущий ответ владельца.

24 сторожа, все 24 показаны красными двенадцатью ножами.
Полный прогон 4954 проверки, 4950 зелёных, 4 пропущено, красных 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 20:35:21 +03:00
Дмитрий b1f5bb1c6b docs(приёмка Яндекса): предсказание сбылось — хоронил я его на полчаса раньше времени
У #16 и #21 появилось по показу, списано по 0,50 руб в 16:00. Директ по всем
трём живым кампаниям пишет «Идут показы», объявления приняты: #16 — 15 из 15,
#21 — 13 из 13, #19 — 13 принято и 2 отклонено, как и задумано.

Вчерашнее предсказание «показы у #16 пойдут к 15:00» я объявил провалившимся
в 15:28. Первый показ пришёл между 15:35 и 16:00 — промах меньше часа.

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

Раскачка теперь известна по трём кампаниям: 4 ч 41 мин, 5 ч 17..42 мин,
3 ч 15..40 мин. Открытым осталось, почему после раскрутки #16 идёт по одному
показу в час против 25-42 у #13 — предсказание на 06.08 записано с допуском.
2026-08-05 20:07:52 +03:00
Дмитрий e572e492c4 docs: скелет отчёта круга З-2.3 — приём материалов клиента
Создан первым действием круга, до разведки, чтобы наработки не сгорели
при обрыве. Дальше файл наполняется по ходу работы.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 19:09:58 +03:00
Дмитрий 1b1c1879d7 docs(приёмка Яндекса): «ноль показов» оказался не нулём — найдено единственное различие
Спросили не портал, а сам Яндекс: у #16 и #21 по одному показу, у #13 — 193
против 169 в портале (отставание часового обхода, не поломка).

Сверены две оси, которых в прежней таблице не было: стратегия целиком и
расписание по часам. У всех четырёх кампаний совпадают дословно. Отличается
ровно одно — период: у #13 срок кончается сегодня, у остальных сегодня лишь
первый день из двух.

Версия записана вместе с предсказанием, по которому её можно казнить:
06.08 у #16/#19/#21 показы обязаны пойти, у #16 примерно вдвое быстрее.
Если утром ноль при мёртвой #13 — версия неверна.
2026-08-05 19:07:24 +03:00
Дмитрий 26a897fb87 docs,обзвон: приёмочный лист круга З-2.3 заведён ДО работы
Разведка перед заданием сверила командой всё, что задача утверждает о коде.
Разошлось пять утверждений из пяти проверенных: хранилища, названного в задаче,
не существует; таблицы обзвона живут в другом файле канона; проверка про старый
отказ беспредметна; журнал ПДн есть, но зовётся иначе; хозяин срока не построен.

Своя ошибка названа первой. Я чуть не объявил, что журнала ПДн нет вовсе: два
прибора подряд сказали "нет", и вывод напрашивался крупный. Третий прибор показал
живую таблицу с готовым сервисом записи. Приборы искали своё начертание слова, а
таблица названа сокращённо. Правило метода отработало дословно.
2026-08-05 19:04:52 +03:00
Дмитрий 1fd0170ded docs,приёмка Яндекса: закрыты Я1, Я2, Я5 и карточка Я-М1 — 7 комбинаций из 9
Я1 закрыт замером #16: приняты 15 картинок из 15, показов 0, списано 0,
850 рублей в заморозке одной строкой. Доказывает, что одобрение само по себе
денег не берёт.

Я2 и вместе с ним карточка Я-М1 закрыты вердиктом по #17: отклонены оба
объявления, заморозка вернулась целиком, ни одной строки списания. Оба вердикта
существовали только в передаточной записке, в журнал приёмки записаны не были.

Я5 проведён и закрыт за смену кампанией #22: свободные ровно равны смете,
полный отказ модерации, возврат до копейки, прогон стоил ноль. Рычаг отказа
подтверждён третий раз подряд теми же двумя картинками.

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

Поправка к скорости показов, третья за два дня: по полной летописи #13 это
5,5 показа в час, а не 13-25 — прежнее число взято с куска разгона. Отсюда
следует, что #19 своё до срока не доберёт; владелец решил оставить как есть
и записать недостигнутым.

Молчание #16, #19 и #21 разобрано не до конца. Настройка снята с подозрения
по шести осям — у крутящейся и у молчащих совпадает всё. Но предсказание,
выведенное из объяснения, не сбылось, поэтому вопрос записан открытым, а не
закрытым красивым рассказом.

Промт смене 24.
2026-08-05 18:52:37 +03:00
Дмитрий 2da4721644 docs,обзвон: в плане отмечена одна закрытая задача из восьми — исправлено
Владелец сказал про промт «почти». Пересчёт бумаг командой вскрыл дыру,
которой промт не закрывал. Первая смена построила восемь задач, а в плане
отметила одну — З-0.2. Семь денежных задач стояли в плане как непостроенные,
то есть для следующей смены их не существовало, хотя код лежит в ветке.
Ошибка надзирателя номер 11, класс тот же: считал код и не считал бумаги.

Врезки «ПОСТРОЕНО» дописаны всем семи, с коммитом, ссылкой на приёмочный лист
и тем, чем замер разошёлся с текстом задачи. Главные расхождения теперь видны
прямо в задачах: крайняя цена разговора 1252 рубля вместо записанных 602,
цена брошенной трубки 12 рублей вместо 2, намеренно оставленный ноль за минуту
и молчаливая недостача трёх живых каналов. Датчик сходится: восемь отметок при
восьми закрытых задачах.

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

В промт добавлен раздел 0.9 про бумаги — четвёртую обязанность надзирателя,
которой в нём не было вовсе. Куда класть свой приёмочный лист и как называть,
что обновляется в том же круге, датчик пересчёта и работа в конце смены.
Обязанностей в листе стало пятнадцать, правил девять.
2026-08-05 18:51:25 +03:00