Document active feedback, credential dependencies and permission round lifecycle

This commit is contained in:
evgeny committed 2026-10-26 14:44:03 +01:00
1 parent f3be00438b
commit 1634499d84
2 files changed
+48 -16

No files matched your search

+18 -5
View File
@@ -4,7 +4,7 @@
Транспортный движок не занимается подписями и версиями участников.
Аудит 26.10.2026 частичный: реализации member_sync/merkle_sync/merkle_tree прочитаны,
найденный дефект очистки исправлен по уточнённому плану. Полный аудит остальных
найденные дефекты очистки и загрузки feedback исправлены. Полный аудит остальных
контрактов чата не завершён. Подробности и результаты
проверок: [отчёт](../../doc/member_merkle_audit_findings.txt).
@@ -27,20 +27,28 @@
Уведомления GUI/топологии и changed выполняются после commit.
Каждый member_sync_apply_record также имеет savepoint, поэтому ошибка пересчёта не оставляет запись без индекса.
При внешней транзакции вызывающая сторона после commit вызывает
member_sync_record_committed для каждой изменённой записи: одного changed недостаточно
member_sync_record_committed с полной маской результата для каждой изменённой записи: одного changed недостаточно
для уведомления свойств и планировщика группы. Локальный put доверяет блоку участника
и подписи приглашения; подпись непустого блока владельца проверяется также локально.
MS_APPLY_FEEDBACK отмечает изменение удостоверения, trusted key или deleted, влияющее на feedback.
Такое изменение и пересчёт зависимых feedback-листьев во всех каналах входят в транзакцию MEMBERS.
Ошибка пересчёта откатывает запись, общий ключ и оба индекса; сохранённый feedback не удаляется.
Обычное обновление имени/профиля/stream options не выставляет этот бит и не запускает feedback-раунды.
При обработке страницы маска сохраняется до внешнего commit; JOIN также передаёт полный результат.
После commit разрешённые этим битом уведомления будят feedback и обновляют адресные результаты.
verify_and_purge владеет отдельной транзакцией канала: требует autocommit на входе,
открывает BEGIN IMMEDIATE до чтения, проверяет записи и размеры BLOB/строк,
сохраняет собственный список повреждённых node_id и закрывает SELECT.
Удаление строк и пересчёт их Merkle-листьев выполняются до общего COMMIT.
Удаление строк, пересчёт MEMBERS и зависимых feedback-листьев выполняются до общего COMMIT.
Если FEEDBACK ещё не зарегистрирован при startup purge, его индекс позднее строит chat_feedback_init.
При отказе чтения/проверки/памяти/SQL/индекса/commit выполняется rollback;
ошибка возвращается как -1 без публикации удаления. Чужая транзакция отклоняется до изменений.
Если SQLite не может выполнить rollback и транзакция остаётся открытой, ошибка явно
логируется и сбрасывается inst.running: требуется перезапуск приложения.
После commit очистка уведомляет Merkle, снимает mute, удаляет соединение из конкретной
После commit очистка уведомляет оба набора Merkle и затронутые результаты, снимает mute, удаляет соединение из конкретной
CHAT-группы и уведомляет props-потребителей; общий транспорт других владельцев сохраняется.
Результат >=0 — число подтверждённых удалений. Ошибка публикации после commit
не означает откат уже сохранённых данных. Props-подписчик может снять подписку
@@ -62,7 +70,12 @@ finish проверяет имеющиеся ненулевые подписи
рекурсивного обхода цепочки предков нет, отсутствие сертификата само по себе пропускается.
validate_pubkey и validate_peer проверяют наличие строки без фильтра source/deleted;
допуск CHAT-группы отдельно проверяет topo_node_sqlite_member_allowed.
verified_ed25519 требует source=0/deleted=0, доверенный ключ, join и сертификат приглашения.
author_key требует source=0/deleted=0, доверенный ключ, join и сертификат непосредственного пригласившего.
Возвращает ACTIVE, INACTIVE, PENDING, INVALID или ERROR; выходной ключ меняется только при ACTIVE.
PENDING означает недостающий ключ/сертификат, а не отзыв членства или ошибку SQLite/OpenSSL.
source=0 само по себе не доказывает полный допуск: dependency может разрешиться позднее.
Ключи nodes общие; поступление ключа через другой канал пересматривает авторов с таким node_id/signed_by.
verified_ed25519 сохраняет строгий контракт 0/-1 для radio/attachments и разрешает только ACTIVE.
## Канонический хеш
+30 -11
View File
@@ -1,10 +1,9 @@
# merkle_sync — протокол 3
Аудит 26.10.2026 частичный: движок и адаптер участников прочитаны полностью,
контракты ниже уточнены; найденный дефект очистки member_sync исправлен отдельно.
Разделы feedback/опросов целиком не пересверены в этом аудите.
Продолжение остановлено на подтверждённом отказе запуска feedback после исключения
автора сохранённого состояния. Исправление очистки завершено; новый дефект описан в разделе7 отчёта.
контракты ниже уточнены; дефекты очистки member_sync и запуска feedback исправлены.
Для feedback проверены исключение/возврат, отложенные ключи, атомарность и сетевая сходимость.
Это не завершает аудит всех контрактов чата, db_sync и внешних callers.
Результаты: [отчёт](../../doc/member_merkle_audit_findings.txt).
## Разделение ответственности
@@ -91,6 +90,11 @@ WAKE также перезапускает незавершённый раунд
Истечение завершает ожидания MT_ERR_TIMEOUT; по одному таймеру на активную сессию.
Периодического bg_check и отдельного WAL-таймера в текущем merkle_sync нет.
При отзыве допуска модели revalidate_peers завершает ожидания этого пира MT_ERR_DATA,
освобождает подготовленный пакет/таймер/waiter, но сохраняет подписку в FAILED.
После восстановления changed запускает новый раунд: ждать ответа на ранее отброшенный пакет не нужно.
Вызовы выполняются после commit; done callback может отменить сессию без use-after-free.
## Wire
Заголовок: `service:1 | namespace:8 | type:1 | round:8 | request:4 | dataset:1` (23 байта).
@@ -140,12 +144,24 @@ ver положителен, максимум INT64_MAX. Меньшая верс
Wire-запись: message_id:32, node_id:8, kind:1, ver:8, data_len:2, data, signature:64.
Страница: count:2 и count записей; все числа big-endian, data максимум 2048 байт.
Хеш листа включает канонические тела без signature: разные корректные подписи одного тела
не создают расхождения корней. Входящие и сохранённые подписи всё равно проверяются.
не создают расхождения корней. Подписи проверяются перед включением записи в активный набор.
Членство проверяется через подписи дерева приглашений и join, привязывающий Ed25519 к узлу.
Текущий member_sync_verified_ed25519 также требует deleted=0. Его повторное применение
ко всем сохранённым feedback при init вызывает отказ запуска после исключения автора;
собственное членство узла и другие каналы могут оставаться корректными.
Контракт исторических состояний после исключения ещё требует согласования.
Для init/hash/page используется общий отбор: только author_key=ACTIVE, с повторной проверкой
подписанного состояния и его record_key/bucket. INACTIVE/PENDING/INVALID не включаются в набор.
SQLite/OpenSSL-ошибки не кодируются пустым листом или отсутствующим автором.
Исключённый/отсутствующий автор и ожидающий ключ сохраняются в БД с прежними ver и отменами,
не блокируют startup, но не входят в корень, выдачу и результаты. После возврата они проверяются заново.
Новые состояния INACTIVE/PENDING не сохраняются; такая запись устаревшей страницы
не мешает применению остальных корректных записей. Локальное действие требует ACTIVE даже при no-op.
Изменение удостоверения/deleted/общего ключа атомарно пересчитывает feedback автора и записей,
зависящих от его ключа как signed_by, во всех каналах. Отложенный ключ не блокирует пачку MEMBERS;
его поступление, включая другой канал, включает ранее сохранённые допустимые состояния.
Отдельного сохраняемого флага активности нет: проверка принадлежит member_sync.
После внешнего commit обновляются сессии и адресные FEEDBACK_CHANGED; профиль без изменения
удостоверения/допуска не требует такого пересчёта и уведомлений.
Формат не содержит подписанной границы отзыва: после восстановления применяются обычные ver/data,
без утверждения, что подпись была создана до исключения.
Слой feedback хранит подписанные байты независимо от наличия исходного сообщения;
семантику выбранных пунктов и эмодзи проверяет вызывающий модуль до учёта результата.
@@ -181,5 +197,8 @@ chat_feedback_command в потоке ядра. Desktop и Android получа
это нужно и при restart поверх сохранившегося UP-транспорта, когда нового conn_up не будет.
test_chat_poll проверяет пользовательский API, кодеки, ограничения, отмены и отложенный опрос.
test_chat_poll_network проверяет A ↔ B ↔ C, собственный Unicode-ответ, реакцию и восстановление C
после остановки чата без возвращения отменённых состояний.
test_chat_poll_network проверяет A ↔ B ↔ C, Unicode-ответ, реакцию, остановку/запуск C,
исключение A, позднее подключение D без неактивной истории и возврат A.
После возврата D получает сохранённые состояния, A передаёт новую отмену через прежний UP-транспорт;
результаты и корни активного набора сходятся. test_chat_feedback проверяет также purge,
межканальную зависимость ключа, отсутствие уведомлений от профиля и rollback SQL/index/commit.