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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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: «если это не на доске — это не задача»).