feat(mappa-knowledge): merge using-wiki + using-wiki-graph → mappa-knowledge v1.0.0 (cycle ingest/query/lint + graph layer, guarded failure-mode, old names = trigger synonyms) [skip-tdd: visual]

This commit is contained in:
2026-08-24 22:42:45 +03:00
parent fe8484bb2b
commit b9c13a0aaf
5 changed files with 271 additions and 493 deletions

View File

@@ -0,0 +1,261 @@
---
name: mappa-knowledge
author: ours
version: 1.0.0
description: >
Цикл работы со знаниями проекта в Mappa (Karpathy LLM Wiki, канал =
mappa-сущности): ingest → query → lint + граф-слой для
реляционных/структурных вопросов. Поглощает using-wiki + using-wiki-graph
(старые имена — триггер-синонимы). Триггеры: «заингесть», «обнови вики»,
«запроси вики», «проверь вики», «use project wiki», «query the wiki»,
«что связывает X и Y», «как связаны», «путь между X и Y», «what connects
X and Y», «что ссылается на X», «backlinks of X», «сироты», «битые ссылки»,
«orphan pages». Wiki = сущности type=wiki (чтение — карв-аут лиза; запись —
под лизом проекта, решение 19). Реляционные вопросы — через graph_* (BFS на
стороне сервиса), guarded failure-mode: одна страница и стоп, без
многохоповых цепочек чтением. Skip для одно-страничных контентных вопросов.
---
# mappa-knowledge
Единый цикл работы со знаниями проекта в **Mappa**: три операции (ingest /
query / lint) + **граф-слой** для реляционных и структурных вопросов. Скилл =
цикл, не тул: знание **компилируется один раз и держится актуальным**
(ingest), к нему обращаются (query), его проверяют (lint), а связи между
сущностями читают через граф (graph_*).
Канал — Mappa (`mcp__mappa__*`), НЕ файлы. Страница — сущность `type=wiki`
(`wiki:N`); чтение — карв-аут лиза, запись — под лизом проекта (решение 19).
Файлового `.wiki/` больше нет; `setup-wiki` умер (нечего настраивать).
## Когда использовать
- Заингестить документ/источник в вики («заингесть X», «обнови вики»).
- Ответить из вики / проверить вики («запроси вики», «проверь вики», lint).
- Реляционный/структурный вопрос («что связывает X и Y», «backlinks», «сироты») — граф-слой.
- Модифицировать любую страницу — форматы ниже обязательны; конвенции проекта
живут в `AGENTS`-сущности (legacy — `CLAUDE`-указатель).
**НЕ для:** разовых вопросов по коду (обычное чтение файлов), однофайловых
README/ADR (не персистентная база знаний), проекта без вики в mappa.
## Три слоя (не смешивать)
1. **Raw-источники**`sources/<slug>` страницы. Иммутабельны: читай, не
редактируй (единственное исключение — блок-цитата `> Status` по явной
просьбе пользователя).
2. **Вики** — остальные страницы (entities/concepts/packages/contradictions/open-questions/overview).
3. **Схема** — сущности `AGENTS` (канон, slug `AGENTS`) + `CLAUDE` (legacy-
указатель «Canon is AGENTS»). Читай `AGENTS` первой; она перекрывает этот
скил при конфликте.
## Первый шаг любой операции
1. `mcp__mappa__wiki_get(project, 'AGENTS')` — если есть, читай (канон; если
нет — `wiki_get(project, 'CLAUDE')`, легаси-указатель).
2. `mcp__mappa__wiki_get(project, 'index')` — каталог; найди нужные страницы.
(Каталог по умолчанию — `entity_search`, решение 1; `index` — опора ориентации.)
3. Только потом действуй.
Если `AGENTS`/`CLAUDE` нет — вики либо новая, либо неухоженная: не
импровизируй структуру, первый ingest создаёт `AGENTS` (+ `CLAUDE`-указатель).
## MCP-поверхность
| Операция | Тул | Примечание |
|---|---|---|
| Чтение страницы | `mcp__mappa__wiki_get(project?, slug)` | чтение — карв-аут (решение 19) |
| Поиск страниц | `mcp__mappa__entity_search(q, type='wiki', project?, scope?, limit)` | ILIKE по body/title |
| Лиз для записи | `mcp__mappa__task_claim_next(project, owner)` | → `token`; таска может отсутствовать |
| Продление лиза | `mcp__mappa__task_heartbeat(project, claim_token)` | долгие ingest-циклы |
| Создать страницу | `mcp__mappa__wiki_create(project, slug, body, claim_token)` | под лизом |
| Обновить страницу | `mcp__mappa__wiki_update(project, id, title?, body?, claim_token)` | под лизом; id — internal |
| Путь между сущностями | `mcp__mappa__graph_path({from, to})` | кратчайшая цепочка, BFS |
| Соседи / исходящие | `mcp__mappa__graph_neighbors({id})` | рёбра узла с резолвом целей |
| Входящие ссылки | `mcp__mappa__graph_backlinks({id})` | кто ссылается на узел |
| Здоровье графа | `mcp__mappa__graph_stats()` | nodes/edges/components |
**Запись всегда под лизом.** Мутации wiki гейтятся лизом проекта: без
валидного `claim_token` — 422 busy. Лиз экспирится по TTL (дефолт 600s);
закрыть вручную нечем (кроме `admin_release_lease` для залипших) — пиши,
затем отпусти (не держи лиз на время чтения/размышлений).
**Рефы и id (#1037/#1028).** Публичная поверхность несёт per-type реф полным
именем первым полем: `ref: "wiki:3"` (решение 20, конвенция #1028), `num`
следом, глобальный `id` — internal (последним). Для `wiki_update` нужен
internal `id` — из ответа `wiki_get`/`entity_search`. В прозе — слаг/имя
первым, реф как якорь: «спека `concepts/session-live-ingest` (wiki:2604)».
В теле страниц — викилинки по слагу (`[[concepts/foo]]`, решение 4) или
per-type рефы полными именами (`[[task:N]]`/`[[inbox:N]]`).
---
## Цикл: три операции
### Ingest — «заингесть X»
1. Прочитай источник полностью.
2. Извлеки: entities, concepts, packages, кросс-резы.
3. Создай `sources/<slug>` — одну страницу-резюме на источник (~50150 строк;
ссылку на raw клади в frontmatter `raw_path` + `ingested:`).
4. Для каждой затронутой страницы:
- есть → обнови (`wiki_update(project, id, body, claim_token)`). **Противоречия
помечай явно** блоком `> **Противоречие:** источник A говорит X, источник B — Y`.
Не затирай молча.
- нет → создай (`wiki_create`).
5. Обнови `index` (каталог: одна строка на страницу) — опционально; каталог
по умолчанию — `entity_search` (решение 1).
6. Отчитайся пользователю: что создано, что обновлено, какие противоречия.
Первый ingest новой вики: создай `AGENTS` (канон) + `CLAUDE` (указатель).
**Оп-лог — автоматический.** Каждая write-операция уже пишется сервисом в
таблицу `logs` (component=тип сущности, message=slug+operation; смотреть —
`mcp__mappa__admin_logs`). Ручную `log`-страницу НЕ веди — это дубль,
аудит-след живёт в сервисе (решение 12, ратификация 2026-08-24).
**Один ingest может затронуть 1015 страниц. Это нормально — для того LLM и нужны.**
Порядок записи: сначала лиз (`task_claim_next`), затем все wiki-мутации одним
циклом (не бери лиз на чтение), затем отпусти (лиз живёт TTL — просто закончи
писать; heartbeat только если цикл реально долгий).
### Query — вопрос по вики
1. Читай `index` сначала, затем углубляйся в страницы (`wiki_get` по слагу).
2. Отвечай с цитатами-викилинками: `[[concepts/foo]]` (рёбра создаются при
записи, решение 4).
3. **Компаундируй вики.** Если ответ — реальный синтез (сравнение, анализ,
новая связь) — спроси пользователя: «Сохранить как страницу wiki?» Хорошие
вопросы становятся страницами в `concepts/`.
**Реляционные/структурные вопросы — не читай, а зови граф** (следующая секция):
связи образуют граф, который LLM не обходит надёжно чтением.
### Lint — «проверь вики»
Ищи:
- **Противоречия** между страницами.
- **Сирот** — страницы без входящих ссылок: `graph_backlinks(id)` (id из
`wiki_get`) → нет входящих рёбер = сирота.
- **Stale-claims** — `updated_at` страницы старше источника, который она резюмирует.
- **Потерянные сущности** — понятия из текста без своей страницы
(`entity_search` по имени → пусто).
- **Пустые/TODO-секции.**
Отчёт — панч-лист. Ничего не удаляй автоматически.
---
## Граф-слой (реляционные/структурные вопросы)
**Stop and call the graph.** На реляционный/структурный вопрос о вики или
любых сущностях mappa (таски, письма, сессии) **не отвечай, прочитав одну
страницу** — это 0%-recall провал, ради которого существует граф-слой.
Сервис ходит по рёбрам детерминированно (BFS) и возвращает ответ в
нескольких строках; контекст не засоряется.
Формы вопроса → тул:
| Вопрос | Тул |
|---|---|
| relational — «что связывает X и Y», «путь между», "what connects", "shortest path" | `graph_path({from, to})` |
| neighbourhood — «соседи X», "neighbours of X" | `graph_neighbors({id})` |
| incoming — «кто ссылается на X», «backlinks», "what links to X" | `graph_backlinks({id})` |
| health — «сироты», «битые ссылки», «здоровье вики», "orphan pages" | `graph_stats()` + `graph_backlinks(id)` |
**Адресация: slug → internal id.** Резолвь `id` через `wiki_get`/`entity_search`
(последнее поле ответа; `ref`/`num` — для показа). Ответы graph несут per-type
refs полными именами (`task:N`/`inbox:N`/`wiki:N`, конвенция #1028) — реферируй
по ним, не по id. Пустой `path` = связи реально нет — так и скажи; не выдумывай
цепочку из текстовой близости.
**Precondition — граф реально связан.** Если сомневаешься — сначала
`graph_stats()`: `edges` ≈ 0 ⇒ граф пуст, отвечай чтением. (Слаги без
[[линков]] рёбер не создают; сироты — норма для разреженных вики.)
---
## Форматы страниц (ОБЯЗАТЕЛЬНО)
### Frontmatter
```yaml
---
title: Человекочитаемое имя
type: entity | concept | package | source | contradiction | open-question | overview
tags: [short, tokens]
sources: [concepts/mappa.md]
updated: 2026-08-24
---
```
Страницы `sources/` дополнительно несут `ingested: YYYY-MM-DD` и `raw_path: …`.
`contradictions/``status: open | resolved | accepted-divergence` и `affects:`.
`open-questions/``status: open | answered | obsolete` и `touches:`.
### Слаги
- `kebab-case`, **только латиница**. Кириллицу/др. скрипты транслитерируй
(`план переписывания``ozon-client-rewrite`). Оригинальный title — в H1 и frontmatter.
- `entities/<name>`, `concepts/<name>`, `packages/<name>`, `sources/<slug>`,
`contradictions/<slug>`, `open-questions/<slug>`.
### Оп-лог — таблица `logs`, не страница
File-based `log.md` мёртв (решение 12/15, ратификация 2026-08-24). Сервис пишет
оп-лог сам при каждой write-операции: `mcp__mappa__admin_logs` (фильтры
level/since/component/entity, retention 14d). Ручную `log`-страницу не заводи,
не дописывай, не парси.
### `index` — каталог через поиск
Каталог = `entity_search(q, type='wiki', project)` (решение 1). `index`-страница
— опциональная опора для ориентации: одна строка на страницу
`- [Title](concepts/foo.md) — hook.`, секции по типам. Обновляй только если
страница уже существует; не плоди каталог-дубли.
## Quick reference
| Ситуация | Что трогаем |
|---|---|
| Ingest одного документа | `sources/<slug>` (новая) + 315 entities/concepts/packages (+ опционально `index`) |
| Query | (чтение) + возможно новая страница |
| Query реляционный | graph_* (BFS), не чтение |
| Lint | (чтение) + graph_backlinks/stats для сирот |
| Новая вики проекта | первый ingest создаёт `AGENTS` + `CLAUDE`-указатель; оп-лог — автоматический |
## Частые ошибки
- **Правка `sources/`.** Нельзя. Только статус-блок по явной просьбе.
- **Дамп сырья в `sources/`.** Резюме — это резюме. Ссылайся на raw, не копируй.
- **Молчаливые перезаписи.** Новый источник противоречит странице — пометь
блоком `> **Противоречие:**`; не затирай.
- **Нарративный оп-лог.** Не веди его руками: сервис пишет logs сам (admin.logs).
- **Не-ASCII слаги.** Ломают grep и кросс-платформенность. Транслитерируй.
- **Пропущенные противоречия в lint.** Ценность вики — во вскрытых напряжениях,
а не в ложном консенсусе.
- **Запись без лиза.** Wiki-мутации без `claim_token` → 422 busy.
- **Держать лиз на чтение/раздумья.** Лиз — на время записи. Чтение — карв-аут.
- **Реляционный вопрос чтением одной страницы.** Это тот самый 0%-recall
провал — зови graph_*.
- **Слаги/пути в graph-тулы.** Только internal id, и только свежие (удалённая
сущность → ошибка).
- **Тащить всю вики в контекст**, чтобы «проследить» связи руками — сервис
делает это за ноль токенов.
## Red flags
- Реляционный вопрос → читаешь страницу вместо `graph_*`.
- Правка `sources/` или молчаливая перезапись противоречия.
- Wiki-мутация без лиза (422) или лиз держится на чтение.
- Нарративный оп-лог руками.
---
## Reference
- Поиск по сущностям: `mcp__mappa__entity_search` (FTS, решение 1).
- Оп-лог: `mcp__mappa__admin_logs` (автоматический, решение 12).
- Дерево/зонтики: `mcp__mappa__graph_tree(root, depth?, fields?, limit?)`.
- Задачи: `mappa-task-work`. Почта: `mappa-messaging`. Делегирование: `mappa-delegation`.
- Related: `using-projects-meta` (мост до флипа), `project-discipline`.