Skip to content

fix: create stops its host and names the session on every error of its readiness wait - #294

Merged
ThomasK33 merged 14 commits into
mainfrom
fix/264-create-giveup
Nov 3, 2026
Merged

ThomasK33 merged 14 commits into
mainfrom
fix/264-create-giveup

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Why

ThomasK33 asked to work every deferred follow-up of the first autopilot round until none is left. This PR fixes items 2 to 5 of #264, the follow-ups after #247 (for #209). Item 1, the Windows stop channel, comes in a second PR, which closes #264.

On Linux and macOS, a create that gives up on its host stops that host since #247. Three gaps were left. Errors in the readiness loop other than HOST_UNREACHABLE and HOST_TIMEOUT rethrew without the stop, so a host could still serve a session whose create had failed, the #209 leak (item 4). The create error envelope did not name the session (item 4). USAGE did not describe a stopped host or the cleanup timing (items 2 and 3), and no test or check pinned the stop after the host exits or the order of the host's SIGTERM handler (item 5).

What changed

  • src/cli/commands/create.ts
    • The readiness loop moved into waitForReadyHost. It returns the create result, or throws. runCreateCommand wraps it in one try. Every error of the wait, the last failed inspect included, calls host.stop() and then rethrows. A failed first manifest write inside allocateSession keeps its old path: create removes the folder, and the host exits without spawning once create exits. Examples are a manifest that is gone after the host answered, a manifest read that throws, and an error that is not a CliError.
    • The Windows rule stays: there create stops the host only once the manifest names the program. The catch reads the manifest again for that rule, and a read error counts as no program.
    • withSessionId adds details.sessionId to the rethrown error and keeps its code, message, retryable and other details. An error that is not a CliError becomes INTERNAL_ERROR with the same message, as the top-level handler printed it before.
  • Lifecycle check (.agents/skills/verify-session-lifecycle)
    • facts.mjs reads CreateStopsOnGiveUp from the try around waitForReadyHost: its only statement is the wait, and its catch ends with the invariant, the manifest read, the platform if with host.stop(), and throw withSessionId(error, sessionId).
    • The same guard now also requires that runHost registers its SIGTERM handler before waitForManifestFromCreate (item 5). A handler after the wait, a catch without the stop, and a plain throw error each read CreateStopsOnGiveUp as FALSE (checked by hand on three mutated copies).
    • waitForReadyHost joins the covered functions.
    • SKILL.md: the CreateStopsOnGiveUp section and the Scope list name the stopped host (item 2).
  • Docs: docs/USAGE.md (items 2, 3 and 4), src/cli/commands/README.md, src/host/README.md.
  • Tests: 7 new or changed create unit tests, a golden envelope for the shape of a create error with details.sessionId, details.sessionId in the give-up integration test, and 2 launchHost unit tests (stop() signals a running host, and sends nothing and does not throw once the host has exited).

Behavior changes for CLI and JSON users (automation-facing)

  • Additive: every create error after the session was allocated carries error.details.sessionId. Error codes, exit codes and the other details keys do not change. The error envelope's details is a free-form record (CommandError.details: Record<string, unknown> in src/protocol/envelope.ts), so no Zod schema or message type changes. The create unit tests (test/unit/commands/create.test.ts) and the give-up integration test (test/integration/lifecycle.test.ts) pin details.sessionId on the error that create throws. The golden envelope test pins only the envelope shape with that key.
  • A create that fails after the launch for a reason other than an unreachable host now stops its host too (Linux and macOS, and on Windows once the manifest names the program). Before, such a host kept serving the session.
  • No other output changes.

