Skip to content

fix: make the Opus DM default work end-to-end (per-turn budget + cold-open latency) - #684

Merged
100yenadmin merged 4 commits into
mainfrom
fix/opus-per-turn-budget-scaling
Jun 6, 2026
Merged

fix: make the Opus DM default work end-to-end (per-turn budget + cold-open latency)#684
100yenadmin merged 4 commits into
mainfrom
fix/opus-per-turn-budget-scaling

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Jun 6, 2026

Copy link
Copy Markdown
Member

#682 flipped the default DM model to Opus but the surrounding tuning was Sonnet-shaped, so the Opus default was broken at the cold-open. This PR makes it work end-to-end. All findings are measured on the VM (2026-06-06), not guessed.

Bug 1 — per-turn budget (backend never seated a PC)

The per-DM-turn cap defaulted to the Sonnet-tuned $1.50; the Opus cold-open world-build costs ~5× → the first turn tripped error_max_budget_usd, the backend never seated a PC (failure_bucket=no_actor, spend $0).

  • scripts/play.sh + scripts/play_party.sh: model-aware per-turn + session budget defaults (opus → $12 / $30; sonnet unchanged $1.50 / $15).
  • qa/ui_playtest_app.sh: the claude lane pinned CLAWDND_PLAY_BUDGET=\$1.50 unconditionally → scale it to DM_MODEL.

Bug 2 — cold-open latency (timed out before writing narration)

With the budget fixed, the Opus --effort max cold-open is generation-bound and never finished <400s — the turn was killed before writing narration, the harness grace-proceeded into an empty scene, and the timeout-retry minted a second campaign (the #640 condition).
Measured: Opus --effort high finishes ~300s with a full, BG-caliber opening ("the lamps of Sorcerous Sundries burn low and blue… Ramazith's old tower"), cost $2.36, 1 clean campaign.

  • qa/lib_beat_driver.sh: cold-open effort model-aware (opus → high, sonnet → max); cold-open timeout model-aware (opus → 500s, sonnet → 400s). Routine tier unchanged (medium / 200s).
  • qa/ui_playtest_app.sh: the part-B player-ready narration-wait is now env-configurable and defaults longer for an Opus DM, so QA waits for the ~300s opening instead of grace-proceeding.

Guards (Tier-0, CI-covered)

  • servers/engine/tests/test_dm_budget_scaling.py (3) + servers/engine/tests/test_opus_coldopen_tuning.py (3) — 6 assertions, pass locally.

Validation

Cold-open proven (above). Full narrative-persona session at Opus + high-cold-open + medium-routine + lean in flight (sat / give-up / arc / story).

…max_budget_usd)

#682 flipped the default DM model to Opus but left the per-turn budget cap at the
Sonnet-tuned $1.50. The Opus max-effort cold-open world-build costs ~5x a Sonnet turn,
so the very first (cold-open) DM turn tripped error_max_budget_usd and the faithful
backend never seated a player character (VM 2026-06-06: failure_bucket=no_actor, spend $0).

- scripts/play.sh + scripts/play_party.sh: model-aware per-turn + session budget DEFAULTS
  (opus -> $12 per-turn / $30 session; sonnet unchanged $1.50 / $15). Caps, not spends.
- qa/ui_playtest_app.sh: the claude backend lane pinned CLAWDND_PLAY_BUDGET=$1.50
  unconditionally, overriding the script default -> scale it to DM_MODEL too.
- servers/engine/tests/test_dm_budget_scaling.py: Tier-0 guard (3 assertions).

This is a release-blocker for the Opus default: every Opus cold-open (the production .app
included) would otherwise fail to seat a PC.
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Too much diff to scan? Review this PR in Change Stack to start with the highest-impact changes.

Review Change Stack

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 1 hour, 49 minutes, and 8 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ 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: fe3336a8-1ad1-4609-a3e7-2a99ffdc4e12

📥 Commits

Reviewing files that changed from the base of the PR and between 29e9d8d and db342ca.

📒 Files selected for processing (2)
  • qa/run_duo.sh
  • servers/engine/tests/test_dm_budget_scaling.py
📝 Walkthrough

Walkthrough

This PR makes DM budget, timeout, and polling defaults model-aware across shell scripts. Opus models now receive higher per-turn and session budgets, increased cold-open effort and timeout, and longer polling grace windows. Production play scripts and QA harness apply the new defaults; tests validate the branching logic and value constraints.

Changes

Model-aware Opus defaults across shell scripts and tests

