Ctrl K
ComunidadGuías…

CONTRIBUTING.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Contributing Guidelines

## Development Requirements

### Python Version

- **Required**: Python **3.11 or 3.12 only** — not 3.13 or 3.14. Pinned dependencies have no
  builds for newer versions (verified via a fresh-clone probe, 2026-08-31; `requirements.txt`'s
  pip wall is the first failure a newcomer on a newer Python hits).
- **Recommended**: Python 3.12 (latest of the two supported versions)

All development must be compatible with Python 3.11. Key features we rely on:

- `asyncio.timeout()` (Python 3.11+ feature)
- Enhanced error messages
- Performance improvements

### Code Quality

- All code must pass with Python 3.11
- Use Python 3.11+ type hints where beneficial
- Async/await patterns must be Python 3.11 compatible

### Testing

```bash
# All tests must pass with Python 3.11
python --version  # Verify 3.11+
pytest tests/ -v

# Check for Python 3.11 compatibility
python -W error::DeprecationWarning -m pytest tests/
```

## Development Workflow

### 1. Environment Setup

```bash
# Ensure Python 3.11 is active
python --version  # Should show 3.11.x

# Create virtual environment
python -m venv venv
source venv/bin/activate  # Linux/macOS
# OR venv\Scripts\activate  # Windows

# Install dependencies
pip install -r requirements.txt

# Verify Python 3.11 features
python -c "import asyncio; asyncio.timeout(1.0); print('✅ Python 3.11 ready')"
```

### 1b. Running the Full App Locally

