Remove completed task tracker
This commit is contained in:
386
TASKS.md
386
TASKS.md
@@ -1,386 +0,0 @@
|
||||
# Rolemaster Support Plan
|
||||
|
||||
## Goal
|
||||
|
||||
Extend the app with a new `rolemaster` ruleset that supports generic standard Rolemaster expressions plus the special open-ended percentile case:
|
||||
|
||||
1. Standard expressions: `NdS + x`, with an implicit dice count of `1` when no digit appears before `d`
|
||||
2. Open-ended percentile: `d100! + x` with Rolemaster low-end and high-end behavior
|
||||
|
||||
The initial scope is only roll definition, validation, execution, logging, and UI support for generic standard Rolemaster rolls and open-ended percentile rolls. This does not include Rolemaster attack tables, critical tables, resistance rolls, maneuver tables, or character sheet math beyond the explicit roll modifier entered for a skill.
|
||||
|
||||
## Scope Assumptions
|
||||
|
||||
- A Rolemaster campaign chooses the new `rolemaster` ruleset at campaign creation time.
|
||||
- Rolemaster skills are ruleset-specific and should not reuse D6-only options such as `WildDice` and `AllowFumble`.
|
||||
- Open-ended percentile behavior is defined as:
|
||||
- Roll the first `d100`.
|
||||
- If the first roll is `96` or higher, roll another high-ended `d100` recursively and add it.
|
||||
- If the first roll is less than or equal to the skill's configured fumble range, roll another high-ended `d100` recursively and subtract it.
|
||||
- Recursive follow-up rolls are high-ended only.
|
||||
- Standard Rolemaster rolls do not open-end and do not use a fumble range.
|
||||
- The modifier `x` should be an integer.
|
||||
- Negative modifiers are supported for Rolemaster only.
|
||||
- D6 and D&D 5e keep their current non-negative modifier rules unless separately re-scoped in a future change.
|
||||
- Existing D6 and D&D 5e behavior must remain unchanged.
|
||||
- The migration must be validated against a copied temp-file instance of `RpgRoller/App_Data/rpgroller.development.db`, which currently contains a D6 campaign.
|
||||
|
||||
## Clarifications
|
||||
|
||||
- The Rolemaster modifier should allow negative values only for Rolemaster.
|
||||
- The standard fumble range for open-ended percentile skills is `0-5`, but can be configured individually for each skill.
|
||||
- The fumble range has to be guaranteed to be less than 96.
|
||||
- Roll breakdown text format for low-ended subtraction: `12 (03) -97 -44 +15 = -114`
|
||||
- Skill groups need to support Rolemaster defaults for all of these fields, to stay consistent with current prototype behavior
|
||||
- Rolemaster uses expression parsing with canonical syntax:
|
||||
- standard roll with implicit count: `d10`
|
||||
- standard roll with explicit count: `15d10`
|
||||
- standard percentile: `d100+4`
|
||||
- open-ended percentile: `d100!+85`
|
||||
- negative modifiers are valid only for Rolemaster, for example `d100-15`
|
||||
- open-ended syntax is only valid for `d100!`
|
||||
|
||||
## Architecture Guardrails
|
||||
|
||||
- Keep minimal API endpoint handlers thin and continue to place gameplay validation and roll execution in services.
|
||||
- Keep Blazor components focused on form state, rendering, and API orchestration; do not duplicate Rolemaster rules in component code.
|
||||
- Keep request/response DTOs separate from domain/persistence models.
|
||||
- Preserve the current lazy log-detail loading flow so Rolemaster detail stays out of hot list payloads.
|
||||
- Prefer additive changes to contracts and storage over replacing current D6 / D&D shapes outright.
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
- Existing D6 and D&D 5e API request and response fields must remain valid throughout the Rolemaster rollout.
|
||||
- Existing persisted skills, skill groups, and roll log rows must continue to load without migration-time data loss.
|
||||
- Startup migration against the existing development SQLite database shape must succeed without data loss or post-migration behavior regressions for legacy D6 data.
|
||||
- Any richer die metadata must deserialize safely for old rows that only contain the current `RollDieResult` shape.
|
||||
- Payload budgets for roster, log page, roll mutation responses, and lazy-loaded roll detail must remain explicitly guarded by tests.
|
||||
|
||||
## Design Direction
|
||||
|
||||
### 1. Add a new ruleset
|
||||
|
||||
Introduce `RulesetKind.Rolemaster` and expose it through `DiceRules` and campaign ruleset APIs.
|
||||
|
||||
Tasks:
|
||||
- Add `Rolemaster` to `RulesetKind`.
|
||||
- Update `DiceRules.TryParseRulesetId`.
|
||||
- Update `DiceRules.ToRulesetId`.
|
||||
- Add `rolemaster` to `DiceRules.SupportedRulesets`.
|
||||
- Update tests that enumerate supported rulesets and campaign creation behavior.
|
||||
|
||||
Affected areas:
|
||||
- `RpgRoller/Domain/GameModels.cs`
|
||||
- `RpgRoller/Services/DiceRules.cs`
|
||||
- `RpgRoller/Contracts/ApiContracts.cs`
|
||||
- related service and API tests
|
||||
|
||||
### 2. Refactor skill definition from "expression + D6 options" to "ruleset-aware roll definition"
|
||||
|
||||
The current model is D6-shaped:
|
||||
- `DiceRollDefinition`
|
||||
- `WildDice`
|
||||
- `AllowFumble`
|
||||
|
||||
That shape is not a clean fit for Rolemaster. The Rolemaster extension should still preserve expression parsing, but it needs a ruleset-aware internal definition so the app can validate, execute, and display Rolemaster rolls safely.
|
||||
|
||||
Recommended model additions:
|
||||
- Keep existing fields working for D6 and D&D 5e.
|
||||
- Preserve `DiceRollDefinition` as the authoritative user-facing input for D6, D&D 5e, and Rolemaster.
|
||||
- Add only the extra Rolemaster fields that cannot be encoded cleanly in the expression itself, specifically the fumble range.
|
||||
- Centralize parsing and validation into a single ruleset-aware validator that returns a canonical internal representation.
|
||||
|
||||
Tasks:
|
||||
- Define a ruleset-aware skill definition model in domain/contracts.
|
||||
- Keep `DiceRollDefinition` as persisted state and define canonical formatting rules for Rolemaster expressions.
|
||||
- Add mapping helpers so UI and API get a stable, ruleset-aware DTO.
|
||||
- Ensure skill groups can store the same Rolemaster defaults as skills.
|
||||
|
||||
Affected areas:
|
||||
- `RpgRoller/Domain/GameModels.cs`
|
||||
- `RpgRoller/Contracts/ApiContracts.cs`
|
||||
- `RpgRoller/Services/GameService.cs`
|
||||
- `RpgRoller/Components/Pages/Home.Models.cs`
|
||||
|
||||
### 3. Add Rolemaster-specific validation
|
||||
|
||||
Current validation is split between generic expression parsing and D6 option validation. Rolemaster needs its own validation layer.
|
||||
|
||||
Validation rules to add:
|
||||
- standard Rolemaster expressions
|
||||
- supports generic `NdS` syntax with any supported side count
|
||||
- assumes a dice count of `1` when the count is omitted before `d`
|
||||
- integer modifier required
|
||||
- no fumble range
|
||||
- `RolemasterOpenEndedPercentile`
|
||||
- fixed base roll `1d100`
|
||||
- integer modifier required
|
||||
- fumble range required and validated
|
||||
- fumble range must be below `96`
|
||||
- reject D6-only options for Rolemaster skills
|
||||
- reject Rolemaster-only fields for D6 / D&D 5e skills
|
||||
- reject negative modifiers for D6 / D&D 5e expressions
|
||||
- accept negative modifiers for Rolemaster expressions only
|
||||
|
||||
Tasks:
|
||||
- Replace or extend `ValidateSkillDefinition`.
|
||||
- Extend `DiceRules.ParseExpression` with a Rolemaster-focused parser/validator path.
|
||||
- Add canonical Rolemaster expression parsing rules:
|
||||
- `d10`, `2d10+48`, and `15d10-15` for generic standard rolls
|
||||
- `d100+4` and `d100-20` for standard percentile
|
||||
- `d100!+85` and `d100!-15` for open-ended percentile
|
||||
- reject open-ended syntax for non-percentile or multi-die expressions such as `2d10!+1`
|
||||
- Keep Rolemaster fumble range validation separate from the expression because it is configured independently.
|
||||
- Add canonical display formatting for Rolemaster skills, for example:
|
||||
- `Rolemaster: d10`
|
||||
- `Rolemaster: 15d10+15`
|
||||
- `Open-ended percentile: OE 1d100+48, fumble <= 5`
|
||||
- Add explicit regression tests that D6 / D&D still reject negative modifiers after Rolemaster support lands.
|
||||
|
||||
Affected areas:
|
||||
- `RpgRoller/Services/DiceRules.cs`
|
||||
- `RpgRoller/Services/GameService.cs`
|
||||
- `RpgRoller.Tests/Services/DiceRulesTests.cs`
|
||||
- `RpgRoller.Tests/Services/ServiceSkillGroupAndOwnershipTests.cs`
|
||||
- `RpgRoller.Tests/Services/ServiceSkillRollTests.cs`
|
||||
|
||||
### 4. Implement Rolemaster roll execution
|
||||
|
||||
Add a new Rolemaster execution path alongside the existing D6 and standard roll logic.
|
||||
|
||||
Recommended internal shape:
|
||||
- `ComputeRoll` dispatches by ruleset and roll kind.
|
||||
- Add dedicated methods:
|
||||
- `ComputeRolemasterStandardRoll`
|
||||
- `ComputeRolemasterOpenEndedRoll`
|
||||
- helper `RollRolemasterHighOpenEndedChain`
|
||||
|
||||
Open-ended algorithm:
|
||||
- Roll first `d100`.
|
||||
- Start total with first roll.
|
||||
- If first roll `>= 96`:
|
||||
- roll one or more high-ended follow-up `d100`s
|
||||
- add all follow-up rolls
|
||||
- Else if first roll `<= fumble range`:
|
||||
- roll one or more high-ended follow-up `d100`s
|
||||
- subtract the follow-up total
|
||||
- Apply modifier after base/follow-up math.
|
||||
- Produce a full breakdown string.
|
||||
- Persist enough die detail to reconstruct the event in log detail and UI.
|
||||
|
||||
Tasks:
|
||||
- Extend `ComputeRoll` dispatch.
|
||||
- Add Rolemaster-specific roll methods.
|
||||
- Parse Rolemaster expressions into an internal roll definition before execution rather than branching on raw strings in multiple places.
|
||||
- Decide whether the current `RollDieResult` DTO is sufficient.
|
||||
- likely not sufficient, because it only has `Crit`, `Fumble`, `Wild`, `Removed`, `Added`
|
||||
- Recommended DTO extension:
|
||||
- `Sequence` or `Order`
|
||||
- `Phase` / `Kind` such as `initial`, `open-ended-high`, `open-ended-low-subtract`
|
||||
- `SignedContribution` or equivalent metadata for subtraction
|
||||
- Update log summary generation so Rolemaster rolls remain understandable in compact log entries without bloating list payloads.
|
||||
- Keep lazy detail expansion as the place where the full Rolemaster breakdown and rich die metadata are loaded.
|
||||
|
||||
Affected areas:
|
||||
- `RpgRoller/Services/GameService.cs`
|
||||
- `RpgRoller/Contracts/ApiContracts.cs`
|
||||
- `RpgRoller/Contracts/RpgRollerJsonSerializerContext.cs`
|
||||
- `RpgRoller/Components/Pages/HomeControls/RollDiceStrip.razor.cs`
|
||||
|
||||
### 5. Update persistence and migrations
|
||||
|
||||
Rolemaster support needs persisted structured fields for skills and skill groups, and possibly richer serialized roll-die details.
|
||||
|
||||
Tasks:
|
||||
- Update `Skill` and `SkillGroup` EF models.
|
||||
- Update `RpgRollerDbContext` configuration.
|
||||
- Add EF Core migration for new Rolemaster fields.
|
||||
- Preserve existing data for D6 / D&D 5e campaigns.
|
||||
- Decide migration defaults for legacy rows.
|
||||
- Update `SqliteSchemaUpgrader` coverage expectations if schema assumptions change.
|
||||
- Verify serialized roll log payloads remain readable for old entries after DTO extension.
|
||||
- Ensure additive schema changes allow mixed old/new data during migration and startup upgrade.
|
||||
- Validate the real startup migration path against a copied temp-file instance of `RpgRoller/App_Data/rpgroller.development.db`.
|
||||
- Verify that the migrated copy still loads the existing D6 campaign data and that legacy D6 skills remain rollable after startup migration.
|
||||
|
||||
Data migration recommendations:
|
||||
- Legacy D6 / D&D 5e skills should retain current behavior with deterministic defaults.
|
||||
- New Rolemaster fields should be nullable or have safe defaults during migration.
|
||||
- Avoid destructive migration patterns; favor additive schema evolution.
|
||||
- Never run destructive migration verification against the source development DB file; always copy it first and test the copy.
|
||||
|
||||
Affected areas:
|
||||
- `RpgRoller/Data/RpgRollerDbContext.cs`
|
||||
- `RpgRoller/Migrations/*`
|
||||
- `RpgRoller/Hosting/SqliteSchemaUpgrader.cs`
|
||||
- `RpgRoller.Tests/HostingCoverageTests.cs`
|
||||
|
||||
### 6. Expose Rolemaster in APIs and frontend models
|
||||
|
||||
The UI currently assumes only `IsD6` versus "not D6". That binary split will not scale to Rolemaster.
|
||||
|
||||
Tasks:
|
||||
- Replace `IsD6` branching with a ruleset-aware UI model.
|
||||
- Extend skill and skill-group request/response contracts with Rolemaster fields.
|
||||
- Ensure campaign creation UI includes `Rolemaster` in the ruleset picker.
|
||||
- Update workspace models and display helpers so Rolemaster skill summaries render correctly.
|
||||
|
||||
Recommended frontend model changes:
|
||||
- Introduce ruleset-aware form state rather than raw D6 toggles.
|
||||
- Keep "Expression" as the primary input, and provide Rolemaster-specific help text, examples, and validation when the selected campaign ruleset is `rolemaster`.
|
||||
- Show fumble range input only when the current Rolemaster expression is an open-ended percentile roll.
|
||||
- Use progressive disclosure so only the fields relevant to the current Rolemaster expression are shown.
|
||||
- Add inline validation on blur and submit, visible required indicators, and `aria-live` / alert semantics for validation errors.
|
||||
- Preserve the existing app visual language instead of introducing a separate Rolemaster-specific theme.
|
||||
|
||||
Affected areas:
|
||||
- `RpgRoller/Contracts/ApiContracts.cs`
|
||||
- `RpgRoller/Components/Pages/Home.Models.cs`
|
||||
- `RpgRoller/Components/Pages/HomeControls/SkillFormModal.razor`
|
||||
- `RpgRoller/Components/Pages/HomeControls/SkillFormModal.razor.cs`
|
||||
- `RpgRoller/Components/Pages/HomeControls/CharacterPanel.razor`
|
||||
- `RpgRoller/Components/Pages/HomeControls/CharacterPanel.razor.cs`
|
||||
- `RpgRoller/Components/Pages/Workspace.razor.cs`
|
||||
|
||||
### 7. Update roll visualization and log readability
|
||||
|
||||
Rolemaster open-ended rolls will be hard to interpret if they reuse the current D6-oriented chip styling without extra context.
|
||||
|
||||
Tasks:
|
||||
- Extend `RollDiceStrip` to distinguish:
|
||||
- initial percentile roll
|
||||
- added high-open-ended rolls
|
||||
- subtracted low-end follow-up rolls
|
||||
- Add tooltip or title text that explains each die's role in the chain.
|
||||
- Update compact log summaries so they surface open-ended behavior.
|
||||
- Ensure private/public visibility behavior remains unchanged.
|
||||
- Keep roll list rows dense and readable; reserve multi-line breakdown detail for expanded rows or detail fetches.
|
||||
|
||||
Recommended display goals:
|
||||
- A normal percentile roll should read as simple and uncluttered.
|
||||
- A high-open-ended roll should clearly show chained additions.
|
||||
- A low-ended roll should clearly show subtraction, not just a list of numbers.
|
||||
|
||||
Affected areas:
|
||||
- `RpgRoller/Components/Pages/HomeControls/RollDiceStrip.razor`
|
||||
- `RpgRoller/Components/Pages/HomeControls/RollDiceStrip.razor.cs`
|
||||
- `RpgRoller/Components/Pages/Workspace.razor.cs`
|
||||
- `RpgRoller/Services/GameService.cs`
|
||||
|
||||
### 8. Expand tests to preserve behavior and coverage
|
||||
|
||||
This repo expects very high coverage and already has strong service/API regression tests. Rolemaster support should land with exhaustive tests, not just happy paths.
|
||||
|
||||
Service-level tests to add:
|
||||
- parse and ruleset mapping for `rolemaster`
|
||||
- skill creation validation for each Rolemaster roll type
|
||||
- rejection of invalid fumble ranges
|
||||
- rejection of D6-only options on Rolemaster skills
|
||||
- rejection of negative modifiers on D6 / D&D skills
|
||||
- acceptance of negative modifiers on Rolemaster expressions
|
||||
- generic standard Rolemaster roll math
|
||||
- standard percentile roll math
|
||||
- open-ended high roll with one extra roll
|
||||
- open-ended high roll with recursive extra rolls
|
||||
- open-ended low roll with subtraction
|
||||
- open-ended low roll where the subtract chain itself recursively high-opens
|
||||
- breakdown formatting and die metadata correctness
|
||||
|
||||
API tests to add:
|
||||
- create Rolemaster campaign
|
||||
- create/update skill groups with Rolemaster defaults
|
||||
- create/update Rolemaster skills
|
||||
- roll each Rolemaster skill type via API
|
||||
- verify log page and detail endpoints for Rolemaster rolls
|
||||
- verify old D6 / D&D contracts still round-trip without requiring Rolemaster-only fields
|
||||
- verify that a migrated copy of `RpgRoller/App_Data/rpgroller.development.db` still supports legacy D6 API flows after startup migration
|
||||
|
||||
Frontend/regression checks:
|
||||
- Rolemaster ruleset appears in campaign creation UI
|
||||
- Rolemaster skill form shows correct conditional fields
|
||||
- roll results render correctly for open-ended cases
|
||||
- validation errors are announced and visible for invalid Rolemaster expressions / fumble ranges
|
||||
- the compact log remains readable and detail expansion shows the full Rolemaster breakdown
|
||||
|
||||
Coverage-sensitive files likely needing tests:
|
||||
- `RpgRoller.Tests/Services/DiceRulesTests.cs`
|
||||
- `RpgRoller.Tests/Services/ServiceSkillRollTests.cs`
|
||||
- new dedicated `Rolemaster` service tests
|
||||
- `RpgRoller.Tests/Api/CampaignApiTests.cs`
|
||||
- `RpgRoller.Tests/HostingCoverageTests.cs`
|
||||
- `RpgRoller.Tests/PayloadBudgetTests.cs`
|
||||
|
||||
### 9. Documentation updates
|
||||
|
||||
The repository instructions require related docs to be updated whenever behavior changes.
|
||||
|
||||
Tasks:
|
||||
- Update `README.md` to list `Rolemaster` as a supported ruleset.
|
||||
- Document the three supported Rolemaster roll types.
|
||||
- Document the open-ended percentile algorithm, including:
|
||||
- `96+` recursive addition
|
||||
- `<= fumble range` recursive subtraction
|
||||
- Document any limits on modifier and fumble range values.
|
||||
- If API contracts change materially, update `openapi/RpgRoller.json`.
|
||||
|
||||
### 10. Delivery plan in small iterations
|
||||
|
||||
Recommended implementation order:
|
||||
|
||||
#### Iteration 1: ruleset plumbing
|
||||
- Add `Rolemaster` ruleset enum/id/display support.
|
||||
- Add campaign creation support.
|
||||
- Add parser/validator scaffolding for Rolemaster expressions and Rolemaster-only negative modifier support.
|
||||
- Add baseline tests for ruleset mapping and validation.
|
||||
|
||||
#### Iteration 2: structured skill model
|
||||
- Preserve `DiceRollDefinition` as the canonical persisted expression and add only the extra persisted Rolemaster fields the expression cannot represent.
|
||||
- Add migration and schema tests.
|
||||
- Add startup-migration validation against a copied temp-file instance of `RpgRoller/App_Data/rpgroller.development.db`.
|
||||
- Update API contracts and service mapping.
|
||||
- Keep existing D6 / D&D behavior green.
|
||||
|
||||
#### Iteration 3: roll engine
|
||||
- Implement generic standard and standard percentile execution.
|
||||
- Implement open-ended percentile execution with recursive high-end chaining and low-end subtraction.
|
||||
- Extend die-result metadata and breakdown formatting.
|
||||
- Add focused service tests for roll math and payload/detail serialization compatibility.
|
||||
|
||||
#### Iteration 4: frontend editing
|
||||
- Update campaign ruleset selection UI.
|
||||
- Replace D6-only form branching with ruleset-aware skill editing.
|
||||
- Support Rolemaster skill groups and skills in create/edit flows.
|
||||
- Add accessible inline validation and progressive disclosure to the Rolemaster editor.
|
||||
- Verify with ephemeral Playwright.
|
||||
|
||||
#### Iteration 5: log/detail polish and docs
|
||||
- Improve roll chip rendering and compact summaries for Rolemaster.
|
||||
- Re-run payload-budget checks and confirm lazy detail loading still holds.
|
||||
- Update README/OpenAPI/docs.
|
||||
- Run full local CI and coverage checks.
|
||||
|
||||
## Risks
|
||||
|
||||
- The current skill contract is tightly coupled to D6-era fields, so a shallow patch will create long-term complexity.
|
||||
- The current `RollDieResult` type is too generic for clear Rolemaster open-ended auditing.
|
||||
- Allowing negative Rolemaster modifiers requires carefully scoping validation changes so D6/D&D rules do not loosen unintentionally.
|
||||
- Migration design needs care to avoid breaking legacy SQLite databases.
|
||||
- A migration that works on an empty test database but fails on the existing D6 production-shaped database would be a release blocker.
|
||||
- UI complexity will grow if ruleset-specific fields are bolted onto the current `IsD6` logic instead of replacing it with a ruleset-aware form model.
|
||||
- Richer Rolemaster die metadata could regress payload sizes or list readability if detail is not kept behind the existing lazy-load flow.
|
||||
|
||||
## Recommended Acceptance Criteria
|
||||
|
||||
- A campaign can be created with ruleset id `rolemaster`.
|
||||
- Rolemaster skill groups and skills can be created and edited through API and UI.
|
||||
- Supported Rolemaster roll types are:
|
||||
- generic standard rolls `NdS + x`, with implicit dice count `1` for `dS`
|
||||
- open-ended percentile `d100! + x` with fumble range
|
||||
- Open-ended percentile rolls correctly:
|
||||
- add recursively on first-roll `96+`
|
||||
- subtract a recursive high-end chain on first-roll `<= fumble range`
|
||||
- Roll logs and detail views clearly show how a Rolemaster result was produced.
|
||||
- Existing D6 and D&D 5e flows remain unchanged.
|
||||
- App startup successfully migrates a copied temp-file instance of `RpgRoller/App_Data/rpgroller.development.db`.
|
||||
- The migrated copy preserves the existing D6 campaign data and passes legacy D6 read/roll regression checks after startup migration.
|
||||
- Local CI, coverage checks, and frontend verification all pass.
|
||||
Reference in New Issue
Block a user