# ТЗ — ORCH-069: QG-0 title-лимит → параметр ORCH_QG0_TITLE_MAX (дефолт 200) Work Item ID: ORCH-069 ## 1. Задействованные модули `src/` | Файл | Текущее состояние | Требуемое изменение | |------|-------------------|---------------------| | `src/config.py` | `Settings(BaseSettings)`, `env_prefix = "ORCH_"` (строки 4, 347-349) | Добавить поле `qg0_title_max: int = 200` с комментарием-описанием. | | `src/webhooks/plane.py` | `_qg0_errors` (строки 357-367), хардкод `if len(name) > 80:` (строка 362); `from ..config import settings` уже импортирован (строка 11) | Заменить хардкод `> 80` на `> settings.qg0_title_max`; текст ошибки — динамический с подстановкой лимита. | Других модулей изменение не затрагивает. ## 2. Изменение config.py Добавить в класс `Settings` новое поле (рядом с другими `ORCH_*` группами, рекомендуется отдельный блок с комментарием): ```python # ORCH-069: QG-0 upper title-length limit (entry gate _qg0_errors). The 80-char # cap was a hygiene limit, not structural (slug is cut to [:30] independently, # DB title TEXT is unbounded). Configurable via env ORCH_QG0_TITLE_MAX; default # 200 (was hardcoded 80). Invalid/empty value -> default (graceful, no crash). qg0_title_max: int = 200 ``` - Env-переменная: `ORCH_QG0_TITLE_MAX` (автоматически из `env_prefix = "ORCH_"`). - Тип `int`, дефолт `200`. ## 3. Изменение `_qg0_errors` (src/webhooks/plane.py) Текущий блок (строки 362-363): ```python if len(name) > 80: errors.append("Title слишком длинный (максимум 80 символов)") ``` Требуемое: ```python if len(name) > settings.qg0_title_max: errors.append( f"Title слишком длинный (максимум {settings.qg0_title_max} символов)" ) ``` Требования: - Лимит берётся из `settings.qg0_title_max` (динамически, на каждый вызов — чтобы тесты могли подменять значение через мок/патч settings). - Текст ошибки содержит актуальное число лимита (для AC-1/AC-2: текст упоминает 200 / 120 соответственно). - Нижний лимит заголовка `< 5` (строка 360-361) и проверка description `< 20` (строка 364-365) — **не трогать**. - Сигнатура `_qg0_errors(name, description) -> list` не меняется. ## 4. Поведение границы (точная семантика) - Условие fail — строго `len(name) > limit`. То есть `len == limit` → PASS, `len == limit + 1` → FAIL. - При дефолте: 200 символов → PASS, 201 → FAIL. - При `ORCH_QG0_TITLE_MAX=120`: 120 → PASS, 121 → FAIL. ## 5. Graceful-обработка невалидного значения (требование AC-3) Требование: невалидное/отсутствующее `ORCH_QG0_TITLE_MAX` → используется дефолт 200, процесс не падает. Нюанс для архитектора/разработчика: `pydantic_settings` по умолчанию при непарсящемся в `int` значении env (например `ORCH_QG0_TITLE_MAX=abc` или пустая строка) выбрасывает `ValidationError` на инстанцировании `Settings()` — т.е. падение на старте процесса. Это противоречит требованию graceful. Реализация должна обеспечить, что: - отсутствие переменной → дефолт 200 (это стандартное поведение, ОК «из коробки»); - пустая строка / нечисловое значение → дефолт 200 без исключения. Способ (на усмотрение архитектора, без предписания со стороны аналитика) — например field-validator с `mode="before"`, который при невалидном входе возвращает дефолт. Конкретный механизм фиксируется в ADR на стадии architecture. ## 6. Изменения API Нет. Эндпоинты не меняются. ## 7. Изменения схемы БД Нет. `tasks.title TEXT` остаётся без ограничения длины. ## 8. Новые QG checks Нет. Реестр `QG_CHECKS` и `STAGE_TRANSITIONS` не меняются. QG-0 — не зарегистрированный stage-gate, а inline-валидация входа (`_qg0_errors`), её контракт сохраняется. ## 9. Артефакты pipeline, которые должны быть созданы/обновлены - `.env.example` — добавить `ORCH_QG0_TITLE_MAX=200` с комментарием. - `.env.staging.example` — добавить `ORCH_QG0_TITLE_MAX` (дефолт/комментарий). - `CHANGELOG.md` — запись об ORCH-069. - README-таблица конфигов / `CLAUDE.md` — обновить при наличии релевантной таблицы параметров (по требованию reviewer; документация = golden source). - Юнит-тесты (`tests/`) — см. `04-test-plan.yaml`. ## 10. Обратная совместимость - Дефолт 200 > прежних 80 → все ранее проходившие заголовки проходят и теперь. - Поведение при не заданном env идентично «как было», но с порогом 200 вместо 80. - Изменение чисто аддитивное; откатов/миграций не требует.