feat(skills): сверка mappa-* скилов с деплоем — репо догнал установленные 1.2.0/1.4.0 (интерактивный контракт wiki:2660) [skip-tdd: visual]

- mappa-task-work 1.1.0→1.2.0, mappa-delegation 1.1.0→1.2.0, mappa-knowledge 1.1.0→1.2.0, mappa-messaging 1.1.0→1.2.0, mappa-brainstorm-promote 1.3.0→1.4.0, mappa-closing-ritual 1.0.0→1.2.0
- репо нёс гибрид ae45a51 (1.1.0, следы 'карв-аут лиза'); установленные (деплой, результат #1040) чище: claim/лиз выпилены, owner=персистентный assignee, живность из session владельца
- dist/*.skill пересобраны (build.ps1); установленные уже были в этом состоянии — репо стал источником правды, совпадающим с деплоем
- сверка: claim_next/claim_expires/task_heartbeat/admin_release_lease — 0 вхождений в установленных mappa-* (подтверждено и на этом хосте)
This commit is contained in:
2026-08-25 01:04:12 +03:00
parent ae45a51420
commit c213997e1d
12 changed files with 134 additions and 119 deletions

View File

@@ -1,12 +1,13 @@
---
name: mappa-brainstorm-promote
author: ours
version: 1.3.0
version: 1.4.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-борд (create — карв-аут без лиза wiki:2660), 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 +28,7 @@ description: >
- **workshop-meta** → локальный `.wiki/concepts/` (методология самой зоны).
- **domain** → глобал через `mcp__projects-meta__knowledge_ingest` в `~/projects/<proj>/.wiki/`.
- **mappa-service** → сервисные борды (mappa, .common, …): таски/вики-сущности через `mcp__mappa__task_create`/`wiki_create` (карв-аут, wiki:2660); review-umbrella — сервисная таска; covering-письмо в инбокс цели.
- **mappa-service** → сервисные борды (mappa, .common, …): таски/вики-сущности через `mcp__mappa__task_create`/`wiki_create` (**create — карв-аут без лиза**, wiki:2660; update — version+409); pointers-таска НЕ нужна, если спека уже в вики проекта (wiki:NNNN); review-umbrella — сервисная таска; covering-письмо в инбокс цели.
- **skill** → `~/projects/claude-skills/skills/<name>/SKILL.md` (только шапка + пустой каркас тела, локальный коммит без push/install/build-hermes).
Буфер уезжает в `.archive/`. Action-items уходят тасками в target-проект. **Всегда, при любом маршруте, в воркшоп-вики остаётся summary-страница.**
@@ -63,7 +64,7 @@ description: >
│ │ │ │
│ ▼ ▼ ▼
│ knowledge_ingest mcp__mappa__wiki_create dialog: description (trigger contract)
│ │ (карв-аут, wiki:2660) │
│ │ (карв-аут, wiki:2660)
│ │ │ ▼
│ │ │ preview + confirm
│ │ │ │
@@ -118,9 +119,11 @@ description: >
- **Определить канал борда:** есть ли у проекта файловая доска `.tasks/STATUS.md` (file channel) или борд живёт в mappa-сущностях (service channel — сервисные проекты: mappa, .common, …). Проверка: файл `.tasks/STATUS.md` в чек-ауте (file) против `mcp__mappa__task_list(project=<proj>)` / `entity_search` (service). Если файловой доски нет, а mappa-сущности есть → **service channel**.
4. **Если domain + service channel (mappa-борд, fold-in 1):**
- **Спека → вики-сущность:** `mcp__mappa__wiki_create(project, slug, body)` (или `wiki_update(project, id, version)`, если страница уже есть). Если спека уже в вики проекта (w:NNNN) — не дублировать, описание импл-тасок ссылается на неё.
- **Create — карв-аут, лиз НЕ нужен** (wiki:2660): `task_create`/`wiki_create`
без claim_token (интерактивный контракт, поллер вне mappa).
- **Спека → вики-сущность:** `mcp__mappa__wiki_create(project, slug, body)` (или `wiki_update(project, id, version, …)`, если страница уже есть). Если спека уже в вики проекта (wiki:NNNN) — не дублировать, описание импл-тасок ссылается на неё.
- **Pointers-таска НЕ нужна**, если спека уже в вики проекта — дыра pointers закрыта инлайн (описание импл-тасок прямо ссылается на спеку).
- **Импл-таски:** `mcp__mappa__task_create(project, slug, title, description, status='ready')` (карв-аут, wiki:2660)**ПОСЛЕДОВАТЕЛЬНО, не батчем** (см. NB в шаге 7).
- **Импл-таски:** `mcp__mappa__task_create(project, slug, title, description, status='ready')`**ПОСЛЕДОВАТЕЛЬНО, не батчем** (см. NB в шаге 7).
- **Review-umbrella:** сервисная таска `mcp__mappa__task_create(status='blocked', blocker=<номера импл-тасок>)`.
- **Covering-письмо:** `mcp__mappa__inbox_send(project=<target>, from=<своя>, subject='Промоушен <topic>: таски <#N>…', body=<перечень>).` — канон mappa-delegation: таска на борде не пингует живую сессию.
@@ -366,9 +369,9 @@ description: >
- Если `tasks_create` review-таски упала — сообщить пользователю, **продолжить** к шагу 11 (архивация буфера). Review-таску можно создать вручную позже из `.archive/<date>-<topic>.md`.
- **domain (service channel):** review-umbrella — **сервисная таска**: `mcp__mappa__task_create(project=<target>, slug=<topic>-review, status='blocked', blocker=<номера импл-тасок через запятую>, description=<шаблон domain выше, спека = w:NNNN в вики проекта>)`. Pointers-таска отсутствует (спека в вики).
- **domain (service channel):** review-umbrella — **сервисная таска**: `mcp__mappa__task_create(project=<target>, slug=<topic>-review, status='blocked', blocker=<номера импл-тасок через запятую>, description=<шаблон domain выше, спека = wiki:NNNN в вики проекта>)` — create = карв-аут (без лиза). Pointers-таска отсутствует (спека в вики).
**Covering-письмо в инбокс цели (оба канала; канон mappa-delegation).** После создания тасок — `inbox_send` получателю-проекту: таска на борде не пингует живую сессию, письмо = пинг + контекст. File channel: `mcp__mappa__inbox_send(project=<target>, from=<своя>, subject='[event: created] <topic> — <N> тасок', body=<перечень: #N slug> )`. Service channel: то же, но `from` = своя папка (или сервисный адрес) и тело ссылается на w:NNNN-спеку.
**Covering-письмо в инбокс цели (оба канала; канон mappa-delegation).** После создания тасок — `inbox_send` получателю-проекту: таска на борде не пингует живую сессию, письмо = пинг + контекст. File channel: `mcp__mappa__inbox_send(project=<target>, from=<своя>, subject='[event: created] <topic> — <N> тасок', body=<перечень: #N slug> )`. Service channel: то же, но `from` = своя папка (или сервисный адрес) и тело ссылается на wiki:NNNN-спеку.
10. **Workshop-wiki summary (обязательно для всех маршрутов):**
@@ -423,9 +426,8 @@ description: >
- `mcp__projects-meta` недоступен → abort до записей.
- Целевой проект (для domain) не найден в `meta_status` → abort.
- `knowledge_ingest` упал → abort до `tasks_create` и `git mv`. Буфер остаётся.
- **Service channel:** create — карв-аут (wiki:2660), 422 busy больше не бывает; 409 на `wiki_update` (version) → retry со свежей версией.
- **Service channel:** `task_create` упал (гонка счётчика/переходный период) → **повторить последовательно**, не батчем; при стабильном отказе — abort до архивации.
- **Service channel:** спека уже существует в вики проекта (w:NNNN) → не дублировать `wiki_create`, ссылаться на неё.
- **Service channel:** create упал (гонка счётчика/переходный период) → **повторить последовательно**, не батчем; при стабильном отказе — abort до архивации.
- **Service channel:** спека уже существует в вики проекта (wiki:NNNN) → не дублировать `wiki_create`, ссылаться на неё.
- **domain:** `tasks_create` для `[<topic>-pointers]` упал → **abort** до content-тасок и до review-таски. Без pointers оставшиеся таски бесполезны (агент будет угадывать). Сообщить пользователю; буфер оставить на месте для retry.
- `tasks_create` упал на N-й content-таске → продолжить остальные. Сообщить partial. **Не делать** `git mv` без подтверждения пользователя.
- `tasks_create` упал на review-таске (шаг 8) → не блокировать; перейти к архивации, сообщить пользователю чтобы создал вручную из `.archive/`.
@@ -439,7 +441,7 @@ description: >
- **Всегда (любой маршрут):** создаёт summary-страницу `.wiki/concepts/<topic>.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`, карв-аут wiki:2660); импл-таски + review-umbrella — сервисные таски (`mcp__mappa__task_create`, карв-аут); covering-письмо в инбокс цели (`inbox_send`). Pointers-таска НЕ создаётся (спека уже в вики).
- **domain:** создаёт также **mandatory pre-impl** таску `[<topic>-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/<name>/SKILL.md` — **только шапка + пустой каркас**. Локальный коммит в `claude-skills/`. **Без** установки, push, или build-hermes — это всё в созданных baseline-тасках.
- Создаёт N тасок в target `.tasks/` через MCP.
@@ -459,6 +461,6 @@ description: >
- **Skill:** не бампить `version` после первой записи (это работа владельца `claude-skills/`).
- **Skill:** не промоутить в существующий скил (см. Failure modes — abort).
- **Skill:** не пропускать обязательный preview + confirm перед `Write` — действие выходит за пределы мастерской, изменяет соседний репозиторий.
- **Service channel:** не батчить `task_create` (гонка счётчика, инцидент 2026-08-24: 6/7 упали) — только последовательно; `wiki_update`/`task_close` со свежей version (409 → retry).
- **Service channel:** не плодить pointers-таску, если спека уже в вики проекта (w:NNNN) — описание импл-тасок ссылается на неё инлайн.
- **Service channel:** не батчить `task_create` (гонка sha-CAS счётчика, инцидент 2026-08-24: 6/7 упали) — только последовательно. Create — карв-аут, лиз не нужен.
- **Service channel:** не плодить pointers-таску, если спека уже в вики проекта (wiki:NNNN) — описание импл-тасок ссылается на неё инлайн.
- **Service channel:** не забывать covering-письмо в инбокс цели — таска на борде не пингует живую сессию.

View File

@@ -1,7 +1,7 @@
---
name: mappa-closing-ritual
author: ours
version: 1.0.0
version: 1.2.0
description: >
Финиш-фаза форкфлоу: handoff write (mcp__mappa__handoff_write, версия h:N)
+ PROPOSE wiki-ingest + PROPOSE закрытий тасок. Мутации — только после
@@ -78,13 +78,13 @@ Forward-looking, не timeline: handoff = связка новых вещей к
### 5. Propose wiki-ingest (не писать!)
Если за сессию появилось durable-знание — **ПРЕДЛОЖИТЬ** ingest
(`mappa-knowledge`: mappa wiki_create/update — version+409, wiki:2660), перечислив кандидатов.
(`mappa-knowledge`: mappa wiki create — карв-аут, update — version+409, wiki:2660), перечислив кандидатов.
Ничего не писать без подтверждения.
### 6. Propose task-board closes (не закрывать!)
Если есть задачи, выглядящие закрытыми — **ПРЕДЛОЖИТЬ** закрытия
(`mappa-task-work`: task_close version+409). Уважать ralph-loop: verifier-задачи
(`mappa-task-work`: task_close с version+409, wiki:2660). Уважать ralph-loop: verifier-задачи
закрывать только через verifier (attempt/harness-record).
### 7. Формат предложения — один блок

View File

@@ -1,7 +1,7 @@
---
name: mappa-delegation
author: ours
version: 1.1.0
version: 1.2.0
description: >
Цикл делегирования задачи другому агенту/проекту: pre-flight gate →
шаблон тела → dry-run preview → confirm → covering-письмо в инбокс
@@ -44,10 +44,10 @@ steering-loop поля (notify/weight), парную review-таску для im
Номер задаче присваивает сервер (`tasks_create` из счётчика agenda/task-counter) — постановщик номер не придумывает и не резервирует. Возвращённый `#n` из preview/confirm — машинный ключ задачи: им ссылаются блокеры, письма, decision-trail.
> **Интерактивный контракт (wiki:2660).** `task_create` — карв-аут, лиз НЕ
> нужен (create = INSERT, входной контур). `task_close`/`task_update` — optimistic
> version+409 (конфликт → свежая version из `task_get` → retry). File channel —
> sha-CAS через Gitea (projects-meta), там свои правила.
> **Контракт (interactive, wiki:2660).** `task_create` — **карв-аут без
> лиза** (create-без-лиза как принцип); update/close — version+409 (409 →
> re-GET → retry). file channel — sha-CAS через Gitea. Claim/TTL нет —
> «взять таску» = conditional update по version (поллер вне mappa).
## Steps (цикл)
@@ -64,7 +64,7 @@ steering-loop поля (notify/weight), парную review-таску для im
4. **notify — кому докладывать о завершении/затыке?** (slug проекта; обычно `.workshop` или `OpeItcLoc03/workshop`)
5. **Session-break после этой задачи?** — нужен ли разрыв сессии после её закрытия (domain-switch, milestone, heavy infra)?
- Если **да** → проставить `session_break` в теле задачи (см. шаблон): `true` или строка-hint с названием следующего трека. `mappa-task-work` остановится после close и предложит завершить сессию, не клеймя следующую задачу.
- Если **нет** → поле не добавлять (дефолт — агент продолжает `claim-next`).
- Если **нет** → поле не добавлять (дефолт — агент продолжает цикл).
### 2. Составить тело задачи по шаблону
@@ -132,7 +132,8 @@ mcp__mappa__inbox_send(
)
```
(`task_create` — карв-аут (wiki:2660), доставка письма — карв-аут.)
(Мутации update/close — version-based (409 → retry); доставка письма —
карв-аут, лиза не требует.)
Причина: таска на борде **не пингует живую сессию** получателя. Поллер
подхватит по `Weight`/`Notify`, но живая интерактивная сессия узнаёт только
@@ -175,7 +176,7 @@ task» — общий случай (шаг 7 — его частность дл
## Side effects
- Создаёт таску в target-проекте через `tasks_create` (file channel — Gitea commit; service channel — mappa-сущность карв-аутом, wiki:2660).
- Создаёт таску в target-проекте через `tasks_create` (file channel — Gitea commit; service channel — mappa-сущность, create = карв-аут без лиза wiki:2660).
- Опционально создаёт парную review-таску (status=blocked).
- Covering-письмо в инбокс получателя (кросс-проектная делегация).

View File

@@ -1,7 +1,7 @@
---
name: mappa-knowledge
author: ours
version: 1.1.0
version: 1.2.0
description: >
Цикл работы со знаниями проекта в Mappa (Karpathy LLM Wiki, канал =
mappa-сущности): ingest → query → lint + граф-слой для
@@ -10,8 +10,8 @@ description: >
«запроси вики», «проверь вики», «use project wiki», «query the wiki»,
«что связывает X и Y», «как связаны», «путь между X и Y», «what connects
X and Y», «что ссылается на X», «backlinks of X», «сироты», «битые ссылки»,
«orphan pages». Wiki = сущности type=wiki (чтение — карв-аут лиза; запись
version+409, wiki:2660). Реляционные вопросы — через graph_* (BFS на
«orphan pages». Wiki = сущности type=wiki (чтение — карв-аут; create
карв-аут, update — version+409; контракт wiki:2660). Реляционные вопросы — через graph_* (BFS на
стороне сервиса), guarded failure-mode: одна страница и стоп, без
многохоповых цепочек чтением. Skip для одно-страничных контентных вопросов.
---
@@ -25,7 +25,8 @@ query / lint) + **граф-слой** для реляционных и стру
сущностями читают через граф (graph_*).
Канал — Mappa (`mcp__mappa__*`), НЕ файлы. Страница — сущность `type=wiki`
(`wiki:N`); чтение — карв-аут, запись — version+409 (wiki:2660).
(`wiki:N`); чтение — карв-аут; **create — карв-аут без лиза; update —
optimistic concurrency (version+409 → retry)** (контракт wiki:2660, v0.12.0).
Файлового `.wiki/` больше нет; `setup-wiki` умер (нечего настраивать).
## Когда использовать
@@ -64,19 +65,19 @@ README/ADR (не персистентная база знаний), проект
| Операция | Тул | Примечание |
|---|---|---|
| Чтение страницы | `mcp__mappa__wiki_get(project?, slug)` | чтение — карв-аут (решение 19) |
| Чтение страницы | `mcp__mappa__wiki_get(project?, slug)` | чтение — карв-аут |
| Поиск страниц | `mcp__mappa__entity_search(q, type='wiki', project?, scope?, limit)` | ILIKE по body/title |
| Создать страницу | `mcp__mappa__wiki_create(project, slug, body)` | карв-аут (wiki:2660), лиз не нужен |
| Обновить страницу | `mcp__mappa__wiki_update(project, id, title?, body?, version)` | version+409; id — internal |
| Создать страницу | `mcp__mappa__wiki_create(project, slug, body)` | **карв-аут без лиза** |
| Обновить страницу | `mcp__mappa__wiki_update(project, id, title?, body?, version)` | **version-based**: конфликт → 409 → retry со свежей version из wiki_get |
| Путь между сущностями | `mcp__mappa__graph_path({from, to})` | кратчайшая цепочка, BFS |
| Соседи / исходящие | `mcp__mappa__graph_neighbors({id})` | рёбра узла с резолвом целей |
| Входящие ссылки | `mcp__mappa__graph_backlinks({id})` | кто ссылается на узел |
| Здоровье графа | `mcp__mappa__graph_stats()` | nodes/edges/components |
**Запись — version+409 (wiki:2660 interactive contract).** `wiki_create`
карв-аут (лиз не нужен); `wiki_update` несёт `version` из последнего чтения,
конфликт → 409 → `wiki_get` заново → retry. Долгих лизов/TTL/heartbeat больше
нет — живость владельца из session live-ingest.
**Запись — карв-аут (create) / version-based (update), без лиза (interactive
contract, wiki:2660).** `wiki_create` не требует claim_token; `wiki_update`
принимает ожидаемую `version` (свежую из `wiki_get`) — конфликт → 409 →
re-GET → retry.
**Рефы и id (#1037/#1028).** Публичная поверхность несёт per-type реф полным
именем первым полем: `ref: "wiki:3"` (решение 20, конвенция #1028), `num`
@@ -97,10 +98,11 @@ per-type рефы полными именами (`[[task:N]]`/`[[inbox:N]]`).
3. Создай `sources/<slug>` — одну страницу-резюме на источник (~50150 строк;
ссылку на raw клади в frontmatter `raw_path` + `ingested:`).
4. Для каждой затронутой страницы:
- есть → обнови (`wiki_update(project, id, body, version)`). **Противоречия
помечай явно** блоком `> **Противоречие:** источник A говорит X, источник B — Y`.
- есть → обнови (`wiki_update(project, id, body, version)` — version свежая
из `wiki_get`; 409 → re-GET → retry). **Противоречия помечай явно** блоком
`> **Противоречие:** источник A говорит X, источник B — Y`.
Не затирай молча.
- нет → создай (`wiki_create`).
- нет → создай (`wiki_create`, карв-аут).
5. Обнови `index` (каталог: одна строка на страницу) — опционально; каталог
по умолчанию — `entity_search` (решение 1).
6. Отчитайся пользователю: что создано, что обновлено, какие противоречия.
@@ -113,8 +115,9 @@ per-type рефы полными именами (`[[task:N]]`/`[[inbox:N]]`).
**Один ingest может затронуть 1015 страниц. Это нормально — для того LLM и нужны.**
Порядок записи: все wiki-мутации одним циклом; `wiki_update`со свежей
`version` из чтения (409 → retry). Создание новых страниц — карв-аут.
Порядок записи: все wiki-мутации одним циклом; create — карв-аут, update — с
version (свежей из `wiki_get`); 409 → re-GET → retry. Лиз/claim для записи НЕ
нужен (wiki:2660).
### Query — вопрос по вики
@@ -231,8 +234,9 @@ level/since/component/entity, retention 14d). Ручную `log`-страниц
- **Не-ASCII слаги.** Ломают grep и кросс-платформенность. Транслитерируй.
- **Пропущенные противоречия в lint.** Ценность вики — во вскрытых напряжениях,
а не в ложном консенсусе.
- **Запись version+409 (wiki:2660).** `wiki_create` — карв-аут; `wiki_update` со свежей `version` (конфликт → 409 → retry).
- **Держать лиз на чтение/раздумья.** Лиз — на время записи. Чтение — карв-аут.
- **Запись без version (update).** `wiki_update` без свежей version
last-write-wins, риск затирания чужого; бери version из `wiki_get`, 409 → retry.
- **Держать claim на чтение/раздумья.** Claim — на время работы; чтение — карв-аут.
- **Реляционный вопрос чтением одной страницы.** Это тот самый 0%-recall
провал — зови graph_*.
- **Слаги/пути в graph-тулы.** Только internal id, и только свежие (удалённая
@@ -244,7 +248,7 @@ level/since/component/entity, retention 14d). Ручную `log`-страниц
- Реляционный вопрос → читаешь страницу вместо `graph_*`.
- Правка `sources/` или молчаливая перезапись противоречия.
- Wiki-мутация без лиза (422) или лиз держится на чтение.
- Wiki-мутация update без version (last-write-wins) или create с выдуманным claim.
- Нарративный оп-лог руками.
---

View File

@@ -1,7 +1,7 @@
---
name: mappa-messaging
author: ours
version: 1.1.0
version: 1.2.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` (карв-аут + version+409, wiki:2660)
— никогда не «решаются» внутри письма.
меняются через `task_create` / `task_close` — никогда не «решаются» внутри
письма. (Create — карв-аут; update/close — version+409, wiki:2660.)
Следствие: **если это не на доске — это не задача и не решение, это разговор.**
Значимый дизайн-выбор должен лечь на доску (или в вики), инбокс лишь указывает

View File

@@ -1,36 +1,33 @@
---
name: mappa-task-work
author: ours
version: 1.1.0
version: 1.2.0
description: >
Центральный цикл работы с тасками в Mappa: ориентация → выбор работы
(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).
(priority/due) → исполнение → сдача (close + review-umbrella) +
loop-mode «поработай очередь». Борд = сущности mappa (решения 14/15/19/20);
create — карв-аут, update/close — optimistic concurrency (version+409),
owner = персистентный assignee, живость из session владельца
(interactive contract, wiki:2660). Поглощает 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`, `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` пишется сама), не таймер.
сдача**. Борд — сущности mappa (`type=task`, `task:N`): чтение — карв-аут;
**create — карв-аут без лиза; update/close — optimistic concurrency
(version+409 → retry)**; **owner = персистентный assignee; живость таски —
из session владельца** (interactive contract, wiki:2660; поллер вне mappa).
Скилл = цикл, не тул: одна механика на выбор/исполнение/сдачу, плюс
**loop-mode** («поработай очередь») внутри — отдельный скил не создаётся.
> **Переходное (file channel).** Пока поллер/кэш читают файловые борды
> (`.tasks/STATUS.md`), legacy-канал живёт: блоки в файле обязаны строгому
@@ -51,29 +48,32 @@ version+409, конфликт → retry со свежей version из `task_get
| Операция | Тул | Примечание |
|---|---|---|
| Взять таску | `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 |
| Взять следующую ready-таску | `mcp__mappa__task_update(project, id, owner=<своя>, status=active, version)` | **conditional update**: status→active, owner=X, version+409 (кто первый с верной version — тот и взял) |
| Создать таску | `mcp__mappa__task_create(project, slug, title?, description?, status?, priority?, due?)` | **карв-аут без лиза**; per-type номер (решение 20) |
| Закрыть таску | `mcp__mappa__task_close(project, id, version)` | **version-based**: конфликт → 409 → retry со свежей version из task_get |
| Обновить таску | `mcp__mappa__task_update(project, id, parent?, owner?, status?, reason?, version)` | version-based; 409 → retry |
| Прочитать таску | `mcp__mappa__entity_get(id)` | id internal из search |
| Список борда | `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__session_list(project, stale_minutes?)` | сессия владельца жива/стала stale → таска active or not |
| Уведомление при закрытии | `mcp__mappa__inbox_send(project=<notify>, from=<своя>, subject, body)` | письмо комиссионеру |
**Взятие таски = version+409, не лиз.** Каждая таска несёт `version`; conditional
update (`status=active, owner=<сессия>, version=N`) проходит, только если никто
не изменил её после твоего чтения. Конфликт → **409**`task_get` заново →
выбирай другую. Конкуренции «проект занят» нет: два агента берут разные таски
свободно. Живость — из сессии: пока твоя pi-сессия активна (end-state≠clean),
твои 🔴 видны как «в работе».
**Owner = персистентный assignee; живость — из session (interactive contract,
wiki:2660).** Нет TTL/claim/таймера на таске: «взял таску» = conditional
update (`status→active, owner=X` + version, 409 при конфликте — кто первый,
тот и взял). Живость владельца — сессия: таска с owner=X активна, пока сессия
X жива (end-state≠clean, не stale; `session_list(project)`); краш = stale →
решает человек/оркестратор (поллер вне mappa, работает на файловых досках
projects-meta). Write-пути (create/update/close) лизов/claim не требуют —
только version на update/close (409 при конфликте).
**Рефы и id (#1037/#1028).** Таски наружу несут `ref: "task:N"` полным именем
первым полем (конвенция #1028), `num` следом, глобальный `id` internal
(последним, для addressing в тулах). Ссылайся на таску `[[task:N]]`/`task:N`
в прозе (слаг/имя первым, реф как якорь: «таска `mappa-task-work` (task:1062)»),
никогда `#<глобальный id>`.
**Рефы и id (#1037/#1028).** Таски наружу несут `ref: "t:N"` полным именем
первым полем (`task:N`, конвенция #1028), `num` следом, глобальный `id`
internal (последним, для addressing в тулах). Ссылайся на таску
`[[task:N]]`/`task:N` в прозе (слаг/имя первым, реф как якорь: «таска
`mappa-task-work` (task:1062)»), никогда `#<глобальный id>`.
## Статусы (эмодзи для презентации)
@@ -101,19 +101,19 @@ update (`status=active, owner=<сессия>, version=N`) проходит, то
4. Подтверди одним предложением: «Мы в середине X, следующий шаг — Y».
5. Спроси, верен ли план, перед действиями.
### Фаза 1 — Выбор работы (owner, priority/due)
### Фаза 1 — Выбор работы (priority/due)
1. Собери кандидатов: `entity_search(q, type='task', project=<имя>)`
готовые ⚪ ready. Порядок приоритета: **P0-пул первый, внутри по дедлайну
(просроченные первыми), потом P1, потом P2**; отсутствующий priority = P1
(сортировка — клиентская, wiki:2660).
1. **Выбор таски — из списка борда** (`entity_search(q, type='task', project)`):
порядок — **P0-пул первый, внутри по дедлайну (просроченные первыми),
потом P1, потом P2**; отсутствующий priority = P1 (task-priority-due).
«Взять таску» = `task_update(project, id, owner=<своя>, status='active',
version)` — conditional update: status→active, owner=X, version+409; кто
первый с верной version — тот и взял (interactive contract, wiki:2660).
`owner` = `<machine>:<runtime>:<session>`.
2. **Локально-первая рекомендация** — борд cwd первым; кросс-проект — футонота
(`Cross-project: N 🔴 active — см. tasks_aggregate`) только если N>0 и в cwd
нет активной 🔴. Кросс-проектные ургенты — информация, не драйвер «что делать здесь».
3. **Взять таску:** `task_update(project, id, status='active', owner='<machine>:<pi>:<session>', version=<из чтения>)`.
- 200 → таска твоя (🔴, owner=твоя сессия).
- **409** → кто-то уже взял (version устарела) → `entity_get` → бери следующую.
4. **Priority/Due — территория человека (раздел task-priority-due):**
3. **Priority/Due — территория человека (раздел task-priority-due):**
- Агент ставит `priority`/`due` **только при создании** таски (явные параметры
или строки `**Priority:** P0|P1|P2` / `**Due:** yyyy-mm-dd` в description).
Отсутствует → дефолт P1, без дедлайна.
@@ -127,10 +127,10 @@ update (`status=active, owner=<сессия>, version=N`) проходит, то
- **Одна активная таска** 🔴 на проект. Не параллель.
- Читай description + per-task файл (`<slug>.md`, где есть) до старта.
- Heartbeat не нужен: живость = живая pi-сессия (session-sync пишет её в mappa;
stale-детект — по сессии владельца, не таймер на таске).
- Живость — из сессии владельца (`session_list(project)`), не таймер; долгие
таски heartbeat не требуют (interactive contract, wiki:2660).
- **`session_break` gate** (из task-loop): если в description таски есть маркер
`session_break` — после close НЕ бери следующую: печатай
`session_break` — после close НЕ клейми следующую: печатай
`🔚 SESSION BOUNDARY …` и останавливайся (домен-свитч / milestone / тяжёлая инфра).
### Фаза 3 — Сдача (close + review-umbrella)
@@ -139,8 +139,8 @@ update (`status=active, owner=<сессия>, version=N`) проходит, то
каждого — evidence: тест в диффе, артефакт, ссылка на дизайн. Нет evidence на
критерий → спроси user'а «закрывать или подождать coverage'а».
2. Resolve/drop открытые вопросы.
3. `task_close(project, id, version=<из чтения>)` → статус `done`.
**409 на конфликт**`entity_get` → повтори close со свежей version.
3. `task_close(project, id, version)` → статус `done`. `version`
свежая из `entity_get(id)`/`task_get(id)`; конфликт (409) → re-GET → retry.
4. **Notify-письмо (кросс-проектные таски).** Если таска пришла из другого
проекта (в description/meta есть `from:`/`notify:`) — `inbox_send`
комиссионеру: `project=<notify>`, `subject="[event: closed] <slug>"`,
@@ -158,7 +158,8 @@ update (`status=active, owner=<сессия>, version=N`) проходит, то
1. Текущая 🔴 → `task_close` если завершена (см. Фазу 3), иначе пометь
`status=paused` (owner остаётся; «where stopped» — в description или handoff).
2. **Инбокс-свип** на границе тасок (`inbox_monitor`).
3. Возьми следующую: `task_update(status=active, owner=<сессия>)`. Прежняя остаётся 🟡.
3. Возьми следующую: `task_update(owner, status='active', version)` — прежняя
остаётся 🟡.
4. Подтверди ориентацию перед стартом.
> **Never lose Where I stopped** — критичное поле: в description (последний
@@ -174,19 +175,19 @@ update (`status=active, owner=<сессия>, version=N`) проходит, то
пока очередь не пуста или user не сказал стоп. **Интерактивный цикл, не демон.**
```
search(ready) → пусто? → STOP «борд пуст» (не поллить)
↓ кандидат
task_update(status=active, owner=<сессия>, version) → 409? → следующий кандидат
↓ взято
task_update(owner, status=active, version) → 409? re-GET → retry → пусто? → STOP «борд пуст»
таска
работа в этой сессии (read description + <slug>.md)
завершена? нет → park: blocked (внешний) | paused (возобновляемо) → дальше
завершена? нет → park: blocked (внешний) | paused (возобновляемо) → следующая
↓ да
pre-close coverage check → task_close(version)
consult_policy: human-only/strict-human → STOP перед close/commit, спросить user
↓ auto
pre-close coverage check → task_close
session_break на таске? → да: печатай 🔚 SESSION BOUNDARY, STOP
↓ нет
следующий кандидат
следующая
```
- **Пустая очередь — естественный стоп, не wait-loop.** Нет `CronCreate`, нет
@@ -196,8 +197,12 @@ session_break на таске? → да: печатай 🔚 SESSION BOUNDARY, S
- **Не завершаемая таска:** внешний блокер → `status=blocked` + blocker
(конкретный факт + что нужно); прервал ты (бюджет/стоп) → `status=paused` +
where_stopped. Одна упавшая таска не останавливает цикл — паркуй и дальше.
- **409 на взятие** → таска только что взята другим (сессия жива) → следующий
кандидат; 409 на close → свежая version из `entity_get`, повтор.
- **Heartbeat не нужен** — живость владельца из session (wiki:2660); долгая
таска с живой сессией не «протухает».
- **Consult-гейт:** `auto` → автопилот до close; `human-only`/`strict-human`
работай, затем **STOP перед close/commit** и спроси user. Push никогда не
автоматический (project-discipline Rule 4: commit freely, push по явному
гранту).
---
@@ -205,8 +210,8 @@ session_break на таске? → да: печатай 🔚 SESSION BOUNDARY, S
### Primary: mappa task_create
Создание задач — **через тул, не руками** (решение 20): карв-аут, лиз не нужен
(wiki:2660). Номер `task:N` назначает сервер — не выдумывай.
Создание задач — **через тул, не руками** (решение 20): карв-аут, лиз/claim
для create НЕ нужен (wiki:2660). Номер `task:N` назначает сервер — не выдумывай.
```
mcp__mappa__task_create(
@@ -251,7 +256,9 @@ Slug-правила: короткий, lowercase, kebab-case, латиница.
Поля, которые разбирает поллер: `**Weight:**` (cheap-ok | needs-claude |
needs-human — **обязателен** для авто-взятия), `**Notify:**` (<owner>/<repo>),
`**Requirements:**`, `**Runtime allowed:**`, `**Consult policy:**`, `**Blocker:**`
(только на 🔵), `**Priority:**`/`**Due:**` (как выше).
(только на 🔵), `**Priority:**`/`**Due:**` (как выше). `**Owner:**/`**Claim
token:**/`**Claim expires at:**` — claim-штамп, пишет и чистит поллер; залипший
штамп на ⚪ блокирует поллер.
**Weight — поле, решающее взятие:** без `**Weight:**` поллер паркует в 🔵
(`no backend for weight_tier: unknown`). Обычный код → `needs-claude`;
@@ -261,10 +268,11 @@ needs-human — **обязателен** для авто-взятия), `**Notif
## Failure modes
- **409 на взятие** → таска уже взята (живая сессия владельца) → следующий
кандидат; не «бейся о замок».
- **version conflict** на update/close → version устарела; re-GET свежую version,
retry. Не «решай конфликт» перезаписью без version (last-write-wins).
- **task_close на незавершённую** → никогда. Park (blocked/paused).
- **409 на close** → конфликт version → `entity_get` → повтори со свежей version.
- **owner на таске без живой сессии** → таска формально active, но владелец
stale; спроси человека (адvisory, не замок).
- **notify не указан (legacy)** → без него boss не узнает о завершении.
- **weight не указан (legacy)** → поллер паркует (no backend for weight_tier).
- **update Priority/Due после создания** → сервер отклоняет; паркуй вопрос
@@ -273,11 +281,11 @@ needs-human — **обязателен** для авто-взятия), `**Notif
## What NOT to do
- **Не выдумывай номера** — `task:N` назначает сервер (решение 20).
- **Version-дисциплина:** мутации несут version из последнего чтения; 409
перечитай, не перезаписывай вслепую.
- **Version-дисциплина:** update/close — всегда с version (409 при конфликте
re-GET → retry). Create — карв-аут без лиза (wiki:2660).
- **Одна активная таска** — только одна 🔴 на проект.
- **Never close без coverage check** — evidence на каждый acceptance criterion.
- **Не закрывай незавершённое** — park, не close; не оставляй взятое.
- **Не закрывай незавершённое** — park, не close.
- **Не бампай priority/due после создания** — территория человека.
- **Не «решай» задачи письмом/в чате** — борд — единственный источник правды
(канон mappa-messaging: «если это не на доске — это не задача»).