Skip to content

fix(host): stop the marker watch once the host has a new parent, give long TLC runs more workers - #330

Merged
ThomasK33 merged 9 commits into
mainfrom
fix/watch-parent-pid
Nov 4, 2026
Merged

ThomasK33 merged 9 commits into
mainfrom
fix/watch-parent-pid

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Follow-up to #324 and #328. Merged with main after #327.

What changed

  1. The host's create-failed marker watch now stops once the host has a new parent, and after 60 s in any case (src/host/hostMain.ts).
    • Codex found this in fix: on Windows, stop a late host after a failed create in more cases, and name the session in text mode #324 (P2, discussion_r4467725321). A process of the same user that takes the creator's pid before the next 100 ms tick keeps isProcessAlive answering. The watch then ticks at 10 Hz for that process's life. The host stays correct, because no marker comes after a successful create.
    • The host is the creator's child. Linux and macOS give it a new parent when the creator exits, also while the creator is a zombie, and before another process can take the pid. So off Windows, a process.ppid other than the creator's pid ends the watch. The /proc zombie read goes.
    • Windows keeps the parent pid, so there isProcessAlive still decides, as before.
    • CREATE_FAILED_WATCH_MAX_MS (60 s) ends the watch on every platform. A create ends within about 20 s of the host's start-up check. SKILL.md lists the new residual: a create that writes its marker more than 60 s later, for example after a SIGSTOP, leaves the host serving.
    • My reply in fix: on Windows, stop a late host after a failed create in more cases, and name the session in text mode #324 named a different fix: compare the creator's start time from /proc. The parent pid needs no /proc and also covers macOS, so I used it.
  2. check.sh gives the runs that expect pass more TLC workers. These runs explore the whole model. They now share the CPUs: CPUS / min(passes, CHECK_JOBS) workers each, at least 1. A run that expects a violation keeps 1 worker, so its trace stays the shortest. In CI a share has 4 vCPUs and 1 or 2 such runs, so each gets 4 or 2 workers. Before, the longest run (mutant-ReconcileSkipsTerminal) took 43 min with 1 worker and set the time of its share.
  3. Docs.
    • The ci.yml comment of ci: split the lifecycle-model job into 8 shares that start all their runs at once #328 said that check.sh waits for each batch of CHECK_JOBS runs. That was wrong: on Linux it keeps a pool (wait -n) and starts a new run as soon as one ends. Only the bash 3.2 of macOS waits for each batch.
    • SKILL.md on main still says that CI runs the check in four shares and that it takes about an hour. It now describes the 8 shares, CHECK_JOBS=12, the pool and the TLC workers.
  4. coverage.json sync for the covered runHost, facts.mjs and check.sh changes. facts.mjs (pollsCreateFailed) reads the new watch.

No CLI JSON, schema, manifest or event-log change.

