mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
@@ -1,73 +1,194 @@
|
||||
# SPEC-REVIEW-399-r1
|
||||
# SPEC-REVIEW-399-r2
|
||||
|
||||
- Issue: https://github.com/Matysh/houseplan-card/issues/399
|
||||
- ТЗ: `docs/specs/399-backend-gate-honesty.md`
|
||||
- Материал: SHA `a1d7e0da55322ff4309f139e22bc9a165b780f58` (ветка `issue/399-backend-gate-honesty`, единственный коммит поверх `dev`)
|
||||
- Заход: r1 (первый), блокирующих циклов израсходовано 0/4
|
||||
- Трек: полный (issue не помечен `small`/`trivial`; спецификация сама называет причину — три несвязанные поверхности, что нарушает критерий «одна поверхность» §5)
|
||||
- Материал: SHA `6d229c66f1e25460b6cc7efcbb67a88a723a3acb` (ветка
|
||||
`issue/399-backend-gate-honesty`, ревизия 2 поверх `dev`)
|
||||
- Заход: **r2**, не r1 — см. «Расхождение с заданием раунда» ниже
|
||||
- Блокирующих циклов израсходовано: 1/4 (израсходован r1, жёлтый; зелёный
|
||||
цикла не тратит, #227)
|
||||
- Трек: полный (не изменился, наследуется из r1)
|
||||
- Вердикт: **жёлтый**
|
||||
|
||||
## Скоуп
|
||||
## Расхождение с заданием раунда (нужно проговорить явно)
|
||||
|
||||
Три независимые правки бэкенд-гейта, все — класс B (`test/**`, `.github/workflows/**`, `pyproject.toml`, `tests_backend/requirements.txt`), продуктовый код (`src/**`, `custom_components/**/*.py`) не затронут:
|
||||
Задание на этот прогон присвоило заходу номер r1 и указало
|
||||
«блокирующих циклов израсходовано 0 из 4». Это не соответствует
|
||||
фактическому состоянию:
|
||||
|
||||
1. пин `home-assistant-frontend` в `tests_backend/requirements.txt` не выведен из констрейнтов закреплённого `homeassistant`, а назначен вручную;
|
||||
2. `[tool.ruff] include` в `pyproject.toml` шире, чем реально линтуемое в CI дерево;
|
||||
3. `test/validate-workflow.test.mjs:216` пропускает файл без проверки, если в нём не нашлось ни имени пакета, ни пути к файлу пинов — то есть регресс к неверсионированной установке пройдёт гейт молча.
|
||||
- `docs/reviews/SPEC-REVIEW-399-r1.md` уже существует в репозитории
|
||||
(коммит `627a5359`) — это реальный, опубликованный документ ревью, а не
|
||||
черновик;
|
||||
- на issue #399 уже есть комментарий-вердикт `Вердикт: жёлтый · заход r1 ·
|
||||
блокирующих циклов 0/4 · High: 0 · Medium: 1 → в задаче`, оставленный
|
||||
ревьюером;
|
||||
- автор ответил на этот вердикт комментарием «Ревизия 2 — Medium закрыт» и
|
||||
запушил `6d229c66 docs: #399 spec revision 2 per SPEC-REVIEW-399-r1`,
|
||||
который редактирует ровно ту находку, которую назвал r1.
|
||||
|
||||
## Как проверялось
|
||||
То есть цикл r1 реально состоялся и стоил бюджета (жёлтый, 1/4). Присвоение
|
||||
этому прогону имени `r1` создало бы `docs/reviews/SPEC-REVIEW-399-r1.md` поверх
|
||||
уже существующего документа — ровно тот сценарий, от которого предостерегает
|
||||
инструкция «два документа с одинаковым номером затёрли бы друг друга».
|
||||
Поэтому документ и вердикт этого прогона используют номер **r2**, полученный
|
||||
из фактического состояния issue и репозитория, а не из присланного
|
||||
заголовка задания. Далее применяется процедура §2.9/§2.10 для «не первого»
|
||||
цикла: делта, закрытие r1, наследование.
|
||||
|
||||
- прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` (полностью, включая §2.9/§2.10 про делту — не применимо: это r1, предыдущего раунда нет);
|
||||
- прочитано тело issue #399 (комментариев нет);
|
||||
- сверены все три технические претензии ТЗ с текущим состоянием репозитория построчно:
|
||||
- `tests_backend/requirements.txt` — подтверждено: `home-assistant-frontend==20260826.1` (строка 29 в файле) соседствует с `homeassistant==2026.8.3`, комментарий рядом объясняет только выбор `phcc`/`homeassistant`, но не `home-assistant-frontend`;
|
||||
- `pyproject.toml:5` — подтверждено: `include` содержит ровно три дерева, как написано в ТЗ;
|
||||
- `.github/workflows/validate.yml:787-788` — подтверждено: шаг «Линт бэкенда» гоняет только `custom_components/houseplan`;
|
||||
- `test/validate-workflow.test.mjs:210-222` — подтверждено дословно, включая номер строки 216 и точный текст условия `continue`; подтверждено также, что цикл проверки идёт по жёстко заданному списку `['validate.yml', 'mutation-gate.yml']`, а не по каталогу `.github/workflows/*.yml`;
|
||||
- `git grep "pip install" .github/workflows/*.yml` — только `validate.yml` и `mutation-gate.yml` ставят зависимости через pip; остальные пять workflow (`announce`, `docs-screenshots`, `performance`, `process`, `publish-prerelease`, `release-zip`, `release`) не участвуют вовсе — сегодня список из двух файлов исчерпывающий;
|
||||
- история `#392` (`a3dcee52`, `eb5aa2a0`, `56986748`) реальна и соответствует контексту, на который ссылается ТЗ;
|
||||
- формат мутантов (`backend-pins-check-opts-out`, `lint-scope-drifts`) сверен с существующими записями `scripts/mutation-gate.mjs` — совпадает по структуре (`id`, kebab-case), не выдумка;
|
||||
- сверен прецедент `docs/specs/398-sysmodules-guard-scope.md` — тот же формат «Сценарий: разработчик / Пользователь продукта — ничего» уже принят для инфраструктурных гейт-задач этого типа (прошёл ревью ТЗ ранее), так что в #399 это не дефект.
|
||||
- внешний факт «`package_constraints.txt` тега `2026.8.3` требует `home-assistant-frontend==20260729.7`» (сердце находки M3) независимо перепроверить не удалось — в этой среде нет доступа к сети (`WebFetch` заблокирован отсутствием разрешения). Это ограничение разбора, а не довод против ТЗ: AC1 обязывает доказательство без сети (снимок в репозитории + комментарий с источником), так что сам контракт не зависит от того, смог ли ревьюер ТЗ сходить в интернет — сверка достоверности исходного числа ляжет на код-ревью, где оно будет видно построчно.
|
||||
## Дельта, которая является предметом этого раунда
|
||||
|
||||
## Находки
|
||||
`git diff a1d7e0da..6d229c66 -- docs/specs/399-backend-gate-honesty.md`
|
||||
— ровно три хунка:
|
||||
|
||||
### Medium (в скоупе) — AC5 не фиксирует, какой набор файлов должен быть «отказом», а какой — «явно допустимым пропуском»
|
||||
1. строка «Ревизия» в шапке (2, с указанием, что правка отвечает на
|
||||
SPEC-REVIEW-399-r1);
|
||||
2. абзац контракта в разделе «(3) Low «в»» — добавлено явное описание
|
||||
«второй половины дыры» (жёстко заданный массив `['validate.yml',
|
||||
'mutation-gate.yml']`) и переформулирован контракт: перебор идёт по
|
||||
**каталогу** `.github/workflows/*.yml`, для каждого файла ровно два
|
||||
исхода (ставит зависимости бэкенда → пины; не ставит → доказывается явно,
|
||||
не через отсутствие подстроки);
|
||||
3. **AC5** переписан под тот же контракт: доказательство — тест на
|
||||
синтетическом каталоге, где новый (третий) workflow ставит `pip install
|
||||
pytest` без версий и обязан краснеть; плюс зафиксирован факт «сегодня в
|
||||
репозитории девять workflow, установку python-зависимостей делают два».
|
||||
|
||||
**Файл**: `docs/specs/399-backend-gate-honesty.md`, AC5 (строки 125-128) и контракт п.(3) (строки 81-83).
|
||||
Ничего за пределами этих трёх хунков не менялось: разделы про M3 (пин
|
||||
фронтенда) и Low «а» (скоуп ruff), скоуп/не-скоуп, AC1–AC4/AC6, риски,
|
||||
откат, release-артефакты — байт в байт те же, что видел r1.
|
||||
|
||||
**В чём разрыв**: контракт п.(3) сформулирован широко — «если workflow ставит зависимости бэкенда, он обязан делать это из файла пинов; если не ставит вовсе — это тоже утверждение, которое надо доказать, а не предположить». Это читается как требование накрыть **все** файлы `.github/workflows/*.yml`, а не только два, которые проверка сегодня перебирает (`for (const file of ['validate.yml', 'mutation-gate.yml'])` — жёстко заданный массив, не обход каталога).
|
||||
## Закрытие раунда r1
|
||||
|
||||
AC5 при этом требует лишь «перечисление файлов, которые проверка обходит, зафиксировано в самом тесте» — и это выполнимо двумя существенно разными способами:
|
||||
| Находка r1 | Чем закрыта | Где видно |
|
||||
|---|---|---|
|
||||
| Medium: AC5 не фиксирует, перебор по каталогу `.github/workflows/*.yml` или по жёстко заданному списку из двух имён — обе версии формально проходят AC4/AC5, но только первая закрывает цель issue буквально | Контракт п.(3) и AC5 переписаны: явно требуется перебор **каталога**, а не списка; для каждого файла — либо пины, либо явное («не ставит») доказательство отсутствия установки, не через отсутствие подстроки; доказательство AC5 теперь называет синтетический каталог с **третьим** workflow, которого в старом списке из двух не было бы | `docs/specs/399-backend-gate-honesty.md:82-94` (контракт), `:136-144` (AC5), SHA `6d229c66` |
|
||||
|
||||
1. **слабая версия**: оставить перебор тем же жёстко заданным массивом из двух файлов, внутри него заменить implicit `continue` на explicit разрешённый список причин пропуска. Формально удовлетворяет AC4 (синтетический workflow без обеих зацепок краснеет) и AC5 (список пропускаемых случаев есть в тесте) — но семь остальных workflow-файлов (`announce.yml`, `docs-screenshots.yml`, `performance.yml`, `process.yml`, `publish-prerelease.yml`, `release-zip.yml`, `release.yml`) как не проверялись, так и не проверяются, и, что важнее, **новый** workflow с неверсионированной установкой (например, будущий бэкенд-джоб не в `validate.yml`) вообще никогда не попадёт в цикл — гейт не заметит его так же тихо, как заметил бы файл вне списка ещё до этой правки;
|
||||
2. **сильная версия**: перебор строится по фактическому листингу `.github/workflows/*.yml`, и для каждого файла тест либо требует пины, либо явно и поимённо объявляет его исключённым (обоснованно — «не устанавливает питон-зависимости»). Это единственная версия, которая закрывает контракт п.(3) буквально, и единственная, которая не оставляет тот же класс слепого пятна, который и стал поводом для находки Low «в» в аудите.
|
||||
Находка закрыта по существу: слабое прочтение (а) из r1 (список из двух
|
||||
файлов, замена implicit `continue` на explicit skip-list **внутри тех же
|
||||
двух**) текстом контракта теперь прямо исключено — новый p.(3) требует
|
||||
перебора каталога, а не редактирования списка. Это единственная версия,
|
||||
которую r1 признавал закрывающей issue буквально.
|
||||
|
||||
Обе версии проходят AC4/AC5 как написано. Ревью ТЗ обязано различать такие пары («однозначность каждого AC» — задание reviewer'а), а здесь автор реализации может на совершенно законных основаниях выбрать первую и заявить AC выполненными, хотя цель issue («отсутствие обеих зацепок — это отказ, а не пропуск», дословно из тела issue) для будущих файлов не достигается.
|
||||
## Унаследовано из r1 (без повторной проверки)
|
||||
|
||||
**Почему не High**: это не свидетельство того, что задача не может быть выполнена — реализация в любом прочтении будет проходить свои тесты и не ломает ничего рабочего; вопрос ровно в том, какой из двух контрактов фиксируется. Технический вопрос («сканировать каталог или тот же список из двух») — не продуктовый, значит не выносится владельцу (§7.1); его решает автор при реализации, но AC должен явно называть, какой из двух исходов — и ссылаться на п.(3) как на прямое указание. Это Medium в скоупе текущей задачи (правит формулировку AC5, не открывает новый surface) — правится без нового issue (#202).
|
||||
Со ссылкой на `docs/reviews/SPEC-REVIEW-399-r1.md`, SHA `a1d7e0da`:
|
||||
|
||||
**Как закрыть**: одна фраза в AC5 или отдельным пунктом контракта — тест перебирает **все** файлы `.github/workflows/*.yml` (а не фиксированный список из двух), и для каждого, что не входит в проверяемый набор, в самом тесте лежит явное объяснение почему (например, «не запускает Python»), а не молчаливое умолчание через отсутствие подстроки. Дёшево: строчка текста, реализацию не расширяет — `readdirSync` вместо литерала массива на один порядок сложнее не становится.
|
||||
- §7.1: все обязательные разделы на месте (сценарий, что увидит человек,
|
||||
проблема по пунктам, скоуп/не-скоуп, UX/данные/i18n — н/п обоснованно,
|
||||
AC с доказательствами, план автотестов, риски, откат, release-артефакты)
|
||||
— делта их не трогает, кроме плана автотестов (см. новую находку ниже).
|
||||
- Классификация трека (полный, класс B, три несвязанные поверхности) —
|
||||
делта не меняет ни поверхности, ни причину.
|
||||
- Технические утверждения о разделах (1) M3 и (2) Low «а» — номера строк,
|
||||
содержимое `tests_backend/requirements.txt:29`, `pyproject.toml:5`,
|
||||
`.github/workflows/validate.yml:787-788` — делта их не касается, r1 их
|
||||
построчно сверил.
|
||||
- AC1, AC2, AC3, AC4, AC6 — текст не менялся этой ревизией, доказательства
|
||||
оценены r1 как однозначные.
|
||||
- Продуктовое обрамление и персоны SCOPE.md (задача инфраструктурная,
|
||||
J-строка не затронута) — не изменилось.
|
||||
- «Чего не проверял» из r1 (сеть для `package_constraints.txt`, объём
|
||||
ruff-долга, аудит-документ вне репозитория) — остаётся в силе, делта
|
||||
этих вопросов не касается.
|
||||
|
||||
## Что проверено и корректно
|
||||
## Новая находка этого раунда
|
||||
|
||||
- Обязательные разделы §7.1 присутствуют все: сценарий, что человек увидит, проблема (по пунктам), скоуп/не-скоуп, контракт (по пунктам), UX (н/п — обоснованно), модель данных/миграция (н/п — обоснованно), i18n (нет новых строк — обоснованно), AC1–AC6 с указанием способа доказательства, план автотестов, риски, откат, release-артефакты.
|
||||
- Продуктовое обрамление (`Сценарий` / `Что человек увидит`) совпадает по формату с уже принятым прецедентом (#398): «Пользователь продукта — ничего, разработчик — …» — корректно для чисто инфраструктурной задачи класса B, доменных персон `SCOPE.md` это не касается по существу вопроса.
|
||||
- Классификация трека (полный, а не `small`) обоснована прямо в шапке ТЗ явным нарушенным критерием («три несвязанные поверхности») — соответствует требованию §2.2/§5 называть нарушенный критерий, а не полагаться на ощущение.
|
||||
- Все технические утверждения о текущем состоянии кода (номера строк, содержимое `include`, содержимое workflow, логика `continue`) проверены построчным чтением файлов и совпадают дословно — никаких выданных за факт догадок не найдено.
|
||||
- AC1–AC6 пронумерованы, для каждого указан способ доказательства (unit-тест либо явное «проверяется ревьюером» для AC3, что соответствует допустимому в DoR методу «ревью кода»).
|
||||
- Риски названы по существу (объём ruff-долга при исходе (2), сетевая зависимость версии фронтенда, «ложное чувство завершённости») — не общие слова, а конкретные технические ловушки со смягчением.
|
||||
- Откат — тривиальный revert, обосновано отсутствием продуктового кода в диффе.
|
||||
- Не-скоуп корректно исключает соседние решения (#42 сужение линта как таковое, версии `homeassistant`/`phcc`, гвард `sys.modules` из #398) — предотвращает попутные правки за пределами трёх названных находок.
|
||||
- «Одно число — один источник»: неприменимо, пользовательских чисел в диффе нет (весь дифф — CI-конфигурация и тесты).
|
||||
### Medium (в скоупе) — «План автотестов» (п.4) не обновлён вслед за AC5 и описывает как раз ту слабую версию, которую контракт теперь запрещает
|
||||
|
||||
**Файл**: `docs/specs/399-backend-gate-honesty.md:155` (раздел «План
|
||||
автотестов», пункт 4 списка Unit-тестов).
|
||||
|
||||
**Текст сейчас**: «Явный список обходимых файлов зафиксирован; добавление
|
||||
нового файла в workflows без обновления списка краснеет (AC5).»
|
||||
|
||||
**В чём разрыв**: это дословно формулировка **старой** (ревизия 1) версии
|
||||
AC5 — «перечисление файлов, которые проверка обходит, зафиксировано в самом
|
||||
тесте» — которую сам автор в этой же ревизии заменил на «перебор каталога, а
|
||||
не фиксированного списка имён» (строка 137). Пункт 4 плана автотестов не
|
||||
редактировался в этой ревизии (его нет в диффе), и он по-прежнему описывает
|
||||
работу через **список**, который требуется вручную **обновлять** при
|
||||
появлении нового файла — то есть ту самую конструкцию, о которой новый
|
||||
контракт п.(3) говорит: «доказывается явно… а не выводится из отсутствия
|
||||
подстроки [и не из членства в списке]».
|
||||
|
||||
Смысловая разница не косметическая. Реализация, которая берёт «План
|
||||
автотестов» как техническое задание для теста (а не прозу AC5 несколькими
|
||||
абзацами выше), может на законных основаниях построить: `readdirSync` +
|
||||
хардкод-массив «эти N файлов не ставят python-зависимостей» + фейл, если имя
|
||||
нового файла не найдено ни в списке пиновых, ни в списке-исключений. Такая
|
||||
реализация проходит буквальный текст п.4 («список… краснеет при отсутствии
|
||||
файла в нём»), но именно она возвращает эксплуатационную нагрузку —
|
||||
необходимость вручную поддерживать список — которую контракт п.(3) и
|
||||
переписанный AC5 сознательно убрали («доказывается явно… а не выводится из
|
||||
отсутствия подстроки»). Расхождение между двумя разделами одного и того же
|
||||
ТЗ — тот же класс дыры, что и находка r1: AC/раздел проходятся двумя
|
||||
существенно разными реализациями, только на этот раз конфликт не внутри
|
||||
одного AC, а между «Критериями приёмки» и «Планом автотестов».
|
||||
|
||||
Это не гипотетическая тонкость: п.4 — единственное место в документе, где
|
||||
явно описано, ЧТО проверяет unit-тест для AC5, и оно противоречит только что
|
||||
исправленному AC5 в этом же файле.
|
||||
|
||||
**Почему не High**: реализация всё равно проходит написанные тесты в любом
|
||||
из двух прочтений, продуктового кода нет, откат тривиален. Это вопрос
|
||||
формулировки одного ТЗ-раздела, а не невозможности выполнить задачу.
|
||||
|
||||
**Почему Medium, а не Low**: буквальный текст, на который будет смотреть
|
||||
исполнитель при написании теста, указывает в сторону реализации, которую сам
|
||||
документ (двумя разделами выше) явно отверг. Это создаёт тот же риск
|
||||
«формально выполнено, но не решает то, из-за чего заведено», который r1 уже
|
||||
один раз поймал в AC5 — здесь тот же риск переехал в соседний раздел
|
||||
вследствие правки, а не был там с начала (в ревизии 1 AC5 и п.4 плана
|
||||
автотестов формулировались одинаково слабо и не противоречили друг другу;
|
||||
конфликт появился именно этой правкой). Правится в этой же задаче (#202 не
|
||||
применяется — находка в скоупе).
|
||||
|
||||
**Как закрыть**: одна строка. Например: «4. Синтетический каталог
|
||||
`.github/workflows/*.yml`, где один из файлов не входит в набор
|
||||
`validate.yml`/`mutation-gate.yml`, ставит `pip install pytest` без версий и
|
||||
не имеет явного маркера «не устанавливает python-зависимости» — тест
|
||||
краснеет; никакого списка имён для ручного обновления в реализации нет
|
||||
(AC5).» Дёшево: правка одного предложения, план автотестов приводится в
|
||||
соответствие с уже переписанным AC5.
|
||||
|
||||
## Что проверено и корректно (в дополнение к унаследованному)
|
||||
|
||||
- Новый факт в AC5 «в репозитории девять workflow, установку
|
||||
python-зависимостей делают два» — перепроверен на текущем дереве:
|
||||
`ls .github/workflows/*.yml` даёт ровно 9 файлов; `git grep -l "pip
|
||||
install" .github/workflows/*.yml` даёт ровно `mutation-gate.yml` и
|
||||
`validate.yml`. Число и состав совпадают дословно.
|
||||
- Переписанный контракт п.(3) и AC5 внутренне непротиворечивы друг другу
|
||||
(оба говорят про каталог, оба про «явное доказательство отсутствия
|
||||
установки», оба про мутанта с третьим workflow) — конфликт только с планом
|
||||
автотестов, описанным выше.
|
||||
- Правка не меняет трек, скоуп/не-скоуп, риски и не переносит вопрос
|
||||
владельцу — расширение контракта («перебор каталога») лежит внутри уже
|
||||
согласованной цели issue («отсутствие обеих зацепок — отказ, а не
|
||||
пропуск»), это техническое уточнение, а не продуктовое решение (§7.1: не
|
||||
выносится владельцу).
|
||||
- Заголовок «Ревизия 2» корректно ссылается на SPEC-REVIEW-399-r1 —
|
||||
трассировка причины правки на месте.
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- Не проверял по сети фактическое содержимое `package_constraints.txt` тега `2026.8.3` репозитория `home-assistant/core` (претензия M3 из аудита) — инструмент веб-доступа в этой среде недоступен (запрос разрешения не подтверждён). Не блокирует вердикт: AC1 требует доказательства без сети, реализация и код-ревью проверят число построчно с открытым источником в комментарии.
|
||||
- Не гонял `npm test` / `npx tsc --noEmit` / `npm run build` — это ревью ТЗ (документ, не код), гейты не относятся к этому этапу; они будут прогнаны на код-ревью после реализации.
|
||||
- Не проверял сам аудит-документ `AUDIT-2026-08-31-v1700beta1.md` — файл не найден в репозитории (видимо, живёт вне репозитория, как и часть ревью до 1.62); тело issue содержит достаточный самостоятельный контекст, так что отсутствие исходника не мешает оценке ТЗ.
|
||||
- Не проверял объём накопленного ruff-долга («порядка полусотни» находок при исходе (2)) — это оценка автора ТЗ для риска, не факт, требующий проверки на этом этапе; будет виден в CI при выборе исхода (2) на код-ревью.
|
||||
- Сетевое содержимое `package_constraints.txt` тега `2026.8.3`
|
||||
`home-assistant/core` (претензия M3) — как и в r1, недоступно в этой
|
||||
среде; не блокирует, AC1 требует доказательства без сети, число будет
|
||||
видно на код-ревью.
|
||||
- Объём ruff-долга при исходе (2) для Low «а» — не факт, требующий проверки
|
||||
на этом этапе; делта его не касается.
|
||||
- `npm test`/`npx tsc --noEmit`/`npm run build` — это ревью документа
|
||||
(ТЗ), а не кода; правка не трогает `src/**`/`custom_components/**`, гейты
|
||||
кода к этому этапу не относятся и будут прогнаны на код-ревью.
|
||||
- Аудит-документ `AUDIT-2026-08-31-v1700beta1.md` вне репозитория — как и
|
||||
в r1, не найден локально, тело issue самодостаточно.
|
||||
|
||||
## Вердикт
|
||||
|
||||
Жёлтый: единственная блокирующая-по-скоупу находка — Medium, без High. Автор уточняет формулировку AC5 (какой набор workflow-файлов покрывает проверка и почему), проходит повторный цикл ревью ТЗ (лимит лёгкого трека здесь неприменим — трек полный, лимит 4, израсходовано 0/4).
|
||||
Жёлтый: единственная блокирующая находка — Medium, без High. Прежняя
|
||||
Medium-находка (AC5: список vs каталог) закрыта; ревизией 2 введена новая
|
||||
Medium-находка того же семейства в соседнем разделе («План автотестов»,
|
||||
п.4). Автор приводит формулировку п.4 в соответствие с переписанным AC5 и
|
||||
проходит ещё один заход ревью ТЗ (полный трек, лимит 4 цикла, израсходован
|
||||
1/4 после r1; после этого раунда — 2/4).
|
||||
|
||||
Reference in New Issue
Block a user