auto-sync: 2026-06-04 13:40:01
This commit is contained in:
@@ -2,7 +2,22 @@
|
||||
|
||||
---
|
||||
type: backlog
|
||||
updated_at: 2026-06-03
|
||||
updated_at: 2026-06-04
|
||||
---
|
||||
|
||||
## 🐛 Баги (2026-06-04, живой прогон ET-013)
|
||||
|
||||
### ✅ BUG-DEPLOY-LOG-PATH · ложный FAILED деплоя (рассинхрон путей 14-deploy-log.md) · СТАТУС: ✅ ИСПРАВЛЕН (PR #23, `34894f46`, на проде)
|
||||
- **Приоритет:** высокий (бьёт по каждому успешному деплою — ложный откат).
|
||||
- **Симптом (ET-013):** деплой РЕАЛЬНО успешен (тег v0.0.5, deploy-hook RC=0, healthcheck HTTP 200, фича живая в app.js), но QG завернул в FAILED → откат deploy→development.
|
||||
- **Корень:** deployer пишет `14-deploy-log.md` (deploy_status: SUCCESS) и мержит артефакты в **main** через отдельный PR (#27, `4e925cc`). QG `check_deploy_status` (src/qg/checks.py ~284) читает файл через `_repo_path(repo, branch)` из **worktree ВЕТКИ ФИЧИ** (`/repos/_wt/.../feature_ET-013/docs/work-items/ET-013/`), где есть 10/12/13, но нет 14 → «Deploy log not found» → FAILED.
|
||||
- **НЕ трогать:** merge-gate из PR #20 (`gitea.py`, `current_stage==deploy`) — он СРАБОТАЛ ПРАВИЛЬНО (без него фейк-done).
|
||||
- **Решение (PR #23):** новые `_deploy_log_from_main` + `_parse_deploy_status` в qg/checks.py. Порядок: worktree → `git fetch origin main` + `git show origin/main:docs/work-items/<WI>/14-deploy-log.md` на shared-клоне → not found. Любая git-ошибка → деградация (None), таймауты 30s/15s. 277 passed / 9 off-limits. merge-gate gitea.py НЕ тронут.
|
||||
- **Источники:** `memory/2026-06-04.md`, `STATUS.md` (раздел багов), `tasks/orchestrator/DEV_TASK_DEPLOY_GATE_PATH_FIX.md`.
|
||||
|
||||
### ✅ BUG-TRACKER-DUP · трекер плодит дубли · СТАТУС: ✅ ИСПРАВЛЕН (PR #22, `b222d7af`)
|
||||
- См. STATUS.md «Баг A» и `memory/2026-06-04.md`. `edit_telegram` возвращал False на `"message is not modified"` → дубли. Фикс: 4 состояния (ok/not_modified/gone/failed), send только при gone.
|
||||
|
||||
---
|
||||
|
||||
## EPIC: E2E онбординг нового проекта (03.06.2026)
|
||||
|
||||
96
tasks/orchestrator/DEV_TASK_DEPLOY_GATE_PATH_FIX.md
Normal file
96
tasks/orchestrator/DEV_TASK_DEPLOY_GATE_PATH_FIX.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# DEV TASK: orchestrator — ложный FAILED деплоя (рассинхрон путей 14-deploy-log.md)
|
||||
|
||||
Репо: `slin@82.22.50.71:/home/slin/repos/orchestrator` (пароль `motoZ@yaz2010`).
|
||||
Push в main запрещён (pre-receive hook) → **только PR в Gitea**.
|
||||
Gitea токен: `docker exec orchestrator printenv ORCH_GITEA_TOKEN`.
|
||||
Одна ветка `fix/deploy-gate-log-path` от актуального main, **один PR**. НЕ мержить сам.
|
||||
Baseline pytest на этом проде: **272 passed + 9 failed** (9 = off-limits HMAC/401, НЕ чинить).
|
||||
|
||||
---
|
||||
|
||||
## КОНТЕКСТ / БАГ (подтверждён на живой задаче ET-013, 2026-06-04)
|
||||
|
||||
ET-013 **реально и успешно задеплоен на прод** (тег `v0.0.5`, deploy-hook RC=0,
|
||||
healthcheck HTTP 200, фича живая в `app.js`). НО quality-gate ложно завернул задачу
|
||||
в `FAILED` и откатил `deploy → development`.
|
||||
|
||||
### Что произошло по шагам
|
||||
1. Deployer отработал, `exit_code=0`, смержил PR #26 (`be7a052`), запушил тег `v0.0.5`,
|
||||
deploy-hook RC=0, healthcheck 200.
|
||||
2. Deployer написал `14-deploy-log.md` с `deploy_status: SUCCESS` и смержил артефакты
|
||||
через **отдельный PR #27** (`4e925cc`) — то есть файл уехал в **main**.
|
||||
3. QG `check_deploy_status` (`src/qg/checks.py` ~284) читает `14-deploy-log.md` из
|
||||
**worktree ВЕТКИ ФИЧИ** через `_repo_path(repo, branch)` →
|
||||
`/repos/_wt/<...>/feature_ET-013/docs/work-items/ET-013/`.
|
||||
В этом worktree лежат `10-tech-risks`, `12-review`, `13-test-report`, но **НЕТ
|
||||
`14-deploy-log.md`** — он в main, а не в worktree фичи.
|
||||
4. Файла нет → «Deploy log not found» → вердикт **FAILED** → откат `deploy → development`.
|
||||
|
||||
### Корень
|
||||
Артефакты деплоя пишутся/мержатся в **main** (PR #27), а гейт проверки деплоя читает их
|
||||
из **worktree ветки фичи** (`_repo_path(repo, branch)`). Локации не совпадают → ложный
|
||||
not-found → ложный FAILED → лишний откат успешного деплоя. **Каждый** успешный деплой
|
||||
будет так заворачиваться.
|
||||
|
||||
### Хорошая новость (НЕ трогать, это работает правильно)
|
||||
merge-gate из PR #20 (`gitea.py`, `current_stage=="deploy"` → игнор merge-driven done)
|
||||
сработал идеально: лог `"PR merged at deploy stage — done gated by deployer verdict,
|
||||
ignoring merge-driven done"`. Без него merge PR'а проставил бы фейк-done. Теперь done
|
||||
гейтится вердиктом деплоера — это правильно. Чиним только рассинхрон путей под этим гейтом.
|
||||
|
||||
---
|
||||
|
||||
## ШАГ 0 — ПОДТВЕРДИТЬ ПО КОДУ (перед правкой)
|
||||
1. Открой `src/qg/checks.py`, функцию `check_deploy_status` (~стр. 284) и `_repo_path`
|
||||
(~стр. 13). Зафиксируй ТОЧНО: как формируется путь к `14-deploy-log.md`
|
||||
(`_repo_path(repo, branch)` → worktree фичи), имя/паттерн файла, трактовку отсутствия
|
||||
файла (текст «Deploy log not found» → FAILED).
|
||||
2. Найди инструкцию/промпт деплоера (где он пишет `14-deploy-log.md` и через какой PR
|
||||
мержит артефакты в main; искать в `src/agents/launcher.py` и любых промпт-строках).
|
||||
Подтверди: пишет в main через отдельный PR, а не оставляет в worktree фичи.
|
||||
3. Зафиксируй ОБА факта в отчёте (verbatim строки путей до/после).
|
||||
|
||||
## ЧТО СДЕЛАТЬ (выбрать robust-вариант, обосновать в отчёте)
|
||||
|
||||
Цель: `check_deploy_status` должен находить `14-deploy-log.md`, который реально написан
|
||||
деплоером, и НЕ заворачивать успешный деплой.
|
||||
|
||||
**Рекомендуемый вариант (robust, минимум побочек):**
|
||||
- В `check_deploy_status`: если `14-deploy-log.md` НЕ найден в worktree-локации —
|
||||
сделать `git -C <repo_clone> fetch origin main` и прочитать файл из **`origin/main`**
|
||||
(`git show origin/main:docs/work-items/<WI>/14-deploy-log.md`), распарсить `deploy_status`
|
||||
оттуда. SUCCESS в main → PASS. Только если нет НИ в worktree, НИ в main → FAILED.
|
||||
- Это переживает то, что деплоер мержит лог в main отдельным PR (как сейчас и делает).
|
||||
- Аккуратно с repo clone path: использовать shared clone `settings.repos_dir/<repo>`
|
||||
для git-команд (не worktree фичи). Тайм-аут на fetch, не падать — при ошибке fetch
|
||||
деградировать к «нет в main» (а не к исключению).
|
||||
|
||||
**Альтернатива (если по коду чище):** заставить деплоера писать `14-deploy-log.md` в ту же
|
||||
worktree-локацию ветки фичи (где лежат `10/12/13`) ДО проверки гейтом, а не только в main.
|
||||
Тогда гейт находит его там же. Выбрать, если это меньше меняет и не ломает merge артефактов.
|
||||
|
||||
Выбрать ОДИН вариант, обосновать. Требование: успешный деплой с реально написанным
|
||||
`SUCCESS`-логом больше НЕ заворачивается в FAILED; реальный FAILED по-прежнему ловится.
|
||||
|
||||
### НЕ ТРОГАТЬ
|
||||
- merge-gate `gitea.py` (`current_stage=="deploy"`), PLANE_STATES, set_issue_done,
|
||||
launcher deployer-guard (launcher.py:475), HMAC, queue, usage_comment/Plane-комменты,
|
||||
cost_usd, формат трекера/Итого, миграции. Только логика поиска лога деплоя + (опц.)
|
||||
локация записи лога деплоером.
|
||||
|
||||
## ТЕСТЫ (обязательно, мокать git/файлы)
|
||||
- `check_deploy_status`: лог `SUCCESS` есть в worktree → PASS (регресс не сломан).
|
||||
- `check_deploy_status`: лога нет в worktree, но `SUCCESS` есть в `origin/main` → PASS
|
||||
(это и есть фикс — кейс ET-013).
|
||||
- `check_deploy_status`: лог `FAILED` в main → FAILED.
|
||||
- `check_deploy_status`: лога нет нигде (ни worktree, ни main) → FAILED («not found»).
|
||||
- `check_deploy_status`: fetch падает (сеть) → не исключение, деградирует к «нет в main».
|
||||
- Полный pytest зелёный кроме тех же 9 off-limits.
|
||||
|
||||
## СДАЧА
|
||||
- Ветка `fix/deploy-gate-log-path`, один PR в Gitea. НЕ мержить — на ревью Стрим.
|
||||
- Отчёт: `tasks/orchestrator/reports/dev-2026-06-04-deploy-gate-path-fix.md` —
|
||||
commit-хеш, PR-номер, вывод pytest, verbatim путь до/после (где гейт читал и где деплоер
|
||||
писал), какой вариант выбран и почему, как теперь находится лог.
|
||||
- Перенос файлов на прод: на хосте нет scp → через `base64 | ssh 'base64 -d'` либо docker cp.
|
||||
- Сообщить: PR-номер, результат pytest, краткое описание фикса.
|
||||
@@ -1,11 +1,41 @@
|
||||
# Статус проекта: Мультиагентная разработка ПО
|
||||
|
||||
**Дата обновления:** 2026-06-03 20:50 UTC
|
||||
**Дата обновления:** 2026-06-04 10:35 UTC
|
||||
**Ревьюер:** Стрим
|
||||
|
||||
---
|
||||
|
||||
## 📌 Свежее (2026-06-03) — сессия багов входа/выхода analyst
|
||||
## 📌 Свежее (2026-06-04) — observability, живой ТГ-трекер, баги на боевом ET-013
|
||||
|
||||
| Работа | Статус |
|
||||
|--------|--------|
|
||||
| **PR #20** observability: токены (input+cache_read+cache_creation, `15.1M in`), merge-gate `current_stage==deploy`, Plane→Done (`set_issue_done`), артефакты от всех агентов | 🟢 смержен (`2801983d`), на проде |
|
||||
| **PR #21** живой Telegram-трекер B+ (одно editMessageText-сообщение, умные пинги только на алерты) | 🟢 смержен (`3e5c74ce`), на проде |
|
||||
| **PR #22** фикс трекера: дубли (`not modified`=успех, send только при `gone`) + `🔄 Review · попытка N` | 🟢 смержен (`b222d7af`), на проде |
|
||||
| **PR #23** фикс деплой-гейта (ложный FAILED, рассинхрон путей `14-deploy-log.md`; fallback на `origin/main`) | 🟢 смержен (`34894f46`), на проде |
|
||||
| **Доска ET синхронизирована** (6 Done + ET-8 Done вручную + ET-4 Cancelled) | 🟢 сделано |
|
||||
|
||||
**Детали:** `🐛 Известные баги` ниже + `memory/2026-06-04.md` + reports `dev-2026-06-04-*`.
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Известные баги (живой трекер + деплой, 2026-06-04)
|
||||
|
||||
### ✅ Баг A — трекер плодит дубли сообщений (ИСПРАВЛЕН, PR #22)
|
||||
- **Симптом:** вместо одного редактируемого сообщения — новые на каждом цикле. На ET-013: 21 editMessageText / 7 sendMessage = 7 дублей.
|
||||
- **Корень:** `edit_telegram` (src/notifications.py) возвращал `False` на ЛЮБОМ 400, включая Telegram-ответ `"message is not modified"` (текст трекера не менялся). `update_task_tracker` трактовал False как «edit упал» → новое сообщение + перезапись tracker_message_id (старый трекер осиротевал, отставал).
|
||||
- **Фикс (PR #22, `b222d7af`):** `edit_telegram` → `ok|not_modified|gone|failed`. Новое сообщение ТОЛЬКО при `gone`. `render_task_tracker` показывает `🔄 Review · попытка N` на повторных циклах. 272 passed / 9 off-limits.
|
||||
|
||||
### ✅ Баг B — ложный FAILED деплоя (РАССИНХРОН ПУТЕЙ, ИСПРАВЛЕН PR #23)
|
||||
- **Симптом:** ET-013 РЕАЛЬНО задеплоен (тег v0.0.5, deploy-hook RC=0, healthcheck 200, фича живая), но QG завернул в FAILED → откат deploy→development.
|
||||
- **Корень:** deployer пишет `14-deploy-log.md` (deploy_status: SUCCESS) и мержит артефакты в **main** через отдельный PR (#27). А QG `check_deploy_status` (src/qg/checks.py ~284) читает этот файл через `_repo_path(repo, branch)` из **worktree ветки фичи**, где его нет → «not found» → ложный FAILED. Бьёт по КАЖДОМУ успешному деплою.
|
||||
- **Важно:** merge-gate из PR #20 (`current_stage==deploy`) СРАБОТАЛ ПРАВИЛЬНО (без него был бы фейк-done) — НЕ трогать.
|
||||
- **Фикс (PR #23, `34894f46`, на проде):** новые `_deploy_log_from_main` + `_parse_deploy_status` в qg/checks.py. Порядок поиска: worktree → `git fetch origin main` + `git show origin/main:.../14-deploy-log.md` на shared-клоне → not found. Любая git-ошибка → деградация (None, не исключение), таймауты 30s/15s. 277 passed / 9 off-limits. merge-gate gitea.py НЕ тронут.
|
||||
- **ET-013 (=Plane ET-8)** доведена до Done вручную (код реально на проде) + коммент с объяснением.
|
||||
|
||||
---
|
||||
|
||||
## 📌 Предыдущее (2026-06-03) — сессия багов входа/выхода analyst
|
||||
|
||||
| Работа | Статус |
|
||||
|--------|--------|
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
# Dev Report: orchestrator — ложный FAILED деплоя (рассинхрон путей 14-deploy-log.md)
|
||||
Дата: 2026-06-04
|
||||
Статус: DONE
|
||||
|
||||
## Задача
|
||||
QG `check_deploy_status` ложно заворачивал успешные деплои в FAILED и откатывал
|
||||
`deploy → development`. Причина: deployer пишет `14-deploy-log.md` (deploy_status: SUCCESS)
|
||||
и мержит артефакты в **main** отдельным PR, а гейт читает лог из **worktree ветки фичи**
|
||||
через `_repo_path(repo, branch)` — там лога нет → «Deploy log not found» → FAILED.
|
||||
Починить ТОЛЬКО поиск лога деплоя. НЕ трогать merge-gate (`gitea.py`, `current_stage=="deploy"`).
|
||||
|
||||
## ШАГ 0 — подтверждение по коду (verbatim)
|
||||
|
||||
### Где гейт читал лог (ДО фикса) — `src/qg/checks.py`
|
||||
`_repo_path` (стр. 13–24):
|
||||
```python
|
||||
def _repo_path(repo: str, branch: str | None = None) -> str:
|
||||
if branch:
|
||||
wt = get_worktree_path(repo, branch)
|
||||
if os.path.isdir(wt):
|
||||
return wt
|
||||
return os.path.join(settings.repos_dir, repo)
|
||||
```
|
||||
`check_deploy_status` (стр. ~284, ДО):
|
||||
```python
|
||||
repo_path = _repo_path(repo, branch)
|
||||
log_path = os.path.join(repo_path, f"docs/work-items/{work_item_id}/14-deploy-log.md")
|
||||
if not os.path.isfile(log_path):
|
||||
return False, "Deploy log not found (14-deploy-log.md)"
|
||||
```
|
||||
`get_worktree_path` (`src/git_worktree.py:33`):
|
||||
```python
|
||||
def get_worktree_path(repo: str, branch: str) -> str:
|
||||
return os.path.join(settings.worktrees_dir, repo, _safe(branch))
|
||||
```
|
||||
→ при наличии ветки путь = `/repos/_wt/<repo>/<safe-branch>/docs/work-items/<WI>/14-deploy-log.md`
|
||||
(worktree ФИЧИ). Отсутствие файла → текст «Deploy log not found (14-deploy-log.md)» → FAILED.
|
||||
|
||||
### Где деплоер пишет лог (verbatim подтверждение)
|
||||
- `src/usage.py:328`: `"deployer": ("Deploy log", "14-deploy-log.md")` — артефакт деплоера.
|
||||
- Промпт деплоера лежит в целевом репо (`.openclaw/agents/deployer.md` в enduro-trails),
|
||||
не в orchestrator. Лог пишется и **мержится в main отдельным PR** (для ET-013 — PR #27,
|
||||
commit `4e925cc`).
|
||||
- **Живое подтверждение в проде:** в shared-клоне `/home/slin/repos/enduro-trails`:
|
||||
```
|
||||
$ git show origin/main:docs/work-items/ET-013/14-deploy-log.md
|
||||
---
|
||||
deploy_status: SUCCESS
|
||||
version: v0.0.5
|
||||
work_item: ET-013
|
||||
pr: 26
|
||||
merge_commit: be7a052
|
||||
```
|
||||
При этом в worktree ветки фичи файла нет → отсюда ложный FAILED.
|
||||
|
||||
**Рассинхрон подтверждён:** пишется/мержится в `origin/main`, читается из worktree фичи.
|
||||
|
||||
## Выбранный вариант: РЕКОМЕНДУЕМЫЙ (robust, origin/main fallback)
|
||||
|
||||
Выбран вариант с чтением из `origin/main`, а не «деплоер пишет в worktree», потому что:
|
||||
1. Меняет только логику чтения в `check_deploy_status` — ноль изменений в пайплайне
|
||||
деплоера/мержа артефактов (меньше риска, ничего нового не ломает).
|
||||
2. Переживает текущее поведение «деплоер мержит лог в main отдельным PR» как есть.
|
||||
3. Не зависит от состояния worktree (может быть зачищен/переаллоцирован к моменту гейта).
|
||||
4. Альтернатива (писать в worktree ДО гейта) потребовала бы менять промпт деплоера в
|
||||
целевом репо + порядок merge артефактов — больше поверхности изменений.
|
||||
|
||||
### Логика (ПОСЛЕ фикса) — порядок поиска: worktree → origin/main → not found
|
||||
```python
|
||||
repo_path = _repo_path(repo, branch)
|
||||
log_path = os.path.join(repo_path, f"docs/work-items/{work_item_id}/14-deploy-log.md")
|
||||
if os.path.isfile(log_path):
|
||||
...read & _parse_deploy_status(content) # регресс сохранён
|
||||
main_content = _deploy_log_from_main(repo, work_item_id) # git fetch origin main + git show
|
||||
if main_content is not None:
|
||||
return _parse_deploy_status(main_content) # ET-013 fix: SUCCESS в main → PASS
|
||||
return False, "Deploy log not found (14-deploy-log.md)"
|
||||
```
|
||||
`_deploy_log_from_main`: использует shared-клон `settings.repos_dir/<repo>` (НЕ worktree),
|
||||
`git -C <clone> fetch origin main` (timeout 30s) + `git show origin/main:docs/work-items/<WI>/14-deploy-log.md`
|
||||
(timeout 15s). Любая ошибка git (нет клона / нет `.git` / сеть / нет файла в main) →
|
||||
возвращает `None` (деградация к «not found»), **никогда не бросает исключение**.
|
||||
Парсинг frontmatter вынесен в `_parse_deploy_status` (читает только `deploy_status:`).
|
||||
|
||||
## Изменённые файлы
|
||||
- `src/qg/checks.py` — `import subprocess`; новые `_parse_deploy_status`,
|
||||
`_deploy_log_from_main`; `check_deploy_status` с origin/main-fallback.
|
||||
- `tests/test_qg.py` — 5 новых тестов в `TestCheckDeployStatus`.
|
||||
|
||||
## Тесты
|
||||
- worktree `SUCCESS` → PASS (регресс не сломан) — `test_success_verdict_passes` (+short-circuit тест).
|
||||
- нет в worktree, `SUCCESS` в origin/main → PASS (**ET-013 fix**) — `test_origin_main_success_passes_when_absent_in_worktree`.
|
||||
- `FAILED` в main → FAILED — `test_origin_main_failed_fails`.
|
||||
- нет нигде → not found — `test_absent_everywhere_fails`.
|
||||
- fetch падает (TimeoutExpired) → деградация без исключения — `test_fetch_failure_degrades_no_exception`.
|
||||
- worktree-лог короткозамыкает origin/main lookup — `test_worktree_log_short_circuits_main_lookup`.
|
||||
|
||||
### Вывод pytest (на проде, в контейнере orchestrator против `/repos/orchestrator`)
|
||||
- `tests/test_qg.py`: **33 passed** (было 28 + 5 новых).
|
||||
- Полный suite (детерминированно, `-p no:randomly`): **277 passed, 9 failed**.
|
||||
- 9 failed = те же off-limits HMAC/401 в `test_webhooks.py` (НЕ чинить).
|
||||
- Baseline на чистом дереве: **272 passed, 9 failed**. Дельта = +5 (мои тесты), 0 новых падений.
|
||||
- Списки FAILED у baseline и у фикса **идентичны** (сравнил отсортированно).
|
||||
- Прим.: один прогон без `no:randomly` дал «10 failed/276 passed» — это flaky-ordering
|
||||
в 401-webhook-тестах, не связано с фиксом (детерминированный прогон стабильно 9+277).
|
||||
|
||||
## Результат
|
||||
- Ветка `fix/deploy-gate-log-path` от актуального origin/main.
|
||||
- Commit: `4e4cc6c`.
|
||||
- **PR #23** в Gitea: https://git.mva154.duckdns.org/admin/orchestrator/pulls/23 (НЕ смержен, на ревью).
|
||||
- Push в main НЕ делал. merge-gate `gitea.py` НЕ тронут. Off-limits (PLANE_STATES,
|
||||
set_issue_done, launcher:475, HMAC, queue, usage_comment, cost_usd, трекер, миграции) — не тронуты.
|
||||
- Живая валидация ET-013: `_deploy_log_from_main("enduro-trails","ET-013")` фетчит и
|
||||
читает `deploy_status: SUCCESS` из origin/main → теперь PASS (раньше был ложный FAILED).
|
||||
|
||||
## Путь до/после (verbatim)
|
||||
- **ДО (читал):** `_repo_path(repo, branch)` → `/repos/_wt/<repo>/<safe-branch>/docs/work-items/<WI>/14-deploy-log.md` (worktree фичи; файла нет).
|
||||
- **Деплоер писал:** `docs/work-items/<WI>/14-deploy-log.md` → мержил в `origin/main` отдельным PR.
|
||||
- **ПОСЛЕ (читает):** worktree (как раньше) → если нет, fallback `git show origin/main:docs/work-items/<WI>/14-deploy-log.md` на shared-клоне `settings.repos_dir/<repo>` → если нет нигде, «not found».
|
||||
|
||||
## Проблемы и решения
|
||||
- Тесты не в образе контейнера (в `/app` запечён только `src/`). Прогонял в контейнере
|
||||
против смонтированного host-репо: `docker exec orchestrator sh -c 'cd /repos/orchestrator && python -m pytest ...'`.
|
||||
- Кажущийся +1 fail в одном прогоне — flaky-ordering 401-webhook тестов; подтверждено
|
||||
детерминированным `-p no:randomly` (стабильно 9 failed) и идентичными списками FAILED.
|
||||
Reference in New Issue
Block a user