opencode-config/docs/handoff/pr-178-draw-image-race-condition-tmp-render-svg.md
Sergey 39de98dc95
fix(draw-image): race condition on shared .tmp-render.svg breaks parallel renders (#178)
* 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>
2026-07-31 21:38:54 +03:00

27 lines
No EOL
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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`.