v1.0.89 (KUSS-STDIN): stdin=DEVNULL for both kiss children + verdict classes (timeout/spawn/thread-held) + leg 3k-15 #125

Merged
ClaudiuSchuster merged 3 commits from oss-oo/kuss-stdin into main 2026-10-27 13:59:00 +00:00
Member

Two findings from the live validation of the codex seam (2026-10-27, after v1.0.86/87).

  1. Piped stdin hangs the seam. codex exec reads "additional input from stdin" whenever its stdin is a non-tty pipe and starts the turn only afterwards. The kiss child inherited the dispatcher's stdin (only the claude child had /dev/null); under systemd that was /dev/null already, but from a tool harness or a CI step the seam hangs to the bound — measured 12:41: 300 s, no thread created. Every kiss child now gets stdin=DEVNULL.
  2. The app-held thread. codex-core keeps ONE writer per thread, and the ChatGPT desktop app's codex app-server (child of the app process) holds every thread it loaded — with no turn running. codex exec resume into an open conversation fails fast with thread-store conflict: … already has an active writer (measured 12:37 and 12:39, exit 1 in 362/469 ms; lsof showed the app-server holding the rollout). Mama's main chat is held whenever the app is open; reaching it needs a thread the app does not hold, or another transport — the family's design call, not this PR's. The receipt names the class: reason: "thread-held". A codex turn that outruns its timeout_s is named "timeout" (the claude backend already was).

Changes

  • dispatch.py: stdin=subprocess.DEVNULL for both backends; _kiss_verdict classifies codex timeouts, spawn errors and the held thread.
  • stream_functional_test.py: leg 3k-15 — a fake codex answering like the one-writer rule yields exit 4 + reason: thread-held in the --kiss-test JSON and on the receipt, and records via /proc/$$/fd/0 that the probe and the real call both read /dev/null; a hanging fake under a per-target timeout_s: 1 yields reason: timeout with timeout_s: 1; summary clause.
  • docs/USAGE.md §34 and the README --kiss-test row.

Live evidence. Validated the same day against a headless codex thread (a cheap twin of the owner's validation session): --kiss-test → delivered: true in 6.9 s, receipt timeout_s: 300, the kiss line and the answer ok in the thread's rollout, task_complete.

Version. Relabeled from v1.0.88 to v1.0.89 on Z's word (13:14): the fleet's FLOTTE+OO-DISPATCH round takes v1.0.88 and lands first; the relabel commit touches comments, the suite's summary clause and the docs only.

Gates. py_compile green; ruff/pylint on dispatch.py without new findings; laboratory CI on this PR; a local run of the CI image in flight.

Authored and committed as claude <claude@agents.oss-oo.io> under fleet law v2.

🤖 Generated with Claude Code

**Two findings from the live validation of the codex seam (2026-10-27, after v1.0.86/87).** 1. **Piped stdin hangs the seam.** `codex exec` reads "additional input from stdin" whenever its stdin is a non-tty pipe and starts the turn only afterwards. The kiss child inherited the dispatcher's stdin (only the claude child had `/dev/null`); under systemd that was `/dev/null` already, but from a tool harness or a CI step the seam hangs to the bound — measured 12:41: 300 s, no thread created. Every kiss child now gets `stdin=DEVNULL`. 2. **The app-held thread.** codex-core keeps ONE writer per thread, and the ChatGPT desktop app's codex app-server (child of the app process) holds every thread it loaded — with no turn running. `codex exec resume` into an open conversation fails fast with `thread-store conflict: … already has an active writer` (measured 12:37 and 12:39, exit 1 in 362/469 ms; `lsof` showed the app-server holding the rollout). Mama's main chat is held whenever the app is open; reaching it needs a thread the app does not hold, or another transport — the family's design call, not this PR's. The receipt names the class: `reason: "thread-held"`. A codex turn that outruns its `timeout_s` is named `"timeout"` (the claude backend already was). **Changes** - `dispatch.py`: `stdin=subprocess.DEVNULL` for both backends; `_kiss_verdict` classifies codex timeouts, spawn errors and the held thread. - `stream_functional_test.py`: leg 3k-15 — a fake codex answering like the one-writer rule yields exit 4 + `reason: thread-held` in the `--kiss-test` JSON and on the receipt, and records via `/proc/$$/fd/0` that the probe and the real call both read `/dev/null`; a hanging fake under a per-target `timeout_s: 1` yields `reason: timeout` with `timeout_s: 1`; summary clause. - `docs/USAGE.md` §34 and the README `--kiss-test` row. **Live evidence.** Validated the same day against a headless codex thread (a cheap twin of the owner's validation session): `--kiss-test` → `delivered: true` in 6.9 s, receipt `timeout_s: 300`, the kiss line and the answer `ok` in the thread's rollout, `task_complete`. **Version.** Relabeled from v1.0.88 to v1.0.89 on Z's word (13:14): the fleet's FLOTTE+OO-DISPATCH round takes v1.0.88 and lands first; the relabel commit touches comments, the suite's summary clause and the docs only. **Gates.** py_compile green; ruff/pylint on `dispatch.py` without new findings; laboratory CI on this PR; a local run of the CI image in flight. Authored and committed as `claude <claude@agents.oss-oo.io>` under fleet law v2. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude agent added 1 commit 2026-10-27 11:52:48 +00:00
Two findings from the live validation of the codex seam on 2026-10-27:

1. `codex exec` reads "additional input from stdin" whenever its stdin is a non-tty pipe and starts the turn only afterwards. The kiss child inherited the dispatcher's stdin (only the claude child had /dev/null); under systemd that was /dev/null already, but from a tool harness or a CI step the seam hangs to the bound — measured 12:41: 300 s, no thread created, exit 124 at the outer timeout. Every kiss child now gets stdin=DEVNULL.

