Skip to content

Latest commit

 

History

History
62 lines (54 loc) · 7.86 KB

File metadata and controls

62 lines (54 loc) · 7.86 KB

Report'ы выключены по умолчанию, Alert'ы обязаны быть полезными

Notice — всё, что Iva говорит сама (CONTEXT.md). Решено развести два вида и судить их разными правилами. Report (плановая сводка: ночные отчёты памяти, утренний дайджест) по умолчанию выключен и включается тумблером в /menu → Уведомления. Alert (проблема или требуемое действие: алерты brain, предложение обновиться) не выключается — но взамен обязан говорить, что сломалось, чем это грозит и что сделать, и повторяться не чаще раза в неделю на одну и ту же проблему; смена существа проблемы и возврат после починки говорят сразу. Язык любого Notice — один, тот же резолвер, что у чата (settings.languageAGENT_LANGUAGE → ru): половина сообщения по-английски читается как поломка.

Обоснование. Ночной отчёт памяти уходил в чат с первой установки и никто его не просил: пользователь получал утренний текст про SUPERSEDE и card operations, а выключателя не было вовсе. Это нарушает ADR-0001 («работает из коробки как продукт»): чужой self-hoster получает непрошеное сообщение каждое утро и не знает, что с ним делать. Обратная крайность — сделать отключаемым всё — отвергнута: алерт о том, что память не бэкапится, ценен ровно тогда, когда её выключил бы уставший от шума человек, и молчание тут стоит данных (ADR-0002). Компромисс — цена, которую платит Alert: раз в неделю, с конкретной командой в тексте.

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

Дроссель детерминированный: data/alert-state.json, ключ проблемы → существо и время последней отправки, запись атомарная. Битое или отсутствующее состояние трактуется как «слать» (fail-open): пропущенный алерт дороже увиденного дважды. Неотправленный алерт состояние не пишет — иначе один отказ Telegram глушил бы проблему на неделю. Пишется состояние своим кодом на node:fs, без agent/: дроссель нужнее всего установке, у которой это дерево как раз и сломано.

Плановый ход, результат которого доставляет код (ночная сборка памяти и утренний дайджест по расписанию), не отправляет ничего сам. Красная строка agent/instructions.md требует для любого отчёта rich message, поэтому в ней записано исключение ровно для этих двух ходов: иначе системная инструкция и промпт хода спорят, побеждает более громкая, и владелец получает два сообщения вместо одного. Дайджест, запрошенный в чате, — обычный ход, правило действует.

Миграция одноразовая: установка, которая раньше получала утренний отчёт, один раз слышит, почему утро замолчало, и где включить обратно. Свежая установка не слышит ничего — ей нечего терять, а первое сообщение агента не должно быть про настройку, которую пользователь не включал. Решение принимается на ПЕРВОМ прогоне, где маркера нет, и записывается в сам маркер: поздние ночи вопрос не пересматривают, чем бы ни выглядела установка к тому времени. Владелец, трогавший тумблер (ключ memoryReports в settings пишет только экран /menu), получает «not-needed»: рассказывать ему про его же действие — нотация. Установка без настроенного чата тоже закрывает вопрос молча: пока чат появится, новость протухнет.

Признак «отчёты у этой установки были» — best-effort, а не гарантия. Считаются следы ЗАВЕРШЁННОГО прогона: курсор сессии любого периода в data/, запись периода в data/rollup-status.json с полем завершения (lastFinishedAt/lastSuccessAt), дневные сводки в vault/summaries/daily/. Поле завершения обязательно: спавнер расписаний резервирует слот в том же файле ДО запуска, и по одному имени периода самый первый прогон принял бы собственную бронь за чужой прошлый успех. Курсора одного мало — его сносит уборка зависшего хода; сводок одних мало — vault может быть не на месте, поэтому берётся дизъюнкция. Установка ≤0.3.9 без vault под рукой следов не оставит и Notice не получит: отчёты просто замолчат, объяснение — в CHANGELOG. Цена ошибки в эту сторону — молчание вместо объяснения; в обратную — нотация человеку, который отчётов не видел.

Заявка на Notice подаётся ДО отправки (атомарный O_EXCL), поэтому крэш между заявкой и доставкой теряет Notice навсегда. Обратный порядок дал бы дубль на гонке daily и weekly, а дубль хуже потери: пропавший Notice стоит строки в доке, повторяющийся — доверия к тому, что Iva не спамит (тот же выбор, что «ложный ✅ хуже спиннера» в апдейтере).