# СИНГУЛЯР · КРИСТАЛЛ — протокольное ядро связи (v1.0.0)

Дата вшивки: 2026-10-03. Источник: reference-архив
`SINGULYAR_KRISTALL_REFERENCE_2026-10-03.zip` (нормативные инварианты)
+ протокол доставки `protocol/DELIVERY.md` из того же архива.

## Что это

Кристалл — НЕ мессенджер и НЕ страница. Это общий протокольный слой
связи СИНГУЛЯРА: канонический смысл отделён от представления, канала,
транспорта и хранения.

```text
СМЫСЛ ≠ ПРЕДСТАВЛЕНИЕ ≠ КАНАЛ ≠ ТРАНСПОРТ ≠ ХРАНЕНИЕ
```

## Что нормативно (в этой папке)

| Файл | Роль |
|---|---|
| `crystal-core.mjs` | ядро: semantic event, выбор представления, конверт, retention, идемпотентность, машина доставки |
| `journal.mjs` | durable журнал (IndexedDB `singulyar-crystal`): события, дедуп-ключи, записи доставки, purge истёкших |
| `semantic-event.schema.json` | wire-level контракт события (JSON Schema 2020-12) |
| `bridges.mjs` | НЕнормативно: мосты модулей (identity.ref, shared.activity) — потребители контракта |
| `крипта.mjs` | НЕнормативно: E2EE-слой (v1.19) — PBKDF2→AES-GCM, ECDH/ECDSA, цепь журнала |
| `composition.mjs` | НЕнормативно (v0.1.0, такт v1.37.0 «СВОД»): композиция примитивов — реестр, словарь намерений человека, сборка/валидация Space Manifest; машина только предлагает, решает человек (СВОД I-01/I-04/I-06/I-09); эмерджентность доказана test_composition.mjs 12/12 |
| `space.schema.json` | НЕнормативно (черновик 0.1, такт v1.37.0): JSON Schema 2020-12 манифеста возникшей среды — участники-люди, примитивы, память по решению человека, состояние «предложено» |

Правило изменений: три файла выше нормативны. Правка требует новой версии
и заметки о миграции. `bridges.mjs`, `крипта.mjs`, `composition.mjs` и
`space.schema.json` — потребители/надстройки: правятся свободно, ядро не
трогают. Всё остальное в системе — потребители контракта.

GAP-список (честно): в composition.mjs нет исполнителя сред (runtime) —
только протокол проектирования; словарь намерений локальный — общий
словарь дома и UI над ним — следующий такт; space.schema.json не
проверяется библиотекой схем (валидация структурная, без зависимостей).

## Карта модулей (правило интеграции reference)

```text
·19 ЧЕЛОВЕК  → идентичность (identity.ref)      [мост вшит: v1.18]
·21 ОБЩЕНИЕ  → слой представлений/возможностей  [вшито: шина meaning.21.crystal]
·22 СВЯЗЬ    → канал/доставка                   [вшито: журнал + ACK + дедуп + TTL]
·18 ЗАЛ      → общая активность                 [мост вшит: v1.18]
```

Кристалл не заменяет модули — он их общий протокол. UI-контракты
модулей не ломаются: протокольный слой — усилитель, а не критический
путь. Падение импорта ядра = модуль работает как раньше (честный
fallback, в статусе видно).

## Машина доставки (DELIVERY.md, норматив)

```text
CREATED → QUEUED → SENT → ACKED → DELIVERED → READ
Ошибка:  QUEUED/SENT → RETRY[n] → FAILED   (FAILED → QUEUED — ремонт)
```

Правила: id события стабилен; ключ идемпотентности стабилен между
повторами; retry не меняет semantic payload; ACK ≠ READ; падение
транспорта ≠ падение сообщения, пока повторы не исчерпаны.

Реализовано в ·22: CREATED → SENT (уход пакета), ACK от получателя →
ACKED. DELIVERED ставится на стороне получателя при приёме. READ пока
не отправляется нигде — честный GAP, не притворяемся.

## Мосты (bridges.mjs, v1.3.0, ненормативно)

