From 394bd4ffda8106e270abf719258aee3540ca4fe0 Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 18:09:48 +0000 Subject: [PATCH 1/9] docs: add PriceCalculator rule design for Epic 5.4 Refs #43 --- .../2026-01-19-price-calculator-design.md | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 docs/plans/2026-01-19-price-calculator-design.md diff --git a/docs/plans/2026-01-19-price-calculator-design.md b/docs/plans/2026-01-19-price-calculator-design.md new file mode 100644 index 0000000..73b297d --- /dev/null +++ b/docs/plans/2026-01-19-price-calculator-design.md @@ -0,0 +1,235 @@ +# PriceCalculator Rule Design + +> **Context:** Epic 5.4 - Issue #43 +> **Purpose:** Calculate item prices based on quality and basic market conditions + +## Overview + +PriceCalculator is a stateless rule that calculates item prices using: + +1. Base price (from item/recipe definition) +2. Quality multiplier (matching GDD value tiers) +3. Basic supply/demand modifier (settlement-level) + +**Formula:** + +``` +Final Price = Base Price × Quality Multiplier × Supply/Demand Multiplier +``` + +## Design Decisions + +| Decision | Choice | Rationale | +| ------------- | ---------------------------- | ---------------------------------------------------------- | +| Pattern | Static class, pure functions | Matches existing rules (XpCalculator, CraftingOutcomeRule) | +| Quality tiers | 6 tiers from GDD | Proven design from gdd-crafting.md | +| Supply/demand | Simple enum-based | Phase 1 requirement: "basic" | +| Return type | Currency value object | Type safety, matches existing patterns | +| Rounding | Math.Round() | Standard rounding for copper amounts | + +## Quality Multipliers + +Matching GDD crafting system quality tiers and value multipliers: + +| Quality Tier | Quality Range | Price Multiplier | GDD Source | +| ------------ | ------------- | ---------------- | ------------------------- | +| Crude | 0-20 | 0.5x | gdd-crafting.md section 8 | +| Common | 21-40 | 1.0x | gdd-crafting.md section 8 | +| Quality | 41-60 | 1.5x | gdd-crafting.md section 8 | +| Fine | 61-80 | 2.0x | gdd-crafting.md section 8 | +| Superior | 81-99 | 3.0x | gdd-crafting.md section 8 | +| Masterwork | 100+ | 5.0x | gdd-crafting.md section 8 | + +**Implementation:** + +```csharp +private static decimal CalculateQualityMultiplier(int quality) +{ + return quality switch + { + <= 20 => 0.5m, + <= 40 => 1.0m, + <= 60 => 1.5m, + <= 80 => 2.0m, + <= 99 => 3.0m, + _ => 5.0m // 100+ + }; +} +``` + +## Supply/Demand System (Basic) + +**Phase 1 Implementation:** Simple enum-based modifier + +| Level | Modifier | Use Case | +| -------- | -------- | -------------------------------------- | +| Abundant | 0.5x | Local overproduction, common materials | +| Normal | 1.0x | Balanced market (default) | +| Scarce | 1.5x | Limited supply, increased demand | +| VeryRare | 2.0x | Crisis, trade route disruption | + +**Phase 2 Expansion (Deferred):** + +- Per-item inventory tracking +- Dynamic calculation based on supply/demand curves +- Trade route impacts +- Event-driven scarcity +- Regional specialization effects + +## API Design + +### Primary Method + +```csharp +public static Currency CalculatePrice( + Currency basePrice, + int quality, + decimal supplyDemandModifier = 1.0m) +``` + +**Parameters:** + +- `basePrice`: Base currency value for the item (from recipe/definition) +- `quality`: Item quality (0-100+, matches CraftingOutcomeResult.FinalQuality) +- `supplyDemandModifier`: Settlement market modifier (0.5-2.0, default 1.0) + +**Returns:** Final price as `Currency` value object + +**Validation:** + +- `basePrice`: Must be non-negative (Currency enforces this) +- `quality`: Must be non-negative (negative quality = ArgumentOutOfRangeException) +- `supplyDemandModifier`: Must be positive (zero/negative = ArgumentOutOfRangeException) + +### Helper Methods + +```csharp +private static decimal CalculateQualityMultiplier(int quality) +``` + +Maps quality value to price multiplier using tier thresholds. + +## Architecture + +**Location:** `src/FantasyRpgWorld.Core/Rules/PriceCalculator.cs` + +**Pattern:** Static class with pure functions (stateless) + +**Dependencies:** + +- `FantasyRpgWorld.Core.Domain.ValueObjects.Currency` + +**Used By (Future):** + +- `TradeAction` (Issue #44) - NPC trading +- `EconomySystem` (Issue #45) - Trade processing +- Commission pricing +- Shop inventory generation + +## Test Coverage + +**File:** `tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs` + +**Test Cases:** + +1. **Quality Multipliers** (6 tests) + - Crude quality (quality=10) → 0.5x + - Common quality (quality=30) → 1.0x + - Quality tier (quality=50) → 1.5x + - Fine quality (quality=70) → 2.0x + - Superior quality (quality=90) → 3.0x + - Masterwork quality (quality=100) → 5.0x + +2. **Supply/Demand Modifiers** (4 tests) + - Abundant (0.5x) + - Normal (1.0x) + - Scarce (1.5x) + - Very Rare (2.0x) + +3. **Combined Modifiers** (2 tests) + - High quality + scarce supply + - Low quality + abundant supply + +4. **Edge Cases** (5 tests) + - Quality = 0 (minimum) + - Quality > 100 (masterwork tier) + - Zero base price + - Negative quality (throws exception) + - Negative/zero supply modifier (throws exception) + +5. **Rounding Behavior** (2 tests) + - Fractional copper rounds correctly + - Large values don't overflow + +**Total Expected Tests:** ~19 tests + +## Example Calculations + +**Example 1: Common Iron Sword** + +- Base Price: 50 copper +- Quality: 35 (Common) +- Supply/Demand: 1.0 (Normal) +- Final Price: 50 × 1.0 × 1.0 = **50 copper** + +**Example 2: Fine Steel Sword (Scarce Market)** + +- Base Price: 50 copper +- Quality: 75 (Fine) +- Supply/Demand: 1.5 (Scarce) +- Final Price: 50 × 2.0 × 1.5 = **150 copper** + +**Example 3: Masterwork Mithril Blade (Abundant Market)** + +- Base Price: 500 copper (5 silver) +- Quality: 105 (Masterwork) +- Supply/Demand: 0.5 (Abundant) +- Final Price: 500 × 5.0 × 0.5 = **1250 copper (12 silver, 50 copper)** + +## Verification + +Issue #43 requirements: + +✅ **Base price × quality modifier** - Implemented with 6-tier quality multiplier system +✅ **Settlement supply/demand (basic)** - Implemented with 4-level enum-based modifier +✅ **Prices vary by quality** - Prices range from 0.5x to 5.0x based on quality tier + +## Future Enhancements (Phase 2) + +1. **Dynamic Supply/Demand** + - Track settlement inventory levels per item type + - Calculate modifier from supply/demand curves + - Factor in production vs consumption rates + +2. **Market Complexity** + - Regional price variations + - Trade route status impacts + - Event-driven price spikes + - Merchant skill modifiers + +3. **Advanced Pricing** + - Item rarity modifiers + - Material quality impact (beyond outcome quality) + - Enchantment value calculations + - Historical price tracking + +4. **NPC Personality Effects** + - Generous merchants → lower prices + - Greedy merchants → higher prices + - Relationship bonuses/penalties + - Haggling skill impacts + +## Implementation Notes + +- Use `decimal` for intermediate calculations to avoid precision loss +- Round final result to integer copper (Currency.FromCopper expects int) +- Supply/demand modifier defaults to 1.0 for convenience +- Quality validation matches existing quality system (0-100+ range) +- Pattern consistency with XpCalculator (static class, pure functions) + +## References + +- GDD: `docs/design/gdd-crafting.md` (quality tiers, value multipliers) +- GDD: `docs/design/gdd-economy.md` (dynamic pricing factors) +- Existing: `ExpenseDefinition.CalculateCost` (quality-based calculation pattern) +- Existing: `CraftingOutcomeResult.FinalQuality` (quality value source) From f01f69636d0e71c9b0b14758f004aedc20156c08 Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 18:11:23 +0000 Subject: [PATCH 2/9] docs: add PriceCalculator implementation plan Detailed TDD plan with 6 tasks: - Task 1: Quality multiplier tests (6 tiers) - Task 2: Supply/demand modifier tests - Task 3: Combined modifiers tests - Task 4: Edge case tests - Task 5: Rounding behavior tests - Task 6: Full verification Expected: 22 tests total Refs #43 --- ...6-01-19-price-calculator-implementation.md | 654 ++++++++++++++++++ 1 file changed, 654 insertions(+) create mode 100644 docs/plans/2026-01-19-price-calculator-implementation.md diff --git a/docs/plans/2026-01-19-price-calculator-implementation.md b/docs/plans/2026-01-19-price-calculator-implementation.md new file mode 100644 index 0000000..596cc88 --- /dev/null +++ b/docs/plans/2026-01-19-price-calculator-implementation.md @@ -0,0 +1,654 @@ +# PriceCalculator Rule Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. + +**Goal:** Implement PriceCalculator rule that calculates item prices based on quality and basic supply/demand modifiers. + +**Architecture:** Static class with pure functions following existing rule patterns (XpCalculator, CraftingOutcomeRule). Uses 6-tier quality multiplier system from GDD and simple enum-based supply/demand modifier. + +**Tech Stack:** .NET 10, C# 13, xUnit, existing Currency value object + +--- + +## Task 1: PriceCalculator - Quality Multiplier Tests + +**Files:** + +- Create: `tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs` + +**Context:** Following TDD, we start with tests for the quality multiplier system. The GDD defines 6 quality tiers with specific price multipliers (Crude=0.5x, Common=1.0x, Quality=1.5x, Fine=2.0x, Superior=3.0x, Masterwork=5.0x). + +**Step 1: Write failing tests for quality multipliers** + +Create test file with 6 tests covering each quality tier: + +```csharp +using FantasyRpgWorld.Core.Domain.ValueObjects; +using FantasyRpgWorld.Core.Rules; +using Xunit; + +namespace FantasyRpgWorld.Core.Tests.Rules; + +public class PriceCalculatorTests +{ + [Fact] + public void CalculatePrice_CrudeQuality_AppliesHalfMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 10; // Crude tier (0-20) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(50), result); // 100 × 0.5 + } + + [Fact] + public void CalculatePrice_CommonQuality_AppliesBaseMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common tier (21-40) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(100), result); // 100 × 1.0 + } + + [Fact] + public void CalculatePrice_QualityTier_AppliesOnePointFiveMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 50; // Quality tier (41-60) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(150), result); // 100 × 1.5 + } + + [Fact] + public void CalculatePrice_FineQuality_AppliesDoubleMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 70; // Fine tier (61-80) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(200), result); // 100 × 2.0 + } + + [Fact] + public void CalculatePrice_SuperiorQuality_AppliesTripleMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 90; // Superior tier (81-99) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(300), result); // 100 × 3.0 + } + + [Fact] + public void CalculatePrice_MasterworkQuality_AppliesFiveTimesMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 105; // Masterwork tier (100+) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(500), result); // 100 × 5.0 + } +} +``` + +**Step 2: Run tests to verify they fail** + +Run: `dotnet test --filter "FullyQualifiedName~PriceCalculatorTests" --logger "console;verbosity=detailed"` +Expected: 6 FAIL - "PriceCalculator does not exist" + +**Step 3: Create PriceCalculator class with quality multiplier logic** + +Create: `src/FantasyRpgWorld.Core/Rules/PriceCalculator.cs` + +```csharp +using FantasyRpgWorld.Core.Domain.ValueObjects; + +namespace FantasyRpgWorld.Core.Rules; + +/// +/// Calculates item prices based on quality and market conditions. +/// +public static class PriceCalculator +{ + /// + /// Calculates the final price for an item based on base price, quality, and supply/demand. + /// + /// Base currency value for the item + /// Item quality (0-100+) + /// Market modifier (default 1.0 for normal market) + /// Final price as Currency + public static Currency CalculatePrice( + Currency basePrice, + int quality, + decimal supplyDemandModifier = 1.0m) + { + if (quality < 0) + { + throw new ArgumentOutOfRangeException(nameof(quality), + "Quality cannot be negative."); + } + + if (supplyDemandModifier <= 0) + { + throw new ArgumentOutOfRangeException(nameof(supplyDemandModifier), + "Supply/demand modifier must be positive."); + } + + var qualityMultiplier = CalculateQualityMultiplier(quality); + var finalPrice = basePrice.Copper * qualityMultiplier * supplyDemandModifier; + return Currency.FromCopper((int)Math.Round(finalPrice)); + } + + private static decimal CalculateQualityMultiplier(int quality) + { + return quality switch + { + <= 20 => 0.5m, // Crude + <= 40 => 1.0m, // Common + <= 60 => 1.5m, // Quality + <= 80 => 2.0m, // Fine + <= 99 => 3.0m, // Superior + _ => 5.0m // Masterwork (100+) + }; + } +} +``` + +**Step 4: Run tests to verify they pass** + +Run: `dotnet test --filter "FullyQualifiedName~PriceCalculatorTests" --logger "console;verbosity=detailed"` +Expected: 6 PASS + +**Step 5: Commit** + +```bash +git add tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs \ + src/FantasyRpgWorld.Core/Rules/PriceCalculator.cs +git commit -m "feat: add PriceCalculator with quality multipliers + +Implements 6-tier quality multiplier system from GDD: +- Crude (0-20): 0.5x +- Common (21-40): 1.0x +- Quality (41-60): 1.5x +- Fine (61-80): 2.0x +- Superior (81-99): 3.0x +- Masterwork (100+): 5.0x + +Refs #43" +``` + +--- + +## Task 2: Supply/Demand Modifier Tests + +**Files:** + +- Modify: `tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs` + +**Context:** Now add tests for the supply/demand modifier parameter. This is a simple multiplier (0.5x to 2.0x) that adjusts prices based on market conditions. + +**Step 1: Write failing tests for supply/demand modifiers** + +Add to existing test file: + +```csharp +[Fact] +public void CalculatePrice_AbundantSupply_AppliesHalfModifier() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common quality (1.0x) + var supplyDemand = 0.5m; // Abundant + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(50), result); // 100 × 1.0 × 0.5 +} + +[Fact] +public void CalculatePrice_NormalMarket_AppliesNoModifier() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common quality (1.0x) + var supplyDemand = 1.0m; // Normal + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(100), result); // 100 × 1.0 × 1.0 +} + +[Fact] +public void CalculatePrice_ScarceSupply_AppliesOnePointFiveModifier() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common quality (1.0x) + var supplyDemand = 1.5m; // Scarce + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(150), result); // 100 × 1.0 × 1.5 +} + +[Fact] +public void CalculatePrice_VeryRareSupply_AppliesDoubleModifier() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common quality (1.0x) + var supplyDemand = 2.0m; // Very Rare + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(200), result); // 100 × 1.0 × 2.0 +} +``` + +**Step 2: Run tests to verify they pass** + +Run: `dotnet test --filter "FullyQualifiedName~PriceCalculatorTests" --logger "console;verbosity=detailed"` +Expected: 10 PASS (these tests should pass with existing implementation) + +**Step 3: Commit** + +```bash +git add tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs +git commit -m "test: add supply/demand modifier tests + +Tests verify 4 market conditions: +- Abundant (0.5x) +- Normal (1.0x) +- Scarce (1.5x) +- Very Rare (2.0x) + +Refs #43" +``` + +--- + +## Task 3: Combined Modifiers Tests + +**Files:** + +- Modify: `tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs` + +**Context:** Test realistic scenarios where both quality and supply/demand modifiers are applied together. + +**Step 1: Write failing tests for combined modifiers** + +Add to existing test file: + +```csharp +[Fact] +public void CalculatePrice_FineQualityInScarceMarket_AppliesBothModifiers() +{ + // Arrange + var basePrice = Currency.FromCopper(50); // Iron sword base price + var quality = 75; // Fine quality (2.0x) + var supplyDemand = 1.5m; // Scarce market + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(150), result); // 50 × 2.0 × 1.5 = 150 +} + +[Fact] +public void CalculatePrice_CrudeQualityInAbundantMarket_AppliesBothModifiers() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 15; // Crude quality (0.5x) + var supplyDemand = 0.5m; // Abundant market + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(25), result); // 100 × 0.5 × 0.5 = 25 +} + +[Fact] +public void CalculatePrice_MasterworkInAbundantMarket_AppliesBothModifiers() +{ + // Arrange + var basePrice = Currency.FromCopper(500); + var quality = 105; // Masterwork (5.0x) + var supplyDemand = 0.5m; // Abundant market + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(1250), result); // 500 × 5.0 × 0.5 = 1250 +} +``` + +**Step 2: Run tests to verify they pass** + +Run: `dotnet test --filter "FullyQualifiedName~PriceCalculatorTests" --logger "console;verbosity=detailed"` +Expected: 13 PASS (tests should pass with existing implementation) + +**Step 3: Commit** + +```bash +git add tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs +git commit -m "test: add combined modifier scenarios + +Tests verify realistic pricing with both quality and supply/demand: +- Fine quality + scarce market +- Crude quality + abundant market +- Masterwork + abundant market + +Refs #43" +``` + +--- + +## Task 4: Edge Case Tests + +**Files:** + +- Modify: `tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs` + +**Context:** Test boundary conditions and error cases to ensure robustness. + +**Step 1: Write failing tests for edge cases** + +Add to existing test file: + +```csharp +[Fact] +public void CalculatePrice_QualityZero_AppliesCrudeMultiplier() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 0; // Minimum quality + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(50), result); // 100 × 0.5 +} + +[Fact] +public void CalculatePrice_QualityExceedsHundred_AppliesMasterworkMultiplier() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 150; // Well above 100 + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(500), result); // 100 × 5.0 +} + +[Fact] +public void CalculatePrice_ZeroBasePrice_ReturnsZero() +{ + // Arrange + var basePrice = Currency.Zero; + var quality = 50; + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.Zero, result); +} + +[Fact] +public void CalculatePrice_NegativeQuality_ThrowsArgumentOutOfRangeException() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = -10; + + // Act & Assert + var exception = Assert.Throws( + () => PriceCalculator.CalculatePrice(basePrice, quality)); + Assert.Equal("quality", exception.ParamName); + Assert.Contains("cannot be negative", exception.Message); +} + +[Fact] +public void CalculatePrice_ZeroSupplyDemandModifier_ThrowsArgumentOutOfRangeException() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 50; + var supplyDemand = 0m; + + // Act & Assert + var exception = Assert.Throws( + () => PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand)); + Assert.Equal("supplyDemandModifier", exception.ParamName); + Assert.Contains("must be positive", exception.Message); +} + +[Fact] +public void CalculatePrice_NegativeSupplyDemandModifier_ThrowsArgumentOutOfRangeException() +{ + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 50; + var supplyDemand = -1.5m; + + // Act & Assert + var exception = Assert.Throws( + () => PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand)); + Assert.Equal("supplyDemandModifier", exception.ParamName); + Assert.Contains("must be positive", exception.Message); +} +``` + +**Step 2: Run tests to verify they pass** + +Run: `dotnet test --filter "FullyQualifiedName~PriceCalculatorTests" --logger "console;verbosity=detailed"` +Expected: 19 PASS (tests should pass with existing validation) + +**Step 3: Commit** + +```bash +git add tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs +git commit -m "test: add edge case tests for PriceCalculator + +Tests verify boundary conditions and error handling: +- Quality at 0 and > 100 +- Zero base price +- Negative quality (throws exception) +- Zero/negative supply/demand (throws exception) + +Refs #43" +``` + +--- + +## Task 5: Rounding Behavior Tests + +**Files:** + +- Modify: `tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs` + +**Context:** Verify that fractional copper amounts are rounded correctly using standard rounding rules. + +**Step 1: Write failing tests for rounding behavior** + +Add to existing test file: + +```csharp +[Fact] +public void CalculatePrice_FractionalResult_RoundsToNearestCopper() +{ + // Arrange + var basePrice = Currency.FromCopper(33); // Creates fractional results + var quality = 50; // Quality tier (1.5x) + // 33 × 1.5 = 49.5, should round to 50 + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(50), result); +} + +[Fact] +public void CalculatePrice_FractionalResultRoundsDown_WhenBelowHalf() +{ + // Arrange + var basePrice = Currency.FromCopper(31); // Creates fractional result + var quality = 50; // Quality tier (1.5x) + // 31 × 1.5 = 46.5, should round to 46 (banker's rounding) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(46), result); +} + +[Fact] +public void CalculatePrice_LargeValues_DoesNotOverflow() +{ + // Arrange + var basePrice = Currency.FromCopper(100000); // 1000 silver + var quality = 105; // Masterwork (5.0x) + var supplyDemand = 2.0m; // Very rare + // 100000 × 5.0 × 2.0 = 1,000,000 copper (within int range) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(1000000), result); +} +``` + +**Step 2: Run tests to verify they pass** + +Run: `dotnet test --filter "FullyQualifiedName~PriceCalculatorTests" --logger "console;verbosity=detailed"` +Expected: 22 PASS (tests should pass with Math.Round behavior) + +**Step 3: Commit** + +```bash +git add tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs +git commit -m "test: add rounding behavior tests + +Tests verify: +- Fractional copper amounts round correctly +- Large values don't overflow +- Standard Math.Round() behavior + +Refs #43" +``` + +--- + +## Task 6: Run Full Test Suite and Build + +**Files:** + +- None (verification step) + +**Context:** Verify that all tests pass and the build succeeds with zero warnings. + +**Step 1: Run all tests** + +Run: `dotnet test --logger "console;verbosity=normal"` +Expected: All tests PASS (should be 595+ tests now) + +**Step 2: Run build with warnings as errors** + +Run: `dotnet build --warnaserror` +Expected: Build SUCCESS with 0 warnings + +**Step 3: Verify PriceCalculator test count** + +Run: `dotnet test --filter "FullyQualifiedName~PriceCalculatorTests" --logger "console;verbosity=normal"` +Expected: 22 tests PASS + +**Step 4: Tag completion (no commit needed)** + +Implementation complete. Ready for PR creation. + +--- + +## Verification Checklist + +After completing all tasks, verify: + +- [ ] 22 PriceCalculator tests pass +- [ ] All 6 quality tiers tested (Crude, Common, Quality, Fine, Superior, Masterwork) +- [ ] All 4 supply/demand levels tested (Abundant, Normal, Scarce, Very Rare) +- [ ] Combined modifiers tested (quality × supply/demand) +- [ ] Edge cases tested (boundaries, validation, errors) +- [ ] Rounding behavior tested +- [ ] Zero compiler warnings +- [ ] All tests pass (595+ total) +- [ ] Pattern matches existing rules (XpCalculator, CraftingOutcomeRule) +- [ ] GDD quality multipliers match spec (0.5x to 5.0x) + +--- + +## Expected Test Count + +Total PriceCalculatorTests: **22 tests** + +Breakdown: + +- Quality multipliers: 6 tests +- Supply/demand modifiers: 4 tests +- Combined modifiers: 3 tests +- Edge cases: 6 tests +- Rounding behavior: 3 tests + +--- + +## References + +- Design: `docs/plans/2026-01-19-price-calculator-design.md` +- GDD: `docs/design/gdd-crafting.md` (quality tiers, section 8) +- GDD: `docs/design/gdd-economy.md` (dynamic pricing, section 2) +- Existing Pattern: `src/FantasyRpgWorld.Core/Rules/XpCalculator.cs` +- Existing Pattern: `src/FantasyRpgWorld.Core/Rules/CraftingOutcomeRule.cs` +- Value Object: `src/FantasyRpgWorld.Core/Domain/ValueObjects/Currency.cs` From fb32eabd5eaf34253d208278db0d3148dfb96f49 Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 18:13:40 +0000 Subject: [PATCH 3/9] feat: add PriceCalculator with quality multipliers Implements 6-tier quality multiplier system from GDD: - Crude (0-20): 0.5x - Common (21-40): 1.0x - Quality (41-60): 1.5x - Fine (61-80): 2.0x - Superior (81-99): 3.0x - Masterwork (100+): 5.0x Refs #43 --- .../Rules/PriceCalculator.cs | 51 ++++++++++ .../Rules/PriceCalculatorTests.cs | 92 +++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 src/FantasyRpgWorld.Core/Rules/PriceCalculator.cs create mode 100644 tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs diff --git a/src/FantasyRpgWorld.Core/Rules/PriceCalculator.cs b/src/FantasyRpgWorld.Core/Rules/PriceCalculator.cs new file mode 100644 index 0000000..da7b3a6 --- /dev/null +++ b/src/FantasyRpgWorld.Core/Rules/PriceCalculator.cs @@ -0,0 +1,51 @@ +using FantasyRpgWorld.Core.Domain.ValueObjects; + +namespace FantasyRpgWorld.Core.Rules; + +/// +/// Calculates item prices based on quality and market conditions. +/// +public static class PriceCalculator +{ + /// + /// Calculates the final price for an item based on base price, quality, and supply/demand. + /// + /// Base currency value for the item + /// Item quality (0-100+) + /// Market modifier (default 1.0 for normal market) + /// Final price as Currency + public static Currency CalculatePrice( + Currency basePrice, + int quality, + decimal supplyDemandModifier = 1.0m) + { + if (quality < 0) + { + throw new ArgumentOutOfRangeException(nameof(quality), + "Quality cannot be negative."); + } + + if (supplyDemandModifier <= 0) + { + throw new ArgumentOutOfRangeException(nameof(supplyDemandModifier), + "Supply/demand modifier must be positive."); + } + + var qualityMultiplier = CalculateQualityMultiplier(quality); + var finalPrice = basePrice.Copper * qualityMultiplier * supplyDemandModifier; + return Currency.FromCopper((int)Math.Round(finalPrice)); + } + + private static decimal CalculateQualityMultiplier(int quality) + { + return quality switch + { + <= 20 => 0.5m, // Crude + <= 40 => 1.0m, // Common + <= 60 => 1.5m, // Quality + <= 80 => 2.0m, // Fine + <= 99 => 3.0m, // Superior + _ => 5.0m // Masterwork (100+) + }; + } +} diff --git a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs new file mode 100644 index 0000000..ed8b249 --- /dev/null +++ b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs @@ -0,0 +1,92 @@ +using FantasyRpgWorld.Core.Domain.ValueObjects; +using FantasyRpgWorld.Core.Rules; +using Xunit; + +namespace FantasyRpgWorld.Core.Tests.Rules; + +public class PriceCalculatorTests +{ + [Fact] + public void CalculatePrice_CrudeQuality_AppliesHalfMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 10; // Crude tier (0-20) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(50), result); // 100 × 0.5 + } + + [Fact] + public void CalculatePrice_CommonQuality_AppliesBaseMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common tier (21-40) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(100), result); // 100 × 1.0 + } + + [Fact] + public void CalculatePrice_QualityTier_AppliesOnePointFiveMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 50; // Quality tier (41-60) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(150), result); // 100 × 1.5 + } + + [Fact] + public void CalculatePrice_FineQuality_AppliesDoubleMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 70; // Fine tier (61-80) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(200), result); // 100 × 2.0 + } + + [Fact] + public void CalculatePrice_SuperiorQuality_AppliesTripleMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 90; // Superior tier (81-99) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(300), result); // 100 × 3.0 + } + + [Fact] + public void CalculatePrice_MasterworkQuality_AppliesFiveTimesMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 105; // Masterwork tier (100+) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(500), result); // 100 × 5.0 + } +} From 2140013fb790caf1b94c4f40a23d1f8f738bb4ef Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 18:17:33 +0000 Subject: [PATCH 4/9] test: add supply/demand modifier tests Tests verify 4 market conditions: - Abundant (0.5x) - Normal (1.0x) - Scarce (1.5x) - Very Rare (2.0x) Refs #43 --- .../Rules/PriceCalculatorTests.cs | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs index ed8b249..c81a610 100644 --- a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs +++ b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs @@ -89,4 +89,64 @@ public void CalculatePrice_MasterworkQuality_AppliesFiveTimesMultiplier() // Assert Assert.Equal(Currency.FromCopper(500), result); // 100 × 5.0 } + + [Fact] + public void CalculatePrice_AbundantSupply_AppliesHalfModifier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common quality (1.0x) + var supplyDemand = 0.5m; // Abundant + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(50), result); // 100 × 1.0 × 0.5 + } + + [Fact] + public void CalculatePrice_NormalMarket_AppliesNoModifier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common quality (1.0x) + var supplyDemand = 1.0m; // Normal + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(100), result); // 100 × 1.0 × 1.0 + } + + [Fact] + public void CalculatePrice_ScarceSupply_AppliesOnePointFiveModifier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common quality (1.0x) + var supplyDemand = 1.5m; // Scarce + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(150), result); // 100 × 1.0 × 1.5 + } + + [Fact] + public void CalculatePrice_VeryRareSupply_AppliesDoubleModifier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 30; // Common quality (1.0x) + var supplyDemand = 2.0m; // Very Rare + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(200), result); // 100 × 1.0 × 2.0 + } } From 197603f33dae604b164604c1a62c1670c5049937 Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 18:20:11 +0000 Subject: [PATCH 5/9] test: add combined modifier scenarios Tests verify realistic pricing with both quality and supply/demand: - Fine quality + scarce market - Crude quality + abundant market - Masterwork + abundant market Refs #43 --- .../Rules/PriceCalculatorTests.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs index c81a610..9769b1b 100644 --- a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs +++ b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs @@ -149,4 +149,49 @@ public void CalculatePrice_VeryRareSupply_AppliesDoubleModifier() // Assert Assert.Equal(Currency.FromCopper(200), result); // 100 × 1.0 × 2.0 } + + [Fact] + public void CalculatePrice_FineQualityInScarceMarket_AppliesBothModifiers() + { + // Arrange + var basePrice = Currency.FromCopper(50); // Iron sword base price + var quality = 75; // Fine quality (2.0x) + var supplyDemand = 1.5m; // Scarce market + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(150), result); // 50 × 2.0 × 1.5 = 150 + } + + [Fact] + public void CalculatePrice_CrudeQualityInAbundantMarket_AppliesBothModifiers() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 15; // Crude quality (0.5x) + var supplyDemand = 0.5m; // Abundant market + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(25), result); // 100 × 0.5 × 0.5 = 25 + } + + [Fact] + public void CalculatePrice_MasterworkInAbundantMarket_AppliesBothModifiers() + { + // Arrange + var basePrice = Currency.FromCopper(500); + var quality = 105; // Masterwork (5.0x) + var supplyDemand = 0.5m; // Abundant market + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(1250), result); // 500 × 5.0 × 0.5 = 1250 + } } From 2ecd934c11422c81e37f37b7a7ef273754d0e7a2 Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 18:21:07 +0000 Subject: [PATCH 6/9] test: add edge case tests for PriceCalculator Tests verify boundary conditions and error handling: - Quality at 0 and > 100 - Zero base price - Negative quality (throws exception) - Zero/negative supply/demand (throws exception) Refs #43 --- .../Rules/PriceCalculatorTests.cs | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs index 9769b1b..07bb11d 100644 --- a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs +++ b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs @@ -194,4 +194,90 @@ public void CalculatePrice_MasterworkInAbundantMarket_AppliesBothModifiers() // Assert Assert.Equal(Currency.FromCopper(1250), result); // 500 × 5.0 × 0.5 = 1250 } + + [Fact] + public void CalculatePrice_QualityZero_AppliesCrudeMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 0; // Minimum quality + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(50), result); // 100 × 0.5 + } + + [Fact] + public void CalculatePrice_QualityExceedsHundred_AppliesMasterworkMultiplier() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 150; // Well above 100 + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(500), result); // 100 × 5.0 + } + + [Fact] + public void CalculatePrice_ZeroBasePrice_ReturnsZero() + { + // Arrange + var basePrice = Currency.Zero; + var quality = 50; + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.Zero, result); + } + + [Fact] + public void CalculatePrice_NegativeQuality_ThrowsArgumentOutOfRangeException() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = -10; + + // Act & Assert + var exception = Assert.Throws( + () => PriceCalculator.CalculatePrice(basePrice, quality)); + Assert.Equal("quality", exception.ParamName); + Assert.Contains("cannot be negative", exception.Message); + } + + [Fact] + public void CalculatePrice_ZeroSupplyDemandModifier_ThrowsArgumentOutOfRangeException() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 50; + var supplyDemand = 0m; + + // Act & Assert + var exception = Assert.Throws( + () => PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand)); + Assert.Equal("supplyDemandModifier", exception.ParamName); + Assert.Contains("must be positive", exception.Message); + } + + [Fact] + public void CalculatePrice_NegativeSupplyDemandModifier_ThrowsArgumentOutOfRangeException() + { + // Arrange + var basePrice = Currency.FromCopper(100); + var quality = 50; + var supplyDemand = -1.5m; + + // Act & Assert + var exception = Assert.Throws( + () => PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand)); + Assert.Equal("supplyDemandModifier", exception.ParamName); + Assert.Contains("must be positive", exception.Message); + } } From efaaf5f1b138532ae187a694f151baa30c7f028f Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 18:21:56 +0000 Subject: [PATCH 7/9] test: add rounding behavior tests Tests verify: - Fractional copper amounts round correctly - Large values don't overflow - Standard Math.Round() behavior Refs #43 --- .../Rules/PriceCalculatorTests.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs index 07bb11d..bc394b5 100644 --- a/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs +++ b/tests/FantasyRpgWorld.Core.Tests/Rules/PriceCalculatorTests.cs @@ -280,4 +280,50 @@ public void CalculatePrice_NegativeSupplyDemandModifier_ThrowsArgumentOutOfRange Assert.Equal("supplyDemandModifier", exception.ParamName); Assert.Contains("must be positive", exception.Message); } + + [Fact] + public void CalculatePrice_FractionalResult_RoundsToNearestCopper() + { + // Arrange + var basePrice = Currency.FromCopper(33); // Creates fractional results + var quality = 50; // Quality tier (1.5x) + // 33 × 1.5 = 49.5, should round to 50 + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(50), result); + } + + [Fact] + public void CalculatePrice_FractionalResultRoundsDown_WhenBelowHalf() + { + // Arrange + var basePrice = Currency.FromCopper(31); // Creates fractional result + var quality = 50; // Quality tier (1.5x) + // 31 × 1.5 = 46.5, should round to 46 (banker's rounding) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality); + + // Assert + Assert.Equal(Currency.FromCopper(46), result); + } + + [Fact] + public void CalculatePrice_LargeValues_DoesNotOverflow() + { + // Arrange + var basePrice = Currency.FromCopper(100000); // 1000 silver + var quality = 105; // Masterwork (5.0x) + var supplyDemand = 2.0m; // Very rare + // 100000 × 5.0 × 2.0 = 1,000,000 copper (within int range) + + // Act + var result = PriceCalculator.CalculatePrice(basePrice, quality, supplyDemand); + + // Assert + Assert.Equal(Currency.FromCopper(1000000), result); + } } From 5233cc954adefd3f28635c3779c1f02ccb68b87d Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 20:57:46 +0000 Subject: [PATCH 8/9] docs: add completion promise to prompt --- PROMPT.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/PROMPT.md b/PROMPT.md index 5cf8fe2..c9e02f5 100644 --- a/PROMPT.md +++ b/PROMPT.md @@ -6,16 +6,17 @@ > - Read CLAUDE.md and AGENTS.md before starting > - Never use `--no-verify` to bypass git-hook verifications - always fix the root cause > - Never use `--admin` to force the merge of a PR -> - **MANDATORY: Verify BOTH git config AND GitHub CLI account before ANY PR operations** +> - **MANDATORY: Verify BOTH git config AND GitHub CLI account before ANY PR operations using `CLAUDE.local.md`** > - Run `git config user.email` AND `gh auth status` to verify correct account -> - Contributor (martincjarvis) opens PRs and commits code -> - Maintainer (mcj-coder) reviews and merges PRs +> - Contributor opens PRs and commits code +> - Maintainer reviews and merges PRs > - **CRITICAL: Use `gh auth switch --user ` to change accounts** - NEVER use `gh auth login` (requires manual interaction) > - See CLAUDE.local.md "CRITICAL: Verify Both Git and GitHub CLI Credentials" section > - All changes need to be done via feature branch and merged via PR > - Work as `Contributor` implementing code changes and raising PR's. Do not review PR's unless explicitly prompted by the user - just monitor active PR and Issues for comment feedback. +> - If PR is opened with `Maintainer` GH credentials, close PR and re-create with `Contributor` PR > - **BLOCKING: Active PR Polling Loop - DO NOT STOP** -> - **MUST run at the start of EVERY iteration**: `gh pr list --author martincjarvis --state open` +> - **MUST run at the start of EVERY iteration**: `gh pr list --state open` > - **IF open PRs exist**: Execute polling loop (DO NOT proceed to new tasks) > - **Polling loop actions** (repeat until PR is merged/closed): > 1. Check PR status: `gh pr view --json state,reviewDecision,mergedAt,comments` @@ -27,6 +28,7 @@ > 7. IF merged/closed: Proceed to next task > - **DO NOT exit polling loop** until PR is merged or closed > - **DO NOT assume** Maintainer will notify you - actively poll for updates +> - If ALL PR's and ISSUES are closed stop with the message "*!ALL WORK DONE!*" From ca3b98283bc0190b5f7a6163728efc0d3fbf49fd Mon Sep 17 00:00:00 2001 From: Martin Jarvis Date: Mon, 19 Jan 2026 21:03:04 +0000 Subject: [PATCH 9/9] docs: added phrase to PR-PROMPT.md --- PR-PROMPT.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PR-PROMPT.md b/PR-PROMPT.md index 544c9f1..b024f66 100644 --- a/PR-PROMPT.md +++ b/PR-PROMPT.md @@ -6,6 +6,7 @@ > - Never use `--admin` to force the merge of a PR > - **Always verify GitHub account before PR operations** - Contributor opens PRs, Maintainer - CLAUDE.local.md for account details > - All changes need to be done via feature branch and merged via PR +> - If ALL PR's and ISSUES are closed stop with the message "*!ALL WORK DONE!*" As a `Maintainer`/Team Lead monitor for open PRs and perform autonomous code reviews according to repo process - particularly around GH and GIT account usage (see CLAUDE.local.md). If fixes are required use git worktrees. PR should only be merged using automatically and after passing all CI checks.