Version / branch / commit
Source-reviewed on main at 99721c7.
OS and environment
Linux amd64; Go 1.26.6. AI-assisted source audit checked against the implementation. The proposed capacity regression cases below have not been executed.
Steps to reproduce
- Create ProcessManager with MaxProcesses=1.
- Start one long-lived process and leave it running.
- Start a second long-lived process and inspect live processes and the manager snapshot.
- Separately, exercise simultaneous starts at capacity with a fake transport and a victim whose termination is delayed or fails.
Expected behavior
A positive configured capacity is enforced before launching another OS process, or documented and represented separately if it is only a completed-history retention target. Admission failures must not leave untracked child processes.
Actual behavior / source evidence
Start:113-160 starts the transport at line 127 before store performs its capacity check.
store and processToPruneLocked:361-393 insert the new process before terminating a live victim outside the lock. If all existing processes are live and there are eight or fewer, processToPruneLocked returns nil even when MaxProcesses is 1. Concurrent starts can select the same not-yet-terminated victim and each admit a replacement.
terminate:563-571 ignores the kill error, so eviction is not proof that capacity has been recovered.
Suggested fix / regression coverage
Reserve capacity atomically before startTransport, release the reservation on launch failure, and reject or wait when full. If preserving eviction semantics, reserve a unique victim and account for termination completion/failure before admitting replacements. Cover MaxProcesses=1, concurrent starts, and failed termination.
Verification
The full existing non-race suite and focused race tests for internal/execution passed during the audit. This is a source-supported admission/limit defect, not a reported Go data race or an executed resource-exhaustion reproduction.
Version / branch / commit
Source-reviewed on main at 99721c7.
OS and environment
Linux amd64; Go 1.26.6. AI-assisted source audit checked against the implementation. The proposed capacity regression cases below have not been executed.
Steps to reproduce
Expected behavior
A positive configured capacity is enforced before launching another OS process, or documented and represented separately if it is only a completed-history retention target. Admission failures must not leave untracked child processes.
Actual behavior / source evidence
Start:113-160 starts the transport at line 127 before store performs its capacity check.
store and processToPruneLocked:361-393 insert the new process before terminating a live victim outside the lock. If all existing processes are live and there are eight or fewer, processToPruneLocked returns nil even when MaxProcesses is 1. Concurrent starts can select the same not-yet-terminated victim and each admit a replacement.
terminate:563-571 ignores the kill error, so eviction is not proof that capacity has been recovered.
Suggested fix / regression coverage
Reserve capacity atomically before startTransport, release the reservation on launch failure, and reject or wait when full. If preserving eviction semantics, reserve a unique victim and account for termination completion/failure before admitting replacements. Cover MaxProcesses=1, concurrent starts, and failed termination.
Verification
The full existing non-race suite and focused race tests for internal/execution passed during the audit. This is a source-supported admission/limit defect, not a reported Go data race or an executed resource-exhaustion reproduction.