diff --git a/README.md b/README.md index 30aca89..955b660 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Скилл для Claude, который превращает неструктурированное описание процесса в читаемую BPMN 2.0 схему (Camunda 7, Platform) и — по запросу — в Excel-спецификацию, сверенную со схемой. -**Версия:** 2.3.0 +**Версия:** 2.3.1 **Автор:** Andrey Zagreev — [@zagreev](https://t.me/zagreev) **Лицензия:** [MIT](#лицензия) **Целевая платформа:** Camunda 7 (Platform) @@ -20,7 +20,7 @@ - [Требования](#требования) - [Установка](#установка) - [Типовой сценарий использования](#типовой-сценарий-использования) -- [Как работает внутри (9 шагов)](#как-работает-внутри-9-шагов) +- [Как работает внутри (11 шагов)](#как-работает-внутри-11-шагов) - [Что внутри архива](#что-внутри-архива) - [Что гарантировано](#что-гарантировано) - [Чего скилл НЕ делает](#чего-скилл-не-делает) @@ -50,7 +50,7 @@ - Все подписи на русском, продуктовые и бренд-названия сохраняются как есть - Текстовые аннотации на схеме для SLA, регуляторных ссылок, бизнес-правил и открытых вопросов - Автоматический выбор топологии (пулы / лэйны / плоская) и декомпозиции (иерархия с подпроцессами, если узлов больше 9) -- 7 блокирующих проверок корректности XML + 10 рекомендательных best practices перед показом +- 7 блокирующих проверок корректности XML + 11 рекомендательных best practices перед показом **После одобрения схемы** — Excel-спецификация: @@ -115,7 +115,7 @@ Clarification Wizard — шаг перед генерацией BPMN. Он ищ **Что происходит в degraded mode (MCP недоступен, скилл работает на snapshot):** - Генерация XML, валидация, Excel-экспорт идут как обычно - Перед вопросом одобрения схемы скилл явно предупреждает, что использован snapshot -- В заголовке XML указано `` +- В заголовке XML указано `` - Перед prod-деплоем рекомендуется активировать MCP и перегенерировать, либо свериться с live docs вручную ## Установка @@ -135,7 +135,7 @@ Clarification Wizard — шаг перед генерацией BPMN. Он ищ 3. Claude отдаёт: - Классификацию (отрасль, участники, выбранная топология, выбранная декомпозиция) - XML-код схемы (или несколько файлов, если иерархия) - - Отчёт о прохождении 7 валидаций + статус 10 рекомендательных best practices + - Отчёт о прохождении 7 валидаций + статус 11 рекомендательных best practices - Список открытых вопросов, которые нужно уточнить - Вопрос: «Схема корректна? После подтверждения могу выгрузить спецификацию в Excel» 4. Открываете XML в Camunda Modeler, проверяете @@ -143,7 +143,7 @@ Clarification Wizard — шаг перед генерацией BPMN. Он ищ 6. Если всё ок — пишете «да» / «выгружай» / «сделай таблицу» 7. Claude генерирует `.xlsx`, прогоняет 9 проверок сверки, показывает статус-отчёт, отдаёт файл -## Как работает внутри (9 шагов) +## Как работает внутри (11 шагов) 0. **Классификация входа** — text-only, mixed input, zeebe namespace, unsupported format или invalid XML 1. **Загрузка документации Camunda** через MCP — синтаксис BPMN, extension-элементы, паттерны пулов, аннотации, сабпроцессы @@ -152,7 +152,7 @@ Clarification Wizard — шаг перед генерацией BPMN. Он ищ 3. **Выбор топологии** по правилу: несколько организаций → collaboration с пулами; один бизнес с ролями → пул с лэйнами; один актёр → плоский процесс 4. **Выбор декомпозиции** по правилу 7±2: больше 9 узлов или 2+ уровня вложенных шлюзов → overview + drill-down подпроцессы 5. **Генерация BPMN XML** в UTF-8, с русскими подписями, BPMN DI, Camunda extensions, текстовыми аннотациями для SLA / регуляторки / открытых вопросов -6. **Валидация XML**: 7 блокирующих проверок (well-formedness, BPMN schema, структурная целостность + infinite loop + event references + boundary events + duplicate IDs + subprocess types + data objects, message flows + collaboration, Camunda 7 executability, DI completeness, соответствие русского языка) + 10 рекомендательных best practices (technical ID naming, happy path, business vs technical errors, sentence case и др.) +6. **Валидация XML**: 7 блокирующих проверок (well-formedness, BPMN schema, структурная целостность + infinite loop + event references + boundary events + duplicate IDs + subprocess types + data objects, message flows + collaboration, Camunda 7 executability, DI completeness, соответствие русского языка) + 11 рекомендательных best practices (technical ID naming, happy path, business vs technical errors, sentence case и др.) 7. **Показ пользователю**: классификация + XML + отчёт валидации + открытые вопросы + вопрос про Excel 8. **Excel-выгрузка** (только после одобрения схемы) в UTF-8, с цветовой кодировкой типов BPMN, скрытой колонкой `_BPMN_ID` для сверки 9. **Сверка Excel ↔ BPMN** — 9 проверок: количество узлов, ID-маппинг, названия, лэйны, правила на шлюзах, итоги на end-событиях, аннотации, порядок выполнения, UTF-8. Статус показывается перед выдачей файла @@ -164,8 +164,8 @@ bpmn-process-modeler/ ├── README.md — это описание ├── SKILL.md — основная логика скилла └── references/ - ├── bpmn-patterns.md — 8 готовых XML-паттернов (approval loop, 4-eyes, параллельное согласование, таймерная эскалация, компенсация, B2B-обмен сообщениями, DMN, event-based gateway) - ├── camunda-knowledge-snapshot.md — fallback-snapshot Camunda docs на случай недоступности MCP (~1170 строк, версия 1.0 от 2026-04-23); BPMN 2.0 + Camunda 7 extensions + DI + best practices + методология построения (happy path first, explicit modeling, декомпозиция, anti-patterns) + ├── bpmn-patterns.md — 10 готовых XML-паттернов (approval loop, 4-eyes, параллельное согласование, таймерная эскалация, компенсация, B2B-обмен сообщениями, DMN, event-based gateway, documentation pattern, glossary annotation pattern) + ├── camunda-knowledge-snapshot.md — fallback-snapshot Camunda docs на случай недоступности MCP (~1170 строк, версия 1.0 от 2026-04-26); BPMN 2.0 + Camunda 7 extensions + DI + best practices + методология построения (happy path first, explicit modeling, декомпозиция, anti-patterns) ├── industry-patterns/ — отраслевые паттерны, по одному файлу на domain; модель читает ТОЛЬКО соответствующий файл на Step 2 │ ├── fintech-patterns.md — 17 процессов: KYC / KYB / Seller KYB / BaaS onboarding / Payment auth / 3DS / P2P / Chargeback / Refund / BNPL / Collection / Leasing / Factoring / Seller lending / RBF (Merchant Cash Advance) / Settlement-payout / Regulatory reporting │ ├── marketplace-patterns.md — 5 процессов: Order-to-cash / Returns / Pick-Pack-Ship / Seller discovery / Cross-border marketplace @@ -179,7 +179,7 @@ bpmn-process-modeler/ ├── clarification-wizard.md — правила Wizard: missing-facts categories, вопросы, assumption mode ├── input-classification.md — Step 0 routing: text-only, mixed input, rejects, invalid XML ├── reuse-id-rules.md — правила сохранения ID при обновлении существующего BPMN - ├── validation-checklist.md — 7 блокирующих проверок XML с Python-кодом + 10 рекомендательных best practices (на основе Camunda bpmnlint и docs) + ├── validation-checklist.md — 7 блокирующих проверок XML с Python-кодом + 11 рекомендательных best practices (на основе Camunda bpmnlint и docs) ├── excel-spec-template.md — 9-колоночный шаблон + worked example на BNPL └── reconciliation-procedure.md — 9 проверок сверки Excel и BPMN с openpyxl-кодом ``` @@ -229,7 +229,7 @@ bpmn-process-modeler/ **Camunda MCP не подключается.** Проверьте в Settings → Connectors, что URL указан точно: `https://camunda-docs.mcp.kapa.ai`. Перезапустите чат, иногда connector-сессия истекает. Если проблема сохраняется — убедитесь, что у вас актуальный план Claude.ai (MCP доступен на Pro и выше). **Если MCP недоступен — скилл продолжит работать на локальном snapshot** (`references/camunda-knowledge-snapshot.md`), но перед prod-деплоем рекомендуется активировать MCP и перегенерировать XML, либо свериться с live docs. Скилл явно предупредит в выводе, когда работает в degraded mode. -**XML не открывается в Camunda Modeler — «пустой холст».** Обычно означает проблему с BPMN DI. Запросите у Claude: «Проверь DI в XML — не все ли узлы имеют BPMNShape?». Скилл пересоберёт DI-секцию. Если проблема сохраняется — приложите XML и скриншот Modeler в чат, Claude попросит фрагмент ошибки. +**XML не открывается в Camunda Modeler — «пустой холст».** Обычно означает проблему с BPMN DI. Запросите у Claude: «Проверь DI в XML — все ли узлы имеют BPMNShape?». Скилл пересоберёт DI-секцию. Если проблема сохраняется — приложите XML и скриншот Modeler в чат, Claude попросит фрагмент ошибки. **Excel частично на английском.** Не должно случаться — 10-я проверка reconciliation ловит это и автоматически правит. Если всё же пролетело: укажите Claude, какие именно ячейки на английском (лист, колонка, значение) — перегенерирует с корректным переводом. @@ -252,7 +252,26 @@ bpmn-process-modeler/ ## Changelog -### v2.3.0 — дата релиза TBD +### v2.3.1 — 27 апреля 2026 + +Documentation hygiene patch. + +- Исправлены даты snapshot Camunda docs в README: `2026-04-23` → `2026-04-26` (2 места) — соответствует фактическому `snapshot_date` в `SKILL.md` frontmatter и `references/camunda-knowledge-snapshot.md`. +- Исправлено количество BPMN-паттернов в описании архива: `8 готовых XML-паттернов` → `10` (добавлены `documentation pattern` и `glossary annotation pattern` в перечисление). +- Исправлено количество рекомендательных best practices в актуальных секциях: `10` → `11` (включён ранее пропущенный `naming and readability` — секция 8 в `validation-checklist.md`). Затронуты разделы «Что делает», «Как работает внутри» Step 6, «Типовой сценарий», Changelog v2.0. Исторические секции v1.0 / v1.1 не изменялись. +- Заголовок «Как работает внутри (9 шагов)» → «(11 шагов)» — учтены добавленные в v2.3.0 Step 0 (Input classification) и Step 1.5 (Clarification Wizard). +- Исправлена опечатка в Troubleshooting: «не все ли узлы имеют BPMNShape?» → «все ли узлы имеют BPMNShape?» (лишнее «не» меняло смысл фразы на противоположный). +- Подставлена фактическая дата релиза v2.3.0: `27 апреля 2026` (вместо placeholder `TBD`) в README и RELEASE.md. +- Добавлено 6 новых release-тестов в `tests/release/test_metadata.py`, защищающих от drift между README и source-of-truth файлами: + - `test_changelog_release_date_is_filled` — блокирует публикацию, если дата текущей версии в changelog осталась `TBD` или `<дата...>`. + - `test_historic_changelog_dates_are_filled` — защищает исторические секции changelog от регрессии на `TBD` после merge conflict. + - `test_readme_snapshot_date_matches_frontmatter` — синхронизирует обе упоминания snapshot-даты в README со `snapshot_date` из `SKILL.md` frontmatter. + - `test_readme_bpmn_patterns_count_matches_source` — синхронизирует число «N готовых XML-паттернов» в README с фактическим числом `## N.` секций в `references/bpmn-patterns.md`. + - `test_readme_best_practices_count_matches_validation_checklist` — синхронизирует число «N рекомендательных best practices» в актуальных секциях README с числом optional-секций (≥ 8) в `references/validation-checklist.md`. + - `test_release_md_has_current_version_section` — требует наличие pre-release checklist для текущей версии в `RELEASE.md`. +- Поведение генерации BPMN, валидации, Wizard, reuse-ID и Excel-выгрузки не изменялось. + +### v2.3.0 — 27 апреля 2026 Wizard-only minor release. @@ -313,7 +332,7 @@ Release hygiene patch. Валидация и качество: - 7 блокирующих проверок XML: well-formedness, BPMN schema conformance, structural integrity (10 подпунктов: sequence flows, start/end events, reachability, gateway fan-in/out, infinite loops, event references, boundary events, duplicate IDs, subprocess types, data objects), message flows и collaboration, Camunda 7 executability, DI completeness, language conformance -- 10 рекомендательных best practices (на основе Camunda bpmnlint и docs): technical ID naming, business-side event labels, business vs technical errors, happy path emphasis, sentence case, один executable process в collaboration, alignment имени файла с process ID, unused resources, empty process, circular call activity detection +- 11 рекомендательных best practices (на основе Camunda bpmnlint и docs): naming and readability, technical ID naming, business-side event labels, business vs technical errors, happy path emphasis, sentence case, один executable process в collaboration, alignment имени файла с process ID, unused resources, empty process, circular call activity detection - 9 проверок reconciliation Excel ↔ BPMN перед выдачей файла: node count parity, ID-level mapping, name parity, lane/pool parity, gateway decision rules, end event outcomes, annotation coverage, execution order sanity, UTF-8 integrity Excel-спецификация: diff --git a/RELEASE.md b/RELEASE.md index 7329967..b339241 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -28,7 +28,25 @@ Release tags must be signed with an SSH signing key registered on the releasing ## Pre-release checklist -### v2.3.0 — release date TBD +### v2.3.1 — release date TBD + +Release scope: documentation hygiene patch (no behavior changes). + +Required local checks: +- `python3 -m unittest discover -s tests/release -v` +- All existing release tests must pass. +- The 6 new tests in `tests/release/test_metadata.py` must pass for v2.3.1: + - `test_changelog_release_date_is_filled` + - `test_historic_changelog_dates_are_filled` + - `test_readme_snapshot_date_matches_frontmatter` + - `test_readme_bpmn_patterns_count_matches_source` + - `test_readme_best_practices_count_matches_validation_checklist` + - `test_release_md_has_current_version_section` + +No new test modules in v2.3.1. Existing module `tests/release/test_metadata.py` +gets six new test methods. + +### v2.3.0 — 2026-04-27 Release scope: - Step 0 input classification diff --git a/SKILL.md b/SKILL.md index 79e9731..0c65d6a 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: bpmn-process-modeler description: Converts prose, transcripts, notes, process memos, or mixed text + existing BPMN into valid BPMN 2.0 XML for Camunda Platform 7, with Russian labels and optional Excel specification. Use when the user asks to model, draw, map, diagram, convert to BPMN/Camunda/.bpmn/XML, create pools and lanes, export an Excel process table, уточни процесс перед моделированием, обнови существующий BPMN, дополни BPMN, расширь схему, or генерируй с допущениями. The skill classifies input, loads Camunda docs, runs the Wizard when needed, validates XML, asks for approval, then exports a reconciled UTF-8 Excel specification. -version: 2.3.0 +version: 2.3.1 snapshot_version: 1.0 snapshot_date: 2026-04-26 snapshot_expiry: 2026-10-23 diff --git a/tests/release/test_metadata.py b/tests/release/test_metadata.py index 54e9f53..0a01628 100644 --- a/tests/release/test_metadata.py +++ b/tests/release/test_metadata.py @@ -41,6 +41,199 @@ def test_changelog_has_current_version_section(self): expected = rf"^### v{re.escape(frontmatter['version'])}\b" self.assertIsNotNone(re.search(expected, readme, re.MULTILINE)) + def test_changelog_release_date_is_filled(self): + """Current version's changelog section must have a real release date.""" + frontmatter = parse_skill_frontmatter() + readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") + pattern = rf"^### v{re.escape(frontmatter['version'])} — (.+)$" + match = re.search(pattern, readme, re.MULTILINE) + self.assertIsNotNone( + match, + f"Current version v{frontmatter['version']} section not found " + f"in README changelog with em-dash separator", + ) + date_field = match.group(1).strip().lower() + forbidden_markers = ( + "tbd", + "дата релиза tbd", + "release date tbd", + "<дата", + ) + for marker in forbidden_markers: + self.assertNotIn( + marker, + date_field, + f"Release date for v{frontmatter['version']} contains " + f"placeholder {marker!r}: {match.group(1).strip()!r}. " + f"Fill in the actual date before tagging.", + ) + + def test_historic_changelog_dates_are_filled(self): + """All published changelog sections must have real dates (no TBD).""" + frontmatter = parse_skill_frontmatter() + current_version = frontmatter["version"] + readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") + + section_pattern = r"^### v(\d+\.\d+(?:\.\d+)?) — (.+)$" + sections = re.findall(section_pattern, readme, re.MULTILINE) + self.assertGreater( + len(sections), + 0, + "No version sections found in README changelog", + ) + + forbidden = ("tbd", "дата релиза tbd", "release date tbd") + for version, date_field in sections: + if version == current_version: + # Current version is covered by test_changelog_release_date_is_filled + continue + normalized = date_field.strip().lower() + for marker in forbidden: + self.assertNotIn( + marker, + normalized, + f"Historic section v{version} has placeholder " + f"{marker!r}: {date_field.strip()!r}", + ) + + def test_readme_snapshot_date_matches_frontmatter(self): + """README snapshot dates must match SKILL.md frontmatter snapshot_date.""" + frontmatter = parse_skill_frontmatter() + snapshot_date = frontmatter["snapshot_date"] + readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") + + # Pattern 1: degraded mode XML comment in Requirements section + comment_matches = list(re.finditer( + r"snapshot v1\.0 \((\d{4}-\d{2}-\d{2})\)", + readme, + )) + self.assertGreater( + len(comment_matches), + 0, + "README missing 'snapshot v1.0 (YYYY-MM-DD)' marker", + ) + for match in comment_matches: + self.assertEqual( + match.group(1), + snapshot_date, + f"README XML-comment snapshot date {match.group(1)!r} does " + f"not match SKILL.md frontmatter snapshot_date " + f"{snapshot_date!r}", + ) + + # Pattern 2: archive contents description "версия 1.0 от YYYY-MM-DD" + archive_matches = list(re.finditer( + r"версия 1\.0 от (\d{4}-\d{2}-\d{2})", + readme, + )) + self.assertGreater( + len(archive_matches), + 0, + "README missing 'версия 1.0 от YYYY-MM-DD' marker", + ) + for match in archive_matches: + self.assertEqual( + match.group(1), + snapshot_date, + f"README archive snapshot date {match.group(1)!r} does not " + f"match SKILL.md frontmatter snapshot_date {snapshot_date!r}", + ) + + def test_readme_bpmn_patterns_count_matches_source(self): + """README claim 'N готовых XML-паттернов' must equal actual `## N.` count.""" + readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") + patterns_doc = (REPO_ROOT / "references" / "bpmn-patterns.md").read_text( + encoding="utf-8", + ) + + # Count top-level numbered patterns: "## N. Title" + actual_count = len(re.findall(r"^## \d+\. ", patterns_doc, re.MULTILINE)) + self.assertGreater( + actual_count, + 0, + "references/bpmn-patterns.md has no numbered '## N.' sections", + ) + + # README claim + claim_match = re.search(r"(\d+) готовых XML-паттернов", readme) + self.assertIsNotNone( + claim_match, + "README missing 'N готовых XML-паттернов' claim", + ) + claimed_count = int(claim_match.group(1)) + + self.assertEqual( + claimed_count, + actual_count, + f"README claims {claimed_count} BPMN patterns, but " + f"references/bpmn-patterns.md has {actual_count} numbered sections", + ) + + def test_readme_best_practices_count_matches_validation_checklist(self): + """Current README sections must claim correct number of optional best practices. + + Optional best practices are sections numbered >= 8 in + references/validation-checklist.md (sections 1-7 are blocking checks). + Section 9 uses '###' instead of '##' in the source file, so the regex + accepts both heading levels. + + Historic changelog sections (v1.0, v1.1) are intentionally excluded + from the check because their counts reflect the state at that release. + """ + readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") + checklist = (REPO_ROOT / "references" / "validation-checklist.md").read_text( + encoding="utf-8", + ) + + # Count all top-level numbered sections in checklist, then filter to >= 8. + all_section_numbers = re.findall( + r"^#{2,3} (\d+)\. ", + checklist, + re.MULTILINE, + ) + actual_count = sum(1 for n in all_section_numbers if int(n) >= 8) + self.assertGreater( + actual_count, + 0, + "references/validation-checklist.md has no optional sections (>= 8)", + ) + + # Cut off README at first historic section marker `### v1.` so we only + # check current claims. + cutoff_match = re.search(r"^### v1\.", readme, re.MULTILINE) + current_part = readme[: cutoff_match.start()] if cutoff_match else readme + + claims = re.findall( + r"(\d+) рекомендательных best practices", + current_part, + ) + self.assertGreater( + len(claims), + 0, + "No 'N рекомендательных best practices' claims found in current " + "README sections", + ) + + for claim in claims: + self.assertEqual( + int(claim), + actual_count, + f"Current README section claims {claim} best practices, but " + f"references/validation-checklist.md has {actual_count} " + f"optional sections (>= 8)", + ) + + def test_release_md_has_current_version_section(self): + """RELEASE.md must have a pre-release checklist section for current version.""" + frontmatter = parse_skill_frontmatter() + release_md = (REPO_ROOT / "RELEASE.md").read_text(encoding="utf-8") + expected = rf"^### v{re.escape(frontmatter['version'])}\b" + self.assertIsNotNone( + re.search(expected, release_md, re.MULTILINE), + f"RELEASE.md missing pre-release checklist section for " + f"v{frontmatter['version']}", + ) + def test_snapshot_metadata_is_valid(self): frontmatter = parse_skill_frontmatter() for key in ("snapshot_version", "snapshot_date", "snapshot_expiry"):