C-H2: гонка stopping-флага в обработчике выхода `RoxDesignRuntimeManager.start()`/`stop()`

## Что это ## Резюме (RU) C-H2: гонка stopping-флага в обработчике выхода `RoxDesignRuntimeManager.start()`/`stop()` *Полный перевод тела — в работе. Английский оригинал ниже.* --- # Original (EN) ## Objective Eliminate the race condition in `RoxDesignRuntimeManager` where the `child.once("exit")` handler fires during an intentional `stop()` call and spuriously emits `rox-design:sidecar-exited` IPC to the renderer. **Audit source:** [2026-05-20 PR #268 Release-Readiness Audit]() — Finding **C-H2** (HIGH) **Suggested branch:** `fix/rox-design-runtime-stopping-flag-race-t543-c-h2` --- ## Source Links * Audit: [https://github.com/agisota/rox.one/blob/main/docs/audits/2026-05-20-pr268-release-readiness-audit.md]() * File: `packages/electron/src/main/rox-design/RoxDesignRuntimeManager.ts` --- ## Current State `child.once("exit")` is registered unconditionally inside `start()`. When `stop()` calls `child.kill()`, the exit handler fires and emits `rox-design:sidecar-exited` to the renderer — identical to a crash path — causing the UI to show an unexpected error banner during clean shutdown. --- ## Requirements 1. Introduce a `private stopping = false` flag on `RoxDesignRuntimeManager`. 2. Set `stopping = true` at the top of `stop()` before any `child.kill()` call. 3. Guard the `child.once("exit")` handler: if `this.stopping` is `true`, return early without emitting `rox-design:sidecar-exited`. 4. Reset `stopping = false` after `stop()` fully completes (child confirmed dead or timeout). --- ## Specification ```typescript class RoxDesignRuntimeManager { private stopping = false; async stop(): Promise { this.stopping = true; // ... kill child, await exit ... this.stopping = false; } private registerExitHandler(child: ChildProcess): void { child.once("exit", (code, signal) => { if (this.stopping) return; // intentional shutdown — do not emit this.emit("rox-design:sidecar-exited", { code, signal }); }); } } ``` --- ## Acceptance Criteria - [ ] `stop()` sets `stopping = true` before `child.kill()`. - [ ] `exit` handler short-circuits when `stopping === true`. - [ ] `rox-design:sidecar-exited` is NOT emitted during normal `stop()`. - [ ] `rox-design:sidecar-exited` IS still emitted on unex... ## Статус Это задача из текущего backlog'а ROX.ONE (Linear). Текущий статус в Linear: `На ревью — In Review`. Метки: `Баг` / `Bug`. ## 🔗 Linear - [PZD-105](https://linear.app/kuhjie/issue/PZD-105/c-h2-gonka-stopping-flaga-v-obrabotchike-vyhoda) — backing ticket - Parent epic: [PZD-119](https://linear.app/kuhjie/issue/PZD-119)

Please authenticate to join the conversation.

Upvoters
Status

In Review

Board
♾️

Bugs, Fixes, Improvements

Date

About 15 hours ago

Author

agi

Subscribe to post

Get notified by email when there are changes.