Skip to content

fix(openworlds): persist house + biography in engine snapshot (Closes #383) - #656

Merged
100yenadmin merged 1 commit into
mainfrom
fix/383-house-biography-persistence-revive
Jun 5, 2026
Merged

fix(openworlds): persist house + biography in engine snapshot (Closes #383)#656
100yenadmin merged 1 commit into
mainfrom
fix/383-house-biography-persistence-revive

Conversation

@100yenadmin

Copy link
Copy Markdown
Member

TL;DR

Loop-10 follow-up to #277. PR #369 wired house + biography from the Creation wizard's inputs into the bindHero spec, but the engine seating path silently dropped both fields: the Character model, create_character's signature, the Character() constructor call, play.sh's spec-to-create_character bridge, and the /character-surface projection. A player who authored House = "Three Bells" + a Biography in the wizard saw both vanish the moment they hit Bind.

This PR threads both fields end-to-end + adds the UI rendering + the regression test #383's AC asked for. Revives #392, rebased onto current main.

Closes

The five sites threaded

# File What
1 servers/engine/models.py Character gains house: str = "" and biography: str = "" in the identity block. _StrictModel rejects extra fields — adding them at the model is what makes accepting these kwargs possible. Additive: defaults deserialize existing snapshots unchanged.
2 servers/engine/server.py create_character signature accepts both kwargs (positional callers unaffected) + the Character(...) constructor threads them inside campaign_lock.
3 scripts/play.sh The embedded Python that translates the bindHero spec into create_character kwargs now reads both fields from the spec dict with "" coalesce. The single place the wizard's prose crosses the process boundary into the engine.
4 viewer/server.py _character_sheet projects house and biography to the /character-surface read-model via _text() for string safety. (Projection region only — no parity-lane / move-intent / live-view code touched.)
5 viewer/openworlds/screen-character.jsx (a) Hero header renders subtle italic "of House {hero.house}" under the name when set. (b) LineagePanel renders a "Biography" section with eyebrow label + whiteSpace: pre-wrap when set. Both honest-empty otherwise. The empty-guard now also includes biography, so a bio-only hero (no race/flavor) isn't dropped.

Tests

New: servers/engine/tests/test_house_biography_persistence.py — 4 tests

Test Asserts
test_create_character_accepts_house_and_biography_kwargs Sanity: no TypeError on call
test_house_and_biography_persist_on_the_character_model Both fields survive the implicit save_campaign round-trip
test_house_and_biography_default_to_empty_when_omitted Existing call sites (NPC spawn) keep working; defaults are "" not None
test_house_and_biography_round_trip_through_get_character End-to-end: explicit values → snapshot dict → fields intact + pre-existing identity (race, background) still works alongside

Verification

Check Result
Narrow pytest (4 new tests, single-process, canonical engine venv) ✅ 4 passed
Existing test_character_skill_normalization + test_action_economy (additive-safety) ✅ 6 passed
screen-character.jsx transformed via vendor/babel-standalone-7.29.0.min.js (node+vm) ✅ parsed + transformed cleanly
ast.parse on all modified .py + new test
bash -n scripts/play.sh

Out of scope (intentionally)

  • No backstory merge: fix(openworlds): persist house + biography in engine snapshot (Loop 10 follow-up to #277) #383 said NOT to rename personality/backstory or merge biography into them. These stay DISTINCT — engine-side flavor stays in lineageNote; player-authored biography stays in biography.
  • No mid-play rename: seeds at creation only; no update_character path here.
  • Companion / NPC: the model now carries the fields for all characters, but only the player wizard authors them today. Companions/NPCs default "".

Provenance

Revives #392 (same approach, rebased onto current main — diff context had drifted). Verified NOT superseded: main has only one unrelated biography mention (a dossier comment in server.py) and all house refs are house_rules/house-difficulty — no house/biography Character field, signature kwarg, projection, or render existed before this PR.

Engine invariant respected: engine remains the sole state writer; schema change is additive-only.

…383)

Loop-10 follow-up to #277/#369. PR #369 wired `house` + `biography` from the
Creation wizard's inputs into the bindHero spec, but the engine seating path
silently dropped both fields. A player who authored House + Biography in the
wizard saw both vanish the moment they hit Bind.

Threads both fields end-to-end (additive, schema additive-only):
  1. servers/engine/models.py    Character gains house/biography (str = "")
  2. servers/engine/server.py     create_character kwargs + constructor
  3. scripts/play.sh              bindHero spec -> create_character bridge
  4. viewer/server.py             /character-surface read-model projection
  5. screen-character.jsx         "of House X" subtitle + Biography paragraph

Empty strings are honest no-ops — additive defaults deserialize existing
snapshots unchanged; NPC/monster spawn call sites keep working.

Regression guard: servers/engine/tests/test_house_biography_persistence.py
(4 tests: kwargs accept, model persistence, empty defaults, round-trip).

Revives PR #392 (rebased onto current main; LineagePanel empty-guard also
includes biography so a bio-only hero isn't dropped).
@coderabbitai

coderabbitai Bot commented Jun 5, 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 22 minutes and 45 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: a57355e7-75ae-496c-baa3-8d37d71664bc

📥 Commits

Reviewing files that changed from the base of the PR and between 1a604fd and ede6d28.

📒 Files selected for processing (6)
  • scripts/play.sh
  • servers/engine/models.py
  • servers/engine/server.py
  • servers/engine/tests/test_house_biography_persistence.py
  • viewer/openworlds/screen-character.jsx
  • viewer/server.py

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

@100yenadmin
100yenadmin merged commit 1b031bc into main Jun 5, 2026
15 checks passed
@100yenadmin
100yenadmin deleted the fix/383-house-biography-persistence-revive branch June 5, 2026 10:28
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