Skip to content

fix(wrappers): P2 "Wrapper/runner hardening" — codex retry/timeout/stale-status/budget, claude provider_status, run_duo deadline, party actor timeout, play.sh idle+lock, sonnet cold-open margin (Refs #811) - #863

Merged
100yenadmin merged 1 commit into
mainfrom
fix/p2-wrapper-runner-hardening-811
Jun 14, 2026

Conversation

@100yenadmin

Copy link
Copy Markdown
Member

P2 cluster "Wrapper/runner hardening" (issue #811)

Brings the codex / openclaw / claude DM lanes up to the scripts/play.sh protections, per the audited P2 cluster. Every change is additive and bash 3.2-clean; it preserves #828's worldos_timeout shim + retry/timeout behavior and #841's failure-classification (both confirmed intact on main and re-used, not re-implemented).

Source of truth: docs/audits/ENGINE-AUDIT-2026-06-11.md (Part C per-finding specs) + the #811 cluster body.


Fixed (this PR)

Finding Change
F12-2 Sonnet (non-opus) cold-open deadline was 400s — equal to its own documented ~280–400s band TOP (thin margin). Non-opus default 400 → 550 in clawdnd_dm_timeout (opus unchanged at 500; the shipped default-opus path is byte-identical). Env override (WORLDOS_COLDOPEN_TIMEOUT) still wins.
F12-9 scripts/play_codex_dm.sh: (a) EXIT/INT/TERM trap now stamps provider_status "failed" on an abnormal exit (was stuck "running" — viewer kept showing a live-looking dead dashboard); (b) codex exec wrapped in an inline worldos_timeout (WORLDOS_CODEX_TURN_TIMEOUT, default 500s) + ONE retry (codex turns are stateless → session-safe); (c) the budget envs (validated then never used) are now enforcedcodex_session_spend_usd accounts spend from codex's cumulative token_count events at an explicit, overridable rate (WORLDOS_CODEX_USD_PER_MTOK) and stops the session "exhausted" at CLAWDND_PLAY_SESSION_BUDGET.
F12-10 Claude lanes never wrote provider_status.json → factored clawdnd_write_provider_status (atomic tmp+fsync+replace, worldos.provider-status.v1) into qa/lib_beat_driver.sh; play.sh + play_party.sh now write running / stopped (turn_cap|budget|idle) / failed, so the viewer buckets a dead/stopped session as no_provider instead of falling back to "unknown".
F12-11 qa/run_duo.sh DM turn was unbounded and swallowed the real failure cause → wrapped in worldos_timeout "$(clawdnd_dm_timeout "$first")"; reports the structured cause on rc!=0 with no error-class result (dedup-guarded against clawdnd_dm_final_text); the inline cold-open remint is replaced with the shared clawdnd_dm_remint_session_on_retry; the empty-output retry is kept as the second trigger.
F12-12 play_party.sh companion (actor) turn was an unbounded claude -p → wrapped in worldos_timeout "${WORLDOS_ACTOR_TIMEOUT:-120}"; empty on failure, so companion_moves' [ -n "$cm" ] && guard skips it (graceful degradation — the beat still reaches the DM).
F12-13 play.sh (the .app's default solo entry point) had no idle ceiling and no launch lock → ported play_party.sh's MAX_IDLE block (CLAWDND_PLAY_MAX_IDLE, default 1800s) + acquires/releases the single-flight launch lock.

Skipped — already done on main (confirmed still intact)

Deferred (out of this PR's scope)

  • F12-20 (consolidation): play_codex_dm.sh carries an inline copy of worldos_timeout (byte-identical behavior to the lib's canonical copy) because the codex wrapper is deliberately self-contained (own chatlog/log_engine_narration/record_dm_reply that would 3-way clash on source). Flagged in-code; F12-20 tracks the dedup.
  • F12-14+ (the rest of the unit-12 backlog) are separate findings, not this cluster.

Tests

All green locally:

  • Tier-0 fast_gate: 191 passed.
  • Codex wrapper (servers/engine/tests/test_codex_provider_wrapper.py): 34 (28 original + 6 new F12-9, incl. 3 runtime fake-codex: crash→failed, retry-recovers, over-budget→exhausted).
  • wrapper-reliability + opus-tuning + adversarial-release: 43 (updated the F12-2 guards: opus-tuning 400→550, retry-escalation sonnet 400→550).
  • New shell tests (no model calls, macOS + ubuntu-CI safe): qa/test_play_party_actor_timeout.sh, qa/test_run_duo_dm_timeout.sh, qa/test_provider_status_claude_lanes.sh; extended qa/test_play_party_single_flight.sh (+play.sh lock/idle); rewrote the stale qa/dryrun_coldopen_timeout_proof.sh (it still asserted routine=200 after F12-1 moved it to 360 — it was red and not gated).
  • /bin/bash -n clean on every touched script. Full 2351-test engine suite deferred to GitHub CI per the test-execution policy.

DO NOT MERGE — for review. Refs #811 (the cluster remainder beyond F12-2/9/10/11/12/13 is not in this PR's scope).

…meout/stale-status/budget, claude provider_status, run_duo deadline, party actor timeout, play.sh idle+lock, sonnet cold-open margin (Refs #811)

Brings the codex/openclaw/claude lanes up to the play.sh protections per the
audited P2 cluster. All changes additive + bash 3.2-clean; preserves #828's
worldos_timeout shim + #841's failure-classification (both confirmed intact).

F12-2  sonnet cold-open deadline 400 had thin (band-top) margin → non-opus
       default 400→550 in clawdnd_dm_timeout (opus unchanged 500). Updated the
       opus-tuning + wrapper-reliability guards; rewrote the (already-stale,
       routine=200) cold-open timeout proof to 360 + added opus/sonnet margin
       scenarios.
F12-9  codex DM wrapper (play_codex_dm.sh): EXIT/INT/TERM trap now stamps
       provider_status "failed" on abnormal exit; codex exec wrapped in an
       inline worldos_timeout (WORLDOS_CODEX_TURN_TIMEOUT) + ONE session-safe
       retry; session budget ENFORCED via token-count spend accounting
       (WORLDOS_CODEX_USD_PER_MTOK) → "exhausted" stop (the budget envs were
       validated then never used).
F12-10 claude lanes never wrote provider_status.json → factored
       clawdnd_write_provider_status (atomic, v1 schema) into the lib; play.sh +
       play_party.sh write running/stopped(turn_cap|budget|idle)/failed so the
       viewer buckets a dead/stopped session as no_provider instead of "unknown".
F12-11 run_duo DM turn was unbounded + swallowed the real cause → wrap in
       worldos_timeout(clawdnd_dm_timeout); report on rc!=0 (dedup-guarded);
       replace the inline cold-open remint with the shared
       clawdnd_dm_remint_session_on_retry; keep empty-output retry as 2nd trigger.
F12-12 play_party companion (actor) turn was unbounded → worldos_timeout
       ${WORLDOS_ACTOR_TIMEOUT:-120}; empty on failure (companion_moves skip-safe).
F12-13 play.sh had no idle ceiling and no launch lock → port play_party's
       MAX_IDLE block + acquire/release the single-flight launch lock.

Skipped as already-done (confirmed on main): F12-1/3/4/5/8 (#828), SYN-01 (#841).

Tests: fast_gate Tier-0 191 passed; codex wrapper 34 (incl 6 new F12-9, 3 runtime
fake-codex); wrapper-reliability/opus/adversarial 43; new shell tests
test_play_party_actor_timeout.sh, test_run_duo_dm_timeout.sh,
test_provider_status_claude_lanes.sh + extended single-flight + cold-open proof.

Source: docs/audits/ENGINE-AUDIT-2026-06-11.md
@100yenadmin 100yenadmin added this to the v1.0.5 milestone Jun 14, 2026
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@100yenadmin, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 40 minutes and 22 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 634ed3b8-02c6-4cc3-bfa9-76bc27680c7f

📥 Commits

Reviewing files that changed from the base of the PR and between de2a81c and 0d428fa.

📒 Files selected for processing (13)
  • qa/dryrun_coldopen_timeout_proof.sh
  • qa/lib_beat_driver.sh
  • qa/run_duo.sh
  • qa/test_play_party_actor_timeout.sh
  • qa/test_play_party_single_flight.sh
  • qa/test_provider_status_claude_lanes.sh
  • qa/test_run_duo_dm_timeout.sh
  • scripts/play.sh
  • scripts/play_codex_dm.sh
  • scripts/play_party.sh
  • servers/engine/tests/test_codex_provider_wrapper.py
  • servers/engine/tests/test_opus_coldopen_tuning.py
  • servers/engine/tests/test_wrapper_reliability.py

Comment @coderabbitai help to get the list of available commands and usage tips.

@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: 0d428fafcd

ℹ️ 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 scripts/play_codex_dm.sh
Comment on lines +764 to +768
if [ "$status" -ne 0 ]; then
echo "[codex-dm-provider] codex turn rc=$status — retrying once (codex turns are stateless, so the retry is session-safe)" >&2
: > "$LAST_MESSAGE"
status=0
_codex_exec_once || status=$?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid replaying Codex turns after tool writes

When codex exec times out or exits nonzero after it has already invoked engine MCP tools, this retry replays the same prompt from scratch. The non-hero opening prompt can run start_world/seating again, and a move prompt can re-apply the same player action, so a transient timeout after a successful mutation can mint duplicate campaigns or double-apply attacks/persistence. Unlike the Claude cold-open retry path, this has no live-campaign re-grounding or idempotency check before retrying.

Useful? React with 👍 / 👎.

Comment thread scripts/play_party.sh
Comment on lines +391 to +394
worldos_timeout "${WORLDOS_ACTOR_TIMEOUT:-${CLAWDND_ACTOR_TIMEOUT:-120}}" \
claude -p "$msg" "${resume[@]}" --mcp-config "$cfg" --strict-mcp-config \
--model "$CLAWDND_ACTOR_MODEL" --permission-mode bypassPermissions --max-budget-usd "$BUDGET" \
--output-format stream-json --verbose > "$out" 2>> "$STATE_DIR/companion.err" || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Skip the actor nudge after a timed-out companion turn

When the companion claude call times out or otherwise fails here, || true makes turn actor return like an ordinary empty/no-op turn, so actor_move immediately sends its existing “You didn't act” nudge and waits for another full WORLDOS_ACTOR_TIMEOUT. In the wedged-companion case this doubles the pre-DM stall per companion before the human move can resolve, contrary to the intended graceful skip; propagate a timeout/failure sentinel so actor_move can skip the nudge on failed attempts.

Useful? React with 👍 / 👎.

@100yenadmin
100yenadmin merged commit 97c87bd into main Jun 14, 2026
17 checks passed
@100yenadmin
100yenadmin deleted the fix/p2-wrapper-runner-hardening-811 branch June 14, 2026 09:57
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