diff --git a/todo/backlog/TASK-feat-di-check-programmatic-registration.todo.md b/todo/backlog/TASK-feat-di-check-programmatic-registration.todo.md new file mode 100644 index 00000000..442bcca0 --- /dev/null +++ b/todo/backlog/TASK-feat-di-check-programmatic-registration.todo.md @@ -0,0 +1,135 @@ +--- +type: feat +created: 2026-08-31 15:22:55 (1788164575) +due: +started: +completed: +cancelled: +value: V1 +complexity: C3 +priority: P3 +cost_plan: +cost_fact: +depends_on: +epic: +author: Аналитик (codex-cli) +assignee: +branch: +pr: +status: backlog +--- + +# TASK-feat-di-check-programmatic-registration: Поддержать программную регистрацию сервисов в DI-проверке + +## 0. Простое описание (Human Brief) + +### Проблема простыми словами (Problem) +- `coding-standard-di-check` считает проверку успешно завершённой, когда не находит поддерживаемый импорт сервисов в YAML, хотя проект может регистрировать те же сервисы программно. +- Из-за такого ложного зелёного результата разработчик и CI не узнают, что исключения несервисных классов вообще не были проверены. + +### Варианты или путь решения (Solution Sketch) +- Определить универсальный машиночитаемый контракт, через который любой программный регистратор описывает пространства имён сервисов и исключённые пути, и научить команду анализировать этот контракт. +- До реализации сравнить альтернативы контракта и зафиксировать обоснованный вариант; решение не должно зависеть от внутренних классов конкретного проекта-потребителя или от Symfony `resource`/`GlobResource`. + +### Ожидаемый результат (Expected Result) +- Проекты с YAML- и программной регистрацией получают одинаково достоверный контроль исключений, а невозможность применить проверку больше не выглядит как успешное прохождение. + +## 1. Концепция и Цель (Concept and Goal) + +### История (User Story) +> **User Story:** Как разработчик проекта-потребителя с программной регистрацией сервисов, я хочу передавать DI-проверке структуру регистраций в стабильном формате, чтобы CI действительно проверял исключения и не сообщал об успехе без анализа. + +### Цель по SMART (Goal) +- В одной будущей итерации выбрать и реализовать универсальный машиночитаемый контракт программной регистрации для `coding-standard-di-check`, подтвердить его изолированным сценарием проекта-потребителя и сохранить поведение существующего YAML-сценария. + +## 2. Контекст и Границы (Context and Scope) + +- **Где делаем:** `bin/coding-standard-di-check`, код проверки в `src/Di/`, тесты и фикстуры проекта-потребителя в `tests/`, пользовательская инструкция в `README.md`, правило в `docs/conventions/modules/configuration.md`; при необходимости — конфигурация и подключение через `bin/coding-standard-init`. +- **Текущее поведение:** версия `coding-standard-di-check` v0.31.0 распознаёт только namespace-import с `resource`/`exclude` в `services.yaml` и `services.yml`; без него печатает `WARN "no module services.yaml with a resource import found — DI configuration check skipped"` и завершает работу с кодом `0`. +- **Подтверждённый потребительский сценарий:** `prikotov/task-orchestrator` использует PHAR-safe программный обход каталогов; исходными данными служат пространство имён сервиса и исключённые пути, а Symfony `resource`/`GlobResource` намеренно не применяется из-за несовместимости с `phar://`. +- **Границы (Out of Scope):** добавление фиктивных YAML `resource` ради прохождения проверки; подавление или скрытие предупреждения; изменение архитектуры, регистраторов или источника данных проекта-потребителя; привязка публичного решения к классам `task-orchestrator`. + +## 3. Требования, MoSCoW (Requirements) + +### 🔴 Обязательно (Must Have) +- [ ] Исследовать варианты универсального машиночитаемого описания программных регистраций и исключений; сравнить как минимум расширяемость, стабильность публичного контракта, безопасное обнаружение и чтение из корня потребителя, а также работу с обычными путями и `phar://`. +- [ ] Зафиксировать и реализовать выбранный контракт: формат и версию данных, способ обнаружения, правила разрешения относительных путей, обязательные поля, валидацию и диагностику некорректного ввода. +- [ ] Отклонять невалидный контракт с ненулевым кодом выхода и полезной диагностикой как минимум для неподдерживаемой версии и отсутствующего обязательного поля; не игнорировать такой источник и не подменять ошибку успешной проверкой других источников. +- [ ] Не требовать от контракта ссылок на классы или интерфейсы конкретного потребителя; на входе должны быть переносимые данные о пространствах имён, корнях сканирования и исключениях. +- [ ] Сохранить семантику проверки несервисных суффиксов и ошибочных конструкторных зависимостей для описанных программных регистраций. +- [ ] Добавить автоматический сценарий проекта-потребителя, запускающий публичную команду из корня изолированного проекта с программной регистрацией: корректные исключения, утечка несервисного класса и запрещённая конструкторная зависимость. +- [ ] Отличать успешную проверку от неприменимой или не выполненной: отсутствие распознанной конфигурации не должно давать ложный `OK`/успешный CI-результат; состояние и код выхода должны быть машиночитаемыми и документированными. +- [ ] Сохранить обратную совместимость существующих корректного и ошибочного YAML-сценариев `resource`/`exclude` и покрыть её регрессионными тестами. +- [ ] Для смешанного проекта объединять регистрации из YAML- и программных источников в один набор и проверять их за один запуск; одинаковые нормализованные регистрации дедублировать, нарушения в любом источнике считать ошибкой, а невалидность любого источника завершает всю проверку ошибкой. +- [ ] Обновить `README.md` и `docs/conventions/modules/configuration.md`: описать контракт, коды/состояния результата, YAML-совместимость, ограничения и PHAR-safe сценарий без привязки к конкретному проекту. +- [ ] Сохранить и покрыть тестом подключение `coding-standard-di-check` через `coding-standard-init`; если выбранный контракт требует создаваемой конфигурации или иного подключения, добавить их без дубликатов при повторном запуске. + +### 🟡 Желательно (Should Have) +- [ ] Переиспользовать единое внутреннее представление регистраций для YAML- и программного источников, не дублируя правила DI-проверки. + +### 🟢 Опционально (Could Have) +- Нет. + +### ⚫ Не будем делать (Won't Have) +- [ ] Создавать фиктивные `services.yaml` или YAML `resource`, не используемые контейнером приложения. +- [ ] Подавлять текущий warning или оставлять пропуск проверки успешным способом устранения проблемы. +- [ ] Переводить потребителя с программной регистрации на Symfony `resource`/`GlobResource` либо менять его модульную архитектуру. +- [ ] Вводить публичную зависимость от `ModuleServiceRegistrar`, `ModuleInterface`, `RecursiveDirectoryIterator` или иных классов конкретной реализации потребителя. + +## 4. План реализации (Implementation Plan) + +1. [ ] Зафиксировать матрицу текущих исходов команды: валидный YAML, ошибочный YAML, программная регистрация и отсутствие применимой конфигурации. +2. [ ] Сравнить варианты контракта (например, декларативный файл, адаптер-команда или PHP-provider) и оформить решение с обнаружением, форматом данных, версионированием, моделью безопасности и кодами результата. +3. [ ] Преобразовать YAML и новый источник в общее представление регистраций и применить существующие правила анализа. +4. [ ] Создать изолированную фикстуру проекта-потребителя для программной регистрации и регрессионные YAML-сценарии; проверить успех, оба вида нарушения, неприменимость, неподдерживаемую версию контракта и отсутствие обязательного поля. +5. [ ] Добавить смешанный сценарий с YAML- и программными регистрациями: подтвердить объединение источников, дедубликацию одинаковых регистраций и ошибку при нарушении или невалидном контракте в любом источнике. +6. [ ] Обновить README, конвенцию и идемпотентный init wiring, затем выполнить полный проверочный контур. + +## 5. Критерии приёмки (Definition of Done) + +- [ ] Публичный контракт описывает программную регистрацию без знания классов проекта-потребителя и пригоден для автоматического чтения командой. +- [ ] Фикстура программной регистрации с корректными исключениями проходит; утечка несервисного класса и его внедрение в конструктор завершаются ошибкой с полезной диагностикой. +- [ ] Сценарий без распознанного или применимого источника не завершается как успешно проверенный; тест фиксирует сообщение, состояние и код выхода. +- [ ] Контракт с неподдерживаемой версией и контракт без обязательного поля завершаются ненулевым кодом выхода; тесты фиксируют отдельную полезную диагностику для каждого случая. +- [ ] Прежние YAML fixtures сохраняют ожидаемые коды выхода и диагностику. +- [ ] В смешанном проекте YAML- и программные регистрации объединяются и проверяются за один запуск, точные нормализованные дубликаты не анализируются повторно, а нарушение или невалидный контракт в любом источнике завершает проверку ошибкой. +- [ ] PHAR-safe сценарий не требует Symfony `resource`, `GlobResource` или обхода `phar://` средствами Symfony. +- [ ] `coding-standard-init` продолжает идемпотентно подключать команду и, если это требуется выбранным контрактом, создаёт необходимую конфигурацию без дубликатов. +- [ ] README и конвенция согласованно описывают настройку, ограничения и интерпретацию результата. +- [ ] `composer check` проходит; проверка выполнена на TasK без изменения отслеживаемых файлов проекта. + +## 6. Самопроверка (Verification) + +```bash +composer check +php vendor/bin/todo-md validate todo/backlog/TASK-feat-di-check-programmatic-registration.todo.md +``` + +## 7. Риски и зависимости (Risks and Dependencies) + +- Формат должен быть достаточно общим для разных программных регистраторов, но не превращаться в копию Symfony-конфигурации. +- Корни и исключения могут использовать обычные пути, относительные пути и `phar://`; нормализация не должна менять смысл данных. +- Проверка запускается отдельно от приложения. Исполняемый provider или адаптер-команда допустимы только как явно включаемый доверенный режим с описанной моделью угроз; безопасный декларативный способ не должен запускать bootstrap или произвольный код потребителя. +- Изменение кода выхода для неприменимой проверки может выявить ранее скрытые CI-сбои; нужен явный миграционный сценарий в документации. +- Для ручной регрессионной проверки требуется доступ к локальной копии TasK; эта внешняя проверка не заменяет автоматическую изолированную фикстуру. +- Приоритет, запрошенный пользователем как `P4` («пока не сильно актуально»), отображён в `P3` — минимальный поддерживаемый проектом уровень; задача помещена в backlog. +- Текущая ценность зафиксирована как `V1`: улучшение не блокирует текущую работу и нужно ограниченному числу проектов с программной регистрацией, поэтому пользователь явно отложил его. При этом риск сохраняется: такие проекты могут получать ложный успешный результат DI-проверки и пропускать нарушения в CI. + +## 8. Источники (Sources) + +- [Конфигурация модулей](../../docs/conventions/modules/configuration.md) +- [Проверка несервисных классов в DI](../../README.md#проверка-несервисных-классов-в-di) +- Подтверждённый сценарий: `prikotov/task-orchestrator`, программная PHAR-safe регистрация сервисов (контекст постановки, без зависимости на его классы). + +## 9. Комментарии (Comments) + +- Исходная версия наблюдаемого поведения: `coding-standard-di-check` v0.31.0. +- Задача намеренно отложена как неактуальная сейчас; реализацию до перевода из backlog не начинать. + +## История изменений (Change History) + +| Дата | Автор (роль) | Изменение | +| :--- | :--- | :--- | +| 2026-08-31 15:22:55 (1788164575) | Аналитик (codex-cli) | Создание и полное описание backlog-задачи | +| 2026-08-31 15:27:43 (1788164863) | Аналитик (codex-cli) | Самопроверка: исправлены относительные ссылки, устранена развилка «анализ или реализация», уточнены контракт, тестовые сценарии и границы init | +| 2026-08-31 15:38:13 (1788165493) | Аналитик (codex-cli) | Учтены замечания ревью: уточнены YAML-источники, согласованы `V1`/`P3` и дата, добавлены невалидные контракты и обязательное объединение источников |