Repository navigation
Conversation
The cli Runner used exec.CommandContext's default cancel, an immediate SIGKILL to the CLI's pid. The CLI never got to stop what it had started itself, so its children ran on, reparented to init. Measured on the published io.pilot.aegis 0.1.3 bundles: `aegis.exec install-models` with a slow curl hit the 60 s method timeout, and the curl was still running with ppid=1 afterwards (darwin/arm64 pid 21800, linux/arm64 pid 30, linux/amd64 pid 39). The call also took 65 s, because the orphan held the stderr pipe until WaitDelay ran out. cmd.Cancel now sends SIGTERM. exec's existing WaitDelay (killGrace, 5 s) still escalates to SIGKILL, so a CLI that ignores SIGTERM costs at most 5 s more than before and can't hang a call. TestCLICancelSendsSIGTERMFirstE2E builds a real cli adapter over a script with a 1 s method timeout: - graceful: the script traps SIGTERM and kills its own child. On main the trap never runs and the child outlives the call; now both happen. - stubborn: the script ignores SIGTERM. It is still SIGKILLed, about 6 s after the call started (1 s timeout + 5 s killGrace). Both subtests fail on main and pass here (darwin/arm64, 3 runs). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
TeoSlayer
marked this pull request as draft
September 24, 2026 10:39
This was referenced Sep 24, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The cli
Runner(internal/scaffold/templates/client_cli.go.tmpl) usedexec.CommandContext's default cancel. When a call's context ended, the CLI's pid got an immediate SIGKILL. The CLI never got a chance to stop what it had started itself, so those children ran on, reparented to init.Measured on the published io.pilot.aegis 0.1.3 bundles with
aegis.exec {"args":["install-models"]}and a slowcurl:ppid=1: darwin-arm64 pid 21800, linux-arm64 pid 30, linux-amd64 pid 39. The call took 65,004 ms, because the orphan held the stderr pipe untilWaitDelayran out.sleep 600withppid=1, 2 of 2 runs.Fix
cmd.Cancelnow sends SIGTERM. The existingWaitDelay(killGrace, 5 s) still escalates to SIGKILL, so a CLI that ignores SIGTERM costs at most 5 s more than before and still can't hang a call.docs/CLI-ADAPTER.mdsays so.On macOS this change is required. There is no parent-death signal there, so once the CLI is SIGKILLed, nothing can stop its children. I measured an adapter built from the unpushed
fix/miren-lifecyclechange (0467324, which waits for running calls on shutdown and sets Pdeathsig on Linux) without this commit, with the patched aegis. SIGTERM mid-call still left the curl withppid=1on darwin/arm64 (3/3) and darwin/amd64 (3/3), and the adapter took 5 s to exit. With this commit added: 0 left, and the adapter exits in about 50 ms.Test
TestCLICancelSendsSIGTERMFirstE2Ebuilds a real cli adapter over a shell script with a 1 s method timeout:gracefulsleep 600childstubborngo vet ./...andgo test ./... -count=1pass on darwin/arm64.Verified on io.pilot.aegis 0.1.5 (all 4 platforms)
Bundles were built with
publish.BuildBundleand a TEST-ONLY key. Nothing was uploaded or signed with a real key. The template was #111 + 0467324 + this commit, and the natives came from pilot-protocol/aegis#4. The lifecycle harness drove the app: darwin/amd64 under Rosetta, Linux indocker --init.install-modelspast the 60 s timeout: 0 processes left on all four. The call ended at 60,001–60,031 ms, with noWaitDelayoverrun.help,version,statusandexec scan-cmd, 200 calls each: 200/200 ok, fd flat.This branch alone on
main(with aegis#4), darwin/arm64: the in-flight SIGTERM case is also 3/3 clean, and the timeout leaves nothing behind.Aegis 0.1.5 built from each candidate template
Harness measurements, same natives (aegis#4) and TEST-ONLY key. "In-flight" means the app was SIGTERMed while
aegis.exec install-modelswas running, 3 rounds each.With both #116 + this commit and #114, the other checks passed on all four platforms:
install-modelspast the 60 s timeout: IPC error, 0 left;Where the two differ:
help20/20 on all fouraegis.status×200, p50 / p95Related, not in this PR
{"exit":-1}(or 143) as a success. 0467324 (fix/miren-lifecycle, not yet opened) turns it into an IPC error. That change and this one merge cleanly inclient_cli.go.tmpl. They conflict only in the samedocs/CLI-ADAPTER.mdsentence, which is trivial to resolve.watchParent).🤖 Generated with Claude Code