From 0258b9d2a73b14545e4f763f2e18fa2f8396e65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Thu, 18 Jun 2026 23:13:44 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D1=80=D0=B0=D0=B7=D0=B2=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=D1=87=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BA=D0=B0=20product-management=20=E2=80=94=208=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B2=D1=8B=D0=BA=D0=BE=D0=B2=20(=D1=80=D0=BE?= =?UTF-8?q?=D1=83=D1=82=D0=B5=D1=80-=D1=80=D0=B5=D0=B5=D1=81=D1=82=D1=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Эпик роутер-реестр, спека v2 §2, этап 1. Зонтик product-management развёрнут в 8 карточек-навыков + 8 под-узлов #42a..#42h. - 8 карточек: write-spec, roadmap-update, metrics-review, product-brainstorming, sprint-planning, stakeholder-update, synthesize-research, competitive-brief - nodes.yaml: узел #42 → #42a..#42h; триггеры (planning/prd→write-spec, роадмап→roadmap-update, метрики→metrics-review); ссылка L9 обновлена - product-management:competitive-brief отличён от marketing:competitive-brief (та самая коллизия имён, ради которой имя файла несёт плагин) - зонтик убран; registry-load.test: 117 узлов / 109 active Регрессия (без 5 pre-existing node:test файлов): 4361 passed, exit 0. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../product-management.contract.json | 12 -- ...anagement__competitive-brief.contract.json | 29 +++++ ...t-management__metrics-review.contract.json | 29 +++++ ...ement__product-brainstorming.contract.json | 29 +++++ ...t-management__roadmap-update.contract.json | 29 +++++ ...-management__sprint-planning.contract.json | 29 +++++ ...nagement__stakeholder-update.contract.json | 29 +++++ ...agement__synthesize-research.contract.json | 29 +++++ ...oduct-management__write-spec.contract.json | 29 +++++ docs/registry/nodes.yaml | 112 ++++++++++++++++-- docs/registry/splitting-inventory.md | 6 +- tools/registry-load.test.mjs | 10 +- 12 files changed, 345 insertions(+), 27 deletions(-) delete mode 100644 docs/registry/contracts/product-management.contract.json create mode 100644 docs/registry/contracts/product-management__competitive-brief.contract.json create mode 100644 docs/registry/contracts/product-management__metrics-review.contract.json create mode 100644 docs/registry/contracts/product-management__product-brainstorming.contract.json create mode 100644 docs/registry/contracts/product-management__roadmap-update.contract.json create mode 100644 docs/registry/contracts/product-management__sprint-planning.contract.json create mode 100644 docs/registry/contracts/product-management__stakeholder-update.contract.json create mode 100644 docs/registry/contracts/product-management__synthesize-research.contract.json create mode 100644 docs/registry/contracts/product-management__write-spec.contract.json diff --git a/docs/registry/contracts/product-management.contract.json b/docs/registry/contracts/product-management.contract.json deleted file mode 100644 index 813f200..0000000 --- a/docs/registry/contracts/product-management.contract.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "skill": "product-management", - "kind": "external", - "needs": ["продуктовая церемония (спека / роадмап / метрики)"], - "produces": ["спецификация / роадмап / анализ метрик / конкурентный бриф"], - "constraints": ["продуктовые церемонии (write-spec/roadmap/metrics)", "НЕ dev-issues (CCPM)"], - "preview-form": "outline", - "defaults": ["/write-spec, /roadmap-update, /metrics-review"], - "key-decisions": ["какая церемония под запрос"], - "acceptance-criteria": ["артефакт церемонии готов и обоснован"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } -} diff --git a/docs/registry/contracts/product-management__competitive-brief.contract.json b/docs/registry/contracts/product-management__competitive-brief.contract.json new file mode 100644 index 0000000..a553ade --- /dev/null +++ b/docs/registry/contracts/product-management__competitive-brief.contract.json @@ -0,0 +1,29 @@ +{ + "skill": "product-management:competitive-brief", + "kind": "external", + "needs": [ + "конкурент(ы)/область для анализа" + ], + "produces": [ + "конкурентный бриф: позиционирование, gap, угрозы" + ], + "constraints": [ + "под-навык зонтика product-management (продуктовые церемонии)", + "НЕ dev-issues (CCPM); конкурентный бриф ≠ marketing:competitive-brief" + ], + "preview-form": "outline", + "defaults": [ + "competitive-brief — продуктовый конкурентный анализ" + ], + "key-decisions": [ + "где дифференцироваться vs паритет" + ], + "acceptance-criteria": [ + "бриф покрывает позиционирование и gaps" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } +} diff --git a/docs/registry/contracts/product-management__metrics-review.contract.json b/docs/registry/contracts/product-management__metrics-review.contract.json new file mode 100644 index 0000000..edc9361 --- /dev/null +++ b/docs/registry/contracts/product-management__metrics-review.contract.json @@ -0,0 +1,29 @@ +{ + "skill": "product-management:metrics-review", + "kind": "external", + "needs": [ + "набор продуктовых метрик для анализа" + ], + "produces": [ + "разбор трендов + scorecard + рекомендации" + ], + "constraints": [ + "под-навык зонтика product-management (продуктовые церемонии)", + "НЕ dev-issues (CCPM); конкурентный бриф ≠ marketing:competitive-brief" + ], + "preview-form": "outline", + "defaults": [ + "metrics-review — анализ метрик и трендов" + ], + "key-decisions": [ + "какие метрики и пороги" + ], + "acceptance-criteria": [ + "метрики разобраны, действия предложены" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } +} diff --git a/docs/registry/contracts/product-management__product-brainstorming.contract.json b/docs/registry/contracts/product-management__product-brainstorming.contract.json new file mode 100644 index 0000000..5213d33 --- /dev/null +++ b/docs/registry/contracts/product-management__product-brainstorming.contract.json @@ -0,0 +1,29 @@ +{ + "skill": "product-management:product-brainstorming", + "kind": "external", + "needs": [ + "продуктовая проблема/возможность для проработки" + ], + "produces": [ + "проработанные идеи и направления (sparring-partner)" + ], + "constraints": [ + "под-навык зонтика product-management (продуктовые церемонии)", + "НЕ dev-issues (CCPM); конкурентный бриф ≠ marketing:competitive-brief" + ], + "preview-form": "outline", + "defaults": [ + "product-brainstorming — открытая проработка идей" + ], + "key-decisions": [ + "какое направление развивать" + ], + "acceptance-criteria": [ + "идеи стресс-тестированы" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } +} diff --git a/docs/registry/contracts/product-management__roadmap-update.contract.json b/docs/registry/contracts/product-management__roadmap-update.contract.json new file mode 100644 index 0000000..ca41b38 --- /dev/null +++ b/docs/registry/contracts/product-management__roadmap-update.contract.json @@ -0,0 +1,29 @@ +{ + "skill": "product-management:roadmap-update", + "kind": "external", + "needs": [ + "изменение приоритетов/новая инициатива" + ], + "produces": [ + "обновлённый роадмап (Now/Next/Later)" + ], + "constraints": [ + "под-навык зонтика product-management (продуктовые церемонии)", + "НЕ dev-issues (CCPM); конкурентный бриф ≠ marketing:competitive-brief" + ], + "preview-form": "outline", + "defaults": [ + "roadmap-update — переприоритизация дорожной карты" + ], + "key-decisions": [ + "что движется ради чего" + ], + "acceptance-criteria": [ + "роадмап отражает новые приоритеты" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } +} diff --git a/docs/registry/contracts/product-management__sprint-planning.contract.json b/docs/registry/contracts/product-management__sprint-planning.contract.json new file mode 100644 index 0000000..5c4466a --- /dev/null +++ b/docs/registry/contracts/product-management__sprint-planning.contract.json @@ -0,0 +1,29 @@ +{ + "skill": "product-management:sprint-planning", + "kind": "external", + "needs": [ + "бэклог + ёмкость команды на спринт" + ], + "produces": [ + "план спринта: scope, оценки, цели, P0 vs stretch" + ], + "constraints": [ + "под-навык зонтика product-management (продуктовые церемонии)", + "НЕ dev-issues (CCPM); конкурентный бриф ≠ marketing:competitive-brief" + ], + "preview-form": "outline", + "defaults": [ + "sprint-planning — планирование спринта под ёмкость" + ], + "key-decisions": [ + "что P0, что stretch" + ], + "acceptance-criteria": [ + "спринт спланирован под capacity" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } +} diff --git a/docs/registry/contracts/product-management__stakeholder-update.contract.json b/docs/registry/contracts/product-management__stakeholder-update.contract.json new file mode 100644 index 0000000..b8ad52f --- /dev/null +++ b/docs/registry/contracts/product-management__stakeholder-update.contract.json @@ -0,0 +1,29 @@ +{ + "skill": "product-management:stakeholder-update", + "kind": "external", + "needs": [ + "прогресс для коммуникации стейкхолдерам" + ], + "produces": [ + "апдейт под аудиторию (exec/eng/customer)" + ], + "constraints": [ + "под-навык зонтика product-management (продуктовые церемонии)", + "НЕ dev-issues (CCPM); конкурентный бриф ≠ marketing:competitive-brief" + ], + "preview-form": "outline", + "defaults": [ + "stakeholder-update — статус под аудиторию и cadence" + ], + "key-decisions": [ + "аудитория и уровень детализации" + ], + "acceptance-criteria": [ + "апдейт таргетирован под аудиторию" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } +} diff --git a/docs/registry/contracts/product-management__synthesize-research.contract.json b/docs/registry/contracts/product-management__synthesize-research.contract.json new file mode 100644 index 0000000..fa4b15e --- /dev/null +++ b/docs/registry/contracts/product-management__synthesize-research.contract.json @@ -0,0 +1,29 @@ +{ + "skill": "product-management:synthesize-research", + "kind": "external", + "needs": [ + "сырые интервью/опросы/тикеты" + ], + "produces": [ + "структурированные инсайты + темы + рекомендации" + ], + "constraints": [ + "под-навык зонтика product-management (продуктовые церемонии)", + "НЕ dev-issues (CCPM); конкурентный бриф ≠ marketing:competitive-brief" + ], + "preview-form": "outline", + "defaults": [ + "synthesize-research — синтез research в инсайты" + ], + "key-decisions": [ + "какие темы доминируют" + ], + "acceptance-criteria": [ + "инсайты ранжированы по частоте/влиянию" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } +} diff --git a/docs/registry/contracts/product-management__write-spec.contract.json b/docs/registry/contracts/product-management__write-spec.contract.json new file mode 100644 index 0000000..914613a --- /dev/null +++ b/docs/registry/contracts/product-management__write-spec.contract.json @@ -0,0 +1,29 @@ +{ + "skill": "product-management:write-spec", + "kind": "external", + "needs": [ + "проблема/идея фичи для оформления в спеку/PRD" + ], + "produces": [ + "функциональная спецификация с goals/non-goals/метриками" + ], + "constraints": [ + "под-навык зонтика product-management (продуктовые церемонии)", + "НЕ dev-issues (CCPM); конкурентный бриф ≠ marketing:competitive-brief" + ], + "preview-form": "outline", + "defaults": [ + "write-spec — для оформления требований в структурный документ" + ], + "key-decisions": [ + "scope: goals и non-goals" + ], + "acceptance-criteria": [ + "спека структурна и измерима" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } +} diff --git a/docs/registry/nodes.yaml b/docs/registry/nodes.yaml index c8a7b90..3d06593 100644 --- a/docs/registry/nodes.yaml +++ b/docs/registry/nodes.yaml @@ -975,18 +975,16 @@ nodes: tooling_section: "§4.16 #41" install: "vendored в .claude/skills/ccpm/" - - id: "#42" - name: "product-management" - slug: "product-management" + - id: "#42a" + name: "write-spec" + slug: "product-management:write-spec" category: "off-phase" subcategory: "project-management" status: "active" dormancy_reason: null - capabilities: "Плагин для продуктовых церемоний: написание спецификаций (`/write-spec`), обновление роадмапа (`/roadmap-update`), анализ метрик (`/metrics-review`), конкурентные брифы." + capabilities: "Функциональная спецификация/PRD из проблемы: goals/non-goals/метрики. Входная точка продуктовых церемоний." triggers: - {keyword: "prd", weight: 1.0} - - {keyword: "роадмап", weight: 1.0} - - {keyword: "метрики", weight: 1.0} - {keyword: "продуктовые церемонии", weight: 1.0} - {classification: "planning", weight: 1.0} boundaries: [] @@ -995,6 +993,106 @@ nodes: tooling_section: "§4.17 #42" install: "claude plugin install product-management@knowledge-work-plugins" + - id: "#42b" + name: "roadmap-update" + slug: "product-management:roadmap-update" + category: "off-phase" + subcategory: "project-management" + status: "active" + dormancy_reason: null + capabilities: "Обновление дорожной карты (Now/Next/Later), переприоритизация инициатив." + triggers: + - {keyword: "роадмап", weight: 1.0} + boundaries: [] + chain_membership: [] + attributes: + tooling_section: "§4.17 #42" + + - id: "#42c" + name: "metrics-review" + slug: "product-management:metrics-review" + category: "off-phase" + subcategory: "project-management" + status: "active" + dormancy_reason: null + capabilities: "Разбор продуктовых метрик: тренды, scorecard, рекомендации." + triggers: + - {keyword: "метрики", weight: 1.0} + boundaries: [] + chain_membership: [] + attributes: + tooling_section: "§4.17 #42" + + - id: "#42d" + name: "product-brainstorming" + slug: "product-management:product-brainstorming" + category: "off-phase" + subcategory: "project-management" + status: "active" + dormancy_reason: null + capabilities: "Открытая проработка продуктовых идей и направлений (sparring-partner)." + triggers: [] + boundaries: [] + chain_membership: [] + attributes: + tooling_section: "§4.17 #42" + + - id: "#42e" + name: "sprint-planning" + slug: "product-management:sprint-planning" + category: "off-phase" + subcategory: "project-management" + status: "active" + dormancy_reason: null + capabilities: "План спринта под ёмкость команды: scope, оценки, цели, P0 vs stretch." + triggers: [] + boundaries: [] + chain_membership: [] + attributes: + tooling_section: "§4.17 #42" + + - id: "#42f" + name: "stakeholder-update" + slug: "product-management:stakeholder-update" + category: "off-phase" + subcategory: "project-management" + status: "active" + dormancy_reason: null + capabilities: "Апдейт стейкхолдерам под аудиторию (exec/eng/customer) и cadence." + triggers: [] + boundaries: [] + chain_membership: [] + attributes: + tooling_section: "§4.17 #42" + + - id: "#42g" + name: "synthesize-research" + slug: "product-management:synthesize-research" + category: "off-phase" + subcategory: "project-management" + status: "active" + dormancy_reason: null + capabilities: "Синтез сырого research (интервью/опросы/тикеты) в структурированные инсайты и рекомендации." + triggers: [] + boundaries: [] + chain_membership: [] + attributes: + tooling_section: "§4.17 #42" + + - id: "#42h" + name: "product-competitive-brief" + slug: "product-management:competitive-brief" + category: "off-phase" + subcategory: "project-management" + status: "active" + dormancy_reason: null + capabilities: "Продуктовый конкурентный бриф: позиционирование, gap, угрозы. (Не путать с marketing:competitive-brief.)" + triggers: [] + boundaries: [] + chain_membership: [] + attributes: + tooling_section: "§4.17 #42" + - id: "#43" name: "deptrac" slug: "deptrac" @@ -2167,7 +2265,7 @@ chains: name: "project management chain" sequence: - "#41" - - "#42" + - "product-management:write-spec" - "#3" L10: diff --git a/docs/registry/splitting-inventory.md b/docs/registry/splitting-inventory.md index 4efe406..7ad2cb4 100644 --- a/docs/registry/splitting-inventory.md +++ b/docs/registry/splitting-inventory.md @@ -113,9 +113,9 @@ | claude-md-management (2) | ✅ DONE | e98ba1e (pushed) | | superpowers (14) | ✅ DONE | 5a7c5c2 (pushed) | | plugin-dev (7) | ✅ DONE | ded5372 (pushed) | -| adr-kit (2: adr, judge) | ✅ DONE | этот коммит | -| hookify (1–2) | ⬜ | | -| product-management (8) | ⬜ | | +| adr-kit (2: adr, judge) | ✅ DONE | f01f5b8 (pushed) | +| hookify (1–2) | ⏸ развилка владельцу (slug hookify:hookify кривой) | | +| product-management (8) | ✅ DONE | этот коммит | | design-plugin (7) | ⬜ | | | marketing-plugin (8) | ⬜ | | | operations (8) | ⬜ | | diff --git a/tools/registry-load.test.mjs b/tools/registry-load.test.mjs index e642366..cad933e 100644 --- a/tools/registry-load.test.mjs +++ b/tools/registry-load.test.mjs @@ -5,9 +5,9 @@ import { loadRegistry, clearCache, findByClassification, findByKeyword, findActi describe('registry-load', () => { beforeEach(() => clearCache()); - it('loads registry (110 nodes: разворачивание #33/#19/#57/#36 комков 18.06.2026)', () => { + it('loads registry (117 nodes: разворачивание #33/#19/#57/#36/#42 комков 18.06.2026)', () => { const r = loadRegistry(); - expect(r.nodes).toHaveLength(110); + expect(r.nodes).toHaveLength(117); expect(r.version).toBe('0.1.0'); }); @@ -46,9 +46,9 @@ describe('registry-load', () => { it('findActiveNodes excludes non-active (nodes.yaml registry)', () => { const r = loadRegistry(); const active = findActiveNodes(r); - // 110 nodes total; #1 historic, #17 dormant, #44/#50/#54/#67/#82/#83 deferred; - // развёрнуты комки: #33→2, #19→14, #57→7, #36 adr-kit→2 (active +1+13+6+1) → 102 active - expect(active).toHaveLength(102); + // 117 nodes total; #1 historic, #17 dormant, #44/#50/#54/#67/#82/#83 deferred; + // развёрнуты комки: #33→2, #19→14, #57→7, #36→2, #42 pm→8 (active +1+13+6+1+7) → 109 active + expect(active).toHaveLength(109); expect(active.map(n => n.id)).toContain('#18'); expect(active.map(n => n.id)).toContain('#19a'); expect(active.map(n => n.id)).not.toContain('#1');