Remove completed task tracker

This commit is contained in:
2026-04-03 02:35:46 +02:00
parent 7d91e7c900
commit 9581442cab

386
TASKS.md
View File

@@ -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.