Skip to content

fix(dm+engine): the 2 opus golden-spine RED bugs (OOC seating-leak + CompanionQuestArc.summary) - #1077

Merged
100yenadmin merged 1 commit into
mainfrom
fix/opus-run-bugs-ooc-and-summary
Jun 20, 2026
Merged

fix(dm+engine): the 2 opus golden-spine RED bugs (OOC seating-leak + CompanionQuestArc.summary)#1077
100yenadmin merged 1 commit into
mainfrom
fix/opus-run-bugs-ooc-and-summary

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Jun 20, 2026

Copy link
Copy Markdown
Member

What

Fixes the two behavioral-gate REDs the OPUS golden-spine (gs-ember-opus, embergloom-pact, 24 beats) surfaced — the decisive run that proved opus drives the campaign (act 2, 3 locations, quest resolved) and scored story 4.9 (the "DM under-drives" scare was a Sonnet-measurement artifact, not a regression).

1a · narration_no_ooc_leak — OOC seating-preamble leak (DM prompt)

The DM narrated its own casting decision into player-facing prose on the opening beat:

"Now I'll seat Bryn as the player character — a hedge-healer's daughter fits a Bard, complementing Brother Toll's cleric."

The FICTION-ONLY rule (SKILL.md:83) already bans this exact family, but it keeps shipping on the very first beat where PC-seating happens. Fix: a sharp wrong→correct "SEAT THE PC SILENTLY" reminder anchored right at the cold-open pointer. No engine change.

1b · no_rejected_tool_callsCompanionQuestArc.summary rejected (engine model)

set_companion_quest_arc(arc={"summary": ...}) was REJECTED — CompanionQuestArc is extra="forbid" and had no summary field (extra_forbiddenno_rejected_tool_calls FATAL → all lenses RED-capped). Add summary: str = "" additively (mirrors the just-merged #1048 per-stage description fix).

Why it matters

Both are the cap-rate failure class — a single rejected tool call / OOC leak RED-caps the whole run's lenses, which is what kept the honest opus story score (4.9 raw) from showing as a clean GREEN run.

Tests

  • +2 regression tests in test_companion_arc.py (summary accepted+persisted; arc without summary defaults "" so old snapshots round-trip).
  • uv run --directory servers/engine python -m pytest tests/test_companion_arc.py77 passed.

Invariants

Additive-by-default (empty == today; old snapshots round-trip); engine stays sole-writer; no gate weakened. 1a is a prompt-only change.

Verification (post-merge)

A short opus golden-spine → narration_no_ooc_leak GREEN (seating leak gone). Reported in the standardized closeout.

Summary by CodeRabbit

  • New Features

    • Added summary field to companion quest arcs, enabling quest narratives to include a one-line emotional anchor.
  • Documentation

    • Enhanced beat cycle guidance with clarified instructions for scene setup and narration flow.
  • Tests

    • Added comprehensive test coverage for quest arc summary functionality.

…CompanionQuestArc.summary)

Both surfaced on the gs-ember-opus golden-spine (embergloom-pact, 24 beats, OPUS DM)
that RED'd on narration_no_ooc_leak + no_rejected_tool_calls.

1a — narration_no_ooc_leak: the DM narrated its own seating decision into player prose
("Now I'll seat Bryn as the player character — a hedge-healer's daughter fits a Bard…")
on the opening beat. The FICTION-ONLY rule (SKILL.md:83) already bans the phrasing, but the
leak keeps shipping on the very first beat where seating happens. Add a sharp wrong→correct
'SEAT THE PC SILENTLY' reminder anchored to the cold-open pointer (no engine change).

1b — no_rejected_tool_calls: set_companion_quest_arc(arc={"summary": ...}) was REJECTED
because CompanionQuestArc (extra='forbid') had no summary field (extra_forbidden ⇒ FATAL ⇒
lenses RED-capped). Add summary: str = '' additively (mirrors the #1048 per-stage description
fix) + 2 regression tests (accepted+persisted; old snapshots round-trip). 77/77 pass.

Refs the standardized-closeout opus run; un-RED-caps authored-companion-arc golden-spines.
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a summary string field (defaulting to "") to the CompanionQuestArc model in models.py, with two new tests covering persistence and backward-compatible default behavior. Separately, updates the DM beat cycle guidance in SKILL.md to require silent PC seating before any fiction is written.

Changes

CompanionQuestArc summary field

Layer / File(s) Summary
summary field declaration and tests
servers/engine/models.py, servers/engine/tests/test_companion_arc.py
Adds summary: str = "" to CompanionQuestArc with inline docs describing it as a DM-authored emotional spine. Two new tests cover round-trip persistence of a provided summary and the empty-string default when the field is absent from older snapshots.

DM Beat Cycle Silent Seating Guidance

