# Издания pro и enterprise: что написано, что объявлено, что осталось

Документ текущего состояния. Отвечает на один вопрос: **по каждой возможности
платных изданий — есть ли код в сборке, и если нет, то что именно не написано.**
Числа и статусы берутся из `src/ragraf/edition_baseline.json` и проверяются
`edition.baseline_problems`; здесь они не перепечатываются «на память».

## 1. Зачем понадобился статус в данных

До этапа И9 раздел `missing` в ответе `python tools/ragraf.py edition` смешивал
два совершенно разных состояния:

* **«написано, но действует другое издание»** — код в сборке есть, лицензия не
  позволяет;
* **«объявлено, кода нет»** — возможность существует только записью в данных.

Причина была одна и та же: `возможность появляется в издании pro`. Читатель не
мог отличить готовую работу от обещания, а платное искали и не находили —
измерено на этапе И9: у enterprise в `missing` стояли пять pro-возможностей, из
которых четыре не имели ни одной операции в сборке.

Поэтому у каждой возможности появилось поле `status` из **закрытого списка**:

| `status` | Что означает | Обязательное поле |
|---|---|---|
| `shipped` | операции возможности есть в сборке | — |
| `declared` | объявлено как запланированное | `planned`: одной строкой, что именно не написано |

Опечатка в статусе, `declared` без `planned` и `shipped` с `planned` —
**отказ проверки данных** (`edition.baseline_problems`), а не «неизвестное
значение, считается объявленным». Иначе `shippd` тихо означал бы что угодно.

Статус не отменяет проверку состава: возможность попадает в список действующих,
только если ВСЕ её операции найдены в сборке. Поэтому `declared` видна в
`missing` с причиной, в которой назван статус, а не только издание.

## 2. Возможности платных изданий

| Возможность | Издание | Статус | Что сделано | Что осталось |
|---|---|---|---|---|
| `quality-loop` | pro | `shipped` | `src/ragraf/quality.py`: набор проверок индекса, запись прогона в добавляющую таблицу `quality_run`, сравнение двух прогонов; операции `quality_suite`, `quality_diff`, `quality_prune` (прореживание журнала прогонов: сухой прогон по умолчанию, копия до удаления, подтверждение); инструменты `ragraf_quality_suite`, `ragraf_quality_diff`, `ragraf_quality_prune`; проверка `tests/test_quality_loop.py` | — |
| `shared-index` | pro | `shipped` | `src/ragraf/shared_index.py`: чтение индекса команды по сети — `serve` отдаёт операции чтения по допуску, `query` возвращает тот же конверт, что локальный фасад, с честной свежестью; запись по сети не публикуется (граница этапа); операции `shared_index_status`, `shared_index_publish`, `shared_index_query`; проверка `tests/test_shared_index.py` (69 свойств) | — |
| `secret-broker` | pro | `shipped` | `src/ragraf/broker.py`: брокер секретов — аренда со сроком (`broker_max_ttl_minutes`), распорядитель (выдать другому агенту может автор записи или администратор), причина в журнале доступа, одноразовое погашение, отказ `lease_stale` при смене значения, план смены и её выполнение; состояние аренд — `catalog/broker.json` (схема хранилища не меняется); операции `broker_issue`, `broker_rotate`, инструменты `ragraf_broker_issue`, `ragraf_broker_rotate`; проверка `tests/test_broker.py` (44 свойства) | — |
| `sso` | enterprise | `shipped` | `src/ragraf/sso.py`: OIDC authorization code + PKCE, роли только из групп отображения | SAML — отказ с причиной |
| `siem-export` | enterprise | `shipped` | `src/ragraf/siem.py`: syslog/HTTP, курсор доставки, только метаданные | — |
| `offline-license` | enterprise | `shipped` | `src/ragraf/license_offline.py`: заявка, выпуск, приёмка по подписи и отпечатку установки, перенос | — |
| `attestation` | enterprise | `shipped` | `src/ragraf/attest.py`: подписанный набор, проверка пересчётом хэшей из файлов | — |

Итог по изданиям: у **enterprise** действуют **12 возможностей** (пять базовых
Community + `quality-loop` + `shared-index` + `secret-broker` + четыре enterprise).
У **pro** действуют **8** (пять базовых + `quality-loop` + `shared-index` +
`secret-broker`), в `missing` — четыре enterprise. Объявленных и не написанных
возможностей не осталось: `connectors` и `fleet` сняты из предмета уровней и названы
в разделе `roadmap` базовой линии с причиной и датой решения.

## 3. Решение 26.10.2026: брокер сделан, две возможности сняты