| Мост | Событие | retention | Ключ |
|---|---|---|---|
| ·19 → журнал | `identity.ref` (id/имя/дата, БЕЗ ключей) | persistent | `identity-ref:<uuid>` |
| ·19 → зал | `hall.join` (верификация ·19: публичный JWK подписи + подпись факта; E2EE v2) | persistent | `hall-join:<room>:<id>:<эпоха>` |
| ·22 → журнал | `hall.epoch` (объявление ротации ключей — ОТКРЫТОЕ: метаданные не секрет; E2EE v2) | persistent | `hall-epoch:<room>:<эпоха>` |
| ·22 → журнал | `call.signal` (звонок как факт: ring/accept/decline/cancel/end — каждый акт отдельное неизменяемое событие; подпись ·19 где есть; SDP/ICE — транспорт, в журнал не пишется) | temporary, TTL = 10 мин | `call-signal:<room>:<звонкаId>:<действие>:<от>` |
| ·18 → журнал | `hall.session` (зеркало манифеста, без аудио) | temporary, TTL = 7 дней зала | `hall-session:<id>` |
| ·18 → журнал | `hall.memory` (память ◈, replyTo → сессия) | persistent | `hall-memory:<id>` |
| ·18 → журнал | `hall.memory.decide` (решение человека помнить/забыть — неизменяемое событие) | persistent | `hall-decide:<цель>:<решение>:<акт>` |

Вид смысла — в `conversation`, payload — в `attachments`; сами события —
обычные semantic.message из ядра. Повторная публикация гасится durable
дедупом. Стирание личности убирает её ref из журнала (адресно, чужие
события не тронуты). Транспорт между устройствами — не мост: им остаётся ·22.

## Что уже работает (проверено тестами)

- смысл не меняется при любом представлении (инвариант reference);
- явный выбор человека выигрывает, недоступный выбор даёт наблюдаемый
  fallback (`explicit-choice-unavailable`), а не тихую подмену;
- временное сообщение умирает по TTL (retention purge в журнале);
- конверт транспорт-нейтрален (local/webrtc/webtransport — метка);
- повторная доставка отбрасывается по durable ключу (перезагрузка
  страницы дедуп не теряет);
- нелегальные переходы доставки отклоняются с `ILLEGAL_TRANSITION`
  (диагностика вместо тихого вранья);
- КРИПТА (v1.19): фраза зала в ·22 запечатывает тексты ДО провода и
  ДО журнала (AES-GCM, свежий IV, kid-отпечаток); ключ живёт только в
  памяти вкладки; у кого фразы нет — честное «§ запечатано»; на шифровках
  работают та же доставка/ACK/дедуп; цепь журнала показывает подделку
  в точном звене (tamper-evident).
- КРИПТА v2 (v1.22): ротация = ЭПОХИ — ключЭпохи(фраза, код, эпоха)
  выводит свой ключ на эпоху, печать v2 несёт ep, вскрытие по карте
  эпох; «новая эпоха» с новой фразой = честный rekey; «стереть прошлое»
  выбрасывает старые ключи из памяти вкладки (стирание, НЕ форвард-
  секретность — носитель фразы старые ключи выводим). Верификация ·19:
  канонБайты (детерминированная сериализация) + завериФакт/верьФакту
  (ECDSA над каноническими байтами) — подписанное приветствие в ·22
  подтверждает имя ключом с устройства, без личности — честный вердикт
  «без подписи», подделка — честный «НЕ сошлась».

## Чего НЕТ (честные GAP, не притворяемся)

- E2EE зала ВШИТ (v1.19: фраза → PBKDF2 → AES-GCM на проводе и в
  журнале; ключ — только память вкладки). Ротация (v2: эпохи + rekey
  сменой фразы) и верификация личности через ·19 (E2EE v2: hall.join +
  подписанные приветствия в ·22) — СДЕЛАНЫ. Остаётся честным GAP:
  полная форвард-секретность (носитель фразы выводит ключи всех её
  эпох), запечатывание голосовых/файлов;
- production сигналинг и серверный релей (`server/README` reference
  описывает требования — вне браузерного прототипа честно);
- multi-device conflict resolution;
- push-инфраструктура и attachment resume;
- READ-статусы (никто их не шлёт);
- независимый accessibility-аудит выбора представлений.

## Как проверить

```bash
node --test ИНСТРУМЕНТЫ/test_crystal_logic.mjs       # инварианты ядра
node --test ИНСТРУМЕНТЫ/test_crystal_bridges.mjs     # мосты ·19/·18
node --test ИНСТРУМЕНТЫ/test_crypto_logic.mjs        # КРИПТА: математика
python3 ИНСТРУМЕНТЫ/test_crystal_browser.py          # два окна ·22: ACK, дедуп, TTL
python3 ИНСТРУМЕНТЫ/test_crypto_browser.py           # три окна ·22: шифровка на проводе/в журнале
```