Validation

  1. Red first: commit 4314dee adds two cases to test/unit/host/hostMarker.test.ts (new parent, 60 s bound). Both fail on the code of 99cb181 and pass after 89ff040. The tests set the host's parent pid through a process.ppid getter, because runHost runs in the test process. The zombie case goes: a zombie creator also gives the host a new parent.
  2. On the head after the merge with fix(destroy): destroy --force ends a session whose program group it cannot read #327 (f7d7da2): tsc --noEmit, oxlint src test vitest.config.ts and oxfmt --check . are clean, and vitest run test/unit passes 2065 tests.
  3. vitest run --maxWorkers=1 --retry=2 test/integration/lifecycle.test.ts test/integration/cli.test.ts passed 148 tests before the merge. After the merge, lifecycle passed. One cli test (uses --home instead of AGENT_TTY_HOME) hit its 5 s timeout while 90 TLC runs loaded the machine. cli.test.ts alone then passed 77 of 77.
  4. facts.mjs: I broke the new watch by hand (without the ppid check, without the deadline) and pollsCreateFailed turned false each time. After the merge, all 41 facts are true.
  5. check.sh --update-coverage after the merge with fix(destroy): destroy --force ends a session whose program group it cannot read #327: all 90 runs end as expected. Distinct states are unchanged: current 64,052,288, current-no-token 63,127,914, current-win32 53,200,220. (Before the merge, all 85 runs also ended as expected.)
  6. CI at d9aa042 (model of fix: on Windows, stop a late host after a failed create in more cases, and name the session in text mode #324): the 8 lifecycle-model shares took 11 to 33 min (share 1, with current and current-unseen, took 33 min). With 1 TLC worker per run they took 15 to 43 min on test: trial of the 8-share lifecycle-model job on #324 (do not merge) #329 and 16 to 36 min in the merge group of fix: on Windows, stop a late host after a failed create in more cases, and name the session in text mode #324. The ci.yml comment and SKILL.md give these times and name the model of fix: on Windows, stop a late host after a failed create in more cases, and name the session in text mode #324.
  7. CI at f7d7da2 (model of fix(destroy): destroy --force ends a session whose program group it cannot read #327, 90 runs): all 26 checks pass. The 8 lifecycle-model shares took 9 to 38 min (24.6 / 9.2 / 13.7 / 11.4 / 37.8 / 32.4 / 31.7 / 15.4), within the 55 min timeout.

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

… 60 s

A process of the same user that takes the creator's pid keeps the probe
answering, so the watch ticked for as long as that process lived. On
Linux and macOS the host is the creator's child and gets a new parent
when the creator exits, and the watch should stop then. It should also
stop 60 s after it started, as on Windows, where the parent pid stays.
Both new cases fail on the head. The tests now set the host's parent pid,
because runHost runs in the test process. The zombie case gives way to the
new-parent case: a zombie creator also gives the host a new parent.
…after 60 s

A process of the same user that took the creator's pid kept the watch's
probe answering, so the watch ticked at 10 Hz for that process's life.
The host is the creator's child, and Linux and macOS give it a new parent
when the creator exits, also while the creator is a zombie and before its
pid can be reused. So off Windows, a process.ppid other than the creator's
pid ends the watch, and the /proc zombie read goes. On Windows the probe
still decides. The watch also stops after 60 s in any case. facts.mjs
reads the new watch, and SKILL.md states the bound as a residual.
A share of CI's lifecycle-model job took as long as its longest run,
which TLC checked with 1 worker: 43 min for mutant-ReconcileSkipsTerminal.
The runs that expect pass now share the CPUs, each with at least 1 worker.
A run that expects a violation keeps 1 worker, so its trace stays the
shortest.
The ci.yml comment of #328 said that check.sh waits for each batch of
CHECK_JOBS runs. On Linux it keeps a pool and starts a new run as soon
as one ends; only the bash 3.2 of macOS waits for each batch. SKILL.md
still said that CI runs the check in four shares, and that it takes
about an hour. Both now describe the 8 shares, CHECK_JOBS 12 and the TLC
workers of the runs that expect pass.
@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 4, 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-04T19:41:22.688224Z f7d7da2 Manual request
🔒 Security Review ✅ Completed 2026-11-04T19:41:28.199863Z f7d7da2 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

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: d9aa04226d

ℹ️ 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: d9aa04226d

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.

On #330, where the runs that expect pass get the 4 vCPUs as TLC workers,
the 8 shares took 11 to 33 min. With 1 worker per run they took 15 to
43 min (#329).
# Conflicts:
#	.agents/skills/verify-session-lifecycle/SKILL.md
#	.agents/skills/verify-session-lifecycle/coverage.json
The times of 996c875 were measured with the model of #324. #327 adds
runs, and a share still holds 10 to 12 runs, of which at most 2 expect
pass.
@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. Already looking forward to the next diff.

Reviewed commit: f7d7da2bb3

ℹ️ 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: f7d7da2bb3

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 4, 2026
Merged via the queue into main with commit d6b3f0c Nov 4, 2026
27 checks passed
@ThomasK33
ThomasK33 deleted the fix/watch-parent-pid branch November 4, 2026 20:50
@github-actions github-actions Bot mentioned this pull request Nov 4, 2026
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.

1 participant