Судьба каждой возможности решается ОДНИМ из двух способов — либо код и
доказательство поведением, либо снятие с названной причиной. Третьего
(«объявлено и висит в `missing`») больше нет: обещание, которое нельзя ни
проверить, ни предъявить, — это долг перед покупателем, а не roadmap.

* `secret-broker` — **сделан**. Он опирался на готовый фундамент: хранилище с
  владельцем записи, сроком, правами и журналом с цепочкой хэшей. Не хватало
  ровно службы: аренда со сроком, распорядитель, одноразовое погашение, план
  смены. Всё это доказывается локально, поэтому и реализовано.
* `connectors` — **снято**. Коннектор требует отдельного контракта на каждый
  внешний вид: адрес, права, повторы, предел. Общая заглушка `connector_run`
  возвращала бы `ok=true`, ничего не запуская, — ровно тот класс ложного успеха,
  из-за которого в проекте действует правило «зелёная проверка, ничего не
  осмотревшая, — провал». Внешних систем, на которых поведение можно доказать,
  здесь нет.
* `fleet` — **снято**. Управлять нечем: парка зарегистрированных установок в
  этой сборке нет, и «применение настроек» применяло бы их к нулю машин,
  отчитываясь об успехе.

Снятое не удалено: `connectors` и `fleet` названы в разделе `roadmap` файла
`src/ragraf/edition_baseline.json` вместе с причиной, датой решения и
операциями, которые понадобятся при возврате. Раздел проверяется так же, как
`features`: имя не повторяется, причина названа, а возможность, попавшая сразу
в оба раздела, отвергается — у неё был бы два статуса.

## 4. Что делает контур качества

Пять проверок, закрытый список и фиксированный порядок (`quality.CHECK_IDS`):

| Проверка | Что измеряет | Когда `problem` |
|---|---|---|
| `chunks_over_budget` | чанки длиннее предела (8000 токенов, `chunk_map.tokens`) | есть хоть один: выдача размывается |
| `signature_truncated` | функции с обрезанной сигнатурой в `node.props` | есть хоть одна: контракт параметров недостижим |
| `vector_available` | доступность `sqlite-vec` и число векторов | никогда (`warn`): честная деградация, не дефект |
| `capability_honest` | рёбра с источником графа свойств кода при `capability=full` | `full` без таких рёбер — завышенный режим |
| `parse_partial` | доля файлов с `parse_status` `partial`/`failed` (промилле) | никогда (`warn` при доле выше 200‰) |

Три свойства — часть контракта, а не украшение:

1. **Детерминизм.** В измерении нет времени и длительностей, доли считаются
   целыми промилле, порядок задан списком. Два прогона на неизменённом индексе
   дают одинаковый `digest` (sha256 канонической записи). Замер 25.10.2026 на
   rev-0266: `0e1944a1e86a578f…` в обоих прогонах.
2. **В журнал — только числа.** Добавляющая таблица `quality_run` (существующие
   таблицы и нумерация ревизий не затрагиваются) хранит ревизию, режим, счётчики
   и JSON измерения: имена проверок, числа, причины словами. Ни строк кода, ни
   путей файлов, ни содержимого чанков — прогон качества не должен становиться
   вторым индексом. Автоматической ротации нет: удаление старых записей —
   отдельное решение владельца, а не побочный эффект.
3. **Сравнение не выносит вердикт через ревизию.** Если прогоны сделаны на
   разных ревизиях, ответ несёт `through_revision: true` и `verdict: null`:
   правка кода законно меняет числа, и называть это деградацией индекса значило
   бы обвинять индекс за работу программиста.

Чего контур НЕ делает: не проверяет конвенции проекта (BOM, доктрину, числа в
документах — это чекер `tools/Invoke-ProjectDoctrine.ps1`), не измеряет качество
ранжирования и полноту ответов (для этого нужны запросы пользователя, а не
индекс). Обе границы названы в поле `limits` каждого ответа.

## 5. Проверки

```powershell
python tools\ragraf.py edition                 # Community: 5 возможностей
python tests\test_editions.py                  # 114 свойств, включая статусы
python tests\test_quality_loop.py              # 153 свойства
python tests\test_broker.py                    # 44 свойства брокера секретов
python tests\test_offline_attest.py            # 78 свойств, enterprise = 12 возможностей
pwsh -NoLogo -NoProfile -NonInteractive -File tools\Invoke-ProjectDoctrine.ps1
```

Чекер — **33 проверки**: `Test-EditionLayer` (27-я) запускает оба набора —
изданий и контура качества — и отдельно требует, чтобы каждый осмотрел не меньше
своего порога свойств. Ноль осмотренных свойств при успехе — провал, а не PASS.
