8e8f06ebe7
Три группы накопившихся auto-правок (НЕ ручные): 1. markdownlint --fix auto-format (~25 .md в docs/superpowers/, docs/security/marketing-vet.md, docs/adr/015, docs/deploy/lkomega-runbook): MD031/MD032 (blank lines around fence/list) + MD004 (bullet markers `+`→`-`). Содержательных текстовых правок 3: ADR-015 bullet, sprint5d-cleanup bullet, router-discipline trailing space. 2. lefthook 2.1.6 → 2.1.8 (package.json + lock): patch-bump, авто-резолвил npm. 3. Observer runtime (docs/observer/): episodes-2026-05.jsonl +420 строк (текущая активность мозга), STATUS.md regen, .pii-counters / .read-counter тики, +2026-05-24-brain-retro.md note. Цель — разблокировать merge feat/llm-first-router → main (этап 0 плана постановки в боевой). Содержание ветки не трогает.
322 lines
21 KiB
Markdown
322 lines
21 KiB
Markdown
# Anthropic Dev-Tooling Formalization — Implementation Plan
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. Git-commit-bearing tasks — **controller-only (Sonnet)**, never delegated to Haiku-subagent (Sprint 3F/5/6 lessons).
|
||
|
||
**Goal:** Формализовать 5 Anthropic-плагинов уже включённых в `~/.claude/settings.json` user-level (skill-creator, plugin-dev, hookify, claude-code-setup, context7) — добавить как позиции #56–#60 в две новые off-phase подкатегории Tooling: **authoring-tooling** (#56-#58) + **dev-support** (#59-#60). Закрыть 🔴-конфликт `hookify_plugin ↔ hk_pre_claude` правилом pre-check в PSR_v1 R10.1.
|
||
|
||
**Architecture:** retrospective formalization paired со spec ADR-010. Никакой кодовой регрессии — только текстовая нормативка (4 файла) + карта (5 узлов refresh + 5 новых edge) + memory + ADR. Worktree уже создан (`feat/anthropic-dev-tooling` от origin/main `b40f2c8`). Спека: `docs/superpowers/specs/2026-05-18-anthropic-dev-tooling-formalization-design.md`.
|
||
|
||
> **Rebase-девиация (исполнение 18.05.2026):** во время эпика origin/main ушёл `b40f2c8`→`781a59c` — параллельная сессия запушила parallel-sessions §15 (Pravila v1.27, CLAUDE.md v2.14). Ветка ребейзнута на `781a59c`; коммиты Pravila/CLAUDE.md дропнуты из rebase (`--skip`) и пересозданы поверх §15. Целевые версии перенумерованы: **Pravila v1.27→v1.28, CLAUDE.md v2.14→v2.15** (Tooling v2.14 / PSR_v1 v3.13 — без изменений, §15 их не трогал). Шаги ниже отражают исходный план — фактические версии нормативки см. §9 CLAUDE.md / §13 Pravila.
|
||
|
||
**Tech Stack:** Tooling Прил. Н / PSR_v1 / Pravila / CLAUDE.md / ADR-010 / automation-graph.html / memory. Pre-push — `bin/gitleaks.exe detect --no-banner` (full-history) + `npx lychee --offline --no-progress .` (или из главного дерева во избежание квирка #92).
|
||
|
||
---
|
||
|
||
## Tool Identity & Decisions (verified 2026-05-18)
|
||
|
||
| # | Plugin | Marketplace | Category | Sub-skills/agents | Role |
|
||
|---|---|---|---|---|---|
|
||
| 56 | `skill-creator@claude-plugins-official` | anthropics/claude-plugins-official | authoring-tooling | skill `skill-creator` | Создание standalone скилов с performance-метриками |
|
||
| 57 | `plugin-dev@claude-plugins-official` | anthropics/claude-plugins-official | authoring-tooling | 8 skills (plugin-structure, agent-development, skill-development, command-development, hook-development, mcp-integration, plugin-settings) + 2 agents (agent-creator, plugin-validator, skill-reviewer) | Конструктор marketplace-плагинов |
|
||
| 58 | `hookify@claude-plugins-official` | anthropics/claude-plugins-official | authoring-tooling | skills (hookify, configure, list, help, writing-rules) + agent (conversation-analyzer) | Генератор хуков из анализа транскриптов |
|
||
| 59 | `claude-code-setup@claude-plugins-official` | anthropics/claude-plugins-official | dev-support | skill `claude-automation-recommender` | Анализатор кодовой базы + рекомендации |
|
||
| 60 | `context7@claude-plugins-official` | anthropics/claude-plugins-official | dev-support | MCP `plugin_context7_context7` (tools `query-docs`, `resolve-library-id`) | Актуальная документация библиотек |
|
||
|
||
**Locked decisions (D1-D8):** см. спеку §Decisions.
|
||
|
||
---
|
||
|
||
## Task 1: Pre-flight — baseline, snapshot
|
||
|
||
**Files:** none modified (read-only)
|
||
|
||
- [ ] **Step 1: Verify worktree state**
|
||
|
||
```bash
|
||
cd ".claude/worktrees/anthropic-dev-tooling"
|
||
git status --short # должен быть clean (spec+plan еще не закоммичены)
|
||
git rev-parse --short HEAD # должен быть b40f2c8
|
||
git branch --show-current # должен быть feat/anthropic-dev-tooling
|
||
```
|
||
|
||
- [ ] **Step 2: Snapshot the live Tooling counter (NUM1)**
|
||
|
||
```bash
|
||
grep -E "^\*\*Прил\. Н" docs/Tooling_v8_3.md | head -1
|
||
grep -E "Итого формализованных позиций.*55" docs/Tooling_v8_3.md
|
||
```
|
||
|
||
Expected: «v2.13», count «55». Если иное (главное origin/main продвинулось дальше) — **остановка**, ребейз worktree на актуальный origin/main, перенумеровка позиций.
|
||
|
||
- [ ] **Step 3: Snapshot map state**
|
||
|
||
```bash
|
||
grep -c "id: 'skill_creator'" docs/automation-graph.html
|
||
grep -c "id: 'plugin_dev'" docs/automation-graph.html
|
||
grep -c "id: 'hookify_plugin'" docs/automation-graph.html
|
||
grep -c "id: 'claude_setup'" docs/automation-graph.html
|
||
grep -c "id: 'context7'" docs/automation-graph.html
|
||
```
|
||
|
||
Each expected = 1. Если 0 — узел не существует, плана недостаточно, нужен add (не refresh). **NB:** claude-code-setup имеет map-id `claude_setup` (verified Task 1, 2026-05-18) — не `cc_setup`.
|
||
|
||
- [ ] **Step 4: Stage spec + plan**
|
||
|
||
```bash
|
||
git add docs/superpowers/specs/2026-05-18-anthropic-dev-tooling-formalization-design.md \
|
||
docs/superpowers/plans/2026-05-18-anthropic-dev-tooling-formalization.md
|
||
git commit -m "docs(adt): brainstorming spec + implementation plan — Anthropic dev-tooling formalization"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 2: ADR-010 — Anthropic dev-tooling decision
|
||
|
||
**Files:** `docs/adr/ADR-010-anthropic-dev-tooling.md` (create)
|
||
|
||
- [ ] **Step 1:** Создать ADR по шаблону ADR-009 (discovery-interview) с секциями:
|
||
- Status: Accepted (date 2026-05-18)
|
||
- Context: 5 плагинов в settings.json без формализации; L1-паттерн повторяется (UPM/21st, Sentry/Redis); карта iter7 audit имеет узлы, но без правил
|
||
- Decision: split на 2 подкатегории (D1); правила D2–D5; ADR-010 как умолчание для retrospective формализации крупнее 2 позиций
|
||
- Consequences: + closes L1 для 5 плагинов; + закрывает 🔴 hookify; − добавляет 5 позиций к 55 (рост реестра)
|
||
- References: spec link, ADR-004/005/006/007/008/009 как прецеденты
|
||
|
||
- [ ] **Step 2:** Commit
|
||
|
||
```bash
|
||
git add docs/adr/ADR-010-anthropic-dev-tooling.md
|
||
git commit -m "docs(adr): ADR-010 — Anthropic dev-tooling formalization decision"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 3: Tooling Прил. Н — 2 подкатегории + 5 позиций
|
||
|
||
**Files:** `docs/Tooling_v8_3.md`
|
||
|
||
- [ ] **Step 1:** §0 счётчик 55→60. Шапка v2.13 → v2.14. Версия в любых других местах файла где упоминается — sync.
|
||
|
||
- [ ] **Step 2:** Добавить §4.31 «authoring-tooling» с подпунктами:
|
||
- §4.31.1 #56 skill-creator (роль, install через marketplace, граница D3, конфликт-аудит SC1: standalone vs plugin-dev; SC2: self-authored — direct Edit, не trigger; SC3: bus-factor — Anthropic Verified)
|
||
- §4.31.2 #57 plugin-dev (роль, 8 sub-skills, граница D3, конфликт-аудит PD1-PD3: marketplace vs standalone; PD2: вендоренные/self-authored — не trigger; PD3: 8 sub-skills overlap внутри plugin'а)
|
||
- §4.31.3 #58 hookify (роль, generator, **HK1 hard-rule pre-check на коллизию с economy/skill-discipline 6-компонентной архитектурой; HK2: только по явному /hookify; HK3: hookify_plugin ↔ hk_pre_claude конфликт — закрыт правилом**)
|
||
|
||
- [ ] **Step 3:** Добавить §4.32 «dev-support» с подпунктами:
|
||
- §4.32.1 #59 claude-code-setup (роль, /claude-automation-recommender, read-only, CCS1: рекомендации фильтровать R0/R10.1)
|
||
- §4.32.2 #60 context7 (роль, MCP-доки, граница D4 с WebFetch/WebSearch, CTX1: первый выбор для known library docs; CTX2: не trigger при WebSearch без библиотеки)
|
||
|
||
- [ ] **Step 4:** §13 (история версий) +entry v2.14: «Anthropic dev-tooling integration — формализация 5 плагинов (#56-#60) в 2 новых off-phase подкатегориях».
|
||
|
||
- [ ] **Step 5:** Commit
|
||
|
||
```bash
|
||
git add docs/Tooling_v8_3.md
|
||
git commit -m "docs(adt): Tooling Прил. Н v2.14 — register #56-#60 (authoring-tooling + dev-support)"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 4: PSR_v1 R10.1 — +5 строк + hookify-special note
|
||
|
||
**Files:** `docs/Plugin_stack_rules_v1.md`
|
||
|
||
- [ ] **Step 1:** R10.1 Блок 1 (`enabledPlugins`) +5 строк по образцу adr-kit / architecture-patterns / operations / product-management / design:
|
||
- skill-creator (роль / когда инвокировать — «при создании нового standalone скила; вендоренное/self-authored — direct Edit»)
|
||
- plugin-dev (роль / когда — «при разработке собственного marketplace-плагина; не для модификации вендоренного/self-authored»)
|
||
- hookify (роль / когда — «только по явному `/hookify`; **обязательный pre-check на коллизию с existing хуками в `~/.claude/settings.json`**; перезапись economy/skill-discipline хуков запрещена»)
|
||
- claude-code-setup (роль / когда — «по запросу или превентивно; рекомендации **фильтровать R0/R10.1**; не устанавливать без явного согласования»)
|
||
- context7 (роль / когда — «**первый выбор для документации известной библиотеки**; fallback на WebFetch при конкретном URL, WebSearch — без знания URL/библиотеки»)
|
||
|
||
- [ ] **Step 2:** Note блока (после строк): «Подкатегории **authoring-tooling** (#56-#58) и **dev-support** (#59-#60) — не UI → вне фильтров R6.0/R6.1 и R14 pipeline. Регулируются PSR_v1 R10.1 Блок 1 как infrastructure (по образцу claude-md-management #33).»
|
||
|
||
- [ ] **Step 3:** §0 (история) +entry: «v3.13 — Anthropic dev-tooling: R10.1 Блок 1 +5 строк + hookify pre-check hard-rule. Связано: Tooling v2.14, Pravila v1.27, CLAUDE.md v2.14.»
|
||
|
||
- [ ] **Step 4:** Шапка PSR v3.12 → v3.13.
|
||
|
||
- [ ] **Step 5:** Commit
|
||
|
||
```bash
|
||
git add docs/Plugin_stack_rules_v1.md
|
||
git commit -m "docs(adt): PSR_v1 v3.13 — R10.1 Блок 1 +5 строк (skill-creator/plugin-dev/hookify/claude-code-setup/context7) + hookify pre-check"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 5: Pravila §13.2 — +2 абзаца
|
||
|
||
**Files:** `docs/Pravila_raboty_Claude_v1_1.md`
|
||
|
||
- [ ] **Step 1:** §13.2 +абзац «Off-phase authoring-tooling»: 3 позиции (#56 skill-creator, #57 plugin-dev, #58 hookify), категория для создания Claude-артефактов; не UI → вне R6/R14; **hookify — особое правило pre-check (PSR_v1 R10.1 hookify-строка hard-rule)**.
|
||
|
||
- [ ] **Step 2:** §13.2 +абзац «Off-phase dev-support»: 2 позиции (#59 claude-code-setup read-only анализатор; #60 context7 MCP-документация для known libraries — первый выбор); не UI → вне R6/R14.
|
||
|
||
- [ ] **Step 3:** §0 +entry v1.27 («Anthropic dev-tooling: 13-я и 14-я off-phase подкатегории»).
|
||
|
||
- [ ] **Step 4:** Шапка Pravila v1.26 → v1.27.
|
||
|
||
- [ ] **Step 5:** Commit
|
||
|
||
```bash
|
||
git add docs/Pravila_raboty_Claude_v1_1.md
|
||
git commit -m "docs(adt): Pravila v1.27 — §13.2 +Off-phase authoring-tooling + dev-support"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 6: CLAUDE.md — §3/§1/§3.3/§6/§9 (worktree-эксцепшн §5 п.10)
|
||
|
||
**Files:** `CLAUDE.md` (прямой Edit в worktree — прецедент A11/C10/discovery, claude-md-management не наводится на worktree-копию), `docs/CHANGELOG_claude_md.md`
|
||
|
||
- [ ] **Step 1:** §3 title «55» → «60». §1 priority chain row 2b «55» → «60».
|
||
|
||
- [ ] **Step 2:** §3.3 +5 строк #56-#60 по образцу #51-#55 (operations / process-modeling / process-analysis / n8n / discovery). Каждая строка: ID-плагина, marketplace, категория (authoring-tooling/dev-support), роль, когда инвокировать, регламент-cross-ref на PSR R10.1 + Pravila §13.2. Для hookify — **bold pre-check note**.
|
||
|
||
- [ ] **Step 3:** §3.3 footer count 55→60 + двенадцатая→четырнадцатая off-phase подкатегория (authoring-tooling + dev-support).
|
||
|
||
- [ ] **Step 4:** §0 cross-refs row Pravila v1.26→v1.27 / PSR v3.12→v3.13 / Tooling v2.13→v2.14.
|
||
|
||
- [ ] **Step 5:** §6 +абзац «2026-05-18 Anthropic dev-tooling integration: формализованы #56–#60 в 2 новых off-phase подкатегориях…».
|
||
|
||
- [ ] **Step 6:** §9 +entry v2.14.
|
||
|
||
- [ ] **Step 7:** Шапка CLAUDE.md v2.13 → v2.14.
|
||
|
||
- [ ] **Step 8:** CHANGELOG_claude_md.md +entry v2.14.
|
||
|
||
- [ ] **Step 9:** Commit
|
||
|
||
```bash
|
||
git add CLAUDE.md docs/CHANGELOG_claude_md.md
|
||
git commit -m "docs(adt): CLAUDE.md v2.14 + CHANGELOG — register #56-#60 (worktree direct Edit, §5 п.10 эксцепшн)"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 7: Карта — refresh узлов + лейблы правил + edge
|
||
|
||
**Files:** `docs/automation-graph.html`
|
||
|
||
- [ ] **Step 1:** Обновить лейблы 4 узлов-правил: pravila v1.27, claude_md v2.14, psr_v1 v3.13, tooling v2.14. NODE_META.changed для всех 4 → 18.05.2026.
|
||
|
||
- [ ] **Step 2:** Обновить nd() 5 узлов (skill_creator, plugin_dev, hookify_plugin, claude_setup, context7):
|
||
- `desc` — добавить номер «#NN» в начало
|
||
- `limits` — добавить ключевые ограничения из R10.1 (для hookify — обязательный pre-check; для plugin-dev — вендоренное не трогать; для context7 — первый выбор для known library docs)
|
||
- `reportsTo` — добавить «PSR_v1 R10.1 Блок 1 / Pravila §13.2 / Tooling §4.31-4.32»
|
||
|
||
- [ ] **Step 3:** Добавить 5 рёбер `psr_v1 → {skill_creator, plugin_dev, hookify_plugin, claude_setup, context7}` тип «R10.1 блок 1» (по образцу `psr_v1→adr_kit`/`arch_patterns`/`ccpm`/...). EDGE_DETAILS — поля type «правило», when «всегда», transfers «coverage», mandatory «обязательно», rule «PSR_v1 R10.1 Блок 1». EDGES_NORMAL +5.
|
||
|
||
- [ ] **Step 4:** Конфликт-edge `hookify_plugin ↔ hk_pre_claude` (строка 1844): тип `RED` → `GREEN`, rule «D2 R10.1 hookify pre-check (ADR-010)». Конфликт-классификация в legend footer: 🔴1/⚫3/🟢7 → 🔴0/⚫3/🟢8.
|
||
|
||
- [ ] **Step 5:** Обновить tooling-узел nd() count «70 / 50» → «75 / 60» (75 — это позиции tooling + ruflo-плагины, 60 — формализованных).
|
||
|
||
- [ ] **Step 6:** NODE_META.changed → 18.05.2026 для 5 узлов.
|
||
|
||
- [ ] **Step 7:** Smoke (Playwright headless или ручной visual в Edge): NODES.length=124, EDGES.length=135 (130+5), 0 JS-ошибок, hookify_plugin конфликт стал 🟢.
|
||
|
||
- [ ] **Step 8:** Commit
|
||
|
||
```bash
|
||
git add docs/automation-graph.html
|
||
git commit -m "feat(map): adt — register #56-#60 in nd(), 5 edges to psr_v1, hookify conflict 🔴→🟢, rule labels v2.14"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 8: Memory updates
|
||
|
||
**Files:** `MEMORY.md` + `feedback_plugin_paired_stack.md` + `project_state.md` + `reference_archive.md` + `project_automation_map.md` + new `project_anthropic_dev_tooling.md`
|
||
|
||
- [ ] **Step 1:** Создать `project_anthropic_dev_tooling.md` (новый файл) — краткий summary эпика: 5 позиций, 2 подкатегории, decisions D1-D8, key learnings (формализация L1-паттерна для Anthropic-плагинов, прецедент).
|
||
|
||
- [ ] **Step 2:** `MEMORY.md` +pointer на новый memory-файл.
|
||
|
||
- [ ] **Step 3:** `feedback_plugin_paired_stack.md` — добавить блок «Обновление 2026-05-18 — Anthropic dev-tooling (новые off-phase подкатегории authoring-tooling + dev-support)». Active versions bump до v2.14/v3.13/v1.27/v2.14. Off-phase подкатегорий теперь 14 (было 12).
|
||
|
||
- [ ] **Step 4:** `project_state.md` — branch state и HEAD update (после push в Task 9).
|
||
|
||
- [ ] **Step 5:** `reference_archive.md` — version refs sync до v2.14/v3.13/v1.27/v2.14.
|
||
|
||
- [ ] **Step 6:** `project_automation_map.md` — добавить entry «2026-05-18 Anthropic dev-tooling: 5 узлов refresh + 5 edge + hookify конфликт 🔴→🟢».
|
||
|
||
- [ ] **Step 7:** Commit
|
||
|
||
```bash
|
||
git add ../../../memory/ # путь от worktree до user-level memory — see memory location convention
|
||
# NB: memory лежит в C:\Users\Administrator\.claude\projects\…\memory — НЕ в репозитории. Memory files правятся через Write, не через git. Commit относится только к репозиторию.
|
||
```
|
||
|
||
**Replan:** memory file commits — N/A. Memory updates делаются через Write, без git. Эта задача не имеет commit-step, только Write-операции.
|
||
|
||
---
|
||
|
||
## Task 9: Pre-push + push
|
||
|
||
**Files:** none (verification + push)
|
||
|
||
- [ ] **Step 1:** Pre-commit verification (последний раз — должен быть зелёным от atomic commits в Task 1-7):
|
||
|
||
```bash
|
||
cd ".claude/worktrees/anthropic-dev-tooling"
|
||
./bin/gitleaks.exe protect --staged --no-banner # 0 leaks ожидается
|
||
```
|
||
|
||
Если квирк #97 «lefthook not in PATH в worktree» — пропустить lefthook, gitleaks вызывать вручную.
|
||
|
||
- [ ] **Step 2:** Pre-push gitleaks full history:
|
||
|
||
```bash
|
||
./bin/gitleaks.exe detect --no-banner # должен быть 0 leaks
|
||
```
|
||
|
||
- [ ] **Step 3:** Pre-push lychee — **запускать из главного дерева** (`c:/моя/проекты/портал crm/Документация/`, не из worktree — квирк #92, относительные пути ломаются из worktree):
|
||
|
||
```bash
|
||
cd "c:/моя/проекты/портал crm/Документация"
|
||
./bin/lychee.exe --offline --no-progress . 2>&1 | tail -5
|
||
# ожидается 0 broken
|
||
```
|
||
|
||
- [ ] **Step 4:** Push:
|
||
|
||
```bash
|
||
cd ".claude/worktrees/anthropic-dev-tooling"
|
||
git push origin feat/anthropic-dev-tooling:main
|
||
```
|
||
|
||
Pattern `<ветка>:main` — разрешённый в `~/.claude/settings.json` `Bash(git push origin main:*)` (хотя тут он `<ветка>:main`, проверить permissions; если deny — ручной push заказчиком).
|
||
|
||
- [ ] **Step 5:** Verify push:
|
||
|
||
```bash
|
||
git fetch origin
|
||
git rev-parse origin/main # должен совпадать с HEAD worktree
|
||
```
|
||
|
||
- [ ] **Step 6:** Update `project_state.md` post-push с новым origin/main HEAD SHA.
|
||
|
||
- [ ] **Step 7:** Сообщить заказчику: «эпик ADT закрыт, push прошёл, новые версии v2.14/v3.13/v1.27/v2.14 на origin/main».
|
||
|
||
---
|
||
|
||
## Verification Plan
|
||
|
||
После каждой task (atomic commit) — короткая локальная проверка:
|
||
|
||
- Task 3: `grep "Итого формализованных позиций.*60" docs/Tooling_v8_3.md` → 1 match
|
||
- Task 4: `grep -c "skill-creator\|plugin-dev\|hookify\|claude-code-setup\|context7" docs/Plugin_stack_rules_v1.md` → ≥5
|
||
- Task 5: `grep "authoring-tooling\|dev-support" docs/Pravila_raboty_Claude_v1_1.md` → ≥2
|
||
- Task 6: `grep "v2.14" CLAUDE.md` → ≥2 (шапка + §0/§9)
|
||
- Task 7: smoke карты — Playwright или Edge
|
||
|
||
Перед claim «эпик закрыт» — invoke `superpowers:verification-before-completion`.
|
||
|
||
---
|
||
|
||
## Risk register (post-execution)
|
||
|
||
- **Push permissions:** `Bash(git push origin main:*)` allowed; `<ветка>:main` — under same pattern? Verify Task 9 Step 4. Если deny — pause, ручной push заказчиком.
|
||
- **lychee из worktree:** квирк #92 — relative paths ломаются. **Mitigation:** Step 3 из главного дерева.
|
||
- **Wholesale rebase нужен:** если за время выполнения origin/main продвинется (parallel session) — Task 9 Step 4 fail, нужен rebase + retry. Mitigation: эпик короткий, parallel sessions сейчас нет (single Claude Code instance).
|
||
- **Memory file path mistake** в Task 8: memory лежит на user-level, не в репозитории — учтено в Task 8 Replan.
|
||
- **adr-judge job 9 in lefthook:** ADR-010 проходит regex-валидацию? Verify Task 2.
|