Goal
Закрыть 2 пробела из CONV-22 What's Next по §5:
- PIN-protected preset — 4-й вариант Public Visibility (защищённая страница для pre-launch teaser scenario), уже задекларирован в §1.2 Object Builder line 732 + Phase 1.10 v4.3 callout, но в §5 не определён.
- Custom preset cleanup — текущий «Custom» preset с granular toggle'ами
<details>блоком запутывает модель; убираем из Stage 1 как не-MVP.
Pattern Chunk 2/3: surgical правки + 1 новая subsection в §5 + light phase callouts. Все изменения внутри launch-plan-stage-1.html + changelog v4.8 + workstream update. Существующая §4.2 Permissions matrix получает minor label update.
Locked Decisions (CONV-25 interview)
| # | Тема | Решение | |
|---|---|---|---|
| A1 | Visibility model granularity | Per-project в Stage 1, без org-default. Org-default Visibility deferred Stage 2 (если многопроектные студии попросят). Каждый проект — independent preset choice в Object Builder + Project Settings. Reasoning: средне 5 проектов на org в первом milestone — выбрать preset 5 раз не больно; убирает confusion «какой layer wins». | |
| A2 | Preset name | «PIN-protected» — consistent с §1.2 line 732 declaration; чёткая mental model для Owner'а («это страница, на которую нужен PIN»). | |
| A3 | PIN scope | Один PIN на проект. Set / change permission: Owner / Admin (matching §4.2 row «Public Visibility settings»). Sales Manager — нет (это strategic positioning decision, не operational). | |
| A4 | Anonymous viewer experience | Blur + PIN entry overlay. Весь content проекта рендерится с CSS filter: blur(...) (силуэты + цвета видны, деталей не разобрать) + поверх — fixed PIN entry card с двумя CTA: «Enter PIN» (input + submit) + «Contact us» (mailto / tel). Не Private hero, не splash gate page — teaser-curiosity без полезной информации. Реализация — копеечная (CSS filter на content wrapper). |
|
| A5 | Cookie lifetime | 30 дней после правильного ввода PIN'а (pin_<project_id> cookie). Re-entry required только если: cookie expired, или Owner изменил PIN, или user в private/incognito browsing. |
|
| A6 | After-PIN view | **Owner выбирает: Discovery | Full sales** (secondary dropdown в Object Builder и Project Settings рядом с PIN config полем). Pre-launch без финальных цен → Discovery (рендеры + 360° + counter «N units», без цен и availability badges). С готовыми ценами → Full sales (всё видно). Гибкая модель: PIN — это «gate», After-PIN — это «что разблокируется». |
| A7 | Buyer-token bypass | Yes — ?b=<token> ссылки bypass'ят PIN entirely. Buyer не знает PIN, agent знает; token = pre-auth со стороны agent'а. Эта behaviour — fundamental к Phase 1.10 buyer flow (state #2 «Buyer с tokenised ссылкой»). |
|
| A8 | Custom preset cleanup | Удаляется полностью из Stage 1. §5 имеет 4 preset'а: Private / Discovery / Full sales / PIN-protected. <details> Advanced overrides блок (6 toggle'ов: Show prices / availability / floorplates / price range / inquiry / heart actions) → Stage 2 placeholder с пометкой «deferred». В Stage 1 хватает 4 preset'ов. |
|
| A9 | «Set up your organisation» wizard | Без изменений — wizard остаётся: types (Studio/Agency/Developer multi-select) + brand (logo + accent color) + invite команды. Visibility туда не добавляется (org-default = Stage 2). | |
| A10 | PIN config UX — contact fields | Когда Owner / Admin выбирает PIN-protected preset → в Project Settings разворачиваются 2 контактных поля: email (required) + phone (optional). Эти контакты показываются на PIN entry screen для anonymous'а. Per-project (на каждом проекте может быть свой контакт — секретарь / менеджер / агент). | |
| A11 | Контакт source | Per-project (не org-level public contact info блок). Каждый PIN-protected проект имеет свой email + phone в Project Settings → PIN config. | |
| A12 | PIN screen «Contact us» action | mailto:<email>?subject=Access request: <Project name> + tel:<phone> ссылки — нативные browser actions, ноль backend'а. Кастомная contact-form с сохранением в БД → Stage 2. Если phone не заполнен — показывается только email кнопка. |
Strategic insight: PIN-protected — не «preset которого не было», а формализация уже задекларированного 4-го варианта из §1.2 Object Builder. Custom cleanup — параллельная работа: убираем «гибрид» который смущал mental model (как preset чтоли, но это и не preset а override mode).
Approach
Approach B (Restructured + PIN-protected как отдельная subsection):
- §5 lead — переписан с «global per Organisation» на «per-project»
- Preset table — 4 чистые rows (Custom удалён, PIN-protected — последняя row с коротким описанием + cross-ref)
- Advanced overrides
<details>→ repurpose как «Stage 2 deferred» placeholder - Новая subsection (внутри
#fd-visibilitydiv'а) — full PIN-protected spec: blur, overlay UX, After-PIN dropdown, cookie, contact fields, buyer-token bypass, audit log - Viewer states table — добавить light note про «PIN-passed» substate
- §4.2 Permissions matrix — minor label update (row «Public Visibility settings» → добавить PIN-protected в список)
- Phase callouts: 1.2 (Object Builder UI surfaces PIN config), 1.10 (sales-app routing handles PIN gate + cookie + buyer-token bypass + blur), 1.4 (operator dashboard может видеть PIN setting для support, но не сам PIN value)
- Changelog v4.8
- Workstream update + preview sync
Pattern Chunk 3 (CONV-25 build): anchor IDs, cross-links, comparison-style spec, callout style.
Steps
A. §5 lead paragraph — rewrite «global per Organisation» → «per project»
A1. Заменить параграф (current line 980-985) — explicitly per-project model + remove Custom mention from preset count.
<h4 style="color:var(--navy); margin:20px 0 10px;">Public Visibility settings — 4 preset'а (per-project)</h4>
<p style="margin-bottom:10px;">Per-project setting (Object Builder + Project Settings → <strong>Public Visibility</strong>). Определяет какие поля видит <strong>anonymous visitor</strong> (state #1 из таблицы выше) на публичной странице конкретного проекта — цены, availability, floorplates, или (для PIN-protected) blurred тизер с PIN-gate. На Buyer-flow (state #2) и team members (state #4) не влияет. <strong>Org-default Visibility — deferred to Stage 2</strong> (если многопроектные студии попросят).</p>
B. Preset table — 4 rows (Custom удалён, PIN-protected добавлен)
B1. Заменить existing 4-row preset table (lines 987-995). Custom row → PIN-protected row.
<table style="margin:8px 0; font-size:13px;">
<thead><tr><th style="width:130px;">Preset</th><th>Что видит anonymous</th></tr></thead>
<tbody>
<tr><td><strong>Private</strong></td><td>Только hero (logo, branding, tagline) + «Request access» CTA. Никаких проектов, юнитов, рендеров.</td></tr>
<tr><td><strong>Discovery</strong> <em style="color:var(--gold);">(по умолчанию для нового проекта)</em></td><td>Все проекты Organisation'ы видны — hero, рендеры, 360°, floorplates, список юнитов. <strong>Цены и индивидуальные статусы юнитов скрыты</strong> — отображается только counter «N units available» на проект. CTA «Request access» открывает запрос на доступ к Full sales view.</td></tr>
<tr><td><strong>Full sales</strong></td><td>Всё что в Discovery + цены per unit + availability badges per unit (<code>available / reserved / sold</code>). Полноценный public sales-сайт — anonymous видит каждый юнит во всех проектах Organisation'ы независимо от stock allocation assignments.</td></tr>
<tr><td><strong>PIN-protected</strong></td><td>Содержимое проекта показывается с CSS blur (силуэты + цвета без деталей); поверх — PIN entry overlay с «Enter PIN» + «Contact us» CTA. Правильный PIN → 30-day cookie + разблокируется выбранный After-PIN view (Discovery или Full sales). Buyer-token (<code>?b=...</code>) bypass'ит PIN. Полный spec — см. <a href="#fd-visibility-pin">§5.1 ниже</a>.</td></tr>
</tbody>
</table>
C. Advanced overrides <details> — repurpose как Stage 2 placeholder
C1. Заменить existing <details> блок (lines 997-1007) — short Stage 2 deferral note без granular toggles.
<details>
<summary class="task-label">Granular field-level overrides — deferred to Stage 2 <span class="count">(deferred)</span></summary>
<p style="font-size:13px; color:var(--text-mid);">В первой итерации planning'а §5 предполагался <strong>«Custom» preset</strong> с granular toggle'ами (show prices / availability / floorplates / price range / inquiry / heart actions). На <em>2026-05-08 (CONV-25)</em> мы удалили этот preset из Stage 1 — 4 базовых preset'а (Private / Discovery / Full sales / PIN-protected) покрывают MVP-needs студий. Granular per-field overrides вернутся в Stage 2 если многопроектная студия запросит гибрид (например, «Discovery + show prices» — между Discovery и Full sales). Heart / «Связаться» actions для anonymous всегда скрыты (требуют buyer-token).</p>
</details>
D. NEW subsection §5.1 — PIN-protected detailed spec
D1. Добавить new subsection после existing <p> "Per-project override" (line 1009 — он сейчас говорит «Stage 2», его удалить заодно since он ставит в conflict с A1's per-project лозунгом). Insert before closing </div> на line 1010.
<h4 id="fd-visibility-pin" style="color:var(--navy); margin:24px 0 10px;">5.1 — PIN-protected preset (deep spec)</h4>
<p style="margin-bottom:10px;"><strong>Use case:</strong> застройщик / студия хочет показать проект приватно (pre-launch teaser, VIP-listing, ранний preview для investor'ов) — отдаёт URL + PIN устно или в одном email. Anonymous, не зная PIN, видит только blurred тизер; знающие PIN — открывают полную страницу.</p>
<div style="margin:12px 0; padding:14px 18px; background:var(--sand-50); border-left:3px solid var(--gold); border-radius:0 6px 6px 0;">
<strong style="color:var(--navy); font-size:14px;">Anonymous visitor flow (без правильного cookie)</strong>
<ol style="margin:8px 0 0 20px; font-size:13.5px; color:var(--text-mid);">
<li>URL: <code>{slug}.offplan.online/projects/{project-slug}</code> — обычный sales-app URL.</li>
<li>Содержимое проекта рендерится в полном объёме (как After-PIN preset выглядел бы) **с CSS <code>filter: blur(12-16px)</code> на content wrapper** — силуэты hero, рендеров, floorplate, units list видны, но не читаемы.</li>
<li>Поверх blur'а — fixed PIN entry overlay (centered card, brandbook v2 styling) с:
<ul style="margin:4px 0 0 16px;">
<li>Заголовок: «<em>Project Name</em>» (project-name виден, чтобы пользователь понял на что зашёл) + строка «Эта страница защищена. Введите PIN для доступа.»</li>
<li>Input field — PIN (numeric 4-8 цифр или alphanumeric password — Owner определяет при setup'е, free-format string)</li>
<li>Кнопка «Open project» (submit)</li>
<li>Sub-block «Не знаете PIN?» с двумя actions: <strong>Email us</strong> (`mailto:<contact_email>?subject=Access request: <Project name>`) + <strong>Call us</strong> (`tel:<contact_phone>` если phone не пустой; иначе кнопка скрыта).</li>
</ul>
</li>
<li>Submit → server validates PIN → если correct → <strong>set cookie <code>pin_<project_id>=<random_token></code> на 30 дней</strong>, redirect на same URL → теперь user видит After-PIN preset (Discovery или Full sales — what Owner выбрал). Если incorrect → form shows error «Wrong PIN» + tracks attempt в audit log; rate-limit 5 attempts → 30s cooldown.</li>
</ol>
</div>
<div style="margin:12px 0; padding:14px 18px; background:var(--sand-50); border-left:3px solid var(--gold); border-radius:0 6px 6px 0;">
<strong style="color:var(--navy); font-size:14px;">PIN bypass cases (visitor видит After-PIN preset напрямую)</strong>
<ul style="margin:8px 0 0 20px; font-size:13.5px; color:var(--text-mid);">
<li><strong>Valid 30-day cookie</strong> на этом проекте — re-entry не нужен.</li>
<li><strong>Buyer-token URL</strong> (<code>?b=<token></code>) — token = pre-auth со стороны Sales Agent'а, который buyer'у эту ссылку прислал. Buyer не должен знать PIN (он его не должен видеть). Token валиден → bypass PIN entirely → render полная unit-page (state #2 в viewer states таблице).</li>
<li><strong>Logged-in team member</strong> owning Organisation — Owner / Admin / Sales Manager / Content Editor / Sales Agent → state #4 в таблице, всегда Full sales (PIN не нужен). Logged-in member guest organisation — same: bypass PIN (он уже authenticated в системе с правом на этот проект).</li>
<li><strong>Owner изменил PIN</strong> → все existing cookies invalidated (security default — изменение PIN это «отозвать access у тех кто PIN знает»). Visitors с invalid cookie возвращаются на blurred PIN entry screen.</li>
</ul>
</div>
<div style="margin:12px 0; padding:14px 18px; background:#fff; border:1px solid var(--border); border-radius:6px;">
<strong style="color:var(--navy); font-size:14px;">PIN config UI (Project Settings → Public Visibility = PIN-protected)</strong>
<p style="font-size:13.5px; color:var(--text-mid); margin:8px 0;">Когда Owner / Admin выбирает «PIN-protected» preset для проекта (в Object Builder при создании ИЛИ в Project Settings потом) — разворачиваются 4 поля:</p>
<ul style="margin:0 0 0 20px; font-size:13.5px;">
<li><strong>PIN</strong> (required) — text input, free-format string (PIN или password — Owner решает; min 4 char). Hashed at rest (bcrypt / argon2 — implementation Phase 1.3).</li>
<li><strong>After PIN: visitor sees</strong> (required) — radio / dropdown: <code>Discovery</code> (по умолчанию) | <code>Full sales</code>. Pre-launch без финальных цен → Discovery. С готовыми ценами → Full sales.</li>
<li><strong>Contact email</strong> (required) — email visitor'а который не знает PIN отправит запрос на доступ. Default = Owner email; editable. Per-project — может быть отдельный «секретарь / менеджер / агент» на каждый проект.</li>
<li><strong>Contact phone</strong> (optional) — phone number в международном формате. Если заполнен — на PIN screen появляется кнопка «Call us» рядом с «Email us».</li>
</ul>
<p style="font-size:13px; color:var(--text-mid); margin-top:8px;">Permission to set / change PIN: <strong>Owner / Admin</strong> (matching <a href="#fd-access">§4.2</a> row «Public Visibility settings»). Sales Manager / Content Editor / Sales Agent — нет.</p>
</div>
<div style="margin:12px 0; padding:14px 18px; background:#fff; border:1px solid var(--border); border-radius:6px;">
<strong style="color:var(--navy); font-size:14px;">Audit log</strong>
<ul style="margin:8px 0 0 20px; font-size:13.5px; color:var(--text-mid);">
<li>PIN set / changed: «User X set / changed PIN for Project Y at TIMESTAMP» — visible to Owner / Admin (НЕ показывает сам PIN value).</li>
<li>Failed PIN attempts (>3 в час с одного IP) — flag в operator panel (Phase 1.4) для anti-brute-force monitoring.</li>
<li>Successful PIN entry — НЕ pers-attributed event (anonymous visitor); только aggregate counter «N PIN-passed views в day» для analytics.</li>
</ul>
<p style="font-size:13px; color:var(--text-mid); margin-top:8px;">Schema-level дизайн audit таблицы — Phase 1.3 implementation level (consistent с §4.6 View-as-Agent audit).</p>
</div>
<p style="font-size:13px; color:var(--text-mid); margin-top:14px;"><strong>Cross-link:</strong> <a href="#phase-1-2">Phase 1.2 Object Builder</a> — surface этих 4 полей в creation flow · <a href="#phase-1-10">Phase 1.10 Sales App</a> — routing logic для blur + PIN entry + cookie + buyer-token bypass · <a href="#phase-1-4">Phase 1.4 Operator Dashboard</a> — operator может видеть «Project X is PIN-protected» (для support troubleshooting) но не PIN value.</p>
E. Viewer states table — light note про «PIN-passed» substate
E1. Добавить one-line note под viewer states table (after line 973 closing </table>) — короткое пояснение что state #1 anonymous может иметь substate «PIN-passed cookie» когда проект на PIN-protected preset.
<p style="margin:8px 0 0; font-size:13px; color:var(--text-mid);"><strong>Substate (PIN-protected projects):</strong> visitor в state #1 может иметь valid <code>pin_<project_id></code> cookie от предыдущего входа — рендер тогда такой же как у соответствующего After-PIN preset (Discovery или Full sales), без blur. См. <a href="#fd-visibility-pin">§5.1</a>.</p>
F. §4.2 Permissions matrix — minor label update
F1. Update row label (current line ~890 в launch-plan-stage-1.html — «Public Visibility settings (Private / Discovery / Full sales)»):
<tr><td>Public Visibility settings (Private / Discovery / Full sales / PIN-protected)</td><td>✅</td><td>✅</td><td>—</td><td>—</td><td>—</td></tr>
(Permissions без изменений: Owner / Admin only, остальные —. PIN setting falls под этот row.)
G. Phase callouts touchpoints (light updates)
G1. Phase 1.2 (Object Builder) — add bullet в существующий v4.5 callout (Atelier rework), либо в v4.6 если есть; или create new v4.8 sub-bullet:
«v4.8 (CONV-25): PIN-protected preset config (4 поля — PIN / After-PIN view / contact email / contact phone) разворачивается в Object Builder когда Owner выбирает PIN-protected. См. <a href="#fd-visibility-pin">§5.1</a>.»
G2. Phase 1.10 (Sales App) — add bullet в существующий v4.4 / v4.7 callout:
«v4.8 (CONV-25): sales-app routing handles PIN gate. Anonymous request на PIN-protected project → render с CSS blur + overlay; valid cookie → After-PIN preset; buyer-token → bypass; logged-in member owning/guest org → bypass. Implementation note: middleware checks (a) buyer token presence/validity, (b) cookie presence/validity, (c) auth status — sequence from least to most invasive.»
G3. Phase 1.4 (Operator Dashboard) — add bullet в существующий v4.4 / v4.7 callout:
«v4.8 (CONV-25): operator может видеть «Project X is PIN-protected» (флаг в Project list / Project drawer) для support troubleshooting (e.g., «client says PIN doesn't work»), но не видит самого PIN value (security — operator не должен знать пользовательские secrets). Anti-brute-force flag — failed PIN attempts >3/hour highlighted.»
H. Changelog v4.8 entry
H1. Append v4.8 entry в launch-plan-changelog.html (поверх v4.7):
- Date: 2026-05-08
- Source: CONV-25 / Wave 2 Chunk 4
- Sections: §5 cleanup (lead rewrite, preset table, Advanced overrides → Stage 2), new §5.1 PIN-protected spec (anonymous flow, bypass cases, config UI, audit log), viewer states substate note, §4.2 row label update, phase callouts 1.2/1.10/1.4.
I. Workstream update
I1. workstreams/stage1-roman-integration.md:
- Add CONV-25 Chunk 4 entry в Session Log
- Update What's Next → Chunk 5 (§6 User Journeys: status-form D+E + request-more F + channels G)
J. Preview repo sync
J1. Sync 2 файла в ~/code/offplan-online/preview/plan/:
launch-plan-stage-1.htmllaunch-plan-changelog.html
Commit + push в preview (analogous Chunks 2/3 sync).
Files
- Primary edit:
docs/rendered/launch-plan-stage-1.html(~150 lines added — §5 lead rewrite + preset table cleanup + advanced overrides note + new §5.1 spec + viewer states substate + §4.2 row label update + 3 phase callouts) - Secondary edit:
docs/rendered/launch-plan-changelog.html(v4.8 entry, ~50 lines) - Workstream update:
workstreams/stage1-roman-integration.md - Optional sync:
~/code/offplan-online/preview/
Dependencies
- Blocked by: nothing (Chunks 1-3 commit'нуты в production, sync'нуты в preview)
- Blocks: nothing (Chunks 5-8 могут идти параллельно, кроме общих anchor cross-links)
Testing
- Visual sanity check: открыть
launch-plan-stage-1.html, проверить:- §5 lead — per-project framing, no "global per Organisation"
- Preset table — 4 rows, no Custom, PIN-protected last row
- Advanced overrides
<details>— collapsed by default, читается как Stage 2 deferral - §5.1 — 4 boxes (anonymous flow, bypass cases, config UI, audit log) рендерятся с styling
- Viewer states table — substate note видна
- §4.2 row label — содержит PIN-protected
- Phase callouts видны в 1.2 / 1.10 / 1.4
- Cross-link sanity: anchor
#fd-visibility-pinработает; cross-refs из §1.2 line 732 и §1.10 callout остались valid - Cross-doc consistency: grep по «Custom preset» — не должен matcher оставшихся mention'ов в §5; grep по «PIN-protected» — должен match'ить §1.2, §5 preset row, §5.1, §4.2 row, 3 phase callouts, changelog
- Preview sync (если выполнили): проверить
https://offplan-online.github.io/preview/plan/launch-plan-stage-1.html
Risks
- §5.1 размер — может вырасти больше чем 150 lines если все 4 boxes (flow / bypass / config / audit) детально расписаны. Mitigate: использовать compact bullet style, не embedded sub-tables. Если в /build выходит >200 lines — split на 5.1 (anonymous + bypass) и 5.2 (config + audit).
- Audit log scope creep — детали аудита легко могут перетянуть в Phase 1.8 (Security infra). Mitigate: упомянуть как requirement без deep dive в схему таблицы — это уровень Phase 1.3 implementation (consistent с pattern §4.6 View-as-Agent).
- Phase 1.2 Object Builder UI — 4 conditional поля (только при PIN-protected) добавляют UI complexity в creation flow. Mitigate: light callout, не deep redesign — детали = Phase 1.2 build / Atelier mockup update separately.
- Custom cleanup может сломать cross-refs — нужно проверить что нигде в плане нет ссылок на «Custom preset» или old
<details>Advanced overrides anchor (если был). Mitigate: grep на «Custom» before commit. - Phase 1.10 routing complexity — middleware logic с тремя bypass cases (cookie / buyer-token / auth) может быть сложнее чем в текущем 1.10 spec. Mitigate: light callout с sequence note (least → most invasive); полный spec routing'а = Phase 1.10 build.
Workstreams
- Updates
workstreams/stage1-roman-integration.md:- Mark Chunk 4 done в Session Log (CONV-25 entry, append к existing)
- Update What's Next → Chunk 5 (§6 User Journeys)
Evaluation
Done when:
- §5 lead — per-project framing, no «global per Organisation»
- Preset table — 4 чистые rows, Custom удалён, PIN-protected — последняя row с cross-ref на §5.1
- Advanced overrides
<details>— Stage 2 placeholder text - §5.1 — full spec (anonymous flow + bypass cases + config UI + audit log)
- Viewer states table — substate note про PIN-passed cookie
- §4.2 row label — содержит PIN-protected
- Phase 1.2 / 1.10 / 1.4 — light v4.8 callouts
- Changelog v4.8 entry
- Workstream Session Log + What's Next обновлены
- Cross-link sanity check passed (grep для «Custom preset», «PIN-protected»,
#fd-visibility-pin) - (optional) Preview synced + pushed
Definition of NOT done (deferred):
- Org-default Visibility — Stage 2 if multi-project studios попросят
- Granular per-field overrides («ex-Custom toggles») — Stage 2
- PIN-protected UI mockup в
docs/mockups/admin-panel-atelier.html— отдельный track - PIN backend (hashed storage, rate-limit middleware, audit log table) — Phase 1.3 + 1.10 implementation
- Phase 1.10 sales-app routing detailed pseudocode — Phase 1.10 build / sub-plan
- Wave 2 Chunks 5-8 (§6 Journeys, §7 Edges, deep Phase callouts, ADRs)
Open Questions
- «Request access» CTAs в Private + Discovery preset'ах — currently §5 не указывает куда они ведут. Логично применить ту же модель что и для PIN: per-project contact (email + phone). Но это additional scope; решение по этому может появиться при Chunk 4 /build inline (если place позволяет) или в отдельном мини-патче после Chunk 4.
- PIN format constraint — free-format string с min 4 char (decision A10) даёт максимальную гибкость, но Owner может ввести «1234» (weakly secure). Stage 1: не enforce'им strength (это not security-critical pre-launch teaser, не payment portal). Stage 2: можем добавить «PIN strength» indicator + min-length recommendation.
- Brute-force protection scope — rate-limit 5 attempts → 30s cooldown (decision в плане). IP-based throttling + flag operator dashboard это acceptable для Stage 1; full WAF / IP block / CAPTCHA — Stage 2 if abuse occurs.
- What if Owner deletes PIN-protected project — cookies становятся orphan'ами (но безвредны —
pin_<id>для несуществующего id просто игнорируется при routing'е). Не block'ит, документировать в Phase 1.10 routing spec.