# Contribution Guidelines Thank you for considering contributing to Routstr Core! This document provides guidelines and standards for contributing to the project. ## Code of Conduct ### Our Pledge We pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ### Expected Behavior - Be respectful and inclusive - Accept constructive criticism gracefully - Focus on what's best for the community - Show empathy towards other contributors ## Getting Started ### First Time Contributors 1. **Find an Issue** - Look for issues labeled `good first issue` - Check `help wanted` labels - Ask in discussions if unsure 2. **Claim the Issue** - Comment on the issue to claim it - Wait for maintainer acknowledgment - Ask questions if needed 3. **Fork and Branch** ```bash git clone https://github.com/YOUR_USERNAME/routstr-core.git cd routstr-core git checkout -b feat/your-feature-name ``` ## Code Standards ### Python Style Guide We follow modern Python practices with strict type checking: #### Type Annotations Always use complete type hints: ```python # ✅ Good - Complete type hints async def process_payment( token: str, amount: int, mint_url: str | None = None ) -> PaymentResult: """Process an eCash payment.""" pass # ❌ Bad - Missing or incomplete types async def process_payment(token, amount, mint_url=None): pass ``` #### Modern Python Features Use Python 3.11+ syntax: ```python # ✅ Good - Modern union types def handle_value(data: str | int | None) -> dict[str, Any]: pass # ❌ Bad - Old-style typing from typing import Union, Dict, Optional def handle_value(data: Optional[Union[str, int]]) -> Dict[str, Any]: pass ``` #### Error Handling Be explicit with exceptions: ```python # ✅ Good - Specific exceptions with context class InsufficientBalanceError(RoustrError): """Raised when balance is insufficient for operation.""" def __init__(self, required: int, available: int): super().__init__( f"Insufficient balance: required {required}, available {available}" ) self.required = required self.available = available # ❌ Bad - Generic exceptions raise Exception("Not enough balance") ``` ### Async/Await Patterns All I/O operations must be async: ```python # ✅ Good - Async all the way async def fetch_user_data(user_id: int) -> UserData: async with get_db() as session: result = await session.execute( select(User).where(User.id == user_id) ) return result.scalar_one() # ❌ Bad - Blocking I/O def fetch_user_data(user_id: int) -> UserData: with get_db() as session: return session.query(User).filter_by(id=user_id).first() ``` ### Documentation Standards #### Module Documentation ```python """Payment processing module. This module handles all payment-related operations including: - Token validation and redemption - Balance management - Cost calculation - Transaction logging """ ``` #### Function Documentation ```python async def redeem_token( token: str, mint_url: str | None = None, *, verify: bool = True ) -> RedemptionResult: """Redeem a Cashu eCash token. Args: token: Base64-encoded Cashu token mint_url: Optional mint URL override verify: Whether to verify token with mint Returns: RedemptionResult containing amount and token details Raises: TokenInvalidError: If token format is invalid TokenExpiredError: If token has expired MintConnectionError: If mint is unreachable Example: >>> result = await redeem_token("cashuAey...") >>> print(f"Redeemed {result.amount} sats") """ ``` ### Comments Only add comments for non-obvious logic: ```python # ✅ Good - Explains complex business logic # Apply exponential backoff with jitter to prevent thundering herd # when multiple clients retry simultaneously delay = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay) # ❌ Bad - States the obvious # Increment the counter by 1 counter += 1 ``` ## Testing Requirements ### Test Coverage - New features must include tests - Maintain >80% code coverage - Test edge cases and error conditions ### Test Structure ```python class TestFeatureName: """Test suite for FeatureName functionality.""" async def test_happy_path(self): """Test normal operation succeeds.""" # Arrange input_data = create_test_data() # Act result = await function_under_test(input_data) # Assert assert result.success is True assert result.value == expected_value async def test_error_condition(self): """Test appropriate error is raised.""" with pytest.raises(SpecificError) as exc_info: await function_under_test(invalid_data) assert "descriptive message" in str(exc_info.value) ``` ## Commit Messages Follow [Conventional Commits](https://www.conventionalcommits.org/): ### Format ``` ():