fix(viewer): wire Rest & Prepare relay + browsable level-up subclasses (#610 #617 #607) - #873
Conversation
#610 #617 #607) From the RRI-5e98e6f optimizer sweep — two MAJOR viewer-side wiring gaps where the engine already works (the 31-PR fix-phase landed long_rest/short_rest/prepare_spells + preview_level_up subclass blocks) but the viewer did not use it: (1) #610/#617 — RestPrepareModal "Make camp" + "Seal the choices" were `disabled` display-only stubs ("…not saved to the engine"), so spell re-preparation + slot recovery were non-functional. They now relay a composed `do` move-intent to /move (the SAME read-only move-sink path camp-sidebar.jsx + LevelUpModal use — the engine is sole writer; the viewer never mutates snapshot). Enabled + functional when a session is attached (can_act) AND the DM isn't mid-turn (dmBusy); honestly disabled + explained (hover title + inline note) otherwise. Synchronous double-submit lock. Threads liveSession into ScreenCharacter (additive prop) for the dmBusy gate, mirroring ScreenMap → CampSidebar. (2) #607 — the level-up dialog now BROWSES all engine-exposed subclass options, each with its level-3 feature breakdown (a real comparison, not just the first/name-only), and the disabled "Confirm advancement" says WHY inline + via tooltip: a subclass needs naming, or no XP is earned yet (no legal level to advance into) — never a silently-dead button. Viewer stays read-only + move-sink; engine untouched. Wire contracts frozen (/move kind:"do", /build-options, /character-surface). Round-trip safe. Tests (JSX behaviour harness — transpiles the real .jsx through the vendored babel under node vm, renders the real RestPrepareModal/LevelUpModal, drives the fetch + clicks): viewer/tests/test_rest_camp_levelup_wiring.py — 11 new (8 RED on pre-fix screen-character.jsx). Full viewer suite 516 passed / 1 skipped; fast_gate Tier-0 PASS (195 deterministic engine tests).
|
Warning Review limit reached
More reviews will be available in 1 hour, 44 minutes, and 32 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 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 77fcbae56a
ℹ️ 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".
| const named = Object.keys(prepared) | ||
| .sort((a, b) => Number(a) - Number(b)) | ||
| .flatMap((lv) => (prepared[lv] || []).map((n) => n)) | ||
| .filter(Boolean); |
There was a problem hiding this comment.
Normalize spell slots before relaying prepared spells
When a caster uses this newly wired preparation flow with the current /character-surface shape, prepared never gets populated: hero.spellSlots is projected as an array of {level, max, ...} and hero.spells is grouped as Prepared/Known, while the modal still keys slot capacity by slots[group.level]. That means no spell buttons render/select, so this new relay always falls through to keeps their currently prepared spells and cannot actually prepare the spells the player chose. Please adapt the modal to the same array slot model used by SpellsTab before building this move text.
Useful? React with 👍 / 👎.
What
Two MAJOR viewer-side UI-wiring bugs the optimizer persona filed in the RRI-5e98e6f 5-persona sweep (2026-06-14). In both, the engine already works (the 31-PR fix-phase landed
long_rest/short_rest/prepare_spellsand PR #742 wiredpreview_level_upsubclass blocks) — the viewer just did not display/use it. This is viewer wiring + rendering only; the engine is untouched.(1) Rest & Prepare is now functional — #610 / #617
RestPrepareModal(screen-character.jsx) had its "Make camp" and "Seal the choices" CTAs hard-disabledas display-only stubs ("…not saved to the engine"), so spell re-preparation + slot recovery were dead. They now relay a composeddomove-intent to/move— the same read-only move-sink pathcamp-sidebar.jsxandLevelUpModalalready use (the engine is the sole writer; the viewer never mutates snapshot). The engine resolves it throughlong_rest/short_rest+prepare_spells(refresh HP + slots, advance the clock, record prepared spells).can_act) and the DM isn't mid-turn (dmBusy, fix(viewer): keep latest chronicle beat + action box visible; camp-rest feedback when DM busy #402); honestly disabled + explained (hovertitleand an inline note) otherwise.LevelUpModal/ screen-table.jsx).liveSessionintoScreenCharacter(additive prop) for thedmBusygate, mirroringScreenMap → CampSidebar.(2) Level-up dialog browses ALL subclasses + says why Confirm is disabled — #607
option.subclass.options), each with its level-3 feature breakdown — a real browsable comparison ("what each tradition grants"), not just the first / a name-only line.Invariants held
Viewer stays read-only + move-sink (renders via React text nodes /
createElement; nodangerouslySetInnerHTML; clientsanitizeNarrationpreserved). Additive — no existing screen/test broken. Wire contracts frozen (/move kind:"do",/build-options,/character-surface). No engine change — round-trip safe.Tests
New
viewer/tests/test_rest_camp_levelup_wiring.py— the JSX behaviour harness (transpiles the realscreen-character.jsxthrough the vendored babel under a node vm, renders the realRestPrepareModal/LevelUpModal, drives the scripted/build-options+/movefetch, finds nodes by testid, invokesonClick, re-renders). 11 new tests (8 verified RED against pre-fix screen-character.jsx).RestPrepareWiringTests(6): Make-camp enabled + POSTs onedo/move (long-rest intent naming slot recovery); disabled + reason when read-only / dm-busy; opening writes nothing; the prep step's Seal CTA relays too; no display-only "(preview)" / "not saved" copy remains.LevelUpSubclassBrowseTests(4): all subclass options + their feature breakdowns render; selecting one enables Confirm; the unnamed-subclass disable carries the inline+tooltip why.LevelUpNoXpTooltipTests(1): no-XP Confirm is disabled with an explanatory "no XP earned" tooltip + inline note.Gates: full viewer suite 516 passed / 1 skipped;
bash qa/fast_gate.shTier-0 PASS (195 deterministic engine tests, engine untouched).These are gate-movers from the RRI-5e98e6f optimizer sweep. Do not merge (milestone v1.0.4 staging).