Layer / File(s) Summary
Cold-open effort and timeout model-aware tuning
qa/lib_beat_driver.sh
clawdnd_dm_effort_arg and clawdnd_dm_timeout branch on CLAWDND_DM_MODEL to set Opus defaults (effort: high vs max; timeout: 500 vs 400s) and wire them through worldos_env.
QA harness model-aware play budget and polling
qa/ui_playtest_app.sh
Part B claude lane now sets CLAWDND_PLAY_BUDGET via model-dependent defaults, and configurable polling thresholds (WOS_APP_PLAYER_READY_POLLS, WOS_APP_NARRATION_GRACE_POLLS) apply longer Opus defaults to replace fixed poll counts.
Production play scripts model-aware budget defaults
scripts/play.sh, scripts/play_party.sh
Both scripts read CLAWDND_DM_MODEL and use case branching to select per-turn and session budget defaults (higher for Opus, prior values otherwise), replacing hardcoded literals.
Model-aware tuning test coverage
servers/engine/tests/test_dm_budget_scaling.py, servers/engine/tests/test_opus_coldopen_tuning.py
New unittests validate that shell scripts implement required *opus* branching, set Opus per-turn budgets ≥$10, correctly wire environment variables, and enforce timeout/polling/grace increases without unconditionally pinning lower Sonnet defaults.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • electricsheephq/WorldOS#563: Wires the computed model-aware cold-open effort from clawdnd_dm_effort_arg into qa/run_party.sh's cold-open vs continuing beat logic, directly aligning with this PR's effort-tiering behavior.
  • electricsheephq/WorldOS#567: Also modifies qa/lib_beat_driver.sh's cold-open timeout resolution, with this PR adding Opus-specific default tuning on top.
  • electricsheephq/WorldOS#374: Introduced the UI playtest harness that this PR now makes model-aware for budget and polling defaults.

Poem

🐰 Budget scales with Claude, now wise and aware,
Opus gets thresholds that linger and care—
Five hundred seconds to ponder and dream,
Grace polls grow generous, a patient regime.
Tests stand as sentries, ensuring the way.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately describes the primary change: making the Opus DM default work end-to-end by addressing per-turn budget and cold-open latency issues mentioned throughout the PR.
Description check ✅ Passed The description provides comprehensive context including bug details, measured findings, specific code changes, and validation evidence, but lacks the explicit Licensing/CLA checkbox completion required by the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Eva added 2 commits June 6, 2026 08:10
…old-open is slow)

The Opus max-effort cold-open seats the PC (~204s) long before the opening narration
finishes (>400s), so the hardcoded ~2.5min grace proceeded into an empty scene. Make the
player-ready poll count + the no-narration grace threshold env-configurable
(WOS_APP_PLAYER_READY_POLLS / WOS_APP_NARRATION_GRACE_POLLS; defaults unchanged) so a slow
Opus cold-open can be given time to write its narration before the harness grace-proceeds.
… narration-wait)

