diff --git a/skills/mappa-brainstorm-promote/SKILL.md b/skills/mappa-brainstorm-promote/SKILL.md index fe30b87..26d2858 100644 --- a/skills/mappa-brainstorm-promote/SKILL.md +++ b/skills/mappa-brainstorm-promote/SKILL.md @@ -1,12 +1,12 @@ --- name: mappa-brainstorm-promote author: ours -version: 1.2.0 +version: 1.3.0 description: > Finalize a matured brainstorm buffer on the boss's desk (~/projects/.workshop/.brainstorm/): ask routing (workshop-meta → local .wiki/concepts/, domain → target project wiki via knowledge_ingest, - mappa-service → mappa-борд под лизом, skill → claude-skills skeleton), + mappa-service → mappa-борд (карв-аут), skill → claude-skills skeleton), extract action-items into target .tasks, create pointers + review umbrella for impl tasks, archive the buffer. Старое имя — триггер-синоним: workshop-promote-brainstorm. Location-agnostic: fires from ANY folder; all @@ -27,7 +27,7 @@ description: > - **workshop-meta** → локальный `.wiki/concepts/` (методология самой зоны). - **domain** → глобал через `mcp__projects-meta__knowledge_ingest` в `~/projects//.wiki/`. -- **mappa-service** → сервисные борды (mappa, .common, …): таски/вики-сущности через `mcp__mappa__task_create`/`wiki_create` **под лизом** (`task_claim_next`); pointers-таска НЕ нужна, если спека уже в вики проекта (w:NNNN); review-umbrella — сервисная таска; covering-письмо в инбокс цели. +- **mappa-service** → сервисные борды (mappa, .common, …): таски/вики-сущности через `mcp__mappa__task_create`/`wiki_create` (карв-аут, wiki:2660); review-umbrella — сервисная таска; covering-письмо в инбокс цели. - **skill** → `~/projects/claude-skills/skills//SKILL.md` (только шапка + пустой каркас тела, локальный коммит без push/install/build-hermes). Буфер уезжает в `.archive/`. Action-items уходят тасками в target-проект. **Всегда, при любом маршруте, в воркшоп-вики остаётся summary-страница.** @@ -63,7 +63,7 @@ description: > │ │ │ │ │ ▼ ▼ ▼ │ knowledge_ingest mcp__mappa__wiki_create dialog: description (trigger contract) - │ │ (под лизом) │ + │ │ (карв-аут, wiki:2660) │ │ │ │ ▼ │ │ │ preview + confirm │ │ │ │ @@ -118,10 +118,9 @@ description: > - **Определить канал борда:** есть ли у проекта файловая доска `.tasks/STATUS.md` (file channel) или борд живёт в mappa-сущностях (service channel — сервисные проекты: mappa, .common, …). Проверка: файл `.tasks/STATUS.md` в чек-ауте (file) против `mcp__mappa__task_list(project=)` / `entity_search` (service). Если файловой доски нет, а mappa-сущности есть → **service channel**. 4. **Если domain + service channel (mappa-борд, fold-in 1):** - - **Лиз:** `mcp__mappa__task_claim_next(project=, owner=<своя>)` → `token`. - - **Спека → вики-сущность:** `mcp__mappa__wiki_create(project, slug, body, claim_token)` (или `wiki_update`, если страница уже есть). Если спека уже в вики проекта (w:NNNN) — не дублировать, описание импл-тасок ссылается на неё. + - **Спека → вики-сущность:** `mcp__mappa__wiki_create(project, slug, body)` (или `wiki_update(project, id, version)`, если страница уже есть). Если спека уже в вики проекта (w:NNNN) — не дублировать, описание импл-тасок ссылается на неё. - **Pointers-таска НЕ нужна**, если спека уже в вики проекта — дыра pointers закрыта инлайн (описание импл-тасок прямо ссылается на спеку). - - **Импл-таски:** `mcp__mappa__task_create(project, slug, title, description, status='ready', claim_token)` — **ПОСЛЕДОВАТЕЛЬНО, не батчем** (см. NB в шаге 7). + - **Импл-таски:** `mcp__mappa__task_create(project, slug, title, description, status='ready')` (карв-аут, wiki:2660) — **ПОСЛЕДОВАТЕЛЬНО, не батчем** (см. NB в шаге 7). - **Review-umbrella:** сервисная таска `mcp__mappa__task_create(status='blocked', blocker=<номера импл-тасок>)`. - **Covering-письмо:** `mcp__mappa__inbox_send(project=, from=<своя>, subject='Промоушен : таски <#N>…', body=<перечень>).` — канон mappa-delegation: таска на борде не пингует живую сессию. @@ -367,7 +366,7 @@ description: > - Если `tasks_create` review-таски упала — сообщить пользователю, **продолжить** к шагу 11 (архивация буфера). Review-таску можно создать вручную позже из `.archive/-.md`. - - **domain (service channel):** review-umbrella — **сервисная таска**: `mcp__mappa__task_create(project=, slug=-review, status='blocked', blocker=<номера импл-тасок через запятую>, description=<шаблон domain выше, спека = w:NNNN в вики проекта>, claim_token)` под тем же лизом. Pointers-таска отсутствует (спека в вики). + - **domain (service channel):** review-umbrella — **сервисная таска**: `mcp__mappa__task_create(project=, slug=-review, status='blocked', blocker=<номера импл-тасок через запятую>, description=<шаблон domain выше, спека = w:NNNN в вики проекта>)`. Pointers-таска отсутствует (спека в вики). **Covering-письмо в инбокс цели (оба канала; канон mappa-delegation).** После создания тасок — `inbox_send` получателю-проекту: таска на борде не пингует живую сессию, письмо = пинг + контекст. File channel: `mcp__mappa__inbox_send(project=, from=<своя>, subject='[event: created] тасок', body=<перечень: #N slug> )`. Service channel: то же, но `from` = своя папка (или сервисный адрес) и тело ссылается на w:NNNN-спеку. @@ -424,7 +423,7 @@ description: > - `mcp__projects-meta` недоступен → abort до записей. - Целевой проект (для domain) не найден в `meta_status` → abort. - `knowledge_ingest` упал → abort до `tasks_create` и `git mv`. Буфер остаётся. -- **Service channel:** лиз занят (422 busy от `task_claim_next`) → abort или retry после освобождения; не писать без лиза. +- **Service channel:** create — карв-аут (wiki:2660), 422 busy больше не бывает; 409 на `wiki_update` (version) → retry со свежей версией. - **Service channel:** `task_create` упал (гонка счётчика/переходный период) → **повторить последовательно**, не батчем; при стабильном отказе — abort до архивации. - **Service channel:** спека уже существует в вики проекта (w:NNNN) → не дублировать `wiki_create`, ссылаться на неё. - **domain:** `tasks_create` для `[-pointers]` упал → **abort** до content-тасок и до review-таски. Без pointers оставшиеся таски бесполезны (агент будет угадывать). Сообщить пользователю; буфер оставить на месте для retry. @@ -440,7 +439,7 @@ description: > - **Всегда (любой маршрут):** создаёт summary-страницу `.wiki/concepts/.md` в `.workshop/` + добавляет строку в `index.md`. - **workshop-meta:** summary IS контент (шаг 6 записывает полное тело; шаг 9 дополняет секцию «задачи/ссылки» или пропускается если уже полный). - **domain:** создаёт запись в target-wiki через MCP (`mcp__projects-meta__knowledge_ingest`). -- **domain (service channel):** создаёт спека-сущность в вики mappa-проекта (`mcp__mappa__wiki_create` под лизом); импл-таски + review-umbrella — сервисные таски (`mcp__mappa__task_create` под лизом); covering-письмо в инбокс цели (`inbox_send`). Pointers-таска НЕ создаётся (спека уже в вики). +- **domain (service channel):** создаёт спека-сущность в вики mappa-проекта (`mcp__mappa__wiki_create` — карв-аут); импл-таски + review-umbrella — сервисные таски (`mcp__mappa__task_create` — карв-аут); covering-письмо в инбокс цели (`inbox_send`). Pointers-таска НЕ создаётся (спека уже в вики). - **domain:** создаёт также **mandatory pre-impl** таску `[-pointers]` в target — pre-filled блок текста для `.wiki/CLAUDE.md` Domain conventions (ссылки на global wiki slug + workshop archive trace + local overview.md). Без неё последующий импл-агент попадает в дыру: where_stopped one-liner + пустой Domain conventions stub. - **skill:** создаёт `~/projects/claude-skills/skills//SKILL.md` — **только шапка + пустой каркас**. Локальный коммит в `claude-skills/`. **Без** установки, push, или build-hermes — это всё в созданных baseline-тасках. - Создаёт N тасок в target `.tasks/` через MCP. @@ -460,6 +459,6 @@ description: > - **Skill:** не бампить `version` после первой записи (это работа владельца `claude-skills/`). - **Skill:** не промоутить в существующий скил (см. Failure modes — abort). - **Skill:** не пропускать обязательный preview + confirm перед `Write` — действие выходит за пределы мастерской, изменяет соседний репозиторий. -- **Service channel:** не писать в mappa-борд без лиза (422 busy); не батчить `task_create` (гонка sha-CAS счётчика, инцидент 2026-08-24: 6/7 упали) — только последовательно. +- **Service channel:** не батчить `task_create` (гонка счётчика, инцидент 2026-08-24: 6/7 упали) — только последовательно; `wiki_update`/`task_close` со свежей version (409 → retry). - **Service channel:** не плодить pointers-таску, если спека уже в вики проекта (w:NNNN) — описание импл-тасок ссылается на неё инлайн. - **Service channel:** не забывать covering-письмо в инбокс цели — таска на борде не пингует живую сессию. diff --git a/skills/mappa-closing-ritual/SKILL.md b/skills/mappa-closing-ritual/SKILL.md index b466677..cf08f41 100644 --- a/skills/mappa-closing-ritual/SKILL.md +++ b/skills/mappa-closing-ritual/SKILL.md @@ -78,13 +78,13 @@ Forward-looking, не timeline: handoff = связка новых вещей к ### 5. Propose wiki-ingest (не писать!) Если за сессию появилось durable-знание — **ПРЕДЛОЖИТЬ** ingest -(`mappa-knowledge`: mappa wiki_create/update под лизом), перечислив кандидатов. +(`mappa-knowledge`: mappa wiki_create/update — version+409, wiki:2660), перечислив кандидатов. Ничего не писать без подтверждения. ### 6. Propose task-board closes (не закрывать!) Если есть задачи, выглядящие закрытыми — **ПРЕДЛОЖИТЬ** закрытия -(`mappa-task-work`: task_close под лизом). Уважать ralph-loop: verifier-задачи +(`mappa-task-work`: task_close — version+409). Уважать ralph-loop: verifier-задачи закрывать только через verifier (attempt/harness-record). ### 7. Формат предложения — один блок diff --git a/skills/mappa-delegation/SKILL.md b/skills/mappa-delegation/SKILL.md index 8824dc7..1be429c 100644 --- a/skills/mappa-delegation/SKILL.md +++ b/skills/mappa-delegation/SKILL.md @@ -1,7 +1,7 @@ --- name: mappa-delegation author: ours -version: 1.0.0 +version: 1.1.0 description: > Цикл делегирования задачи другому агенту/проекту: pre-flight gate → шаблон тела → dry-run preview → confirm → covering-письмо в инбокс @@ -44,11 +44,10 @@ steering-loop поля (notify/weight), парную review-таску для im Номер задаче присваивает сервер (`tasks_create` из счётчика agenda/task-counter) — постановщик номер не придумывает и не резервирует. Возвращённый `#n` из preview/confirm — машинный ключ задачи: им ссылаются блокеры, письма, decision-trail. -> **Лизинговая модель (#1054).** Мутации тасок гейтятся лизом проекта -> (`mcp__mappa__task_claim_next` → token для `task_create`; file channel — -> sha-CAS через Gitea). `#1054 lease-model-generalization` (create-без-лиза как -> принцип, claim на таску) — **опционально**: контракт этого скила работает на -> текущих тулах; перейти на create-без-лиза, когда #1054 имплементится. +> **Интерактивный контракт (wiki:2660).** `task_create` — карв-аут, лиз НЕ +> нужен (create = INSERT, входной контур). `task_close`/`task_update` — optimistic +> version+409 (конфликт → свежая version из `task_get` → retry). File channel — +> sha-CAS через Gitea (projects-meta), там свои правила. ## Steps (цикл) @@ -133,8 +132,7 @@ mcp__mappa__inbox_send( ) ``` -(Мутация тасок гейтится лизом проекта — `task_claim_next`; доставка письма — -карв-аут, лиза не требует.) +(`task_create` — карв-аут (wiki:2660), доставка письма — карв-аут.) Причина: таска на борде **не пингует живую сессию** получателя. Поллер подхватит по `Weight`/`Notify`, но живая интерактивная сессия узнаёт только @@ -177,7 +175,7 @@ task» — общий случай (шаг 7 — его частность дл ## Side effects -- Создаёт таску в target-проекте через `tasks_create` (file channel — Gitea commit; service channel — mappa-сущность под лизом). +- Создаёт таску в target-проекте через `tasks_create` (file channel — Gitea commit; service channel — mappa-сущность карв-аутом, wiki:2660). - Опционально создаёт парную review-таску (status=blocked). - Covering-письмо в инбокс получателя (кросс-проектная делегация). diff --git a/skills/mappa-knowledge/SKILL.md b/skills/mappa-knowledge/SKILL.md index 1ec11e1..955c01d 100644 --- a/skills/mappa-knowledge/SKILL.md +++ b/skills/mappa-knowledge/SKILL.md @@ -1,7 +1,7 @@ --- name: mappa-knowledge author: ours -version: 1.0.0 +version: 1.1.0 description: > Цикл работы со знаниями проекта в Mappa (Karpathy LLM Wiki, канал = mappa-сущности): ingest → query → lint + граф-слой для @@ -11,7 +11,7 @@ description: > «что связывает X и Y», «как связаны», «путь между X и Y», «what connects X and Y», «что ссылается на X», «backlinks of X», «сироты», «битые ссылки», «orphan pages». Wiki = сущности type=wiki (чтение — карв-аут лиза; запись — - под лизом проекта, решение 19). Реляционные вопросы — через graph_* (BFS на + version+409, wiki:2660). Реляционные вопросы — через graph_* (BFS на стороне сервиса), guarded failure-mode: одна страница и стоп, без многохоповых цепочек чтением. Skip для одно-страничных контентных вопросов. --- @@ -25,7 +25,7 @@ query / lint) + **граф-слой** для реляционных и стру сущностями читают через граф (graph_*). Канал — Mappa (`mcp__mappa__*`), НЕ файлы. Страница — сущность `type=wiki` -(`wiki:N`); чтение — карв-аут лиза, запись — под лизом проекта (решение 19). +(`wiki:N`); чтение — карв-аут, запись — version+409 (wiki:2660). Файлового `.wiki/` больше нет; `setup-wiki` умер (нечего настраивать). ## Когда использовать @@ -66,19 +66,17 @@ README/ADR (не персистентная база знаний), проект |---|---|---| | Чтение страницы | `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__wiki_create(project, slug, body)` | карв-аут (wiki:2660), лиз не нужен | +| Обновить страницу | `mcp__mappa__wiki_update(project, id, title?, body?, version)` | version+409; 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` для залипших) — пиши, -затем отпусти (не держи лиз на время чтения/размышлений). +**Запись — version+409 (wiki:2660 interactive contract).** `wiki_create` — +карв-аут (лиз не нужен); `wiki_update` несёт `version` из последнего чтения, +конфликт → 409 → `wiki_get` заново → retry. Долгих лизов/TTL/heartbeat больше +нет — живость владельца из session live-ingest. **Рефы и id (#1037/#1028).** Публичная поверхность несёт per-type реф полным именем первым полем: `ref: "wiki:3"` (решение 20, конвенция #1028), `num` @@ -99,7 +97,7 @@ per-type рефы полными именами (`[[task:N]]`/`[[inbox:N]]`). 3. Создай `sources/` — одну страницу-резюме на источник (~50–150 строк; ссылку на raw клади в frontmatter `raw_path` + `ingested:`). 4. Для каждой затронутой страницы: - - есть → обнови (`wiki_update(project, id, body, claim_token)`). **Противоречия + - есть → обнови (`wiki_update(project, id, body, version)`). **Противоречия помечай явно** блоком `> **Противоречие:** источник A говорит X, источник B — Y`. Не затирай молча. - нет → создай (`wiki_create`). @@ -115,9 +113,8 @@ per-type рефы полными именами (`[[task:N]]`/`[[inbox:N]]`). **Один ingest может затронуть 10–15 страниц. Это нормально — для того LLM и нужны.** -Порядок записи: сначала лиз (`task_claim_next`), затем все wiki-мутации одним -циклом (не бери лиз на чтение), затем отпусти (лиз живёт TTL — просто закончи -писать; heartbeat только если цикл реально долгий). +Порядок записи: все wiki-мутации одним циклом; `wiki_update` — со свежей +`version` из чтения (409 → retry). Создание новых страниц — карв-аут. ### Query — вопрос по вики @@ -234,7 +231,7 @@ level/since/component/entity, retention 14d). Ручную `log`-страниц - **Не-ASCII слаги.** Ломают grep и кросс-платформенность. Транслитерируй. - **Пропущенные противоречия в lint.** Ценность вики — во вскрытых напряжениях, а не в ложном консенсусе. -- **Запись без лиза.** Wiki-мутации без `claim_token` → 422 busy. +- **Запись — version+409 (wiki:2660).** `wiki_create` — карв-аут; `wiki_update` со свежей `version` (конфликт → 409 → retry). - **Держать лиз на чтение/раздумья.** Лиз — на время записи. Чтение — карв-аут. - **Реляционный вопрос чтением одной страницы.** Это тот самый 0%-recall провал — зови graph_*. diff --git a/skills/mappa-messaging/SKILL.md b/skills/mappa-messaging/SKILL.md index b40f236..d1445e3 100644 --- a/skills/mappa-messaging/SKILL.md +++ b/skills/mappa-messaging/SKILL.md @@ -1,7 +1,7 @@ --- name: mappa-messaging author: ours -version: 1.0.0 +version: 1.1.0 description: > Цикл межсессионной почты через Mappa: SEND (inbox_send) → RECEIVE (inbox_monitor) → POLICY (peer ≠ authority). Адрес = имя папки проекта из @@ -156,8 +156,8 @@ mcp__mappa__inbox_send( lifecycle-уведомления («таска создана», «закрыта», «заблокирована»). Не больше. - **Задачи — только через `mcp__mappa__task_*`.** Доска — единственный источник правды о задаче: существование, статус, скоуп, решения создаются и - меняются через `task_create` / `task_close` — никогда не «решаются» внутри - письма. (Мутации тасок гейтятся лизом проекта — `task_claim_next`.) + меняются через `task_create` / `task_close` (карв-аут + version+409, wiki:2660) + — никогда не «решаются» внутри письма. Следствие: **если это не на доске — это не задача и не решение, это разговор.** Значимый дизайн-выбор должен лечь на доску (или в вики), инбокс лишь указывает diff --git a/skills/mappa-task-work/SKILL.md b/skills/mappa-task-work/SKILL.md index a35c3e2..db88bac 100644 --- a/skills/mappa-task-work/SKILL.md +++ b/skills/mappa-task-work/SKILL.md @@ -1,29 +1,37 @@ --- name: mappa-task-work author: ours -version: 1.0.0 +version: 1.1.0 description: > Центральный цикл работы с тасками в Mappa: ориентация → выбор работы - (claim, priority/due) → исполнение → сдача (close + review-umbrella) + - loop-mode «поработай очередь». Борд = сущности mappa (решения 14/15/19/20); - мутации под лизом. Поглощает using-tasks + task-format + task-loop - (loop-mode ВНУТРИ) + priority-due-раздел (старые имена — триггер-синонимы). - Триггеры: «что на досках», «возьми таску», «какой статус», «update status», - «pause», «switch to X», «где мы остановились», «work the queue», «поработай - очередь», «прогони доску». Приоритет = территория человека: агенты ставят - P0-P2/дедлайн только при создании, дефолт P1; просрочка → notify, без - авто-бампа. НЕ про делегирование (→ mappa-delegation), НЕ про доску-обзор - (→ ops/using-system-snapshot). + (owner, priority/due) → исполнение → сдача (close + review-umbrella) + + loop-mode «поработай очередь». Борд = сущности mappa (решения 14/15/20); + мутации — version+409 (wiki:2660 interactive contract), «взять таску» = + status→active + owner, живность владельца из session live-ingest. Поглощает + using-tasks + task-format + task-loop (loop-mode ВНУТРИ) + priority-due-раздел + (старые имена — триггер-синонимы). Триггеры: «что на досках», «возьми таску», + «какой статус», «update status», «pause», «switch to X», «где мы остановились», + «work the queue», «поработай очередь», «прогони доску». Приоритет = территория + человека: агенты ставят P0-P2/дедлайн только при создании, дефолт P1; + просрочка → notify, без авто-бампа. НЕ про делегирование (→ mappa-delegation), + НЕ про доску-обзор (→ ops/using-system-snapshot). --- # mappa-task-work Центральный цикл работы с задачами: **ориентация → выбор работы → исполнение → -сдача**. Борд — сущности mappa (`type=task`, `t:N`): чтение — карв-аут лиза, -**любая мутация — под лизом проекта** (решение 19). Скилл = цикл, не тул: -одна механика на выбор/исполнение/сдачу, плюс **loop-mode** («поработай +сдача**. Борд — сущности mappa (`type=task`, `task:N`): чтение — карв-аут, +**мутации — optimistic concurrency** (wiki:2660 interactive contract): +version+409, конфликт → retry со свежей version из `task_get`. Скилл = цикл, +не тул: одна механика на выбор/исполнение/сдачу, плюс **loop-mode** («поработай очередь») внутри — отдельный скил не создаётся. +> **Интерактивный контракт (wiki:2660).** claim/TTL/heartbeat выпилены: +> поллер не клиент mappa (живёт на файловых досках projects-meta), клиент — +> интерактивные сессии. «Взять таску» = `task_update(status=active, owner=<сессия>)` +> с верной version; конфликт (уже взято) → 409 → выбор другой таски. Живость +> владельца — из session live-ingest (сессия `pi` пишется сама), не таймер. + > **Переходное (file channel).** Пока поллер/кэш читают файловые борды > (`.tasks/STATUS.md`), legacy-канал живёт: блоки в файле обязаны строгому > формату (см. «Формат таски» ниже), мутации — через `mcp__projects-meta__tasks_*` @@ -43,27 +51,29 @@ description: > | Операция | Тул | Примечание | |---|---|---| -| Взять следующую ready-таску | `mcp__mappa__task_claim_next(project, owner)` | атомарно: лиз + таска; → `{ok, token, task}` | -| Продлить лиз | `mcp__mappa__task_heartbeat(project, claim_token)` | долгие таски | -| Создать таску | `mcp__mappa__task_create(project, slug, title?, description?, status?, priority?, due?, claim_token)` | под лизом; per-type номер (решение 20) | -| Закрыть таску | `mcp__mappa__task_close(project, id, claim_token)` | под лизом | -| Прочитать таску | `mcp__mappa__entity_get(id)` | id internal из search/claim | +| Взять таску | `mcp__mappa__task_update(project, id, status='active', owner=<сессия>, version)` | «взять» = conditional update; 409 → уже взята | +| Сбросить/отдать | `mcp__mappa__task_update(project, id, status='ready', owner='', version)` | release = обычный update | +| Создать таску | `mcp__mappa__task_create(project, slug, title?, description?, status?, priority?, due?)` | карв-аут, лиз не нужен (wiki:2660) | +| Закрыть таску | `mcp__mappa__task_close(project, id, version)` | version+409 (конфликт → retry) | +| Прочитать таску | `mcp__mappa__entity_get(id)` | id internal из search; несёт version | | Список борда | `mcp__mappa__entity_search(q, type='task', project=<имя>, limit)` | все статусы | | Дерево parent_of | `mcp__mappa__graph_tree(root, depth?, fields?, limit?)` | зонтики/иерархия | | Связанные сущности | `mcp__mappa__graph_neighbors/backlinks(id)` | рефы к таске | | Просрочка | `mcp__mappa__admin_overdue_scan(project?)` | P2-джоба: notify в инбокс, без мутаций | | Уведомление при закрытии | `mcp__mappa__inbox_send(project=, from=<своя>, subject, body)` | письмо комиссионеру | -**Лиз = лок на запись (решение 19).** Одна строка leases на проект: если другой -агент держит лиз — `task_claim_next` вернёт **422 busy**. Это серверный аналог -старого `.tasks/.lock`: проверять «а не поллер ли работает» руками не нужно — -сам claim скажет. Чтения лиза не требуют. +**Взятие таски = version+409, не лиз.** Каждая таска несёт `version`; conditional +update (`status=active, owner=<сессия>, version=N`) проходит, только если никто +не изменил её после твоего чтения. Конфликт → **409** → `task_get` заново → +выбирай другую. Конкуренции «проект занят» нет: два агента берут разные таски +свободно. Живость — из сессии: пока твоя pi-сессия активна (end-state≠clean), +твои 🔴 видны как «в работе». -**Рефы и id (#1037/#1028).** Таски наружу несут `ref: "t:N"` полным именем -первым полем (`task:N`, конвенция #1028), `num` следом, глобальный `id` — -internal (последним, для addressing в тулах). Ссылайся на таску -`[[task:N]]`/`task:N` в прозе (слаг/имя первым, реф как якорь: «таска -`mappa-task-work` (task:1062)»), никогда `#<глобальный id>`. +**Рефы и id (#1037/#1028).** Таски наружу несут `ref: "task:N"` полным именем +первым полем (конвенция #1028), `num` следом, глобальный `id` — internal +(последним, для addressing в тулах). Ссылайся на таску `[[task:N]]`/`task:N` +в прозе (слаг/имя первым, реф как якорь: «таска `mappa-task-work` (task:1062)»), +никогда `#<глобальный id>`. ## Статусы (эмодзи для презентации) @@ -91,16 +101,19 @@ internal (последним, для addressing в тулах). Ссылайся 4. Подтверди одним предложением: «Мы в середине X, следующий шаг — Y». 5. Спроси, верен ли план, перед действиями. -### Фаза 1 — Выбор работы (claim, priority/due) +### Фаза 1 — Выбор работы (owner, priority/due) -1. `mcp__mappa__task_claim_next(project, owner)` — атомарно: лиз + следующая - ready-таска. `owner` = `::`. - Порядок выдачи: **P0-пул первый, внутри по дедлайну (просроченные первыми), - потом P1, потом P2**; отсутствующий priority = P1 (task-priority-due). +1. Собери кандидатов: `entity_search(q, type='task', project=<имя>)` → + готовые ⚪ ready. Порядок приоритета: **P0-пул первый, внутри по дедлайну + (просроченные первыми), потом P1, потом P2**; отсутствующий priority = P1 + (сортировка — клиентская, wiki:2660). 2. **Локально-первая рекомендация** — борд cwd первым; кросс-проект — футонота (`Cross-project: N 🔴 active — см. tasks_aggregate`) только если N>0 и в cwd нет активной 🔴. Кросс-проектные ургенты — информация, не драйвер «что делать здесь». -3. **Priority/Due — территория человека (раздел task-priority-due):** +3. **Взять таску:** `task_update(project, id, status='active', owner='::', version=<из чтения>)`. + - 200 → таска твоя (🔴, owner=твоя сессия). + - **409** → кто-то уже взял (version устарела) → `entity_get` → бери следующую. +4. **Priority/Due — территория человека (раздел task-priority-due):** - Агент ставит `priority`/`due` **только при создании** таски (явные параметры или строки `**Priority:** P0|P1|P2` / `**Due:** yyyy-mm-dd` в description). Отсутствует → дефолт P1, без дедлайна. @@ -114,9 +127,10 @@ internal (последним, для addressing в тулах). Ссылайся - **Одна активная таска** 🔴 на проект. Не параллель. - Читай description + per-task файл (`.md`, где есть) до старта. -- Долгие таски: `task_heartbeat(project, claim_token)` (лиз по TTL, дефолт 600s). +- Heartbeat не нужен: живость = живая pi-сессия (session-sync пишет её в mappa; + stale-детект — по сессии владельца, не таймер на таске). - **`session_break` gate** (из task-loop): если в description таски есть маркер - `session_break` — после close НЕ клейми следующую: печатай + `session_break` — после close НЕ бери следующую: печатай `🔚 SESSION BOUNDARY …` и останавливайся (домен-свитч / milestone / тяжёлая инфра). ### Фаза 3 — Сдача (close + review-umbrella) @@ -125,7 +139,8 @@ internal (последним, для addressing в тулах). Ссылайся каждого — evidence: тест в диффе, артефакт, ссылка на дизайн. Нет evidence на критерий → спроси user'а «закрывать или подождать coverage'а». 2. Resolve/drop открытые вопросы. -3. `task_close(project, id, claim_token)` → статус `done`. +3. `task_close(project, id, version=<из чтения>)` → статус `done`. + **409 на конфликт** → `entity_get` → повтори close со свежей version. 4. **Notify-письмо (кросс-проектные таски).** Если таска пришла из другого проекта (в description/meta есть `from:`/`notify:`) — `inbox_send` комиссионеру: `project=`, `subject="[event: closed] "`, @@ -143,7 +158,7 @@ internal (последним, для addressing в тулах). Ссылайся 1. Текущая 🔴 → `task_close` если завершена (см. Фазу 3), иначе пометь `status=paused` (owner остаётся; «where stopped» — в description или handoff). 2. **Инбокс-свип** на границе тасок (`inbox_monitor`). -3. Возьми следующую: `task_claim_next` (лиз + таска). Прежняя остаётся 🟡. +3. Возьми следующую: `task_update(status=active, owner=<сессия>)`. Прежняя остаётся 🟡. 4. Подтверди ориентацию перед стартом. > **Never lose Where I stopped** — критичное поле: в description (последний @@ -155,23 +170,23 @@ internal (последним, для addressing в тулах). Ссылайся ## Loop-mode — «поработай очередь» Один триггер-сёрфейс: «поработай очередь» / «work the queue» / «прогони доску» -→ этот режим. Work the board **в этой сессии**: claim → работа → close → claim, +→ этот режим. Work the board **в этой сессии**: взять → работа → close → взять, пока очередь не пуста или user не сказал стоп. **Интерактивный цикл, не демон.** ``` -claim_next(project, owner) → пусто? → STOP «борд пуст» (не поллить) - ↓ таска +search(ready) → пусто? → STOP «борд пуст» (не поллить) + ↓ кандидат +task_update(status=active, owner=<сессия>, version) → 409? → следующий кандидат + ↓ взято работа в этой сессии (read description + .md) ↓ -завершена? нет → park: blocked (внешний) | paused (возобновляемо) → claim_next +завершена? нет → park: blocked (внешний) | paused (возобновляемо) → дальше ↓ да -consult_policy (из claim): human-only/strict-human → STOP перед close/commit, спросить user - ↓ auto -pre-close coverage check → task_close +pre-close coverage check → task_close(version) ↓ session_break на таске? → да: печатай 🔚 SESSION BOUNDARY, STOP ↓ нет -claim_next … +следующий кандидат … ``` - **Пустая очередь — естественный стоп, не wait-loop.** Нет `CronCreate`, нет @@ -181,12 +196,8 @@ claim_next … - **Не завершаемая таска:** внешний блокер → `status=blocked` + blocker (конкретный факт + что нужно); прервал ты (бюджет/стоп) → `status=paused` + where_stopped. Одна упавшая таска не останавливает цикл — паркуй и дальше. -- **Heartbeat:** claim живёт ~10 мин — если таска дольше ~8 мин, `task_heartbeat` - периодически. -- **Consult-гейт:** `auto` → автопилот до close; `human-only`/`strict-human` → - работай, затем **STOP перед close/commit** и спроси user. Push никогда не - автоматический (project-discipline Rule 4: commit freely, push по явному - гранту). +- **409 на взятие** → таска только что взята другим (сессия жива) → следующий + кандидат; 409 на close → свежая version из `entity_get`, повтор. --- @@ -194,8 +205,8 @@ claim_next … ### Primary: mappa task_create -Создание задач — **через тул, не руками** (решение 20): сначала лиз -(`task_claim_next`) → `task_create`. Номер `t:N` назначает сервер — не выдумывай. +Создание задач — **через тул, не руками** (решение 20): карв-аут, лиз не нужен +(wiki:2660). Номер `task:N` назначает сервер — не выдумывай. ``` mcp__mappa__task_create( @@ -205,8 +216,7 @@ mcp__mappa__task_create( description: , // тело; [[refs]] → рёбра (решение 4) status: ready | active | paused | blocked | done, // по умолчанию ready priority: P0 | P1 | P2, // только при создании; отсутствует → P1 - due: yyyy-mm-dd, // только при создании; отсутствует = нет - claim_token: <токен лиза проекта> // мутация под лизом (решение 19) + due: yyyy-mm-dd // только при создании; отсутствует = нет ) ``` @@ -241,9 +251,7 @@ Slug-правила: короткий, lowercase, kebab-case, латиница. Поля, которые разбирает поллер: `**Weight:**` (cheap-ok | needs-claude | needs-human — **обязателен** для авто-взятия), `**Notify:**` (/), `**Requirements:**`, `**Runtime allowed:**`, `**Consult policy:**`, `**Blocker:**` -(только на 🔵), `**Priority:**`/`**Due:**` (как выше). `**Owner:**/`**Claim -token:**/`**Claim expires at:**` — claim-штамп, пишет и чистит поллер; залипший -штамп на ⚪ блокирует поллер. +(только на 🔵), `**Priority:**`/`**Due:**` (как выше). **Weight — поле, решающее взятие:** без `**Weight:**` поллер паркует в 🔵 (`no backend for weight_tier: unknown`). Обычный код → `needs-claude`; @@ -253,10 +261,10 @@ token:**/`**Claim expires at:**` — claim-штамп, пишет и чисти ## Failure modes -- **422 busy** на `task_claim_next` → лиз держит другой агент; не параллель, - retry позже или спроси user. +- **409 на взятие** → таска уже взята (живая сессия владельца) → следующий + кандидат; не «бейся о замок». - **task_close на незавершённую** → никогда. Park (blocked/paused). -- **claim истёк (zombie)** → не бросай claimed-таску: park/close по факту. +- **409 на close** → конфликт version → `entity_get` → повтори со свежей version. - **notify не указан (legacy)** → без него boss не узнает о завершении. - **weight не указан (legacy)** → поллер паркует (no backend for weight_tier). - **update Priority/Due после создания** → сервер отклоняет; паркуй вопрос @@ -264,11 +272,12 @@ token:**/`**Claim expires at:**` — claim-штамп, пишет и чисти ## What NOT to do -- **Не выдумывай номера** — `t:N` назначает сервер (решение 20). -- **Лиз-дисциплина:** мутации — только под лизом; 422 busy = кто-то другой пишет. +- **Не выдумывай номера** — `task:N` назначает сервер (решение 20). +- **Version-дисциплина:** мутации несут version из последнего чтения; 409 → + перечитай, не перезаписывай вслепую. - **Одна активная таска** — только одна 🔴 на проект. - **Never close без coverage check** — evidence на каждый acceptance criterion. -- **Не закрывай незавершённое** — park, не close; не оставляй claimed-таску. +- **Не закрывай незавершённое** — park, не close; не оставляй взятое. - **Не бампай priority/due после создания** — территория человека. - **Не «решай» задачи письмом/в чате** — борд — единственный источник правды (канон mappa-messaging: «если это не на доске — это не задача»).