Validation

  • Red first. At the tests-only commit (915de003, which I ran as ce427270 before the rebase onto 307c0e99), 7 create unit tests failed: no stop on the other errors, no details.sessionId, and a raw TypeError instead of INTERNAL_ERROR. All pass on the head.

  • launchHost tests: with stop() changed to process.kill(pid, 'SIGTERM'), both tests fail (the stop after the exit throws ESRCH). They pass on the head.

  • Live, with the CLI (node --import tsx src/cli/main.ts), an isolated AGENT_TTY_HOME and XDG_STATE_HOME, and a preload that delays the host's listen by 9 s, so create gives up after about 6 s:

    Case main 50860e8d head (on 50860e8d, rerun on 307c0e99)
    create exit code and error code 6, HOST_UNREACHABLE 6, HOST_UNREACHABLE
    error.details.sessionId absent the session id
    Program that exits on SIGHUP: status right after create exits, then time to destroyed destroyed, 0.02 s destroyed, 0.02 s (3 of 3)
    Program that ignores SIGHUP destroying, then destroyed after 2.03 to 2.06 s destroying, then destroyed after 2.08 to 2.10 s (3 of 3)
    Host start-up write held 12 s running at the exit and 3 s later, destroyed about 6 s after the exit
    Later destroy exit 4, SESSION_ALREADY_DESTROYED exit 4, SESSION_ALREADY_DESTROYED
    Host stopped with SIGSTOP before the give-up running after the exit and 3 s later, plain destroy exit 6 HOST_UNREACHABLE with the group alive, destroy --force exit 0 with the group and the host gone

    The issue estimated "about 2 to 6 s" for item 3. The measurements show 0 to 2 s with a responsive host, and longer only while the host's start-up write is slow, so USAGE says that.

  • Lifecycle check (.agents/skills/verify-session-lifecycle/scripts/check.sh --update-coverage) on the head: all 66 runs as expected, coverage synced in e9926007. The TLC constants that facts.mjs reads are the same as on main, so only the fingerprints of runCreateCommand, waitForReadyHost and facts.mjs change. The model does not change.

  • Gates on the head: typecheck, lint and format pass. Unit 1882/1882. lifecycle and cli integration 138/138 (vitest run --maxWorkers=1 --retry=2). CI runs the full suite. Live receipts: timing.sh, stopped.sh and delay-listen.mjs with their results, in the trail folder of this autopilot round.

  • Round 2 (Codex round 1 on e9926007, security clean): the code review found that the docs promised a stop and details.sessionId "after the launch", but a failed first manifest write in allocateSession gets neither. That path leaves nothing to stop or name: the folder is removed, and the host exits without spawning once create exits. Live, with a preload that fails that rename: create exits 8 with STORAGE_WRITE_ERROR, no folder is left, the _host is gone within 3 s, and no program ran. 17143437 narrows the comment, USAGE and the READMEs to errors after the first manifest write. create unit 19/19.

  • Round 3, no Codex round (Codex round 2 on 17143437 was clean in both lanes; root's conditional GO): merge of main 142f7793 (fix(host): keep sockets under a per-uid root and remove a dead host socket #288, 390ed0c2, only coverage.json conflicted), b03c9823 (the facts.mjs comment says "every error of the readiness wait"), 36c2bae0 (USAGE: HOST_UNREACHABLE exit 6 after about 6 s, HOST_TIMEOUT exit 5 after about 10 s; measured live at 6.0 s with a delayed listen and 10.0 s with a host that accepts but never answers). check.sh on the head: all 66 runs as expected, current 23,479,528 distinct states and current-no-token 22,893,820, the same as SKILL.md. facts.mjs drift 0. Unit 1914/1914. lifecycle and cli integration 138/138.

  • Merges of main 374937f9 and 0024ddfe (fix(host): read a group out of the CLI's pid space as running #291, fix(release): raise the Communique response token limit so release notes are not cut off #295, fix(host): read a terminal session next to the destroy marker as destroyed #284; merge 64edbfdd, coverage 4365f221), no Codex round (root's GO for merge-only deltas). Only coverage.json conflicted. check.sh on the head: all 71 runs as expected, current 25,534,376 distinct states and current-no-token 24,675,744. facts.mjs drift 0. Unit 1937/1937. lifecycle and cli integration 139/139. Typecheck, lint and format pass.

Refs #264


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: xhigh

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-03T16:59:28.216685Z 1714343 Manual request
🔒 Security Review ✅ Completed 2026-11-03T16:59:38.031176Z 1714343 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e99260072e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli/commands/create.ts Resolved
@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: e99260072e

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33 ThomasK33 changed the title fix: create stops its host on every error after the launch and names the session fix: create stops its host and names the session on every error of its readiness wait Nov 3, 2026
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 17143437ea

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 17143437ea

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Nov 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 3, 2026
@ThomasK33
ThomasK33 added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 8064471 Nov 3, 2026
25 of 26 checks passed
@ThomasK33
ThomasK33 deleted the fix/264-create-giveup branch November 3, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

create give-up: follow-ups after #247 (Windows stop channel, stopped host, timing docs, other loop errors)

1 participant