From 8fef11622ef112b03d1e563fed1dc69047e4e3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Thu, 6 Aug 2026 14:59:49 +0300 Subject: [PATCH] =?UTF-8?q?docs=20=D0=BE=D0=B1=D0=B7=D0=B2=D0=BE=D0=BD:=20?= =?UTF-8?q?=D0=B2=D0=BB=D0=B0=D0=B4=D0=B5=D0=BB=D0=B5=D1=86=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BA=D1=80=D1=8B=D0=BB=20=D0=B4=D0=B5=D1=81=D1=8F=D1=82=D1=8C?= =?UTF-8?q?=20=D1=80=D0=B0=D0=B7=D0=B2=D0=B8=D0=BB=D0=BE=D0=BA=20=D0=A0105?= =?UTF-8?q?-=D0=A0114?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Обход дерева развилок 06.08.2026, порядок «сначала необратимое». Пройдены все восемь вопросов, висевших на владельце, и открытая развилка внутри задачи З-2.4. Р105 облачное хранилище под записи — пока не заводим, звук на диске портала. Р106 очередь обзвона на боевом — отдельный работник, ставится при выкате. Р107 заготовки робота — кладём в хранилище все, 4,8 МБ. Р108 лишняя копия моста с дырой — переложена в игнорируемую папку, исполнено. Р109 подпись столбца в боевой базе — правим вместе с выкатом обзвона. Р110 четыре чужие бумаги про несуществующую защиту — дописываем замер рядом. Р111 сторожа машины робота — заводим задачей, с письмом при красноте. Р112 в сделке значение сверху и лента всех контактов под ним. Р113 тот же номер в новом списке — прошлое показываем, звонить не запрещаем. Р114 «не звоните мне больше» — робот заносит в список сам. Замеры, добытые по ходу и изменившие ответы: - 🔴 прежнее число «полтерабайта записей» завышено впятеро: считалось без учёта решения Р95, по которому звук живёт месяц. Верно около 87 ГБ при десяти клиентах, цена порядка 200 ₽ в месяц; - 🔴 на живом боевом замерено только чтением: работник очередей запущен без указания очереди и берёт только default; очередь obzvon не разбирает никто. Вреда сегодня ноль — модуль не выкачен; - заготовки робота оказались синтезом машины, а не голосами живых людей — личных данных в них нет. Семь папок из восьми делаются заново своими скриптами; невосстановима одна, tempy2; - копия моста в корне побайтово совпала с резервной копией на машине робота, слепок 0975e226672853efa785a0fbb6f188a00aa3c3c2; - итог по номеру уже привязан к кампании уникальным ключом, поэтому вопрос «сколько живёт итог» снят устройством, а не решением; - развилка про стоп-лист оказалась уже записанной в спеке как открытая. 🪤 Своя ошибка при замере, названная первой: приговор «подписи в боевой базе нет» был ложным. Первый прибор сопоставлял столбцы по порядковому номеру, а он расходится с внутренним, если из таблицы удаляли столбец. Второй прибор показал, что подпись есть и она старая. Ровно тот случай, ради которого в методе записано: приговор «этого нет» — только вторым прибором. Проверено прибором: решений 114, номера без пропусков, разметка 0 ошибок. --- .../2026-08-03-metodika-lena-pod-klienta.md | 473 ++++++++++++++++++ 1 file changed, 473 insertions(+) diff --git a/docs/grilling/2026-08-03-metodika-lena-pod-klienta.md b/docs/grilling/2026-08-03-metodika-lena-pod-klienta.md index 7319b295..10ce0b5e 100644 --- a/docs/grilling/2026-08-03-metodika-lena-pod-klienta.md +++ b/docs/grilling/2026-08-03-metodika-lena-pod-klienta.md @@ -2936,8 +2936,481 @@ Managed PG стоит `anon 1.3.2`, статическое маскирован --- +### Р105. Облачное хранилище под записи разговоров — пока не заводим + +**Вопрос.** Задача З-2.1 построила у портала приёмную сторону для звука: склад, +переезд, три замка. Склад сделан **переключаемым**: он может лежать либо на диске +машины портала, либо в облачном хранилище — это одна строка настройки, код правит +не надо. Но у местного диска **не бывает ссылок со сроком**: замерено запуском — +портал отдаёт вечную ссылку либо не отдаёт никакой. Мы выбрали не отдавать +никакой. ⇒ пока склад местный, кнопки «послушать запись» у человека **нет вовсе**. + +Вопрос владельцу: заводить ли облачное хранилище — это деньги. + +**Замеры к вопросу (собраны 06.08.2026):** + +- 🔴 **Поправка к прежнему числу.** В промте смене 5 стояло «50 ГБ за полгода, при + десяти клиентах — полтерабайта». Оно посчитано так, будто записи копятся вечно, + и **не учитывает Р95**: звук живёт месяц, старое удаляется. В хранилище всё + время лежит **месяц** записей, а не полгода — около **8,7 ГБ на клиента**, при + десяти — около **87 ГБ**. +- Цена облачного хранилища Яндекса: обычное ≈ **2,2 ₽** за гигабайт в месяц, + холодное ≈ **1,2 ₽**, первый гигабайт бесплатно; раздача наружу — первые 100 ГБ + в месяц бесплатно. ⇒ один клиент ≈ **20 ₽ в месяц**, десять ≈ **200 ₽**. + Вперёд платить не нужно, счёт идёт по занятому месту. + +**Решение владельца: пока не заводим.** Звук ложится на диск машины портала. + +**Отрезано и почему:** + +- ✂️ **«завести сейчас»** — отрезано владельцем, **хотя цена оказалась мала** + (порядок двухсот рублей в месяц). Решение принято не из-за денег; +- ✂️ **«решить в день первого живого звонка»** — отрезано: владелец не отложил + вопрос, а ответил на него. Склад местный, и это рабочее положение, а не пауза. + +🔴 **Чего это НЕ закрывает.** + +1. 🔴 **Ссылки «послушать запись, срок час» не будет.** Не «вечная» — **никакой**. + Это не недоделка и не долг: это прямое следствие решения. Тому, кто будет + рисовать экран разговора, надо знать заранее — кнопки там не появится. +2. 🔴 **Свободное место на диске машины портала НЕ ЗАМЕРЕНО.** Мерить его — значит + лезть на боевой сервер, а туда без слова владельца нельзя. 87 ГБ голоса при + десяти клиентах — не мелочь, и портал падает от переполненного диска целиком, а + не одним обзвоном. +3. 🔴 **Месячная уборка до нового склада ещё не доведена.** Р95 исполнен на машине + робота — там скрипт и расписание. Про склад портала это **отдельная работа**, и + пока её нет, «лежит месяц» — намерение, а не устройство. Без неё диск копит + без предела, и оценка 87 ГБ неверна. +4. **Момент возврата к вопросу не назначен.** Годный признак для возврата — не + календарь, а замер: сколько свободного места осталось на машине портала. + +--- + +### Р106. Очередь обзвона на боевом — отдельный работник, ставится при выкате + +**Вопрос.** У обзвона три фоновые работы, и все три положены в **свою** очередь +`obzvon`: перевозка звука в хранилище, шаг заморозки под лид, запуск обзвона базы. +Смена 3 заметила по бумагам, что работник очередей на боевом запущен **без +указания очереди** — такой берёт только `default`. Бумага — не замер, и владелец +разрешил сходить на боевой **посмотреть, ничего не меняя**. + +**Замерено на живом боевом 06.08.2026, только чтение:** + +| работник | чем запущен | жив | +|---|---|---| +| `liderra-queue` | `queue:work redis` — 🔴 **очередь не указана** ⇒ только `default` | да | +| `liderra-queue-bot` | `queue:work redis --queue=bot` | да | + +Размер очередей: `default` — 0, `obzvon` — 0, `bot` — 0. Павших работ — 3, старые, +к обзвону отношения не имеют. + +⇒ **Догадка подтвердилась: очередь `obzvon` не разбирает никто.** Но вреда сегодня +**ноль**: модуль обзвона на боевой не выкачен, класть в эту очередь некому. + +Вопрос владельцу: каким способом чинить в день выката. + +**Решение владельца: заводим отдельного работника только под обзвон** — так же, как +уже сделано для бота. + +**Отрезано и почему:** + +- ✂️ **«дописать очередь `obzvon` к общему работнику»** — отрезано, хотя это правка + одной строки без новых частей. Причина: работы обзвона **долгие** — перевозка + звука и запуск целой базы. В общей очереди они придержат письма, выгрузки и СМС; +- ✂️ **«решим в день выката»** — отрезано: в день выката будет спешка, а выбор + всё равно пришлось бы делать. + +🔴 **Чего это НЕ закрывает.** + +1. **Работника ещё нет.** Решение назначает способ, а не исполнение. Пункт + обязан попасть в лист выката модуля обзвона, иначе повторится ровно то же: + код есть, работы копятся, журнал чист. +2. 🔴 **Беда была бы МОЛЧАЛИВОЙ.** Ненайденная, она выглядит как здоровье: + портал отвечает, ошибок нет, обзвон просто не едет. Это тот же класс, что + уборка без расписания (Р98) — построено, но никем не позвано. +3. **Отдельный работник — это ещё и отдельная точка отказа.** Он может умереть + один, не уронив портал. Кто и чем это заметит — не решено. +4. **Три павшие работы на боевом не разобраны.** Они чужие и старые, обзвона не + касаются, но лежат. + +--- + +### Р107. Заготовки робота — кладём в хранилище ВСЕ + +**Вопрос.** Заготовки, на которых настраивали голос Лены, лежат во **временной** +папке машины `/tmp/lena-inworld`. Временную папку уносит перезагрузка, и никто эти +файлы не воссоздаёт. Машина не перезагружалась с 05.07.2026. + +**Замерено на машине робота 06.08.2026, только чтение:** + +- во временной папке 68 МБ, но **63 из них — записи разговоров**, у которых своя + месячная уборка. Собственно заготовки — **4,8 МБ**: четыре файла подставного + собеседника и восемь папок; +- 🔑 **это не голоса живых людей.** Всё наговорено машиной: подставной собеседник + озвучен синтезом голосом «Tamara» (нарочно не «Elena» — чтобы на записи было + слышно, кто где), плюс девять образцов женских голосов для выбора. ⇒ **личных + данных в заготовках нет**, класть их в хранилище можно; +- **семь папок из восьми делаются заново**: скрипты, которые их создают, лежат в + надёжной папке и перезагрузку переживут; +- 🔴 **папка `tempy2` невосстановима** — шесть образцов скорости речи + (0,9 · 1,0 · 1,1 · 1,2 · 1,35 · 1,5), 404 КБ. Скрипта, который их сделал, + **больше нет**: о папке помнит только уборка, которая её бережёт. + +**Решение владельца: класть в хранилище ВСЕ заготовки, 4,8 МБ.** + +**Отрезано и почему:** + +- ✂️ **«только невосстановимое `tempy2`»** — отрезано, хотя это 404 КБ вместо 4,8 МБ. + Владелец выбрал не полагаться на «переозвучим заново»: переозвучка — это время, + ключ, работающая сторонняя ручка синтеза и деньги, и любое из четырёх может + однажды не совпасть; +- ✂️ **«не класть ничего»** — отрезано: шесть образцов скорости погибли бы навсегда. + +🔴 **Чего это НЕ закрывает.** + +1. 🔴 **Записи разговоров — 63 МБ — в хранилище НЕ КЛАДЁМ.** Это настоящий звук + настоящих звонков, и решение к нему не относится. Тот, кто будет исполнять, + обязан взять **только** заготовки, иначе личные данные уедут в коммит. +2. **Решение не назначает, кто раскладывает их обратно.** Положить в хранилище — + половина дела. Чтобы после перезагрузки они снова оказались на машине, нужен + тот, кто их туда вернёт. Иначе повторится Р98: положено, но никем не позвано. +3. **Скрипт, делавший `tempy2`, не восстановлен.** Файлы уцелеют, а умение сделать + их заново — нет. +4. **Заготовки — не эталон.** Побайтовые сторожа их не стерегут, и расхождение + между хранилищем и машиной никто не заметит. + +--- + +### Р108. Лишняя копия моста в корне — переложена в игнорируемую папку + +**Вопрос.** В корне хранилища лежал `most-server.py` — 322 строки, никем не +заведённый: гит его не отслеживал. Смена 3 заподозрила, что это копия моста **до** +починки З-0.8, то есть с дырой внутри. + +**Замерено 06.08.2026:** + +- 🔑 **это побайтово та самая резервная копия**, снятая на машине робота 03.08 + перед правкой. Слепки сошлись знак в знак: + `0975e226672853efa785a0fbb6f188a00aa3c3c2` — и у файла в корне, и у + `/home/ubuntu/lena-inworld/most.py.bak-20260803-104305`; +- 🔴 **дыра настоящая**: строка 211 печатает дословные слова человека — + `👤 человек: <сказанное>`. Ровно то, что З-0.8 убирала. + +Опасен он был не тем, что лежал, а тем, что **выглядел рабочим мостом**: скопировать +его на машину — и вся работа З-0.8 отменилась бы молча. + +**Решение владельца: переложить в папку `моя/`,** которая в хранилище не попадает. + +**Исполнено в тот же час, проверено:** слепок после переноса **не изменился** +(`0975e226…`), из корня файл исчез, гиту не виден. Новое имя названо так, чтобы +следующий человек не ошибся: +`моя/most-server-kopiya-do-pochinki-03-08-2026-S-DYROY.py`. + +**Отрезано и почему:** + +- ✂️ **«удалить совсем»** — отрезано: побайтовая копия есть на машине робота, но + машина однажды может пропасть, и тогда пропадёт и она. Перенос ничего не теряет; +- ✂️ **«оставить как есть»** — отрезано: ловушка осталась бы лежать на виду рядом + с рабочими файлами. + +🔴 **Чего это НЕ закрывает.** + +1. **Копия с дырой продолжает существовать** — и в `моя/`, и на машине робота под + именем `.bak`. Решение убирает её с дороги, а не из мира. +2. **Откуда она взялась в корне — не выяснено.** Гит её не помнит, значит она + попала туда мимо коммитов. Тот же путь открыт и для следующего такого файла. +3. **Сторожа на «в корне нет ничего лишнего» нет.** Найдено глазами при разборе, а + не прибором. + +--- + +### Р109. Подпись столбца в боевой базе — правим вместе с выкатом обзвона + +**Вопрос.** Решением Р103 поправлена **бумага**: канон схемы перестал обещать +защиту, которой нет. Но такая же надпись живёт **внутри самой боевой базы** — +у столбца `pd_subject_requests.processing_restricted` есть подпись, и она осталась +прежней. + +**Замерено на живом боевом 06.08.2026, только чтение. Текст подписи:** + +> «При TRUE все операции с ПДн субъекта блокируются на уровне сервиса +> (**ProcessingRestrictedException**). Сохраняется только право на хранение и +> удаление.» + +🔴 **Класса `ProcessingRestrictedException` в проекте не существует** — проверено +двумя приборами: ни поиском по коду, ни поиском по именам файлов. Подпись называет +защиту **поимённо**, и этой защиты никогда не было. + +🪤 **Своя ошибка при замере, названная первой.** Первый прибор ответил «подписи +нет» — сопоставлял столбцы по порядковому номеру, а он расходится с внутренним +номером, если из таблицы когда-то удаляли столбец. Второй прибор показал, что +подпись есть. Ровно тот случай, ради которого в методе записано: **приговор «этого +нет» — только вторым прибором, и «ноль» — самый опасный ответ прибора.** + +**Решение владельца: править вместе с выкатом модуля обзвона,** отдельного похода +на боевой не делаем. + +**Отрезано и почему:** + +- ✂️ **«править отдельно и сейчас»** — отрезано: лишнее касание боевого ради + текста. Подпись данных не трогает, срочности нет; +- ✂️ **«не трогать вовсе»** — отрезано: база и бумага говорили бы разное, а + проверяющий скорее поверит базе — она ближе к делу. + +🔴 **Чего это НЕ закрывает.** + +1. 🔴 **До дня выката ложь остаётся в боевой базе.** Если проверка придёт раньше + выката, она прочтёт именно её. +2. **Пункт обязан попасть в лист выката** — иначе он потеряется так же, как + потерялся работник очереди (Р106). +3. **Подпись — единственная у этой таблицы.** У остальных четырнадцати столбцов + подписей нет вовсе, и вопрос «а надо ли им» не ставился. +4. **Решение не строит защиту.** Флаг «прекратить обработку» как не запрещал + ничего, так и не запрещает (Р103). + +--- + +### Р110. Четыре чужие бумаги про несуществующую защиту — дописываем замер рядом + +**Вопрос.** Решением Р103 поправлен канон схемы. Но то же обещание — «флаг +„прекратить обработку" всё блокирует» — живёт ещё в **четырёх** бумагах, которые +обзвону не принадлежат. + +**Замерено 06.08.2026, командой по каждой бумаге:** + +| бумага | что обещает | +|---|---| +| `Analiz_originala_v8_3.md:736` | дословно повторяет старую подпись столбца, включая `ProcessingRestrictedException` **и защиту по строкам** | +| `CRM_bp-gr_Инструкция_v8_5.md:38` | жёсткий запрет входа под клиента, «единый охранник в `SaasAdminAuthService`» — такого класса **нет** | +| `Workflow_pd_subject_requests_v8_2.md:7` | «✅ **закрыт**… все операции обязаны проверять флаг и отказывать» | +| `Открытые_вопросы_v8_3.md:2163` | 🔴 **Ю-9 стоит среди двенадцати закрытых P1** — построено под ним ничего | + +Худшая — последняя: пункт числится в списке **сделанного**. + +**Решение владельца: дописать рядом с каждым обещанием врезку-замер** — «замер +06.08.2026: не построено, класса такого нет». Ничего не удалять и не переписывать. + +**Отрезано и почему:** + +- ✂️ **«переписать разделы по-настоящему»** — отрезано: снять у Ю-9 галочку + «закрыт» значит **двигать закрытый вопрос обратно в открытые**, а это отдельное + решение владельца, а не побочный итог правки бумаги; +- ✂️ **«не трогать вовсе»** — отрезано: канон базы говорил бы одно, четыре + бумаги — другое. + +🔴 **Чего это НЕ закрывает.** + +1. 🔴 **Ю-9 остаётся в списке закрытых.** Врезка объяснит, что под ним пусто, но + счётчик «двенадцать закрытых» останется прежним. Кто читает только счётчик — + будет введён в заблуждение по-прежнему. +2. **Защиты как не было, так и нет.** Правка бумаги делает положение честным, а не + защищённым — то же, что записано при Р103. +3. **Сторожа на эти четыре бумаги нет.** Живой сторож канона читает бумаги под + `db/`, а эти лежат в `docs/`. Ложь сможет вернуться незамеченной. +4. **Формулировка врезки не согласована.** В каноне она вышла длинной; в чужих + бумагах её длину и место придётся выбирать исполнителю. + +--- + +### Р111. Сторожа машины робота — заводим задачей, с письмом при красноте + +**Вопрос.** На машине робота живут три сторожа — 26 проверок на уборку звука, +46 на текстовый след и 27 на сам скрипт уборки. Они ходят по связи и меряют +**жизнь**, а не бумагу. Но зовёт их только человек, который помнит про них. +Уборка, умершая молча, выглядит как уборка, которой нечего делать. + +**Замерено на машине 06.08.2026:** + +- 🔴 **почтовых программ на машине НЕТ вовсе**, и получатель в расписании не задан. + ⇒ поставить сторожей расписанием прямо там — значит получить отчёт, который + **никто никогда не прочтёт**. Это ровно та болезнь, от которой лечим; +- в расписании машины сегодня три записи: своя уборка звука, уборка выжимок проб и + системная `e2scrub_all`. + +**Решение владельца: завести задачей.** Машина раз в сутки проверяет себя сама и +кладёт итог файлом; портал этот файл читает и **шлёт письмо, если красно**. + +**Отрезано и почему:** + +- ✂️ **«вписать сторожей в общий прогон проверок портала»** — отрезано: сторожам + нужен ключ от машины. У соседних смен его может не быть, и тогда либо чужой + прогон краснеет зря, либо сторож зеленеет **«не глядя»** — а зелёный, означающий + «не смотрел», опаснее отсутствия сторожа (урок смены 4); +- ✂️ **«оставить руками»** — отрезано: живёт ровно до первой смены, которая + пропустит шаг; +- ✂️ **«расписание прямо на машине»** — отрезано **замером**: голос подать нечем. + +🔴 **Чего это НЕ закрывает.** + +1. **Задачи ещё нет.** Решение назначает устройство, а не исполнение: задачу надо + завести в плане, и счётчик задач в шапке плана вырастет. +2. 🔴 **Появляется новый молчун.** Тот, кто носит итог с машины в портал, сам может + умереть тихо — и тогда писем не будет, а выглядеть это будет как «всё хорошо». + У новой задачи обязана быть проверка **на свежесть итога**, а не только на его + содержимое. +3. **Адрес получателя не назначен.** Куда именно идёт письмо — не решено. +4. **Ключа от машины у портала нет.** Каким путём итог попадает с машины в портал — + не выбрано, и это самая тонкая часть будущей задачи. + +--- + +### Р112. В сделке — значение сверху и лента всех контактов под ним + +**Вопрос.** План З-2.4 оставил открытым: семь исходов Т21 надо разложить на «про +попытку» и «про номер», потому что у номера бывает много попыток, а в карточке +сделки место одно. + +**Владелец постановку переиграл.** Дословно: *«мы сохраняем каждый контакт если +есть хоть секунда разговора! и показываем его клиенту — если человек взял и сразу +скинул мы это демонстрируем, и если перезвонил тоже показываем. Недозвон просто +пишем сколько попыток было.»* + +То есть в сделке живёт не один победивший исход, а **история**. + +**Решение владельца — устройство карточки:** + +1. **Сверху одно значение** — исход **последнего состоявшегося** разговора. + 🔴 Недозвоны его **не меняют**: двенадцать недозвонов после удачного разговора + не затрут удачный разговор. +2. **Под ним лента всех контактов**, где была хоть секунда разговора: дата, + длительность, исход, запись. Перезвонил человек сам — тоже строка в ленте. +3. **Недозвоны в ленту не попадают** — они сворачиваются в одну строку + «не дозвонились: N раз». + +🔑 **Это объясняет прежнее решение Р88 задним числом.** Отдельный исход «взял и +сразу бросил» заводить не нужно именно потому, что контакт длиной в секунду +**показывает себя сам** — своей длительностью в ленте. Р88 не обходится, он +работает. + +**Отрезано и почему:** + +- ✂️ **«в карточке всегда исход последней попытки, какой бы ни был»** — отрезано: + один недозвон стёр бы всю картину; +- ✂️ **«побеждает самый резкий исход — отказ и агрессия перекрывают всё»** — + отрезано: человек, который передумал и согласился, выглядел бы отказавшимся; +- ✂️ **«только лента, никакого одного значения»** — отрезано: в списке сделок + нечем было бы отобрать «покажи всех, кто отказал», и рассыпалось бы требование + Т65 о собственном статусе обзвона. + +🔴 **Чего это НЕ закрывает.** + +1. 🔴 **Требование Т84 в спеке сформулировано теснее этого решения** — там сказано + «в сделке стоит итог по номеру, а не последняя попытка», и про ленту не сказано + ничего. Спеку придётся дописать, иначе построят по старому тексту. +2. 🔴 **Решение Р47 говорит «единственный итог по номеру».** Оно не отменено: + единственный итог остался — это значение сверху. Но читать Р47 теперь надо + вместе с этим решением, иначе он звучит как запрет ленты. +3. **Срок жизни итога не решён.** Что будет, если тот же номер придёт новым + списком через полгода, — отдельный вопрос, он остаётся открытым. +4. **Лента — это лишние запросы к базе.** Проверка 6 задачи З-2.4 требует, чтобы + таблица сделок не стала медленнее. Лента живёт в карточке, но счётчик и + значение придётся показывать и в списке — и вот там лишний запрос на каждую + строку смертелен. На этом месте проект уже спотыкался дважды. +5. **Где кончается «хоть секунда» — не назначено.** Разговор длиной ноль секунд + и разговор длиной одну секунду различаются, а разговор в 0,4 секунды — вопрос. + +--- + +### Р113. Тот же номер в новом списке — прошлое показываем, но звонить не запрещаем + +**Вопрос.** План З-2.4 спрашивал: сколько живёт итог по номеру, если тот же номер +придёт новым списком через полгода. + +🔑 **Замер снял половину вопроса.** Итог уже построен привязанным **к кампании**, +а не к номеру вообще — в каноне стоит +`UNIQUE (tenant_id, campaign_id, phone)`. Значит новый список **сам заводит новый +итог**, а прежний остаётся в истории. Спрашивать «сколько живёт» нечего: он живёт +столько же, сколько своя кампания. + +Заодно замером подтвердилось, что построенное уже совпадает с Р112: в таблице есть +`attempts_count` — тот самый счётчик недозвонов — и ровно **восемь** значений +исхода, как требует Т65. + +**Решение владельца: прошлое показываем, но звонить оно не запрещает.** В карточке +видно «полгода назад отказался»; набор номера это не блокирует. + +**Отрезано и почему:** + +- ✂️ **«прежний отказ запрещает звонок навсегда»** — отрезано: запрещать — работа + стоп-листа, он уже есть и заведён именно для этого (Р45, задача З-3.2). Два + разных запрета рано или поздно разойдутся, и отменить второй будет нечем; +- ✂️ **«прошлое не показываем, новый список с чистого листа»** — отрезано: + менеджер не узнал бы, что этому человеку уже звонили и он ругался. + +🔴 **Чего это НЕ закрывает.** + +1. 🔴 **Итог и стоп-лист теперь обязаны быть связаны руками.** Человек, сказавший + «не звоните», даёт исход «отказ» — но в стоп-лист он попадает **только если его + туда положат**. Кто и в какой миг это делает — не решено, а это и есть главная + защита. +2. **«Показываем» — не значит «видно».** Прежний итог лежит в другой кампании; + чтобы он оказался в карточке, его надо туда достать. Это лишний запрос, и он + попадает ровно под проверку 6 задачи З-2.4. +3. **Сколько прошлого показывать — не назначено.** Одну прошлую кампанию или все. +4. **Решение не касается стирания по требованию.** Р97 уже сказал: стоп-листы при + стирании не вычёркиваем. Прошлые итоги под это правило не подводились. + +--- + +### Р114. «Не звоните мне больше» — робот заносит в список сам + +**Вопрос.** Спека держала это открытым прямым текстом (Т80, §13 п. 28): попадает +ли человек в список «не звонить» **сам**, сказав роботу в трубку «не звоните мне +больше», — или только руками клиента. + +**Цена ошибки неравна.** Робот распознаёт слова и может ослышаться. Ошибка в одну +сторону — не позвонили тому, кто хотел разговора: потеря сделки. Ошибка в другую — +позвонили тому, кто просил не звонить: жалоба и закон. + +**Решение владельца: робот заносит сам, снимает только человек руками.** В карточке +видно, что запись поставил робот, — если это была ошибка слуха, клиент снимет. + +**Отрезано и почему:** + +- ✂️ **«только руками клиента»** — отрезано: отказ жил бы ровно столько, сколько + кто-то помнит его перенести. Это тот же класс, что уборка без расписания (Р98) и + сторожа без зовущего (Р111); +- ✂️ **«робот предлагает, клиент подтверждает»** — отрезано: между просьбой + человека и запретом появилось бы окно, и в это окно ему могли позвонить снова. + +🔴 **Чего это НЕ закрывает.** + +1. 🔴 **По каким словам робот считает, что его попросили,** — не назначено. + «Не звоните мне больше» он поймёт, а «слушайте, хватит уже» — вопрос. Список + слов придётся выбирать, и он же определит, как часто робот будет ошибаться. +2. 🔴 **Исход «агрессия» — не то же самое, что просьба не звонить.** Человек, + сказавший «это незаконно, откуда мой номер», отказа от звонков не заявлял. + Кладём ли и его — не решено. +3. **Как клиент снимает запись — не построено.** Решение опирается на то, что + клиент увидит пометку и сможет её снять; экрана для этого нет. +4. **Список отказов обзвона — пятый, отдельный** (Т79, Р45). Занесённый роботом + номер по-прежнему получит СМС и телеграм: остальные четыре списка этот не + читают. Так решено, но человеку это придётся объяснять. +5. **Стирание по требованию списка не чистит** — Р97. Значит запись переживёт + удаление остальных данных человека, и это осознанно. + +--- + ## Осталось открытым +**Открылось при обходе 06.08.2026 — порождено решениями Р105–Р114:** + +- **По каким словам робот считает, что его попросили не звонить** (Р114). «Не + звоните мне больше» поймёт, «хватит уже» — вопрос. Список слов задаёт и частоту + ошибок слуха. +- **Кладём ли в список отказов исход «агрессия»** (Р114). «Откуда мой номер» — + не заявление об отказе от звонков. +- **Каким путём итог сторожей попадает с машины робота в портал и на какой адрес + идёт письмо** (Р111). Ключа от машины у портала нет. +- **Где кончается «хоть секунда разговора»** (Р112). Ноль секунд и одна секунда + различаются, а 0,4 секунды — вопрос. +- **Сколько прошлых кампаний показывать в карточке** (Р113) — одну или все. +- **Когда возвращаться к вопросу об облачном хранилище** (Р105). Годный признак — + не календарь, а замер свободного места на машине портала; сам замер требует + слова владельца. + +**Открыто раньше:** + - **Путь (в) — письменные итоги сделок из CRM клиента.** Отклонён при Р3 («нет»), но модель Б, которая на нём держалась, тоже отклонена. Нужен ли он как подпорка к аудио — не спрашивали заново.