Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions todo/backlog/TASK-feat-di-check-programmatic-registration.todo.md
Original file line number Diff line number Diff line change
@@ -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` и дата, добавлены невалидные контракты и обязательное объединение источников |
Loading