*Added 2026-08-31, moved from `docs/ALPHA_QUICKSTART.md` — testers now use the hosted app
([piper-morgan.fly.dev](https://piper-morgan.fly.dev)), so this is an engineer/contributor path,
not a tester one. Steps below are probe-measured (Lead, 2026-08-31 fresh-clone test), not
assumed — see #1708.*

⚠️ **Clone `main`, never `production`.** `production` is not a deploy source (CI builds on `main`)
and drifts stale with no warning — see `docs/internal/planning/release-model.md`.

```bash
# 1. Clone and set up Python (see 1. Environment Setup above for the venv steps)
git clone https://github.com/mediajunkie/piper-morgan-product.git
cd piper-morgan-product
python3.12 -m venv venv && source venv/bin/activate
pip install -r requirements.txt   # ~5-10 min cold; requires Python 3.11 or 3.12 (see above)
cp .env.example .env

# 2. Start the local infrastructure — ONE stack per machine
docker compose up -d
# → PostgreSQL on host port 5433, Redis, ChromaDB.
# ⚠️ The compose project/container names are fixed, not per-checkout. A second checkout on the
#    same machine silently commandeers the first one's containers rather than erroring — don't
#    run two Piper checkouts against Docker on one machine without changing the project name.

# 3. Migrate and launch
alembic upgrade head
python main.py
# → Fresh-clone measured: healthy server in ~13s with ZERO API keys configured. It warns, then
#    302s you to /setup, where the wizard collects an Anthropic or OpenAI key. Without a key the
#    server runs but chat won't work — the wizard tells you this rather than failing silently.
```

**If startup hangs silently** at `"Validating LLM providers..."` on macOS: that's a Keychain ACL
dialog for your new Python binary, and it's invisible in a headless/background terminal. Click
**Always Allow** once (a GUI dialog is waiting behind your terminal), or set
`PIPER_CREDENTIAL_STORE=db` to skip Keychain entirely.

**Visit `/setup`** to configure API keys and create your account through the GUI wizard (health
checks, key entry, account creation, confirmation) — or run `python main.py setup` for the
equivalent CLI flow. Both configure the same settings.

### 2. Code Quality Checks

```bash
# Format code with Black
black .

# Sort imports with isort
isort .

# Lint with flake8
flake8 . --count --exit-zero --max-line-length=100

# Run pre-commit hooks
pre-commit run --all-files
```

### 3. Testing

```bash
# Run all tests
pytest tests/ -v

# Run specific test categories
pytest tests/services/ -v  # Service tests
pytest tests/integration/ -v  # Integration tests

# Run with Python 3.11 specific checks
python -W error::DeprecationWarning -m pytest tests/
```

### 4. Known Test Failures Workflow

Piper Morgan uses a **known-failures tracking system** to allow pushes even when some tests are failing, as long as those failures are:
1. **Documented** with clear reason
2. **Tracked** in a bead (issue tracker)
3. **Time-boxed** with expiry date
4. **Categorized** (TDD spec, known bug, or deferred)

#### How It Works

The pre-push hook will:
1. Run the fast test suite (`./scripts/run_tests.sh fast`)
2. If tests fail, check against `.pytest-known-failures`
3. Allow push if all failures are known
4. Block push if new failures are detected
5. Warn about expired or resolved failures

#### Adding a Known Failure

If you need to push with a failing test that's tracked in a bead:

```bash
# Edit .pytest-known-failures file
nano .pytest-known-failures
```

Add an entry following this format:

```yaml
- test_path: "tests/unit/path/to/test_file.py::TestClass::test_method"
  reason: "Clear explanation of why this test is failing"
  bead: "piper-morgan-xyz"  # Must be a valid bead ID
  expires: "2025-12-20"      # Max 30 days from creation
  category: "tdd_spec"       # or "known_bug" or "deferred"
```

**Categories:**
- `tdd_spec`: Test-driven development spec (expected to fail until implementation)
- `known_bug`: Known bug tracked in bead, fix planned
- `deferred`: Work deferred to later sprint, tracked in bead

**Rules:**
- All entries MUST have bead references (for tracking)
- Expiry dates MUST be within 30 days
- Expired entries cause WARNING (not block) - update or remove them
- Resolved tests (now passing) should be removed from the file

#### Validating Known Failures Manually

```bash
# Test the known-failures validation
python scripts/filter_known_failures.py

# Should output:
# ✅ All failures are known - push allowed
# OR
# ❌ NEW FAILURES DETECTED (BLOCKING PUSH)
```

#### Common Scenarios

**Scenario 1: TDD Workflow**
```yaml
- test_path: "tests/unit/services/test_new_feature.py::TestNewFeature::test_method"
  reason: "TDD - NewFeature.method() not implemented yet"
  bead: "piper-morgan-abc"
  expires: "2025-12-15"
  category: "tdd_spec"
```

**Scenario 2: Known Bug**
```yaml
- test_path: "tests/unit/services/test_service.py::TestService::test_edge_case"
  reason: "Bug - service crashes on empty input, tracked for fix"
  bead: "piper-morgan-def"
  expires: "2025-12-10"
  category: "known_bug"
```

**Scenario 3: Deferred Work**
```yaml
- test_path: "tests/integration/test_complex_flow.py::test_end_to_end"
  reason: "Deferred - integration test needs mock data setup"
  bead: "piper-morgan-ghi"
  expires: "2025-12-20"
  category: "deferred"
```

#### Best Practices

✅ **DO:**
- Create a bead BEFORE adding to known-failures
- Use clear, descriptive reasons
- Set realistic expiry dates (max 30 days)
- Remove entries when tests are fixed
- Review warnings about expired entries

❌ **DON'T:**
- Add failures without bead tracking
- Use vague reasons like "broken" or "fails sometimes"
- Set distant expiry dates (>30 days)
- Leave resolved tests in the file
- Ignore expiry warnings

### 5. Docker Validation

```bash
# Build and test Docker containers
docker compose build
docker compose up -d

# Verify container Python version
docker compose exec app python --version  # Should show 3.11.x

# Run tests in container
docker compose exec app pytest tests/ -v
```

## Pull Request Requirements

### Before Submitting

- [ ] **Code runs successfully** with Python 3.11
- [ ] **All tests pass** with Python 3.11
- [ ] **No deprecation warnings** introduced
- [ ] **Docker builds work** with Python 3.11 base images
- [ ] **Documentation updated** if adding Python 3.11+ features
- [ ] **Code formatted** with Black and isort
- [ ] **Linting passes** with flake8
- [ ] **Interface + experience verification (#683 two-layer DoD)** — *for any change that adds/modifies a user-facing surface or a service interface*: **Layer A** — a methodology-30 Consumer-Trace shows the real behavior is reachable by an actual consumer (not just declared/scaffolded upstream); **Layer B** — the delivered experience passes the Colleague Test (or branched rubric) + conforms to its MUX-doc intent. Both hard-gate the surface's committed scope; out-of-scope misses file discovered-work. See `docs/internal/development/interface-verification-dod-layer-a.md` + `experience-verification-dod-layer-b.md`. *(Skip for purely internal changes with no user-facing surface / consumer-relationship.)*

### Pull Request Template

```markdown
## Description

Brief description of changes

## Python Version Compatibility

- [ ] Tested with Python 3.11+
- [ ] No Python version-specific issues introduced
- [ ] AsyncIO.timeout functionality preserved (if applicable)

## Testing

- [ ] All tests pass locally
- [ ] Docker containers build successfully
- [ ] CI/CD workflows pass

## Documentation

- [ ] README.md updated (if needed)
- [ ] Code comments added for complex logic
- [ ] API documentation updated (if applicable)

## Checklist

- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] No console.log or debug statements left
- [ ] Error handling implemented appropriately
- [ ] Interface + experience verification (#683 two-layer DoD) — Layer A Consumer-Trace + Layer B experience pass, if this touches a user-facing surface or service interface
```

## Code Style Guidelines

### Python 3.11 Best Practices

```python
# Use asyncio.timeout() for async operations
import asyncio

async def example_function():
    async with asyncio.timeout(5.0):  # Python 3.11+ feature
        await some_async_operation()

# Use enhanced error messages
try:
    result = await operation()
except Exception as e:
    raise RuntimeError(f"Operation failed: {e}") from e

# Use type hints with Python 3.11 features
from typing import Annotated

def process_data(data: Annotated[dict, "User input data"]) -> dict:
    return {"processed": data}
```

### Async/Await Patterns

```python
# Prefer async context managers
async def resource_management():
    async with asyncio.timeout(10.0):
        async with aiofiles.open('file.txt') as f:
            content = await f.read()
    return content

# Use proper error handling
async def robust_operation():
    try:
        async with asyncio.timeout(5.0):
            result = await external_api_call()
        return result
    except asyncio.TimeoutError:
        logger.warning("Operation timed out")
        return None
    except Exception as e:
        logger.error(f"Operation failed: {e}")
        raise
```

## Windows Development

### Repository Cloning on Windows

Piper Morgan repositories use cross-platform filenames validated by both local pre-commit hooks and GitHub Actions CI/CD. **If you encounter clone failures on Windows**, this is likely due to illegal filename characters.

**Windows cannot use these characters in filenames**: `: < > " | ? *`

Our pre-commit hooks prevent these characters from being committed. If an older version somehow has them:

```powershell
# Clone with a different branch strategy
git clone --no-checkout https://github.com/mediajunkie/piper-morgan-product.git
cd piper-morgan-product
git checkout main  # or your target branch
```

### WSL2 Recommendation for Windows Developers

**Why WSL2?**
- Native Linux environment without VM overhead
- Direct filesystem access to Windows
- Full Python 3.11 support
- All bash scripts work without modification
- Git operations are faster

**Installation Steps:**

1. **Enable WSL2** (Windows 10/11):
   ```powershell
   # Run as Administrator
   wsl --install
   wsl --set-default-version 2
   ```

2. **Install Ubuntu**:
   ```powershell
   wsl --install -d Ubuntu-22.04
   ```

3. **From inside Ubuntu terminal**, set up development environment:
   ```bash
   # Update system
   sudo apt update && sudo apt upgrade -y

   # Install Python 3.11
   sudo apt install python3.11 python3.11-venv python3.11-pip git

   # Clone repository (using WSL terminal)
   git clone https://github.com/mediajunkie/piper-morgan-product.git
   cd piper-morgan-product

   # Continue with normal setup (see Environment Setup section above)
   python3.11 -m venv venv
   source venv/bin/activate
   pip install -r requirements.txt
   ```

4. **Access from Windows**:
   - WSL files are available at: `\\wsl$\Ubuntu-22.04\home\<username>\`
   - Edit files from Windows with WSL paths: `code \\wsl$\Ubuntu-22.04\home\username\piper-morgan-product`

### Native Windows Setup (PowerShell)

If you prefer native Windows development:

1. **Install Python 3.11**:
   ```powershell
   # Using Windows Package Manager (recommended)
   winget install Python.Python.3.11

   # Or download from https://www.python.org/downloads/
   # During installation, MUST check "Add Python to PATH"
   ```

2. **Create virtual environment**:
   ```powershell
   python -m venv venv
   .\venv\Scripts\Activate.ps1
   ```

3. **Install dependencies**:
   ```powershell
   pip install -r requirements.txt
   ```

4. **Verify Python 3.11**:
   ```powershell
   python --version  # Should show Python 3.11.x
   ```

### Pre-commit Hooks on Windows

The `check-windows-filenames` hook prevents commits with illegal Windows characters automatically:

```bash
# This will be blocked by pre-commit hook:
# "❌ Pre-commit hook: Windows-illegal characters found in filenames"
# Windows filenames cannot contain: : < > " | ? *
# Use dashes (-) or underscores (_) instead.

# To bypass (not recommended):
git commit --no-verify
```

### Common Windows Development Issues

**Problem**: "command not found" errors in bash scripts
**Solution**: Use WSL2 (recommended) or ensure PowerShell scripts use proper syntax

**Problem**: Virtual environment activation fails
**Solution**: Use correct activation script for Windows:
```powershell
# PowerShell
.\venv\Scripts\Activate.ps1

# CMD
venv\Scripts\activate.bat
```

**Problem**: File paths with spaces causing errors
**Solution**: Wrap paths in quotes:
```powershell
python -m pytest "tests\my test\test_file.py"
```

**Problem**: `git clone` fails partway through with `Filename too long`
**Solution**: Some `mailboxes/` memo filenames are long by convention (they encode sender,
recipient, and subject inline) and can overflow Windows' 260-character `MAX_PATH` once the
clone-destination path is added. Enable long-path support (per-repo or globally):
```
git config --global core.longpaths true
```
If that isn't enough, Windows itself also needs long paths enabled at the OS level — see
`docs/internal/operations/github-and-tooling-gotchas.md` ("Windows: `git clone` fails with
'Filename too long'") for the registry setting and full detail. New `mailboxes/` filenames are
capped going forward (#1616); existing long ones are intentionally left as historical record.

### GitHub Actions: Windows Validation

GitHub Actions automatically validates repository compatibility on Windows via the `windows-clone-test` job. This ensures:

- ✅ Repository clones successfully on Windows
- ✅ No illegal filename characters present
- ✅ All files transfer without corruption

This validation runs on every push to main/develop branches.

## Common Issues and Solutions

### Python Version Issues

**Problem**: `AttributeError: module 'asyncio' has no attribute 'timeout'`
**Solution**: Ensure Python 3.11+ is active

```bash
python --version  # Check version
pyenv local 3.11.9  # Set correct version
source venv/bin/activate  # Reactivate environment
```

### Docker Issues

**Problem**: Container tests fail with version errors
**Solution**: Rebuild with Python 3.11 base

```bash
docker-compose build --no-cache
docker-compose exec app python --version  # Verify 3.11+
```

### CI/CD Failures

**Problem**: GitHub Actions fail with Python compatibility
**Solution**: Workflows updated to use Python 3.11 - clear cache and retry

### Running the app locally — port, database, and environment issues

*Moved from `docs/ALPHA_QUICKSTART.md`, 2026-08-31 (#1708).*

**Port 8001 already taken?**
```bash
lsof -i :8001 && kill -9 [PID]
```

**Database/migration errors** (e.g. "column does not exist"):
```bash
alembic upgrade head          # from an activated venv
docker ps | grep postgres     # confirm piper-postgres is running on 5433

# Full reset (WARNING: deletes all local data):
docker compose down -v && docker compose up -d && alembic upgrade head
```

**`localhost:8001` doesn't load on Windows, but `127.0.0.1:8001` does**: Windows can resolve
`localhost` to IPv6 (`::1`) while Piper binds IPv4 (`127.0.0.1`) — use the IP form.

**`.env` missing after a `git pull`?** It won't be — `.env` is gitignored and git never touches
it. If you never created one: `cp .env.example .env`, then set `JWT_SECRET_KEY` (generate with
`openssl rand -hex 32`).

**Commands not found in a new terminal?** Your venv deactivated when the terminal closed —
`source venv/bin/activate` (or the Windows equivalent above) and try again.

## Review Process

### Code Review Checklist

- [ ] **Python 3.11 compatibility** verified
- [ ] **Async patterns** follow best practices
- [ ] **Error handling** is appropriate
- [ ] **Tests** cover new functionality
- [ ] **Documentation** is clear and complete
- [ ] **Performance** considerations addressed
- [ ] **Security** implications considered

### Review Guidelines

- Be constructive and specific
- Focus on code quality and Python 3.11 compatibility
- Consider async/await patterns and error handling
- Verify that new code doesn't introduce version-specific issues

## Getting Help

### Resources

- [Development Setup Guide](docs/development/setup.md)
- [Onboarding Checklist](docs/development/onboarding.md)
- [PM-055 Implementation Package](docs/development/pm-055-step1-implementation-package.md)
- [Architecture Documentation](docs/architecture/)

### Support Channels

- GitHub Issues for bug reports
- Team chat for quick questions
- Code review comments for specific feedback

## Thank You! 🎉

Thank you for contributing to Piper Morgan Platform! Your contributions help make this project better for everyone. The Python 3.11 migration ensures a modern, consistent development experience.