The Opus --effort max cold-open world-build is generation-bound and overruns the cold-open
timeout (VM 2026-06-06: max never finishes <400s, the turn is killed before it writes narration,
the backend grace-proceeds into an empty scene). Measured: Opus --effort HIGH finishes ~300s WITH
a full BG-caliber opening (Sorcerous Sundries / Ramazith's tower), cost $2.36, 1 clean campaign.

- qa/lib_beat_driver.sh: cold-open effort model-aware (opus -> high, sonnet -> max); cold-open
  timeout model-aware (opus -> 500s margin, sonnet -> 400s). Routine tier unchanged (medium/200s).
- qa/ui_playtest_app.sh: the part-B player-ready wait defaults longer for an Opus DM so the
  persona sees the real ~300s opening instead of grace-proceeding into an empty scene.
- servers/engine/tests/test_opus_coldopen_tuning.py: Tier-0 guard (3 assertions).

Together with the budget fix, this makes the Opus default cold-open actually work end-to-end.

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/play_party.sh (1)

44-46: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update header comments to reflect model-aware defaults.

Same issue as scripts/play.sh: the comments still reference the old Sonnet-tuned defaults, but the implementation now scales based on the DM model.

📝 Suggested documentation update
 # Safety caps (a runaway loop self-stops; companions count toward the SAME session ceiling):
-#   CLAWDND_PLAY_BUDGET           per-turn USD budget for one agent turn  (default 1.50)
-#   CLAWDND_PLAY_SESSION_BUDGET   aggregate USD ceiling for the session   (default 15.00)
+#   CLAWDND_PLAY_BUDGET           per-turn USD budget for one agent turn  (default: model-aware; Opus $12, others $1.50)
+#   CLAWDND_PLAY_SESSION_BUDGET   aggregate USD ceiling for the session   (default: model-aware; Opus $30, others $15)
 #   CLAWDND_PLAY_MAX_TURNS        hard cap on agent turns (DM + companions)(default 40)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/play_party.sh` around lines 44 - 46, The header comments for the
play_party.sh script still list the old Sonnet-tuned static defaults; update
them to state that per-turn (CLAWDND_PLAY_BUDGET), session
(CLAWDND_PLAY_SESSION_BUDGET) and max turns (CLAWDND_PLAY_MAX_TURNS) are
model-aware and may scale based on the DM model rather than fixed Sonnet
defaults—mention the dynamic scaling behavior and reference that the script
computes budgets from the chosen DM model so readers know values are not
constant.
scripts/play.sh (1)

22-24: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update header comments to reflect model-aware defaults.

The comments still reference the old Sonnet-tuned defaults ((default 1.50) and (default 15.00)), but the implementation now scales these defaults based on the DM model. Consider updating these to something like (default: model-aware; see lines 47-59) or listing both tiers.

📝 Suggested documentation update
 # Safety caps (a runaway DM loop self-stops):
-#   CLAWDND_PLAY_BUDGET           per-turn USD budget for one DM turn   (default 1.50)
-#   CLAWDND_PLAY_SESSION_BUDGET   aggregate USD ceiling for the session (default 15.00)
+#   CLAWDND_PLAY_BUDGET           per-turn USD budget for one DM turn   (default: model-aware; Opus $12, others $1.50)
+#   CLAWDND_PLAY_SESSION_BUDGET   aggregate USD ceiling for the session (default: model-aware; Opus $30, others $15)
 #   CLAWDND_PLAY_MAX_TURNS        hard cap on DM turns                  (default 40)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/play.sh` around lines 22 - 24, Update the header comments for the
three env vars CLAWDND_PLAY_BUDGET, CLAWDND_PLAY_SESSION_BUDGET, and
CLAWDND_PLAY_MAX_TURNS to indicate that the defaults are model-aware rather than
fixed values; replace the old “(default 1.50)” and “(default 15.00)” text with
something like “(default: model-aware; see DM model scaling logic)” or list both
tiers, and add a short pointer to the section of the script where the
model-based default logic lives (the DM model scaling block) so readers know
where to find the implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@scripts/play_party.sh`:
- Around line 44-46: The header comments for the play_party.sh script still list
the old Sonnet-tuned static defaults; update them to state that per-turn
(CLAWDND_PLAY_BUDGET), session (CLAWDND_PLAY_SESSION_BUDGET) and max turns
(CLAWDND_PLAY_MAX_TURNS) are model-aware and may scale based on the DM model
rather than fixed Sonnet defaults—mention the dynamic scaling behavior and
reference that the script computes budgets from the chosen DM model so readers
know values are not constant.

In `@scripts/play.sh`:
- Around line 22-24: Update the header comments for the three env vars
CLAWDND_PLAY_BUDGET, CLAWDND_PLAY_SESSION_BUDGET, and CLAWDND_PLAY_MAX_TURNS to
indicate that the defaults are model-aware rather than fixed values; replace the
old “(default 1.50)” and “(default 15.00)” text with something like “(default:
model-aware; see DM model scaling logic)” or list both tiers, and add a short
pointer to the section of the script where the model-based default logic lives
(the DM model scaling block) so readers know where to find the implementation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 35a00460-2888-4e3d-b390-1fabf3576175

📥 Commits

Reviewing files that changed from the base of the PR and between f89ce94 and 29e9d8d.

📒 Files selected for processing (6)
  • qa/lib_beat_driver.sh
  • qa/ui_playtest_app.sh
  • scripts/play.sh
  • scripts/play_party.sh
  • servers/engine/tests/test_dm_budget_scaling.py
  • servers/engine/tests/test_opus_coldopen_tuning.py

@100yenadmin 100yenadmin changed the title fix: scale per-DM-turn budget to the model (Opus cold-open hit error_max_budget_usd) fix: make the Opus DM default work end-to-end (per-turn budget + cold-open latency) Jun 6, 2026
…r the duo lens)

run_duo's callers pass low per-turn budgets (sweep $2.00, fast_probe $0.80); the Opus
high-effort cold-open costs ~$2.4, so the duo cold-open would trip error_max_budget_usd
just like the .app backend did. Floor the per-turn cap to $4 for an Opus DM (cap, not spend).
@100yenadmin
100yenadmin merged commit b48b8cd into main Jun 6, 2026
15 checks passed
@100yenadmin
100yenadmin deleted the fix/opus-per-turn-budget-scaling branch June 6, 2026 01:33
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