fix(codex): close the consult-mode fence, report turn.failed as a failure, capture exit codes portably (#2671, #2669)

Three defects in the codex skill sections:

- The resumed-session bash block never closed its fence; every fenced region
  after it inverted (prose rendered as code, the synthesis-recommendation tail
  rendered inert). A repo-wide fence-pairing test now scans every generated
  SKILL.md and sections/*.md with a CommonMark-faithful state machine (an
  info-string opener inside a fence is literal content — nested template
  examples in document-generate/make-pdf stay legal; a file ending inside a
  fence fails).

- The JSONL parsers had no turn.failed branch: a turn that STATED its failure
  was reported as 'possible mid-stream disconnect'. Challenge and consult now
  print the event's error and run a three-way completeness check (failed-with-
  reason / silent-disconnect / ok); consult previously had no completeness
  check at all.

- ${PIPESTATUS[0]} is empty under zsh, so hang detection never fired and
  every clean run printed a spurious '[codex exit ]'. All three capture sites
  use ${PIPESTATUS[0]:-${pipestatus[1]}}, pinned statically and EXECUTED
  under real bash and zsh in the new test. Expect a step-change in
  codex_timeout telemetry — the counter starts firing for zsh users.

Receipt: the portability pin fails on a v1.77.0.0 scratch worktree; the fence
fix is structural (17 → 18 fence lines, tail no longer inside a block).

Fixes #2671
Fixes #2669

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-31 21:19:06 +00:00
co-authored by Claude Fable 5
parent 262a605794
commit 9ca92161e2
5 changed files with 176 additions and 10 deletions
+10 -3
View File
@@ -61,12 +61,19 @@ for line in sys.stdin:
usage = obj.get('usage',{})
tokens = usage.get('input_tokens',0) + usage.get('output_tokens',0)
if tokens: print(f'\ntokens used: {tokens}', flush=True)
elif t == 'turn.failed':
turn_failed = True
err = obj.get('error',{}).get('message','') or 'no error message in event'
print(f'[codex turn FAILED] {err}', flush=True, file=sys.stderr)
except: pass
# Fix 2: completeness check — warn if no turn.completed received
if turn_completed_count == 0:
# Fix 2: three-way completeness check (#2671) — a STATED failure is a failure,
# not a network problem; only silence with no terminal event is a disconnect.
if 'turn_failed' in dir():
print('[codex] turn.failed received — the turn errored (reason above), not a disconnect.', flush=True, file=sys.stderr)
elif turn_completed_count == 0:
print('[codex warning] No turn.completed event received — possible mid-stream disconnect.', flush=True, file=sys.stderr)
"
_CODEX_EXIT=${PIPESTATUS[0]}
_CODEX_EXIT=${PIPESTATUS[0]:-${pipestatus[1]}} # bash sets PIPESTATUS; zsh (lowercase, 1-indexed) falls through (#2669)
# Fix 1: hang detection — log + surface actionable message
if [ "$_CODEX_EXIT" = "124" ]; then
_gstack_codex_log_event "codex_timeout" "600"