# #507 · компактный выбор 0–3 тем Один новый дизайн-вариант: три чипа с видимыми нативными checkbox — **Покрытие**, **Свет**, **Удобства**. Группа имеет `fieldset/legend`, подпись «Необязательно · можно выбрать несколько». Отмеченные чипы используют прежние lavender/purple, отметка остаётся видимой независимо от цвета. Все три варианта видны сразу; нет отдельного меню, поиска или обязательной темы. Минимальная область каждого label — 44 px. Flex-wrap допускает перенос, включая увеличение текста. Onest, цвета, фон, шапка, карточка, поля, действия и контекст отзыва наследуются из утверждённого addendum; изменён только выбор тем и обслуживающий его локальный fixture. Открыть `index.html` локально или раздавать только эту папку статическим сервером. Ресурсы локальные, сетевых/API-вызовов нет. Окно редактирования открывается сразу. Лабораторная полоса под продуктовой частью окна отделена пунктиром и подписана «Лаборатория · вне продуктового макета». Она находится в native dialog для доступности при его открытии, но не входит в предлагаемый продуктовый интерфейс. В ней доступны наборы 0/1/3, disabled и ответы UNKNOWN/VERSION_CONFLICT/чтения. Смена набора начинает новый синтетический пример, а не разрешает незавершённую реальную операцию. Основная страница и её лаборатория сохранены из исходного макета. Закрытие окна возвращает контекст чтения/отзыва публикации. ## Точное поведение тем `surface` = Покрытие, `lighting` = Свет, `amenities` = Удобства. Пустой массив допустим. Начальный пример содержит **все три** в намеренно неканоническом порядке `["amenities","surface","lighting"]`, чтобы обнаружить случайную перестановку при редактировании только текста. Это fixture, не новый default продукта. При открытии массив копируется целиком без сортировки, усечения или подстановки. Текстовая правка не меняет темы. Действительное переключение checkbox применяет существующий порядок TOPICS из текущего обработчика select: surface, lighting, amenities. Присваивание уже имеющегося checked не меняет массив и не сбрасывает согласие. Новых правил нормализации нет. После изменения темы или текста прежний preview и согласие очищаются. Требуются новый предпросмотр и явное согласие. Синтетический preview hash — заглушка, не криптографическое или серверное доказательство. Пакет содержит копию всего массива; его topics заморожены. UNKNOWN удерживает тот же ключ, payload и темы, блокирует controls и закрытие; повтор только явный и с тем же пакетом. Лабораторный ответ можно переключить на подтверждённый и нажать «Повторить тот же запрос». Закрытие без правок и повторное открытие сохраняют точные полученные темы. Как в утверждённом макете, закрытие с несохранёнными правками требует подтверждения их потери; повторное открытие читает известный own fixture, а не подставляет первую тему. UNKNOWN нельзя отбросить закрытием. VERSION_CONFLICT сохраняет stale через закрытие/повторное открытие; неуспешное или UNKNOWN чтение его не снимает. Только явное успешное выбранное own-чтение (fixture version 11) снимает stale и закрывает окно; новой автоматической отправки нет. Публичная версия и ожидающая редакция разделены. Withdraw и read-only контекст сохранены; темам не приписывается право изменения или публикации. ## Текущий seam реализации Source pin: `4a607cc7f7de37c3ca284979d671f26e33eda8c4`, tree `a579e939873b42754da50a52c52ee4f20a662885`. Это S2 candidate, не установленный DEV acceptance. В `apps/web/src/components/consumer/venues/VenueReviewComposer.tsx` заменить **только edit-ветку** select в строках 438–452 на checkbox-backed fieldset; оставить new-review ветку в её текущем поведении. TOPICS определён в 24–28. Сохранить массив `topics`, чтение всех значений в 168, `draftKey` и сброс consent/preview в 125–131, копирование `topics: [...topics]` в 317, текущие locked/stale/preview и packet fences. При реальном изменении checkbox использовать ту же фильтрацию TOPICS, что уже выполняет select; не сортировать полученный массив при render, text input или reopen. В `apps/web/src/styles/venue-reviews.css` рядом с field styles 53–63 добавить ограниченные классы группы/чипа, не менять общий select или другие окна. Обработчики должны брать существующее состояние и guards, а не лабораторные переменные этого прототипа. Текущий `apps/web/src/lib/venue-reviews-api.ts` уже имеет `getOwnVenueReview(id)` и `isSelectedOwnVenueReview`, включая проверку id/venueId/reviewHandle и `editContext`. Основание редактирования приходит из выбранной серверной редакции и её basis; внешний источник прав или новая привязка к игре не требуются. Старое ограничение addendum «нет own GET/:id / original-game association» здесь не действует. Контракт `apps/api/src/venues/venue-reviews.dto.ts` разрешает 0–3 темы, default []; он не изменяется. Consent preview, права, публичная идентичность, audience, модерация, API и серверная логика вне scope. В частности, сохранённый двухшаговый preview в этом графическом прототипе не является требованием заменить текущий ensurePreview в приложении. Прототип демонстрирует публичное редактирование; текущий audience UI приложения нужно сохранить при интеграции. ## Минимальные проверки Root 1. На ширинах 390 и 1280 открыть наборы 0, 1 и 3. Для 0 нет отметок/обязательного поля, для 1 только Покрытие, для 3 видны все. Снять все три, затем выбрать 1 и 3; никакой темы автоматически не добавляется. 2. Tab проходит каждый native checkbox; Space переключает ровно его. Проверить видимую фокусную рамку, имя группы и checked/disabled в accessibility tree. Нажатие по всему label работает; область ≥44 px. При 200% zoom/увеличении текста чипы и подписи переносятся без обрезания, горизонтального скролла и наложений; окно прокручивается. Это ожидаемая проверка, не доказанный browser PASS. 3. Получить preview и согласие; изменить одну тему — оба сбрасываются, отправка недоступна. Снова preview/согласие; изменить только текст — согласие сбрасывается, точный массив и его порядок остаются прежними. В раскрытой лаборатории проверить receivedTopics/draftTopics/previewTopics/packet. 4. Для каждого набора 0/1/3 изменить только текст, выбрать UNKNOWN и отправить. Сравнить packet.body.topics с исходным массивом побайтно в JSON, включая порядок; controls заблокированы. Попытка закрыть не теряет пакет. Явный повтор сохраняет key и весь body. Отдельно проверить disabled fixture и визуальное различие выбранного/невыбранного заблокированного чипа. 5. Закрыть без изменений/повторно открыть: исходный массив точен. При подтверждённом отказе от несохранённых правок восстанавливается исходный own fixture. VERSION_CONFLICT → закрыть → переоткрыть: stale остаётся; failed/UNKNOWN fresh read оставляет его; успешный явный read закрывает окно, требует новой проверки/согласия и следующего явного действия. ## Фактически выполнено и ограничения - `node --check public/app.js`: PASS. - Node VM с минимальным stub DOM: PASS для 0/1/3, точного порядка при text-only/close-reopen/UNKNOWN, замороженных topics, того же retry packet, actual-change consent invalidation, disabled и conflict → failed/UNKNOWN/successful explicit read. Это ограниченная авторская проверка логики; не проверка DOM, accessibility, визуала или независимая QA. - SHA256 четырёх frozen source snapshots и RECONCILIATION сверены; шрифт побайтно совпадает с предоставленным. Manifest перечисляет все deliverables кроме самого себя. - Browser: **NOT_RUN**, оставлен Root. Source implementation/API execution/independent QA/CI/DEV acceptance/Owner UAT: **NOT_TESTED** для этой поправки. Приёмка прежнего addendum не означает приёмку этого результата. Реальные права, API, moderation, cache и runtime здесь не исполняются. DONE/READY/PASS продукта не заявлены. Предыдущие assets взяты только из `inputs/approved`: index/app/styles — основа композиции и существующих recovery flows; `assets/onest.ttf` скопирован без изменения. Это предоставленный prior R2 asset, ранее использованный в R31/addendum; SHA256 `3faa4b905661849b2332e394b42f91b5bf5575e553c516caa81811e868a4d589`. Использован предоставленный фактический скриншот 390 только для визуального сравнения native listbox. Он, source snapshots, inputs и логи в public не копируются. Все тексты/площадка/версии/операции вымышлены. Предыдущая история и артефакты не изменены. Engine receipt создаёт только реальная среда исполнения; этот пакет его не имитирует.