Layer / File(s) Summary
Beat cycle admonition
skills/dungeon-master/SKILL.md
Adds two lines at the start of the beat cycle requiring the DM to seat the PC silently via load_canon_character before writing fiction, explicitly forbidding narration that describes or justifies the seating or continuity bookkeeping.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related PRs

  • electricsheephq/WorldOS#111: Originally introduced CompanionQuestArc; this PR extends that model with the new summary field.
  • electricsheephq/WorldOS#1048: Also adds a new persistable field to the companion arc data model and updates test_companion_arc.py around the same set_companion_quest_arc/get_companion_quest_arcs flow.
  • electricsheephq/WorldOS#685: Both PRs tighten SKILL.md DM cold-open/narration rules around seating the canon player before any fiction and suppressing setup narration.

Poem

🐇 A spine for the arc, one line plain and true,
The DM seats the hero — no footnotes in view.
The snapshot round-trips, the default's an empty embrace,
No bookkeeping whispered, just fiction in place.
Hop hop! The quest begins with a tidy, clean grace. ✨

🚥 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
Title check ✅ Passed The title accurately identifies both main fixes: the OOC seating-leak in the DM prompt and the CompanionQuestArc.summary field rejection, directly matching the changeset content.
Description check ✅ Passed The description is comprehensive and well-structured, covering the bugs fixed, rationale, testing performed, and verification plans. It includes all essential information for understanding the PR's purpose and impact.
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.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@servers/engine/tests/test_companion_arc.py`:
- Around line 516-522: The test function
test_companion_quest_arc_summary_defaults_empty_and_old_snapshots_round_trip
claims to verify round-trip behavior but only checks the immediate response from
set_companion_quest_arc without verifying persistence. To fix this, after the
existing assertion on the set_companion_quest_arc response, add a call to
get_companion_quest_arcs to retrieve the persisted companion quest arc data and
assert that the summary field in the retrieved data is still an empty string,
ensuring the data actually round-trips correctly through storage and retrieval.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a5c60680-cb45-4b6a-8367-536f0a2248eb

📥 Commits

Reviewing files that changed from the base of the PR and between 6b3cde2 and 74cb8c9.

📒 Files selected for processing (3)
  • servers/engine/models.py
  • servers/engine/tests/test_companion_arc.py
  • skills/dungeon-master/SKILL.md

Comment on lines +516 to +522
def test_companion_quest_arc_summary_defaults_empty_and_old_snapshots_round_trip(camp):
# Additive invariant: an arc authored WITHOUT a summary keeps today's behavior (empty string),
# so pre-fix snapshots deserialize unchanged.
cid, comp = camp
out = server.set_companion_quest_arc(cid, comp, {"title": "No Summary Arc", "status": "locked"})
assert out["companion_quest_arc"]["summary"] == ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Test name claims round-trip but only verifies write response.

This test currently checks the immediate set_companion_quest_arc payload, not persisted read-back. Add a get_companion_quest_arcs assertion so the “round trip” claim is actually covered.

Suggested patch
 def test_companion_quest_arc_summary_defaults_empty_and_old_snapshots_round_trip(camp):
@@
     cid, comp = camp
     out = server.set_companion_quest_arc(cid, comp, {"title": "No Summary Arc", "status": "locked"})
     assert out["companion_quest_arc"]["summary"] == ""
+    got = server.get_companion_quest_arcs(cid, companion_id=comp)["companion_quest_arcs"][0]
+    assert got["summary"] == ""
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_companion_quest_arc_summary_defaults_empty_and_old_snapshots_round_trip(camp):
# Additive invariant: an arc authored WITHOUT a summary keeps today's behavior (empty string),
# so pre-fix snapshots deserialize unchanged.
cid, comp = camp
out = server.set_companion_quest_arc(cid, comp, {"title": "No Summary Arc", "status": "locked"})
assert out["companion_quest_arc"]["summary"] == ""
def test_companion_quest_arc_summary_defaults_empty_and_old_snapshots_round_trip(camp):
# Additive invariant: an arc authored WITHOUT a summary keeps today's behavior (empty string),
# so pre-fix snapshots deserialize unchanged.
cid, comp = camp
out = server.set_companion_quest_arc(cid, comp, {"title": "No Summary Arc", "status": "locked"})
assert out["companion_quest_arc"]["summary"] == ""
got = server.get_companion_quest_arcs(cid, companion_id=comp)["companion_quest_arcs"][0]
assert got["summary"] == ""
🤖 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 `@servers/engine/tests/test_companion_arc.py` around lines 516 - 522, The test
function
test_companion_quest_arc_summary_defaults_empty_and_old_snapshots_round_trip
claims to verify round-trip behavior but only checks the immediate response from
set_companion_quest_arc without verifying persistence. To fix this, after the
existing assertion on the set_companion_quest_arc response, add a call to
get_companion_quest_arcs to retrieve the persisted companion quest arc data and
assert that the summary field in the retrieved data is still an empty string,
ensuring the data actually round-trips correctly through storage and retrieval.

@100yenadmin
100yenadmin merged commit 0187c75 into main Jun 20, 2026
20 checks passed
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