| 1 | # ADR 012: Multi-canon resolution (личный + org) и workspace-конфиг MCP |
| 2 | |
| 3 | **Статус:** Proposed |
| 4 | **Дата:** 2026-05-15 |
| 5 | **Источник в истории:** один Cursor-workspace (`PersonalCursorFolder`) и много кодовых проектов; появление org-kb ([011](011-aiguiders-org-collaborative-kb-repo-v1.md)); риск дублировать org-знания в личном каноне через `knowledge/organization/`; обсуждение расширения agent-notes-mcp. |
| 6 | **Supersedes:** — |
| 7 | **Extended by:** [013](013-agent-notes-mcp-local-settings-toml-v1.md) (схема TOML, слияние, вывод env) |
| 8 | **Связано:** [003](003-multi-project-scope-and-project-cards.md), [008](008-workspace-scope-map-hot-mcp-and-public-cut.md), [011](011-aiguiders-org-collaborative-kb-repo-v1.md), [001](001-kb-public-publishing-pipeline.md) |
| 9 | |
| 10 | --- |
| 11 | |
| 12 | ## Контекст |
| 13 | |
| 14 | ### 1. Один workspace — много проектов |
| 15 | |
| 16 | Держатель канона часто открывает **один** корневой workspace (monorepo / umbrella), а `active_scope` и карта путей выбирают **кодовый** контекст ([003](003-multi-project-scope-and-project-cards.md), [008](008-workspace-scope-map-hot-mcp-and-public-cut.md)): |
| 17 | |
| 18 | - `workspace_path` в MCP = корень **того** workspace, который передал Cursor; |
| 19 | - `work/local/workspace-scope-map-v1.md` (личный канон) сопоставляет **абсолютные пути** к подпроектам → `door-to-singularity` | `portal` | `harvester` | …; |
| 20 | - hot / `route_context` / `memory_health` читают **один** `agent-notes.md` (primary canon). |
| 21 | |
| 22 | Это уже решает «сижу в одном воркспейсе — работаю с разными проектами» **без** смены KB. |
| 23 | |
| 24 | ### 2. Org-kb и «инфа только в орге» |
| 25 | |
| 26 | Когда появится живой **`AI-Guiders/kb`** ([011](011-aiguiders-org-collaborative-kb-repo-v1.md)), часть playbook/kb будет **принята в org** раньше, чем попадёт в **личный** канон владельца (или никогда — если личное не дублирует всё org). |
| 27 | |
| 28 | **Плохой обход:** завести в личном каноне `knowledge/organization/` (или `work/organization/`) и копировать туда org-файлы. |
| 29 | |
| 30 | | Почему криво | |
| 31 | |--------------| |
| 32 | | Два SSOT на один текст → drift, лишние merge. | |
| 33 | | Смешение **коллаборативного** (org PR) и **личного** (спринт, пути, `personal/`). | |
| 34 | | Публикация kb-public / public-cut не про «organization/» в личном дереве. | |
| 35 | | Агент не отличит «устаревшая копия в личном» от «актуально в org». | |
| 36 | |
| 37 | **Правильная ось:** org-kb — **отдельный git-корень**; личный канон — **primary для записи и операционки**; org — **secondary для чтения** (и явного `canon_path` в тулах). |
| 38 | |
| 39 | ### 3. Что MCP умеет сегодня |
| 40 | |
| 41 | - **Один primary** на процесс: `AGENT_NOTES_CANON_PATH` / `AGENT_NOTES_FILE` → `GetNotesPath`, `read_hot_context`, `route_context`, `memory_health`, запись в `agent-notes.md`. |
| 42 | - **`read_knowledge_file` / `write_knowledge_file` / …** — опциональный аргумент **`canon_path`** → другой корень с `knowledge/`. |
| 43 | - Карта workspace → scope **всегда** из primary (файл под личным каноном), не из org-kb ([008](008-workspace-scope-map-hot-mcp-and-public-cut.md)). |
| 44 | |
| 45 | --- |
| 46 | |
| 47 | ## Решение (принципы) |
| 48 | |
| 49 | ### P1. Роли канонов |
| 50 | |
| 51 | | Роль | Репо | Запись через MCP | Hot / L0 | Карта workspace | |
| 52 | |------|------|------------------|----------|-----------------| |
| 53 | | **primary** | личный `agent-notes` | да (`upsert_*`, `append_*`, …) | да | да (только primary) | |
| 54 | | **secondary** (0..n) | org-kb, при необходимости kb-public | **нет** по умолчанию | **не** сливать в один hot | нет | |
| 55 | | **public** | kb-public | нет | только для потребителей без org | нет | |
| 56 | |
| 57 | ### P2. Не дублировать org в личное дерево |
| 58 | |
| 59 | - **Не** вводить `knowledge/organization/` как зону копирования org-kb. |
| 60 | - В личном hot допустимы **тонкие указатели** (1–2 секции): где org SSOT, как клонировать, политика import — не полнотекстовые копии playbook. |
| 61 | - Принятие org → личный: **import workflow** (cherry-pick / скрипт / ручной merge в `knowledge/worlds/…`), осознанно, с review владельца. |
| 62 | |
| 63 | ### P3. Один workspace — два измерения |
| 64 | |
| 65 | ```text |
| 66 | workspace_path (Cursor) |
| 67 | │ |
| 68 | ├─► active_scope ← workspace-scope-map (primary / личный канон) |
| 69 | │ |
| 70 | └─► primary canon ← agent-notes.md + hot (личный) |
| 71 | │ |
| 72 | └─► secondary[] ← только чтение knowledge/ + опционально route overlay |
| 73 | ``` |
| 74 | |
| 75 | ### P4. Не склеивать два hot в один `read_hot_context` |
| 76 | |
| 77 | Слияние L0 из личного и org в один JSON: |
| 78 | |
| 79 | - размывает бюджет и `memory_health`; |
| 80 | - риск утечки `l0_owner` / `current-task` при ошибке конфига; |
| 81 | - непонятно, куда писать `upsert_agent_notes_section`. |
| 82 | |
| 83 | **Исключение (будущее, отдельная фаза):** явный whitelist секций org для **read-only overlay** (например только `integrity-core` / `l0_manifest` stub), только если нет в primary — **не** в scope первой реализации. |
| 84 | |
| 85 | ### P5. Как агент видит «только в org» |
| 86 | |
| 87 | | Механизм | Когда | |
| 88 | |----------|--------| |
| 89 | | `read_knowledge_file(file_path=…, canon_path=<org>)` | точечно, уже сейчас | |
| 90 | | `route_context` по primary | как сейчас | |
| 91 | | **`route_context` + secondary** (фаза 2) | поиск по индексу/секциям org-kb, блоки с меткой `canon: org` | |
| 92 | | Правило в playbook / Cursor rule | «если тема org — сначала read org path …» | |
| 93 | |
| 94 | --- |
| 95 | |
| 96 | ## Workspace-конфиг (TOML по явному пути) |
| 97 | |
| 98 | Семантика **primary / read-only** knowledge roots — в этом ADR ([P1–P5](#решение-принципы)); в тексте ниже ещё **«canon»** = то же (исторический термин). **Подключение:** с **agent-notes-mcp 2.0** — TOML по **`--config`** — **[013](013-agent-notes-mcp-local-settings-toml-v1.md)** (`[knowledge]`, major MCP). |
| 99 | |
| 100 | ### Пример (шаблон содержимого) |
| 101 | |
| 102 | См. [`knowledge/work/local/agent-notes.workspace.example.toml`](../work/local/agent-notes.workspace.example.toml) — копируешь куда удобно (напр. `D:/Experiments/agent-notes-mcp.local.toml`) и указываешь путь в `args`. |
| 103 | |
| 104 | ### Цепочка резолва primary (целевая) |
| 105 | |
| 106 | 1. Аргумент тула `canon_path` (если есть). |
| 107 | 2. TOML из **`--config`** / `AGENT_NOTES_CONFIG` — [013](013-agent-notes-mcp-local-settings-toml-v1.md). |
| 108 | 3. `AGENT_NOTES_CANON_PATH` / `AGENT_NOTES_FILE` (legacy). |
| 109 | 4. Fallback: `workspace_path/.cascade-ide/agent-notes.md`. |
| 110 | |
| 111 | `scope_map` **всегда** из **primary** knowledge root, даже если в workspace открыт клон org-kb — отдельный профиль (редко). |
| 112 | |
| 113 | --- |
| 114 | |
| 115 | ## Альтернативы (отклонены) |
| 116 | |
| 117 | | Вариант | Почему нет | |
| 118 | |---------|------------| |
| 119 | | `knowledge/organization/` в личном каноне | дублирование SSOT ([P2](#p2-не-дублировать-org-в-личное-дерево)) | |
| 120 | | Три MCP-сервера в Cursor без workspace-файла | работает, но не привязано к umbrella-workspace; дублирует env | |
| 121 | | Один hot = merge personal + org | [P4](#p4-не-склеивать-два-hot-в-один-read_hot_context) | |
| 122 | | Org-kb содержит `work/local` с путями владельца | запрещено политикой [011](011-aiguiders-org-collaborative-kb-repo-v1.md) | |
| 123 | |
| 124 | --- |
| 125 | |
| 126 | ## Последствия |
| 127 | |
| 128 | **Плюсы** |
| 129 | |
| 130 | - Monorepo + много проектов остаётся на [008](008-workspace-scope-map-hot-mcp-and-public-cut.md). |
| 131 | - Org--only контент доступен без копипасты в личное дерево. |
| 132 | - Друг / участник org: `primary = org` в **своём** workspace или только env — без личного канона. |
| 133 | |
| 134 | **Минусы** |
| 135 | |
| 136 | - Две фазы внедрения (спека → код в Core). |
| 137 | - Агент должен **знать**, что искать в secondary (playbook + опционально route overlay). |
| 138 | |
| 139 | **Риски** |
| 140 | |
| 141 | - Забытый `canon_path` → агент отвечает только из личного; mitigation: `route_overlay`, правила Cursor, health-check «secondary configured but unused». |
| 142 | |
| 143 | --- |
| 144 | |
| 145 | ## План внедрения |
| 146 | |
| 147 | | Фаза | Содержание | Статус | |
| 148 | |------|------------|--------| |
| 149 | | **0** | Документ + example toml; правило: org не копировать в `organization/` | этот ADR | |
| 150 | | **1** | Ручной режим: env primary + `read_knowledge_file(canon_path=org)` | сейчас | |
| 151 | | **2** | Core: чтение `.cursor/agent-notes.toml`, `ResolveCanonPath(workspace)` | код | |
| 152 | | **3** | `route_context`: опциональный поиск по `secondary[]` с метками и лимитом chars | код | |
| 153 | | **4** | (опционально) read-only L0 overlay whitelist | только при сценарии | |
| 154 | |
| 155 | Зависимости: [011](011-aiguiders-org-collaborative-kb-repo-v1.md) (репо `AI-Guiders/kb`) для реального secondary; до этого secondary может указывать на клон `kb-public`. |
| 156 | |
| 157 | --- |
| 158 | |
| 159 | ## Открытые вопросы |
| 160 | |
| 161 | 1. Имя файла: `.cursor/agent-notes.toml` vs `.cascade/agent-notes.toml` — зафиксировать одно; поддержать второе как alias? |
| 162 | 2. Walk-up: один umbrella на весь `PersonalCursorFolder` vs per-subproject toml в `Financial/software/open/…`? |
| 163 | 3. Нужен ли `route_overlay` по умолчанию `true`, когда `org` path существует на диске? |
| 164 | |
| 165 | --- |
| 166 | |
| 167 | ## Ссылки |
| 168 | |
| 169 | - Пример workspace-конфига: `knowledge/work/local/agent-notes.workspace.example.toml` |
| 170 | - Runbook wiki / org: `knowledge/work/projects/door-to-singularity/ai-guiders/templates/runbook-gitlab-wiki-to-github-ai-guiders-v1.md` (контуры kb-public / handbook) |
| 171 | |
| 172 | |