ADR 0155: Соответствие документации и кода (correspondence) и архитектурный дрейф¶
Статус: Proposed
Дата: 2026-05-28
Резюме¶
- Сквозной каркас: как в Cascade отслеживать согласованность намерений в документации (ADR, KB, Intercom) с кодом и семантической картой — шире, чем одна связь «relate».
- Не один механизм: несколько слоёв (осведомлённость, навигация, план правок, дискуссия) с общей дисциплиной verify / advisory, без подмены code review.
- 0061 — первый практический шаг (карта путь → ADR); полная автоматическая верификация «текст ADR = реализация» — отдельная дорожная карта.
- Канон видов связи — отдельный версионированный каталог (предпочтительно JSON + JSON Schema); экземпляры привязок (путь → ADR) — в
workspace.toml; per-layer wire сохраняет нативные имена + alias на канон. - Feature (продуктово-архитектурная единица) — хаб: code scope (файлы, слои, неймспейсы) + несколько доков; L1 path map остаётся fallback (§7).
Связанные ADR¶
| ADR | Роль в correspondence |
|---|---|
| 0061 | L1: декларативная карта путь → ADR, PFD, advisory агента (GPWS для доков) |
| 0156 | CRS: страница Mfd для L0–L4; reverse anchors (док → код через CodeAnchor) |
| 0157 | Magic Link cide:// (сайт доков → IDE) |
| 0098 | L0: семантическая карта первична; код/доки/git — проекции; риск drift между проекциями |
| 0039 | L2: код ↔ код («связанные» файлы, subgraph, MCP get_code_navigation_context) |
| 0053 | L2: намерения в коде (control flow, grain intent/detailed) |
| 0042 | L3: план правок vs семантическая карта до записи на диск |
| 0045 | Event log — носитель явных связей Intercom |
| 0128 | Якоря «кусок кода» в сообщении |
| 0137 | L4: gutter ↔ код, message_relate / messages_for_code |
| 0121 | IOP: коммуникация и явные намерения как противоядие хаосу |
| 0021 | Куда подавать сигналы (PFD, advisory, не banner blindness) |
| 0073 | ADR indicator как вариант прибора на PFD |
| 0114 | relation_kind на рёбрах графа (L2); ортогонально graph_kind и provenance |
| 0029 | TOML-first для конфигов; каталоги и wire — отдельно |
| 0006 | Вертикальный feature slice в коде (Features/<Имя>/) — не реестр correspondence |
| 0065 | graph_kind, уровни абстракции графа; фича может агрегировать узлы L2 |
Вне ADR¶
| Документ | Роль |
|---|---|
| feature-archetype-v1.md | Чеклист «как добавить возможность»; кандидат в code_scope фичи |
Контекст¶
Идеи «следить, не разъехались ли код и намерения» уже разбросаны по ADR: карта ADR к путям (0061), semantic-first (0098), навигация и карта намерений кода (0039, 0053), pre-flight (0042), Intercom ↔ код (0137).
Без общего имени и слоёв легко:
- путать «привязку ADR к папке» с «доказательством, что реализация верна»;
- дублировать второй источник истины (TOML-карта vs граф Roslyn vs event log);
- требовать от одного механизма (
relateв чате) то, что он не обещает.
Этот ADR — навигатор по теме, не замена дочерних ADR.
Проблема¶
| Симптом | Что ломается |
|---|---|
| ADR есть, в файле не читают | Норма не участвует в рабочем контексте |
| Код уехал, ADR не обновили | Архитектурный дрейф — тихий |
| Агент правит «как понял», без стыка с ADR/KB | Повторяет ошибку «слепого доверия» |
| В чате обсуждали метод X, в коде правят Y | Потеря correspondence между дискурсом и diff |
| Semantic map и файлы расходятся | Drift проекций (0098) |
Нужна модель шире, чем relates: типизированные связи, слои, политика accept / warn / block (по зрелости).
Решение: модель correspondence¶
1. Термины¶
| Термин | Смысл |
|---|---|
| Документ-носитель намерения | ADR, playbook/KB, TOML-политика, зафиксированное сообщение Intercom, ADR front-matter |
| Артефакт реализации | Исходники, сгенерированный код, тесты, конфиг |
| Correspondence | Заявленная или выведенная связь «этот документ относится к этому участку системы» + ожидаемый характер связи |
| Drift | Наблюдаемое расхождение: правка нарушает заявленное намерение, документ устарел, или проекции разошлись |
| Feature (correspondence) | Именованная продуктово-архитектурная единица: заявленный охват кода + набор доков; см. §7 |
2. Виды связи (шире relates)¶
Ориентир для людей и advisory; машинный канон — §6. Детализация рёбер L2 — 0114 (relation_kind).
kind |
Направление | Пример |
|---|---|---|
documents |
док → код/зона | ADR-0061 описывает src/.../mcp |
implements |
код → док | Класс реализует контракт из ADR-0008 |
constrains |
док → будущие правки | «Публичный API только через X» |
discusses |
Intercom → код | Сообщения 3–5 про метод Foo (0137) |
supersedes |
док → док | ADR-0153 отменяет parser shape |
related |
код ↔ код | project_peer, test_counterpart (0039) |
projects |
смысл → файл | Semantic map / CCU → файловая проекция (0098) |
relates в Intercom — частный случай discusses + явный event в log, не весь correspondence.
3. Слои (кто что делает)¶
L0 Semantic canon (0098) — «где правда о смысле»; проекции синхронизируем осознанно
L1′ Feature registry (§7) — «эта возможность = code scope + docs[]»; приоритет над голым L1
L1 ADR path map (0061) — fallback: префикс пути → ADR, если файл вне фичи
L2 Code intent graph — навигация, CF map, related files (0039, 0053, 0065)
L3 Change intent (0042) — план и preview до apply; семантический diff
L4 Discourse ↔ code (0137) — обсуждение в Intercom привязано к якорю/диапазону
Слои ортогональны: один файл может попасть под L1′ (фича), L1 (path map) и L2 (subgraph). L1′ не заменяет L2 — не дублировать Roslyn-граф в реестре фич.
4. Политика реакции (IOP-совместимая)¶
| Уровень | Кто | Поведение |
|---|---|---|
| Inform | UI (PFD, HUD) | Индикатор, tooltip intent, ссылка на ADR |
| Advisory | Агент / trace | «Курс расходится с ADR-NNN — подтверди» (0061) |
| Review gate | Человек | Pre-flight approve / reject (0042) |
| Verify (будущее) | CI / анализ | Статические проверки, снапшоты контракта — не v1 |
Не-цель v1: автоматический build failed из-за «нарушения ADR» без человека.
5. Источники истины (без дублирования)¶
| Вопрос | Канон | Не дублировать |
|---|---|---|
| Какая фича и какие доки у неё? | Реестр features.v1.json (§7) |
Дублировать scope в ADR-таблицах без CI |
| Какие ADR для пути (fallback)? | [workspace.adr.map] в repo TOML (0061) |
Второй индекс в коде |
| Какие файлы связаны по коду? | Roslyn + solution (0039) | Ручной граф в TOML |
| О чём говорили в чате? | Event log + explicit relate (0137) | Парсинг prose без якоря |
| Где «я» в методе? | Semantic / CF subgraph (0053) | Дублировать CFG в Markdown |
| Какие виды связи существуют? | Каталог correspondence-kinds (JSON + schema), см. §6 |
Второй enum в TOML / ADR-таблицах без синхронизации с wire |
| Какой смысл у ребра в subgraph? | relation_kind (0114) |
Копировать Roslyn-граф в конфиг |
6. Канон видов отношений (формат и гибрид)¶
Решение (направление): разделить словарь (редко меняется, контракт) и экземпляры (часто, per-repo).
| Артефакт | Содержимое | Формат |
|---|---|---|
| Реестр видов | id, семейство (UML-core / cascade-ext), слои L0–L4, uml-метка, alias per-layer, краткое описание |
JSON + JSON Schema (CI, codegen) |
| Экземпляры L1 | путь → [ADR] |
TOML [workspace.adr.map] (0061, 0029) |
| Факты L2 | рёбра subgraph | Roslyn / MCP — не в конфиге |
| Факты L4 | явные связи в event log | Wire extensions (см. ниже) |
TOML (0029) остаётся каноном настроек и привязок; для онтологии связей TOML не обязателен: вложенность, условные поля (target_kind → обязательные поля) и синхронизация с wire удобнее в JSON Schema (уже есть в Intercom wire).
6.1. UML-core + cascade-ext¶
- UML-core (для L2, символьный код):
Generalization,Realization,Dependency, … — маппинг наrelation_kindв 0114 (inherits,implements,references_*, …). - cascade-ext (L1, L3, L4, governance):
documents,discusses,constrains,supersedes,projects— не притворяются чистым UML; в каталоге полеfamily = "cascade-ext".
Три оси из 0114 не схлопываются в один kind:
| Ось | Вопрос |
|---|---|
graph_kind |
В каком доменном графе? (0065) |
edge_provenance |
Кто посчитал? (Roslyn, HCI, event log) |
relation_kind / канонический id |
Какой смысл связи? |
Correspondence в смысле 0155 — надстройка (роли, зоны, дискурс); для рёбер L2 канонический id согласуется с relation_kind, а не дублирует второй словарь без alias-таблицы.
6.2. Per-layer wire и alias¶
Слои сохраняют нативные имена в API и event log; каталог задаёт aliases:
| Слой | Нативно (пример) | Канон (пример) |
|---|---|---|
| L1 | неявно (только path → ADR) | documents |
| L2 | kind_filter, related_kind, relation_kind |
related, implements, … |
| L4 | message_relate, wire relation |
discusses, documents, … |
Агентский фасад (будущий MCP) отдаёт: canonical_id, layer, native_kind, provenance.
6.3. Уже существующий wire (не дублировать enum)¶
Черновики в репозитории — отдельные enum до сведения с общим каталогом:
| Файл | Поле | Значения (v1) |
|---|---|---|
relates-to-v1.schema.json |
relation |
discusses, implements, references, documents, blocks, duplicates |
code-doc-link-v1.schema.json |
link_kind |
specifies, explains, tests, deprecates, see_also |
R2+: один источник истины — каталог correspondence-kinds.v1.json + schema; wire enum — генерация или $ref, тест «wire ⊆ каталог».
6.4. Альтернатива: TOML-каталог (как intent-catalog.toml)¶
Допустимо для единообразия с intent-catalog.toml: [[correspondence_kind]], correspondence_kinds_schema_version, codegen в C# — если есть тест синхронизации с JSON Schema / wire. Без теста — риск двух расходящихся enum.
Не-цель: полный граф связей в любом конфиге; Markdown-таблицы в ADR — для людей, не machine canon.
6.5. Предлагаемое размещение (черновик)¶
wire/correspondence/
correspondence-kinds.v1.json
correspondence-kinds.v1.schema.json
Оверлей repo/workspace — только экземпляры L1 в workspace.toml, не переопределение глобального словаря без форка IDE.
7. Feature как единица correspondence¶
Направление (Proposed): поднять уровень абстракции выше префикса пути — именованная фича как хаб между кодом и документацией.
7.1. Отличие от feature slice в коде¶
| Понятие | Где | Назначение |
|---|---|---|
| Feature slice (0006) | Features/<Имя>/, неймспейс |
Как организовать код (MVVM, DAL/CCU) |
| Feature archetype (feature-archetype-v1.md) | чертёж | DoD при добавлении возможности |
| Feature (correspondence) | реестр §7 | Что эта возможность охватывает и какие доки на неё ссылаются |
Совпадение имени Features/Chat/ и feature_id = "intercom.chat" желательно, но не обязательно: реестр может быть мельче (slash) или крупнее (весь Intercom), чем одна папка.
7.2. Модель записи¶
{
"id": "intercom.slash",
"title": "Slash / unified command line",
"code_scope": {
"paths": ["Features/Chat/**", "IntentMelody/intent-catalog.toml"],
"namespaces": ["CascadeIDE.Features.Chat"],
"projects": ["CascadeIDE"],
"layers": ["Features", "IntentMelody"]
},
"docs": [
{ "path": "docs/adr/0150-slash-line-canonical-resolution.md" },
{ "path": "docs/adr/0153-slash-catalog-only-resolution.md" },
{ "path": "docs/adr/0154-slash-catalog-domain-object-intent.md" }
],
"relations": [
{ "kind": "depends_on", "target_feature_id": "intent-melody.catalog" }
]
}
| Поле | Смысл |
|---|---|
id |
Стабильный ключ (domain.subdomain, kebab/dot) |
code_scope |
Декларативный охват: glob путей, префиксы неймспейсов, проекты solution, горизонтальные слои (0006) |
docs[] |
0..N: ADR, KB, spec, фрагмент каталога; опционально anchor |
relations[] |
Между фичами: depends_on, supersedes — канонический kind из §6 |
Инвариант: code_scope — заявление для GPWS/advisory/CI; фактические связи символов — по-прежнему L2 (Roslyn).
7.3. Разрешение «в какой фиче я сейчас»¶
- Текущий файл (и опционально символ) проверяется против
code_scopeвсех фич (специфичность: longest path, явныйprimaryпри пересечении — см. открытые вопросы). - Если совпадений нет — L1 fallback (0061).
- PFD / advisory: «фича intercom.slash» + краткий intent из
docs[], не только один ADR по папке.
7.4. Drift на уровне фичи¶
| Сигнал | Пример |
|---|---|
| Scope drift | Новый файл в Features/Chat/, не попадающий ни в одну фичу |
| Doc drift | ADR в docs[], помечен Superseded, а фича не обновлена |
| Slice drift | Папка Features/Foo/ есть, записи feature_id нет (обратное) |
| Overlap | Файл попал в две фичи без правила primary |
Реакция — та же политика §4 (Inform / Advisory), не автоблок сборки в v1.
7.5. Связь с Semantic Map и L2¶
- Уровень абстракции «фича» на карте намерений (0039) может агрегировать узлы subgraph под
feature_id. graph_kindиrelation_kind(0065, 0114) остаются осями рёбер; фича — контейнер correspondence, не заменаgraph_kind.
7.6. Формат и размещение¶
Рядом с каталогом видов связи (§6):
wire/correspondence/
correspondence-kinds.v1.json
features.v1.json
features.v1.schema.json
workspace.toml — оверлей: дополнительные docs для фичи в этом репо, отключение фичи, не форк глобального features.v1.json без согласования.
Отдельный ADR (0156 и далее) — при нормативе MCP get_feature_context, CASCOPE, codegen; до тех пор §7 задаёт направление в рамках 0155.
Дорожная карта (по слоям)¶
| Этап | ADR / работа | Критерий готовности |
|---|---|---|
| R0 | Этот ADR Accepted | Единая терминология в индексе и policy |
| R1 | 0061 Implemented | TOML map + PFD indicator + тесты матчинга путей |
| R1b | Каталог §6 + сведение wire enum | correspondence-kinds.v1.json; тест wire ⊆ каталог; alias L4 → канон |
| R1c | Реестр фич §7 (черновик) | features.v1.json для 2–3 пилотных фич (напр. slash); резолвер file → feature; L1 fallback |
| R2 | 0137 + 0128 | messages_for_code / relate стабильны в event log |
| R3 | 0042 | Planned Changes ссылается на ADR map + CNC subgraph |
| R4 | Verify (новый ADR или расширение 0061) | Выбранный минимум статических проверок (API surface, запрещённые зависимости) |
R4 явно не блокирует R1: осведомлённость ценна без полной верификации.
Открытые вопросы¶
- ~~Единый реестр
kindв TOML vs per-layer~~ → закрыто направлением: канон JSON + schema; экземпляры L1 — TOML; per-layer wire + alias (§6). Остаётся: только JSON vs TOML-каталог + тест синхронизации; точный путьwire/correspondence/. - Нужен ли front-matter в ADR (
intent_summary,affected_paths) для автогенерации map. - Как KB/agent-notes (вне
docs/adr/) входят в L1 — отдельная секция map или ссылки из ADR. - MCP для агента: один tool
get_correspondence_contextvs существующиеget_code_navigation_context+ будущий ADR map. - Маппинг
code-doc-link-v1.link_kind↔ каноническийid(отдельная ось doc↔code или подмножествоdocuments/specifies). - Feature: гранулярность (
intercomvsintercom.slash); правило пересеченияcode_scope(primary, теги,shared); полуавто изFeatures/vs только ручной реестр. - ~~Нужен ли отдельный ADR 0156~~ → 0156 (CRS + Reverse Anchors / CodeAnchor).
Альтернативы (отклонены)¶
| Альтернатива | Почему нет |
|---|---|
| Один глобальный граф «всё со всем» | Шум, дорогая поддержка, дублирует Roslyn |
Только чат relate |
Не покрывает ADR и архитектурный дрейф |
| Блокировать merge при любом расхождении с ADR | Ложные срабатывания; против IOP (verify, не trust) |
| Вручную вести correspondence только в Wiki | Не в рабочем контексте IDE |
Онтология связей целиком в workspace.toml |
Смешивает словарь и факты; плохо для schema/CI; против 0029 для каталогов |
| Два независимых enum (TOML + wire) без codegen/теста | Drift relates-to-v1 vs каталог |
| Только L1 path map без фич | Фича размазана по ADR/папкам; GPWS по префиксу шумит на Services/ |
Последствия¶
- Плюс: одна точка входа для агентов, ревьюеров и дизайна приборов (0073).
- Плюс: 0061 и 0137 читаются как части одной системы, а не конкурирующие идеи.
- Плюс: фича даёт один контекст «зачем эти файлы и ADR» для агента и PFD (§7).
- Минус: нужна дисциплина обновления
[workspace.adr.map]и реестра фич при переездах каталогов. - Риск: переоценка автоматики до готовности R4 — см. политику Advisory по умолчанию.
Статус реализации¶
Каркас (этот ADR): Proposed.
Дочерние: см. таблицы статусов в 0061, 0137, 0098.