2. codex-core keeps ONE writer per thread, and the ChatGPT desktop app's codex app-server holds every thread it loaded — with no turn running. `codex exec resume` into an open conversation fails fast: "thread-store conflict: thread … already has an active writer" (measured 12:37 and 12:39 against an open conversation, exit 1 in 362/469 ms). Mama's main chat is held whenever the app is open; reaching it needs a thread the app does not hold, or another transport — the family's design call. The receipt now names this class: reason "thread-held". A codex turn that outruns its timeout_s is named "timeout" (the claude backend already was).

- dispatch.py: stdin=DEVNULL for both backends; `_kiss_verdict` classifies codex timeouts, spawn errors and the held thread.
- stream_functional_test.py: leg 3k-15 — a fake codex answering like the one-writer rule yields exit 4 + reason thread-held in JSON and receipt, and records that the probe and the real call both read /dev/null; a hanging fake under a per-target timeout_s of 1 yields reason timeout with timeout_s 1; summary clause.
- docs/USAGE.md §34 and the README --kiss-test row.

Validated live the same day against a headless codex thread: `--kiss-test` → delivered true in 6.9 s, the kiss line and the answer in the thread's rollout.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent changed title from v1.0.88 (KUSS-STDIN): every kiss child reads /dev/null — codex exec waits for piped stdin to the bound — and codex receipts name the app-held thread (thread-held) and the clock that ran out (timeout) to v1.0.89 (KUSS-STDIN): every kiss child reads /dev/null — codex exec waits for piped stdin to the bound — and codex receipts name the app-held thread (thread-held) and the clock that ran out (timeout) 2026-10-27 12:15:37 +00:00
Author
Member

Gate trail (as claude)

  • The local CI-image run on the first head (fc2ec4f) ended with MAKE_EXIT=2: a TypeError in the new leg 3k-15 — the hang twin's env passed ZDO_KISS_TARGETS twice (kuss_env already pins it). The held-thread half of the leg had passed before the crash; app_driver_test was ALL LEGS GREEN. Laboratory runs 321/322 were cancelled by the pushes.
  • Fixed in 7ee4c34: the env is built once and the pinned target list is overridden. Hermetic smoke of the dispatcher side (fake hanging codex under timeout_s: 1, rig config dir, live files untouched): exit 4, reason: timeout, receipt timeout: true, timeout_s: 1, duration_ms: 1001, probe + one real call.
  • 6ef89d0 was the relabel to v1.0.89 (text only). Laboratory CI and a fresh CI-image run are now in flight on 7ee4c34; verdicts follow.
**Gate trail (as `claude`)** - The local CI-image run on the first head (`fc2ec4f`) ended with `MAKE_EXIT=2`: a `TypeError` in the new leg 3k-15 — the hang twin's env passed `ZDO_KISS_TARGETS` twice (`kuss_env` already pins it). The held-thread half of the leg had passed before the crash; `app_driver_test` was ALL LEGS GREEN. Laboratory runs 321/322 were cancelled by the pushes. - Fixed in `7ee4c34`: the env is built once and the pinned target list is overridden. Hermetic smoke of the dispatcher side (fake hanging codex under `timeout_s: 1`, rig config dir, live files untouched): exit 4, `reason: timeout`, receipt `timeout: true, timeout_s: 1, duration_ms: 1001`, probe + one real call. - `6ef89d0` was the relabel to v1.0.89 (text only). Laboratory CI and a fresh CI-image run are now in flight on `7ee4c34`; verdicts follow.
Author
Member

Gate results on the fixed head 7ee4c34 (as claude)

  • Laboratory CI run 325: success (2026-10-27 12:56 UTC).
  • Local run of the CI image (python:3.12-slim-bookworm, workspace at /workspace/OSS-Singularity/zcode-dispatch): app_driver_test: ALL LEGS GREEN, stream functional test OK with the v1.0.89 clause in the summary line (the codex seam's closed stdin + named receipt classes …), zero STREAM-TEST FAIL, no traceback, MAKE_EXIT=0, PODMAN_EXIT=0. The station's live postbox (11 rows) and kiss receipts (17 rows) did not change during the run. Log: ~/.zcode/tmp/claude-adapter-design-20261027/container-suite/make-functional-container-20261027-132313-v1089.log on envy.

Both gates green. Ready for the co-review; v1.0.88 (#126) lands first per Z's word.

**Gate results on the fixed head `7ee4c34` (as `claude`)** - Laboratory CI run 325: **success** (2026-10-27 12:56 UTC). - Local run of the CI image (`python:3.12-slim-bookworm`, workspace at `/workspace/OSS-Singularity/zcode-dispatch`): `app_driver_test: ALL LEGS GREEN`, `stream functional test OK` with the v1.0.89 clause in the summary line (`the codex seam's closed stdin + named receipt classes …`), zero `STREAM-TEST FAIL`, no traceback, **MAKE_EXIT=0, PODMAN_EXIT=0**. The station's live postbox (11 rows) and kiss receipts (17 rows) did not change during the run. Log: `~/.zcode/tmp/claude-adapter-design-20261027/container-suite/make-functional-container-20261027-132313-v1089.log` on envy. Both gates green. Ready for the co-review; v1.0.88 (#126) lands first per Z's word.
ClaudiuSchuster changed title from v1.0.89 (KUSS-STDIN): every kiss child reads /dev/null — codex exec waits for piped stdin to the bound — and codex receipts name the app-held thread (thread-held) and the clock that ran out (timeout) to v1.0.89 (KUSS-STDIN): stdin=DEVNULL for both kiss children + verdict classes (timeout/spawn/thread-held) + leg 3k-15 2026-10-27 13:58:59 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
OSS-Singularity/zcode-dispatch!125
No description provided.