feat: complete mega-damage combat exchange#55
Conversation
📝 WalkthroughWalkthroughThe change extends persisted combat from S.D.C.-only exchanges to tiered S.D.C./M.D.C. routing, adds deterministic coma/death handling with a persisted dead marker, preserves legacy route history, enforces terminal backend behavior, and updates the web dossier and combat history presentation. ChangesM.D.C. Combat Exchange
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Attacker
participant ConvexCombat
participant RulesEngine
participant Defender
participant WebDossier
Attacker->>ConvexCombat: declare or respond to attack
ConvexCombat->>ConvexCombat: require both combatants living
ConvexCombat->>RulesEngine: resolve strike with damageType
RulesEngine-->>ConvexCombat: tiered route with snapshots and lifeState
ConvexCombat->>Defender: patch armor/sdc/hp or set lifeState dead
ConvexCombat-->>WebDossier: return persisted exchange
WebDossier-->>Attacker: render exchangeResultLabel and route evidence
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
|
@CodeRabbit Please re-review this PR. |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/web/tests/character-sheet.test.ts (1)
8-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMake
source()fail loudly on a missing file.Returning
""for a missing path means every.not.toContain(...)assertion (e.g. Line 84, Line 138) passes vacuously if a source file is ever renamed or moved, silently weakening these contract tests. Throwing keeps the suite honest.♻️ Proposed change
function source(relative: string): string { const url = new URL(relative, import.meta.url); - return existsSync(url) ? readFileSync(url, "utf8") : ""; + if (!existsSync(url)) throw new Error(`Missing source under test: ${relative}`); + return readFileSync(url, "utf8"); }🤖 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 `@apps/web/tests/character-sheet.test.ts` around lines 8 - 11, Update the source() helper to throw an error when the resolved URL does not exist instead of returning an empty string; retain readFileSync for existing files so the contract assertions continue validating the intended source content.
🤖 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.
Nitpick comments:
In `@apps/web/tests/character-sheet.test.ts`:
- Around line 8-11: Update the source() helper to throw an error when the
resolved URL does not exist instead of returning an empty string; retain
readFileSync for existing files so the contract assertions continue validating
the intended source content.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 7cc19d95-52c8-4248-b494-202934139ea8
📒 Files selected for processing (27)
.codex/superpowers/plans/2026-07-21-mdc-combat-exchange.md.codex/superpowers/specs/2026-07-21-mdc-combat-exchange-design.mdREADME.mdapps/web/index.htmlapps/web/src/components/combat-exchange-panel.tsxapps/web/src/components/sheet-view.tsxapps/web/src/layouts/app.tsxapps/web/src/lib/combat-exchange.tsapps/web/src/pages/character-sheet.tsxapps/web/tests/character-sheet.test.tsapps/web/tests/combat-exchange.test.tspackages/backend/convex/character_state.tspackages/backend/convex/characters.tspackages/backend/convex/combat.tspackages/backend/convex/combat_values.tspackages/backend/convex/schema.tspackages/backend/tests/characters.test.tspackages/backend/tests/combat.test.tspackages/rules/src/content/combat/combat-exchange.jsonpackages/rules/src/engine/character.tspackages/rules/src/engine/combat-exchange.tspackages/rules/src/engine/combat.tspackages/rules/src/schema/character.tspackages/rules/src/schema/combat-exchange.tspackages/rules/tests/character.test.tspackages/rules/tests/combat-exchange.test.tspackages/rules/tests/combat.test.ts
|
Resolved the CodeRabbit source-contract nit in commit 1d23ada. Both duplicated helpers now throw with the missing relative path instead of returning an empty string, so negative assertions cannot pass vacuously. TDD evidence: RED 2/48, GREEN 48/48; web package 54/54; root 540/540; vp check clean. |
Summary
Completes the core S.D.C./M.D.C. hostile-combat boundary through the existing persisted exchange protocol.
Architecture and authority
The rules package remains pure and deterministic. It classifies attack/protection tiers, multiplies critical damage before conversion, applies the complete routing matrix, and returns immutable before/after evidence. Convex continues to own dice, current-state rederivation, synchronization, exactly-once character writes, and exchange history. The client chooses only legal IDs/context/response actions; it never authors tiers, conversions, routes, rolls, or after-values.
Compatibility and fatal boundary
Legacy Issue #44 resolved routes remain accepted and formatted without migration. Old or racing pending exchanges stale before new dice or character writes, and duplicate responses cannot double-apply damage.
Exactly
-P.E.remains a survivable coma state. Raw H.P. below-P.E.persists S.D.C. 0, H.P. at the legal floor, andcurrent.lifeState = "dead". Gameplay mutations reject terminal characters while the dossier, inventory, narrative, history, and cancellation cleanup remain available.Fresh automated verification
Recorded 2026-07-22 (Asia/Singapore), with package task caching disabled:
vp run --no-cache @riftforge/rules#check: 60/60 formatted; 46/46 cleanvp run --no-cache @riftforge/rules#test: 17/17 files; 358/358 testsvp run --no-cache @riftforge/backend#check: 13/13 formatted; 15/15 cleanvp run --no-cache @riftforge/backend#test: 3/3 files; 128/128 testsvp run --no-cache @riftforge/web#check: 37/37 formatted; 33/33 cleanvp run --no-cache @riftforge/web#test: 3/3 files; 52/52 testsvp check: 130/130 formatted; 95/95 cleanvp test: 23/23 files; 538/538 testsgit diff --check: cleanLive acceptance and catalog limit
Live acceptance ran 2026-07-21 (Asia/Singapore) with attacker
j5765xjcskpg5jwrj32qx3br9d8azgweand defenderj57b5e6myeyxxhffcqwy09kg8n8ayxw9.Verified through the production UI: legal M.D. selection, native M.D. armor ablation, final-blast absorption with no body spill, depleted-shell strike totals 7/8, sub-100 S.D.C. imperviousness, M.D.-to-body fatal conversion, legacy and version-2 history together, terminal dossier behavior, cleanup cancellation, and same-document dead-to-living parameter navigation. Desktop 1440px and narrow 390x844 acceptance had no horizontal overflow, and the fresh browser console had zero errors and zero warnings. Ports 5173 and 3210 were closed after cleanup.
The legal catalog has no S.D.C. armor and no S.D.C. attack profile capable of 100+ completed damage. The 100+ S.D.C.-against-M.D.C. conversion rows and M.D.-against-S.D.C.-armor A.R. rows are therefore verified by exact pure-rules and atomic-backend tests, not by browser UI. No temporary or invented rules content was added to manufacture those scenarios.
Closes #51
Follow-up #54
Roadmap #53
Summary by cubic
Completed full S.D.C./M.D.C. combat exchange with deterministic routing, armor rules, and terminal life-state persistence. UI shows tiered outcomes, disables gameplay for dead characters, and the backend enforces readiness with atomic history.
New Features
@riftforge/rules: unified S.D.C./M.D. attacks with v2 tiered routes (critical-before-conversion, 100 S.D.C. per M.D., ≥8 strike bypass for depleted M.D.C., final-blast absorption) and terminal life-state viaapplyBodyDamage.@riftforge/backend: validate/persist tiered routes; reject dead combatants; require rolled M.D.C. armor capacity; block updates androllVitalsfor dead; atomic Convex writes; legacy and v2 history coexist.@riftforge/web: clear labels/tones for tiered outcomes; disable gameplay with a friendly reason; terminal dossier; responsive nav on narrow viewports; data-URI favicon to avoid a network request; tests fail loudly when source contracts point to missing files.Migration
Written for commit 1d23ada. Summary will update on new commits.