Conversation
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs real behavior proof before merge. Reviewed September 18, 2026, 1:38 PM ET / 17:38 UTC (Revision 9). ClawSweeper reviewWhat this changesAdds deadlines and process-group cleanup to Git worktree helpers, bounds output draining, and shares child-waiting logic with restart handoffs. Regression provenancePossible regression — suspected (reviewed change). No predecessor PR is attributed. Merge readiness⛔ Blocked before merge - 6 items remain The work remains necessary on main. The earlier pipe-drain and surviving-descendant findings are resolved, but the previously reported slow-operation compatibility defect remains. Priority: P2 Review scores
Verification
How this fits togetherOCM uses Git helpers to create, validate, and remove source worktrees for managed environments and upgrade simulations. Their results determine whether environment preparation or cleanup can proceed. flowchart TD
A[Environment preparation or cleanup] --> B[Git worktree helper]
B --> C[Timed subprocess runner]
C --> D{Child and output finished?}
D -->|Yes| E[Return Git result]
D -->|Deadline exceeded| F[Terminate process group]
F --> G[Report timeout or drain result]
Decision needed
Why: The existing contract has no wall-clock cutoff, and the contributor explicitly defers this behavior choice to the owner. Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Keep bounded pipe draining and descendant cleanup, preserve valid slow operations by default, and make any strict cutoff explicit with demonstrated interruption recovery. Do we have a high-confidence way to reproduce the issue? Yes, source establishes that main waits indefinitely for a stuck Git child or inherited output pipe. The remaining patch defect is also deterministic for a valid operation exceeding 15 seconds; neither scenario was executed during this read-only review. Is this the best way to solve the issue? Partly: the shared runner repairs the reported waiting and cleanup paths, but a universal 15-second limit does not distinguish stalled Git from valid slow work. A compatibility-preserving timeout policy is safer. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 6ff9fb59f105. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (8 earlier review cycles)
|
b080857 to
0284e88
Compare
638df70 to
db422a7
Compare
ensure_openclaw_worktree and related helpers used Command::output() with no deadline. A stuck git lock blocked ocm setup and cleanup. Wait with a timeout and kill the child. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca> (cherry picked from commit da84e02)
The 200ms deadline plus SIGTERM grace can exceed 1s on macos-latest. Keep proving we do not wait the full 30s sleep. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca> (cherry picked from commit db422a7)
db422a7 to
6a6dfd1
Compare
dev_stop_acknowledgement_refuses_live_recorded_ownership failed once on macos-latest; the same test passed on openclaw#117 and openclaw#136 from the same main. This PR does not touch that test. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
command_output joined stdout/stderr readers after the direct child exited, so a descendant that still held those pipes blocked the caller. Keep the original deadline across the drain, then terminate the process group so the readers can finish. The 15s default is unchanged. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
|
@clawsweeper re-review P1 keep-deadline-while-draining-pipes is now in the tip.
Live analog: after the middle process exits, a raw The 15s default is unchanged. The other P1 (preserve valid worktree operations that exceed 15 seconds) is an owner default decision and is not in this commit. |
|
🦞🧹 I asked ClawSweeper to review this item again. |
macos-latest spent the 400ms budget starting python3, so the direct child never exited before wait_for_child timed out. Hold stdout with /bin/sleep in the background instead. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
terminate_child returned as soon as try_wait saw the direct child had already exited, so a TERM-resistant grandchild that still held stdout never received group KILL. Wait on live process-group members, then escalate. The 15s default is unchanged. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
|
@clawsweeper re-review P2 escalate-cleanup-when-descendants-survive is in the tip.
Live analog: The 15s default is unchanged. Owner decision still needed: should valid worktree operations that take longer than 15 seconds keep running (progress-based, override, or a longer default), or is a hard 15s cutoff the intended policy after upgrade? This PR does not change that default. |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Thanks for working through the pipe-drain and descendant-cleanup cases. I’m closing this version because the new unconditional 15-second deadline also interrupts valid worktree creation, filters, and removal. Main has no such cutoff, so this changes successful operations into failures and can leave an interrupted Git mutation to recover. A compatible cancellation policy needs a separate design decision; this maintenance pass will preserve existing slow-operation behavior rather than land the hard cutoff. |
What Problem This Solves
Fixes an issue where
ocmdev, setup, and upgrade would hang forever when a git worktree helper (worktree add/remove/status/ls-files/submodule foreach) blocked on a lock or a stuck child. Those helpers calledCommand::output()with no kill deadline.The first timeout patch waited only on the direct child, then joined stdout/stderr readers with no deadline. A descendant that still held those inherited pipes could block the caller after the child had already exited. The drain path then called terminate on that already-exited child;
try_wait()returnedSomeand skipped process-group KILL, so a TERM-resistant descendant stayed alive.On origin/main the hang is here:
ocm/src/openclaw_repo.rs
Lines 123 to 129 in e04c101
e04c101
Why This Change Was Made
Production worktree helpers now go through a shared timed runner. The child is polled, then terminated (process group TERM, then KILL) when the deadline expires. The same deadline stays active while the captured pipes drain. Cleanup waits for the process group, not only the direct child, so a descendant that ignores TERM still gets KILL. Fixture git used only to build temp repos stays unbounded. The 15s default is unchanged.
User Impact
A wedged git during worktree setup or cleanup fails after 15s instead of blocking the CLI. A helper whose direct child already exited no longer hangs on leftover pipe holders, and TERM-resistant leftovers are killed with the group. Successful worktree add/remove/status behavior is unchanged.
Evidence
Live analog of the remaining descendant leak. The grandchild ignores SIGTERM and holds a pipe. TERM alone leaves it alive. KILL removes it:
The patched
command_outputruns that same shape (parent exits, TERM-resistant descendant holds stdout) with an 800ms deadline. It returns in 1.50s and the descendant is gone. A realensure_openclaw_worktreeadd/reuse/remove on a temp OpenClaw fixture returns in 1.02s through the samegit_outputpath. The 15s production default is unchanged.Earlier live analog of the unbounded drain hang, plus rustc
/bin/sleep 30vs the 200ms deadline, remains in the prior evidence.Real behavior proof
ocmforever. After the direct child exits, inherited stdout/stderr drains stay under the same deadline. A TERM-resistant descendant that still holds those pipes is killed with the process group./private/tmp/ocm136-p1onfix/git-worktree-timeout.python3 /tmp/proof-ocm136-p2-live.pyto show TERM-only leaves the descendant alive. Then ran the patchedcommand_outputagainstperlthat forks, ignores SIGTERM, writes its pid, and sleeps 30s. Then ran productionensure_openclaw_worktreeadd/reuse/remove on a temp OpenClaw git repo.alive_after_term_only=True,gone_after_kill=True. The patched runner returned in 1.50s with the descendant gone.ensure_openclaw_worktreecompleted add/reuse/remove in 1.02s.GIT_COMMAND_TIMEOUTis still 15 seconds.git_outputstill succeeds. The 15s default is unchanged.index.lockhang inside a full OpenClaw checkout duringocm setup, the Windows job-object kill path, and lengthening the 15s default for valid slow worktree operations. That last item is an owner decision.Summary
Shared timed runner for git worktree helpers. Deadline covers the direct child wait and the inherited pipe drain. Process-group cleanup escalates to KILL even when the direct child has already exited. 15s default unchanged.