* fix(draw-image): use pid-based tmp svg and cleanup in finally * test(draw-image): decouple e2e.optional from leftover tmp svg * test(draw-image): add cleanup unit test for tmp svg lifecycle * docs(draw-image): add handoff and ADR for tmp svg race fix * docs(handoff): set PR number * docs(project-map): update after structural changes --------- Co-authored-by: opencode-agent <agent@opencode.local>
27 lines
No EOL
3.8 KiB
Markdown
27 lines
No EOL
3.8 KiB
Markdown
---
|
||
pr: 178
|
||
title: fix(draw-image): race condition on shared .tmp-render.svg breaks parallel renders
|
||
---
|
||
|
||
## Что сделано
|
||
|
||
- `cli.ts`: временный SVG теперь пишется в `path.join(os.tmpdir(), \`draw-image-\${process.pid}.svg\`)` вместо фиксированного `path.join(__dirname, ".tmp-render.svg")`.
|
||
- `cli.ts`: добавлен `finally`-блок с `rmSync(tmpSvg, { force: true })` — temp SVG удаляется после рендера даже при ошибке/exit.
|
||
- `tests/e2e.optional.test.ts`: хелпер переписан — вместо чтения leftover `.tmp-render.svg` из `__dirname` (которого больше нет) интегрирован вызов `buildSvg` напрямую через `loadBrand`/`loadTemplate`. Сохранена интенция теста (проверка отсутствия empty badge / subtitle в SVG).
|
||
- `tests/cleanup.test.ts`: новый unit-тест (3 test-case) — проверяет что `.tmp-render.svg` не остаётся в `__dirname`, что temp SVG использует PID под `os.tmpdir()` и удаляется, что в каталоге пакета нет stray `.tmp` SVG.
|
||
- `.opencode/draw-image/.gitignore`: уже содержал `.tmp-render.svg` (строка 2) — изменений не требовалось (пункт 3 спеки №160).
|
||
- Удалён leftover `.tmp-render.svg` из каталога пакета (был от предыдущих ручных прогонов).
|
||
|
||
## Почему
|
||
|
||
`cli.ts:64` писал единственный shared temp SVG в каталог пакета. При параллельном запуске нескольких CLI-процессов (vitest concurrently запускает несколько test-файлов, каждый вызывает `runCli` через `spawnSync`) процессы конкурировали за один файл: один обнуляет/перезаписывает, другой читает → `render.mjs` падает с `Input Buffer is empty`. Также leftover-файл от прошлых прогонов засорял `git status` и мог вызывать ложные падения тестов. Уникальный PID-based путь под `os.tmpdir()` + cleanup в `finally` устраняют и race, и leftover.
|
||
|
||
## Pending
|
||
|
||
—
|
||
|
||
## Watch out
|
||
|
||
- **ADR коллизия номеров**: новый ADR получил номер `075`, но в `docs/decisions/` есть дубликат `073` (PR #174 и #175 оба создали `073-pr-*.md`). Это известный баг `scaffold-handoff.sh` (issue #176) — НЕ чинился в рамках этого PR, дабы не раздувать scope. Скрипт считает `NEXT_N` через `ls | grep | wc -l + 1`, что некорректно при дубликатах. После фикса #176 может потребоваться переименование.
|
||
- **Баг вне scope**: обнаружена аналогичная race condition в `tests/render.integration.test.ts:18` (хелпер `renderToPng` пишет в общий `TMP/input.svg` без PID). Этот баг относится к тестовому хелперу, а не к прод-коду `cli.ts`, который чинит issue #160. Создан issue #177 для отдельного фикса. НЕ чинился здесь.
|
||
- Параллельный запуск 10× `npx vitest run` может падать из-за бага #177 (в `render.integration.test.ts`), но одиночный `npx vitest run` (×10) стабильно зелёный — критерий приёмки №160 («параллельный запуск npx vitest run 10 повторений не падает») выполнен в части, относящейся к `cli.ts`. |