Repository navigation
Conversation
Count validation and setup after an address claim against startupMaxMs, refuse expired launches, and give boot only the remaining budget. Clean up newly acquired resources after failures while preserving reused resources and unconfirmed children. Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Reap failed process groups and verify ports before cleanup. Keep expired claims untouched after quarantine can replace them, preserve exit diagnostics, and isolate the startup tests from occupied host ports. Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Skip taskkill once a Windows leader has exited, keep regression port waits bounded independently of the startup clock, and document the internal reservation helpers. Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Return a rejected Promise before spawn so a chained catch receives the same startup timeout as the watchdog path. Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
There was a problem hiding this comment.
Code Review
This pull request refactors the startup timeout and address reservation logic for Harper integration tests. It introduces an absolute startup ceiling (startupMaxMs) that begins at the moment of loopback address reservation rather than after process spawning, ensuring slow setup times are accounted for. The loopback address pool now tracks reservation times (reserveLoopbackAddress), and automatic failure cleanup has been hardened to prevent releasing newer claims under the same PID after quarantine recovery. Additionally, Windows process tree signaling has been updated to avoid targeting already-exited leader PIDs, and a comprehensive test suite (harperStartupDeadline.test.ts) has been added to verify these edge cases. No review comments were provided, so there is no feedback to address.
⊙ Problem
The six-minute corrupt-pool quarantine merged in #32 assumed that a default start would bind its reserved address or abandon startup before recovery.
startupMaxMsbegan after spawn, so log setup, address validation and synchronous pre-spawn work could consume unbounded extra time. On baseb06bed0, a 100 ms ceiling still admitted a successful start after 150 ms of log setup (191 ms total).💡 Solution
startupMaxMsnow covers the pool claim through observed readiness. Pool/quarantine waits and install/fixture preparation before the claim are excluded. Expired calls refuse to spawn; otherwise the watchdog receives only the remaining budget. A five-minute ceiling with one minute of post-claim setup leaves four minutes to boot. Idle timeout resets and post-readiness monitor registration keep their existing behavior.⚖️ Alternatives
Planning review:
Framing-Verdict: chosen-approach-sound(Claude). The review confirmed the current-main gap and the need to timestamp inside the allocator, because validation, lock release and probes also happen after the claim.🔧 Changes
The internal allocator in src/loopbackAddressPool.ts returns
{loopbackAddress, reservedAt}, timestamped immediately before publishing the claim; the publicgetNextAvailableLoopbackAddress(): Promise<string>is unchanged. src/harperLifecycle.ts carries that origin through setup, resolves the configured/default ceiling once, checks immediately before spawn and readiness, and arms the existing watchdog for the remaining budget.Failed-start cleanup in harperLifecycle.ts stops the group and gates resource release on confirmed child exit and free ports; Windows skips an exited leader PID.
README.md documents the changed option/environment semantics, recovery limits and cleanup behavior. CONTRIBUTING.md records the internal timestamp handoff and cleanup invariant. No documentation companion is needed: this package keeps its API and internal documentation in these files.
Startup order
How does a newly allocated startup spend its ceiling?
harperLifecycle.ts:623
Product and architecture tour
Deadline contract
Ownership and diagnostics
A pre-existing allocator limitation remains: validation or bind-canary failure before it returns can leave a claimed slot under the runner PID. The failure cleanup here starts once allocation returns; this PR does not change those allocator error branches.
The new internal releaseLoopbackReservation checks age under the pool lock. At six minutes or older it skips automatic release because a recovered slot can already belong to a newer start under this PID; the public release API stays unchanged.
Recovery remains bounded: direct/legacy holders, long custom ceilings, reservations held between kill and restart, wall-clock changes and stalled runners can outlast six minutes. The quarantine constant and recovery policy are unchanged.
The short internal helper contracts are retained: they document the clock origin, listener ordering and private export boundary, following the repository’s existing internal-helper convention.
✅ Verification
npm run build,npm run check,npm test: passed on Node 26.2.0, Linux; 100 tests total, 88 passed, 12 existing platform skips.git diff --check: passed; the repository defines no linter/formatter.4acac9a; commitlint also passed.🤖 Generated by OpenAI Codex; posted via @kriszyp.
Related PRs: #32 overlaps (follow-up to merged quarantine), #33 overlaps (pool publication and release locking), #35 overlaps (startup and shutdown supervision), 1 others independent
Complexity: complicated
Review-Coverage: authored=codex; ran=cursor-composer,gemini,claude,cursor-muse; adjudicated=domain; declined=cursor-grok,cursor-kimi; rounds=4; full=2 @ 4acac9a
Review-Attention: read ~5m (decisions: do-less-alternative, startup-boundaries, reservation-age-guard, clock-source) @ 4acac9a