docs: separate personal delivery identity from group routing

This commit is contained in:
evgeny committed 2026-11-03 22:09:12 +01:00
1 parent 998efdbb74
commit 307ca10733
2 files changed
+144 -17

No files matched your search

+137 -15
View File
@@ -391,19 +391,141 @@ tests/logs/test_chat_group_isolation.log. Общий ./check.sh:240/240, proxy9/
group_id заказа остаётся прежним, даже если повтор пришёл через другую разрешённую группу.
- dm_custody_store при точном повторе отвечает через новую группу/source, но сохранённые
group_id/supernode не меняются. Фоновая обработка использует старые поля.
- dm_media_holders имеет ключ (id,node_id), без группы. Повторное назначение того же M
через B нельзя считать новым только заменой проверки допуска: оно пересекается с прежним A.
- mb_scope/dm_media_scope пока недостаточно проверяют admitted/source/self и третьего участника;
простое усиление этих условий остановит старые задания, но не даст корректного пересогласования.
- dm_media_holders имеет ключ (id,node_id), без идентификатора попытки. Разные попытки
назначения того же M не различаются; смена группы сама по себе новой попыткой не является.
- mb_scope/dm_media_scope недостаточно проверяют admitted/source/self и смешивают допуск
транспортной пары с требованием общей группы автора/получателя/S/M. Нужны отдельные
предметные проверки и выбор маршрута по паре узлов согласно уточнению пользователя ниже.
Предлагаемый следующий этап:
1. Разделить идентичность неизменяемого файла (UUID/body hash) и контекст задания хранения.
Явно определить атомарную замену group/supernode при новом допустимом PUT/STORE.
Сохранить первоначальные TTL/политику удаления; смена маршрута не продлевает хранение.
2. Связать holder и его ACK/DELETE/EXPIRED с конкретным назначением и группой, чтобы поздний
ответ A не изменял действующее назначение B; согласовать это с одной физической копией M.
3. Добавить общий свежий допуск, проверки всех ролей/участников и отмену заданий/проб;
завершение custody worker проверяет актуальное назначение перед публикацией результата.
4. Проверить реальными A–S–B/M: отзыв только одной группы, новый заказ через другую,
тот же UUID/M, поздние ответы, перезапуск, прежний TTL и сохранность локальной истории.
Изменения mailbox/custody остановлены на этой границе по правилу AGENTS о логических несоответствиях.
Архитектура следующего этапа — проект, ещё не реализация.
Уточнение пользователя: при хранении и передаче личных сообщений/вложений конкретная
CHAT-группа не закрепляется. Можно использовать любую доступную общую группу непосредственных
отправителя и получателя пакета; значение имеют их личности и права на объект.
Это заменяет прежнее предложение связывать назначение хранения с группой.
MEMBER_FILES остаётся файловым сервисом конкретной группы; UTUN в эту доработку не входит.
1. Три независимые сущности.
- Личный объект: подписанное сообщение, UUID вложения, hash полного тела, автор и стороны
беседы. Существующие правила DEVICE/GROUPS и снимок адресатов сообщения сохраняются.
- Назначение хранения: координатор S просит выбранное хранилище M сохранить этот объект.
assignment_id создаётся S и сохраняется до отправки STORE; привязан к S, M и точному телу.
Повтор, рестарт и смена маршрута сохраняют assignment_id. Другой M или новая попытка
после окончательного отказа получают новый assignment_id. Не вводим отдельную эпоху группы.
- Активный сетевой обмен: peer, выбранная сейчас группа, router session/transfer/probe ID.
Только этот слой содержит обязательную привязку к группе. Ответ может прийти другой группой.
2. Маршрут выбирается для каждой пары отдельно.
Автор -> S, S -> M, M -> автор, S -> получатель и M -> получатель могут использовать
разные группы. Не требуем группу, в которой одновременно состоят все четыре узла.
Перед каждой новой отправкой выбирается доступная общая CHAT-группа self/peer;
приём, очередь, повтор и callback проверяют свежий topo_group_chat_allowed этой пары.
Подпись router обязательна для DM_MAILBOX/DM_MEDIA, в том числе header-only controls.
Роль и объектное право проверяются отдельно от выбора сетевого пути.
Роли supernode/storage нужны для выбора и допуска обслуживающего узла к новой работе.
Источник этих сведений — актуальные подписанные строки участников допущенных общих групп
проверяющей стороны и проверяемого узла; роль не обязана находиться в группе текущего пакета.
Строка из чужой группы, source!=0, deleted или admitted!=1 полномочий не даёт.
Смена маршрута не заменяет обслуживающий узел и не отменяет уже принятую им копию.
Сохранённое назначение разрешает учитывать его результаты и завершать его после изменения
роли; оно не даёт права создавать другие назначения или обращаться к групповым API.
PUT принимается от автора точного подписанного сообщения, адресованного указанному получателю.
DELIVER/OFFER проверяют личность отправителя, предметные полномочия и подписанное тело.
Выдача файла проверяет право конкретного устройства/стороны беседы либо допустимого storage;
членство в транспортной группе и знание UUID сами по себе доступа к файлу не дают.
HAVE, передача файла и квитанции используют те же предметные правила, что основной запрос.
Квитанция получателя подтверждает точное тело и подписанта из снимка адресатов.
Локальное совмещение S=M вызывает те же предметные проверки без искусственного сетевого self-сеанса.
3. Постоянное состояние не содержит обязательного group_id.
Удалить group_id из контракта личных pending, receipts, sources, jobs и custody.
Не переносить его в новый ключ и не делать из него сохранённое разрешение на доступ.
При необходимости последний удачный маршрут можно кешировать только как необязательную
runtime-подсказку: после рестарта всё находится по node_id, перед использованием допуск проверяется.
Текстовый mailbox сохраняет существующий ключ сообщения и точное тело; нового assignment_id
для текста не нужно. Повтор через другую группу не создаёт сообщение заново и не отменяет receipt.
На S существующий список dm_media_holders превращается в список назначений:
assignment_id, file_id, M, состояние/ответ, подтверждённые expires и delete_on_open.
Координатор dm_media_jobs ссылается на текущее назначение, прежние назначения сохраняются
до окончательного разрешения. Поля статуса не дублировать без необходимости в обеих таблицах.
На M dm_custody описывает одну физическую копию: точное тело/hash, состояние, первоначальный
deadline и политику удаления. Поля единственного supernode/group_id из копии убираются.
Отдельный список обращений M: (S, assignment_id), file_id/body_hash, принято или отказано.
Принятые обращения нескольких S могут ссылаться на одну копию; ответы адресуются каждому S.
В каждый момент на M для этой копии работает не более одной загрузки/проверки/очистки.
4. Идемпотентный STORE и точные ответы.
STORE и относящиеся к нему RESERVED/STORED/REJECT/DELETE_ACK/EXPIRED несут assignment_id
и file_id. Стороны S/M берутся из проверенной личности отправителя и локальной записи,
тело/hash неизменно закреплены в назначении. Совпадения одного UUID или группы недостаточно.
Повтор принятого STORE возвращает текущее состояние той же копии и прежние TTL/политику.
Окончательный отказ, например по квоте, сохраняется для этого assignment_id до ответа;
его повтор не превращается в принятие. Реальная новая попытка использует новый ID.
Неавторизованный запрос не создаёт запись назначения и не меняет состояние файла.
При конфликте ID/тела/M, SQL-ошибке или неудачном commit успешный ответ не отправляется.
Поздний ответ изменяет только найденное назначение. Изменение текущего назначения возможно
только при совпадении assignment_id; ответ прежнего M не сбрасывает нового M.
RESERVED после STORED не откатывает готовность; терминальное назначение не оживает от STORED.
Ответ той же операции через другую разрешённую группу принимается как обычный ответ.
Даже запоздалый ответ старой группы допустим, если её текущий допуск не отозван.
Если допуск отозван, пакет отвергается до изменения durable состояния.
5. Физическая копия и факты о файле.
Состояния копии M: RESERVED -> READY -> REMOVING -> REMOVED; удаление возможно и из RESERVED.
Первый успешный резерв на данном M фиксирует абсолютный expires и delete_on_open.
Повтор, другой маршрут, ещё один S и перезапуск не продлевают этот срок и не меняют политику.
После удаления сохраняется существующий tombstone по UUID/hash; поздний STORE не возрождает копию.
Это срок конкретной копии на M; не вводим несуществующий сейчас общий TTL для всех хранилищ.
RECEIPT/TAKEN — подписанные факты о файле, не о маршруте и не об assignment_id.
DELETE переносит эти факты; сам координатор не получает права произвольно удалить общую копию.
M проверяет факты и первоначальную политику: открытие получателем либо загрузка всеми
адресатами стороны получателя из исходного снимка. Ещё одно обращение S не меняет этот снимок.
Сначала commit REMOVING, затем отмена передачи и удаление на диске, затем tombstone и ACK.
ACK адресуется конкретному обращению; остальные координаторы также получают конечный результат.
Минимальные терминальные записи нужны для повторов после рестарта; очистка не должна допускать replay.
Разделить EXPIRED назначения S--M и сообщение конечному получателю о недоступности источника.
Второе относится к file_id/body_hash и конкретному holder, не делает весь личный файл удалённым.
Позднее исчезновение M1 не отменяет источник M2, готовую локальную копию или получение оригинала.
6. Отзыв группы и фоновые операции.
Отзыв закрывает только сетевые операции этой группы, включая очереди, probes и waiters.
Общий ETCP и другая допущенная группа продолжают работать. Сохранённое сообщение, назначение
и готовая копия остаются. Недоступность пути не означает REJECT/EXPIRED/доставку.
Планировщик выбирает другой допустимый маршрут для того же peer и того же assignment_id.
Незавершённая FILE_TRANSFER получает новый transfer ID; это не новое назначение хранения.
При отсутствии пути работа ждёт, а первоначальный срок хранения продолжает идти.
Worker занят локальным файлом, не выбранной группой; он не обращается к сети/SQLite.
Уже полученные байты можно проверить локально независимо от исчезновения сетевого маршрута.
Callback в uasync проверяет актуальность объекта, состояние удаления и deadline перед READY.
Начатая дисковая команда может закончиться; результат не возвращается по отозванному маршруту.
Новая сетевая работа требует нового допуска. Терминальное состояние копии не отменяется
поздним callback; cleanup разрешён и после потери доступа. Перезапуск не запускает второй
worker для тех же путей до завершения/отмены первого. Локальная история и готовые файлы сохраняются.
7. Этапы реализации и обязательные проверки.
I. Отделить предметный допуск от маршрута в DM_MAILBOX/DM_MEDIA и выборе источников.
Убрать постоянную привязку к группе; роли искать независимо от группы пакета.
Проверить текстовый mailbox и прямое вложение через разные группы без общей группы всех узлов.
Одного этого этапа недостаточно для объявления custody изолированным.
II. Ввести assignment_id, список обращений на M и транзакционные переходы; изменить wire
и схему вместе, без слоя обратной совместимости. Развести статус назначения и источника.
Проверить дубли STORE, отказ/новую попытку, два S/один M, поздние ответы и SQL rollback.
III. Довести revalidate/callback/retry/cleanup; проверить сетевой стенд и весь ./check.sh.
Стенд: A/S/M/B соединены разными попарными группами, общей для всех нет; вторая группа
одной пары отзывается при живом ETCP. Прежнее назначение завершается через оставшийся путь.
Также: отзыв self, роли и третьего участника; отсутствие любого пути; поздние controls/DATA;
старый M после выбора нового; restart между commit/отправкой; прежний TTL; worker при удалении;
отказ в чужой группе до записи в БД/lookup/выдачи файла; сохранность MEMBER_FILES и локальной истории.
Диагностика каждого значимого перехода: file_id, assignment_id, self/peer, выбранная группа,
предыдущее/новое состояние, deadline и точная причина отказа/отмены. Пауза логируется при
изменении состояния, а не на каждом тике. Ошибки БД/диска/протокола не замалчиваются.
Это архитектурный план по чтению кода и уточнению пользователя. Изменения mailbox/custody
и новые проверки из пунктов 1--7 ещё не реализованы; прежние результаты 65/65 и 240/240
относятся только к описанным выше завершённым доработкам FILE_TRANSFER и прямого DM.
+7 -2
View File
@@ -45,8 +45,13 @@
Воспроизведены усечение файла до отказа, незакрытая операция и запись DM через отозванную живую сессию.
Сетевой стенд65/65; test_dm_media17 фаз PASS, allocations0->0. Общий ./check.sh:240/240,
proxy9/9, burst/load PASS (199с), /tmp/chat-personal-isolation-check.log.
Следующая граница mailbox/custody: повтор через B отвечает в B, но сохраняет старое назначение A;
усиление допуска требует атомарного пересогласования и защиты от поздних ответов A. Схема — в конце плана.
Следующая граница mailbox/custody: постоянные group_id/supernode смешивают маршрут и хранение.
По уточнению пользователя личные объекты передаются через любую доступную общую группу пары узлов;
общей группы автора/получателя/S/M не требуется. Назначение хранения сохраняется при смене маршрута.
Проект решения: предметные права отдельно от маршрута, assignment_id для точных ответов,
одна копия M и отдельные обращения S, неизменные TTL/политика, попарный выбор пути и отзыв сетевой работы.
Подробная схема и три этапа — в конце плана. Пока подготовлена только архитектура;
mailbox/custody не изменены, новые сценарии не запускались. Прежний 240/240 не подтверждает этот проект.
Подмена источника, raw JOIN/invite, личные DM и
оставшиеся сервисы ещё не закрыты общей гарантией; точная граница проверок — раздел 5 плана.
План исправления и критерии по четырём этапам: [group_isolation_plan.txt](group_isolation_plan.txt).