Skip to content

feat(viewer): wire 5 OpenWorlds screens to live engine data + GM-Advisory (playable app) - #161

Merged
100yenadmin merged 1 commit into
mainfrom
feat-viewer-readmodels
May 26, 2026
Merged

feat(viewer): wire 5 OpenWorlds screens to live engine data + GM-Advisory (playable app)#161
100yenadmin merged 1 commit into
mainfrom
feat-viewer-readmodels

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented May 26, 2026

Copy link
Copy Markdown
Member

Turns OpenWorlds from 4-live-screens + 5-mockups into a fully-playable session — wiring journal, character, inventory, relations, and parley to live engine read-models (mirroring the 4 already-wired surfaces). Entirely the viewer lane; zero collision with the macOS Swift shell.

New viewer/server.py surfaces (+ wired screens)

  • /journal-surface — quests (status/objectives/entries) + quest_hooks (rumors) + Campaign Director top-3 debts ([campaign-director] Add Campaign Director and Scene Debt Monitor #72; real scene_debt.detect/director.compute off the snapshot, heuristic fallback). → screen-journal.jsx + a GM-Advisory widget on screen-table.jsx.
  • /character-surface — full 5e sheets (classes, AC, saves, skills+expertise, spells, class_resources, conditions, death_saves). → screen-character.jsx.
  • /inventory-surface — per-PC inventory + equipped + currency. → screen-inventory.jsx.
  • /relations-surface — factions (reputation) + companion dossiers (approval/banter/relationships) + companion_arcs + met NPCs. → screen-relations.jsx.
  • /parley-surface — lead-PC parley slots (skill+modifier+suggested_dc, alignment, free_form) mirroring generate_parley_options snapshot-only. → screen-dialogue.jsx (closes [harness][parley] Relay DM-generated Parley options to the AI player (pick-one-or-freeform) #141's UI).

Tests / safety

  • 51 viewer tests (41 + 10 new); a CON-save ability-name bug caught + fixed by a test.
  • Additive: data.js + the 4 wired screens untouched; each screen falls back to demo until its first live fetch.

Closes the journal/character/inventory/relations/parley wiring; surfaces the Director (#72) in-play; closes #141's UI.

Summary by CodeRabbit

  • New Features

    • Character, Inventory, Journal, and Relations screens now display live, real-time updates.
    • Interactive Parley system with skill-based dialogue choices and difficulty adjustments.
    • Inventory hero switcher to view different party members' equipment and currency.
    • GM Advisory panels on Table and Journal screens displaying campaign debt information.
  • Tests

    • Added comprehensive test coverage for live data endpoints.

Review Change Stack

…GM-Advisory (the playable app)

OpenWorlds had 4 screens on live engine data (table/combat/atlas/launcher) and 5
rendering hardcoded prototype data. Wires those 5 to the engine snapshot the app
already carries — turning it from 4-live+5-mockups into a fully-PLAYABLE session.
All in the viewer lane (zero collision with the macOS Swift shell).

New viewer/server.py surfaces (projection fn + do_GET branch via a shared
_serve_simple_surface helper mirroring the atlas dispatch; resolve-latest-snapshot
like the wired surfaces; graceful empty):
- /journal-surface: quests (status/objectives/entries) + quest_hooks (rumors) + the
  Campaign Director top-3 debts (real scene_debt.detect/director.compute off the
  snapshot; snapshot-only heuristic fallback). Wired screen-journal.jsx.
- /character-surface: full 5e sheets (classes, AC, saves, skills w/ expertise, spells,
  class_resources, conditions, death_saves). Wired screen-character.jsx.
- /inventory-surface: per-PC inventory + equipped + currency. Wired screen-inventory.jsx.
- /relations-surface: factions (reputation bar) + companion dossiers (approval/banter/
  relationships) + companion_arcs + met NPCs. Wired screen-relations.jsx.
- /parley-surface: lead-PC parley slots (skill+modifier+suggested_dc, alignment,
  free_form) mirroring generate_parley_options' math snapshot-only. Wired
  screen-dialogue.jsx (closes #141's UI). Old tree kept as a demo fallback.
- GM-Advisory widget on screen-table.jsx surfaces the top Director debt in play (#72).

Additive: data.js + the 4 wired screens untouched; each screen falls back to demo
until its first live fetch. 51 viewer tests pass (41 + 10 new; a CON-save
ability-name bug was caught + fixed by a test).
@100yenadmin
100yenadmin merged commit 94b3e8d into main May 26, 2026
2 checks passed
@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 09afa80c-1711-4b2c-b827-dec7c95d8deb

📥 Commits

Reviewing files that changed from the base of the PR and between 2fbf0c5 and edca859.

📒 Files selected for processing (9)
  • viewer/openworlds/app.jsx
  • viewer/openworlds/screen-character.jsx
  • viewer/openworlds/screen-dialogue.jsx
  • viewer/openworlds/screen-inventory.jsx
  • viewer/openworlds/screen-journal.jsx
  • viewer/openworlds/screen-relations.jsx
  • viewer/openworlds/screen-table.jsx
  • viewer/server.py
  • viewer/tests/test_readmodel_surfaces.py

Cache: Disabled due to Reviews > Disable Cache setting


📝 Walkthrough

Walkthrough

This PR introduces five server-side read-model "surface" endpoints that project snapshot campaign state into browser-safe JSON shapes for OpenWorlds screens. Client screens now poll these surfaces every 5 seconds with visibility-aware pausing. The parley screen renders a new interactive menu with skill/free-form moves; journal and table screens display a director advisory panel surfacing structural campaign debts; relations screen renders dynamic faction/NPC lists with companion dossiers.

Changes

OpenWorlds live read-model surfaces

Layer / File(s) Summary
Screen capability marking
viewer/openworlds/app.jsx
capabilityForScreen now classifies character, inventory, relations, journal, and dialogue as "wired" by viewer read models.
Server-side read model builders
viewer/server.py
Implements directors advisory system (engine-backed with heuristic fallback), then five surface builders: journal (quests + rumors + advisory), character (full party sheets with AC/saves/skills), inventory (per-hero items + shared stash + currency), relations (factions + NPCs/companions with dossiers), and parley (lead PC skills + difficulty-based DCs). Adds generic _serve_simple_surface dispatcher and GET routes for each surface.
Client polling infrastructure
viewer/openworlds/screen-character.jsx, screen-inventory.jsx, screen-journal.jsx, screen-relations.jsx
Four screens now derive surfaceQuery from campaign state, maintain surface state, and poll their respective endpoints every 5 seconds. Polling is visibility-aware: stops when tab is hidden, resumes when visible, and cleans up on unmount. Surfaces fall back to static state when fetch fails.
Parley menu and dialogue
viewer/openworlds/screen-dialogue.jsx
New ParleyMenu component renders skill-slot choices, free-form input, difficulty control, and history rail. Submits moves to /move endpoint. ScreenDialogue polls /parley-surface and conditionally renders ParleyMenu or demo fallback. Demo header text switches based on parley status. Window exports updated to include ScreenDialogueDemo and ParleyMenu.
Inventory hero switcher
viewer/openworlds/screen-inventory.jsx
Hero pill buttons allow switching active character; stash derives from active hero's live items. Dynamic per-hero currency renders in Coin Purse via hero.currency values.
Journal and table advisory panels
viewer/openworlds/screen-journal.jsx, screen-table.jsx
Journal renders tab-specific "no quests" empty state and conditional "GM Advisory" panel. Table fetches advisory from /journal-surface and displays top debt details + navigation.
Relations dynamic content
viewer/openworlds/screen-relations.jsx
Faction and NPC lists now render dynamically from live surface with ID-based selection and empty states. NPCDetail extends to show companion dossier (approval, banter tags, ties) when applicable; dues section tolerates missing data and shows empty state.
Comprehensive test suite
viewer/tests/test_readmodel_surfaces.py
Integration tests for all five surfaces validating HTTP 200, envelope metadata, player-facing projection (no private keys), empty behavior, quest/hook mapping, director advisory detection (engine vs heuristic), character math, inventory items/currency, faction/NPC rosters, and parley difficulty parameter.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Screen as Screen Component
  participant Surface as /X-surface endpoint
  participant Snapshot as Campaign Snapshot
  
  rect rgba(100, 150, 200, 0.5)
  Note over Screen,Snapshot: Initial load & visibility-aware poll
  Screen->>Surface: GET /X-surface?campaign=...
  Surface->>Snapshot: Read campaign state
  Snapshot-->>Surface: Projection
  Surface-->>Screen: {surface, advisory, ...}
  Screen->>Screen: Update local state
  end
  
  rect rgba(150, 100, 200, 0.5)
  Note over User,Screen: 5-second polling with visibility
  rect rgba(200, 200, 100, 0.5)
  Note over Screen: Tab hidden: stop polling
  end
  rect rgba(200, 200, 100, 0.5)
  Note over Screen: Tab visible: resume polling
  Screen->>Surface: Poll request
  Surface-->>Screen: Updated surface
  end
  end
  
  rect rgba(200, 100, 150, 0.5)
  Note over User,Screen: User interaction (parley example)
  User->>Screen: Choose skill / free-form move
  Screen->>Surface: POST /move {check, campaign}
  Surface-->>Screen: {outcome}
  Screen->>Screen: Update history, show toast
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Complexity drivers: Multiple new server-side projection functions with dense logic (character sheets, inventory stash inference, parley DC computation), five similar but distinct client polling patterns requiring careful review of visibility handling and error swallowing, new interactive parley menu with move submission, and comprehensive test suite validating all surfaces and advisory paths. Substantial cross-file coordination (server projections ↔ client polling ↔ UI rendering) with no significant refactoring of existing code, making each change independently verifiable but collectively heterogeneous.

Possibly related issues

  • 100yenadmin/ClawDnD#115: Requests session/table surface from engine read models; this PR implements /journal-surface advisory that powers table's advisory panel, directly addressing the core request.
  • 100yenadmin/ClawDnD#118: Requests relations/companion rendering; this PR adds /relations-surface and updates ScreenRelations to render companion dossiers with approval, banter, and ties, fully addressing the feature.

Possibly related PRs

  • 100yenadmin/ClawDnD#149: Implements engine-level director/scene_debt detection (#72); this PR wires those detections into /journal-surface advisory and GM Advisory UI panels, forming the complete director advisory feature.
  • 100yenadmin/ClawDnD#135: Also updates capabilityForScreen in viewer/openworlds/app.jsx; coordinated changes to screen capability classification may require conflict resolution.
  • 100yenadmin/ClawDnD#128: Also refactors viewer/openworlds/screen-table.jsx to poll server surfaces; both PRs drive table from read models and may require merge sequencing.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

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.

[harness][parley] Relay DM-generated Parley options to the AI player (pick-one-or-freeform)

1 participant