fix: honor context in waitForPair and waitForHello - #6
Conversation
waitForPair (6m) and waitForHello (30s) selected only on deadline, bridge errors, and frames. SIGINT during first-run pairing or hello stayed blocked until timeout. Honor the process context in both selects. Map cancel at the pair/run call sites to a clean exit, matching the reconnect loop. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
|
🦞👀 Pull request received. I will update this pull request when review starts. |
|
Codex review: needs maintainer review before merge. Reviewed September 2, 2026, 9:17 PM ET / September 3, 2026, 01:17 UTC. ClawSweeper reviewWhat this changesThe PR passes the process context into bridge pairing and hello waits so SIGINT or SIGTERM exits Merge readiness✅ Ready for maintainer review Keep open: current main still leaves pairing and hello waits outside the process cancellation context, while this focused PR adds the missing cancellation paths and provides real before/after CLI evidence. Priority: P2 Review scores
Verification
How this fits togetherClawgo is a headless node client that connects to the gateway bridge, pairs when needed, then completes hello before starting its node services. These waits sit between the bridge connection and the running node, so process cancellation must reach them to allow a prompt shutdown. flowchart TD
A[Operator starts run or pair] --> B[Process signal context]
A --> C[Gateway bridge connection]
C --> D[Pairing or hello wait]
B --> D
D --> E[Paired and connected node]
B --> F[Clean client close and exit]
D --> F
Before mergeNone. Agent review detailsSecurityNone. Review metrics
Technical reviewBest possible solution: Merge the narrow context propagation and retain the regression tests so startup pairing and hello waits honor the same shutdown contract as the rest of the node loop. Do we have a high-confidence way to reproduce the issue? Yes. The PR supplies a concrete before/after SIGINT scenario against a silent bridge, and current main retains the same non-cancelable wait implementation used by the baseline. Is this the best way to solve the issue? Yes. Threading the existing process context into the two bounded wait loops is the narrowest solution and matches the cancellation contract already used by the run loop. AGENTS.md: not found in the target repository. Codex review notes: model internal, reasoning high; reviewed against c6e46796a1c8. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (11 earlier review cycles; latest 8 shown)
|
What Problem This Solves
clawgo run(andclawgo pair) already installsignal.NotifyContextfor SIGINT and SIGTERM. After a first-run connect,waitForPair(6 minutes) andwaitForHello(30 seconds) selected only on the deadline,c.errs, and incoming frames.Ctrl+C during pairing or hello therefore did nothing until that deadline fired. The inner reconnect loop already returns on
ctx.Done(). These two waits did not.This PR threads the process context into both waits and returns on
ctx.Done(), matching the reconnect-loop pattern from #5. On cancel,run/pairclose the client and exit 0, same as the rest of the run loop.The wait functions were introduced in
f601408(2026-01-04) without a cancel case.Evidence
Before (binary from
upstream/main). Silent TCP acceptor, empty token, SIGINT duringwaitForPair. Process still running 2.027s later:After (this patch). Same silent acceptor and SIGINT. Process exits 0 in 0.017s:
Canceled wait returns
context.Canceledbefore the 6m/30s deadline. Without thectx.Done()case the same command failed; with it, it passed:Real behavior proof
Behavior or issue addressed: SIGINT during first-run pairing or hello no longer waits out the 6 minute / 30 second deadline.
Real environment tested: macOS 26.6.2 (Darwin 25.6.0 arm64), go1.27.0, clawgo built from this branch at
/tmp/oc-pr-clawgo-F002. Compared against a binary built fromupstream/main.Exact steps or command run after this patch: Started a silent TCP acceptor. Wrote a state file with no token. Ran
clawgo run -bridge 127.0.0.1:$PORT -mdns=false -tts-engine none -chat-subscribe=false. Afterrequesting pairing, sent SIGINT. Also rango test ./cmd/clawgo -run TestWaitForPairCancelUnblocks|TestWaitForHelloCancelUnblocks -count=1 -timeout 15s -vbefore and after thectx.Done()case.Evidence after fix: terminal output from the patched binary:
The unfixed binary stayed up:
Observed result after fix: After SIGINT during pairing,
clawgo runreturned in 0.017s with exit 0. The unfixed binary was still inwaitForPair2.027s later.What was not tested: Live pairing against a real OpenClaw gateway, and a 30s hello wait against a gateway that accepts the pair but never sends hello-ok. Hello cancel uses the same select as pair and is covered by
TestWaitForHelloCancelUnblocks.Command:
go test ./cmd/clawgo -run 'TestWaitForPairCancelUnblocks|TestWaitForHelloCancelUnblocks' -count=1 -timeout 15s -vand liveclawgo runplus SIGINT against a silent TCP acceptor.Observed: red step failed at 2.00s (
did not return after cancel). Green step passed at 0.00s. Live patchedclawgo runexited 0 in 0.017s after SIGINT; unfixed binary still running at 2.027s.Expected: cancel unblocks both waits with
context.Canceledbefore the 6m/30s deadline; SIGINT during pairing exits the process promptly.Time: 11:11:30 PDT
Date: 2026-08-29
Environment: macOS 26.6.2, Darwin 25.6.0 arm64, go1.27.0 darwin/arm64