docs(copilot): overhaul instructions — Ruff toolchain, 100% coverage, agent workflow, modern Python

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-23 21:48:11 +00:00
parent dbea61dc0b
commit 156e0ba524
4 changed files with 57 additions and 34 deletions
+34 -18
View File
@@ -66,36 +66,50 @@ pytest --cov=app --cov-report=html
## Lint / Format Commands ## Lint / Format Commands
```bash ```bash
# Format code with Black (line length 120) # Format and lint with Ruff (replaces Black, isort, Flake8, Bandit — all-in-one)
black app/ tests/ ruff format app/ tests/
ruff check app/ tests/ --fix
# Sort imports with isort (Black-compatible profile)
isort app/ tests/
# Lint with flake8 (max line length 120, ignores E203/W503)
flake8 app/ --max-line-length=120
# Type checking with mypy # Type checking with mypy
mypy app/ mypy app/
# Security lint with bandit (excludes tests)
bandit -r app/
# Check for dependency vulnerabilities # Check for dependency vulnerabilities
safety check safety check
# Run all pre-commit hooks at once # Run all pre-commit hooks at once (recommended — runs ruff, mypy, secret detection, etc.)
pre-commit run --all-files pre-commit run --all-files
``` ```
## Agent Workflow (Follow for Every Task)
Follow these steps **in order** for every task — do not skip any:
1. **Understand** — read the issue/request in full before writing any code
2. **Explore** — search the codebase for existing patterns and relevant implementations
3. **Plan** — outline your changes as a checklist before starting
4. **Implement** — make the smallest correct change that solves the problem
5. **Test** — write or update tests; new code requires 100% test coverage
6. **Document** — update all relevant docs in `docs/`; this is mandatory, not optional
7. **Quality Gate** — run the single gate command below and fix every failure before committing:
```bash
ruff format app/ tests/ && \
ruff check app/ tests/ --fix && \
safety check && \
pytest --tb=short -q
```
8. **Review** — re-read your own diff; confirm it is clean, secure, minimal, and well-documented
> All commands in the quality gate must exit with code 0. Never submit with failures.
## Core Principles ## Core Principles
### Code Quality ### Code Quality
- **Security first**: treat security as a non-negotiable requirement, not an afterthought — review [SECURITY_AUDIT.md](../SECURITY_AUDIT.md) for every change - **Security first**: treat security as a non-negotiable requirement, not an afterthought — review [SECURITY_AUDIT.md](../SECURITY_AUDIT.md) for every change
- Write **clean, modern, well-documented code** — prioritize readability, maintainability, and idiomatic Python - Write **clean, modern, well-documented code** — prioritize readability, maintainability, and idiomatic Python
- Always use **Black** for formatting (line length: 120) - Use **Ruff** for all formatting, linting, import sorting, and security scanning — `ruff format` + `ruff check --fix` (replaces Black, isort, Flake8, Bandit)
- Use **isort** with Black profile for import sorting - Line length: 120 characters (configured in `pyproject.toml`)
- Use **flake8** for linting (ignore E203, W503)
- Use **type hints** for all function parameters and return values - Use **type hints** for all function parameters and return values
- Write **docstrings** for all public functions, classes, and modules - Write **docstrings** for all public functions, classes, and modules
- Maintain **100% test coverage** for new code - Maintain **100% test coverage** for new code
@@ -103,7 +117,8 @@ pre-commit run --all-files
### Python Conventions ### Python Conventions
- Use descriptive variable names (e.g., `user_document_path`, not `udp`) - Use descriptive variable names (e.g., `user_document_path`, not `udp`)
- Follow PEP 8 naming: `snake_case` for functions/variables, `PascalCase` for classes - Follow PEP 8 naming: `snake_case` for functions/variables, `PascalCase` for classes
- Use type hints from `typing` module (Dict, List, Optional, etc.) - Use modern Python 3.10+ type hints: `list[str]`, `dict[str, Any]`, `str | None` — avoid `List`, `Dict`, `Optional` from `typing`
- Only import from `typing` for `Any`, `Callable`, `TypeVar`, `Protocol`, and other constructs unavailable natively
- Prefer `pathlib.Path` over string paths for file operations - Prefer `pathlib.Path` over string paths for file operations
- Use f-strings for string formatting, not `.format()` or `%` - Use f-strings for string formatting, not `.format()` or `%`
- Handle exceptions explicitly - avoid bare `except:` clauses - Handle exceptions explicitly - avoid bare `except:` clauses
@@ -114,7 +129,8 @@ pre-commit run --all-files
- Validate and sanitize all user inputs - Validate and sanitize all user inputs
- Use parameterized queries with SQLAlchemy (never raw SQL with user input) - Use parameterized queries with SQLAlchemy (never raw SQL with user input)
- Review [SECURITY_AUDIT.md](../SECURITY_AUDIT.md) before making security-related changes - Review [SECURITY_AUDIT.md](../SECURITY_AUDIT.md) before making security-related changes
- Run `bandit` to check for security issues in Python code - Security linting is built into Ruff via `S` rules — runs automatically with `ruff check`; fix all `S`-prefixed findings
- Run `safety check` to scan dependencies for known CVEs before submitting any PR
### FastAPI Patterns ### FastAPI Patterns
- Organize endpoints by feature in `app/api/` directory - Organize endpoints by feature in `app/api/` directory
@@ -318,7 +334,7 @@ These files are managed entirely by the semantic-release automation.
- Configuration in `app/config.py` - Configuration in `app/config.py`
### Common Patterns ### Common Patterns
- Use `from typing import Optional, Dict, List, Any` for type hints - Use modern Python 3.10+ type hints: `list[str]`, `dict[str, Any]`, `str | None`; only import from `typing` for `Any`, `Callable`, `TypeVar`, `Protocol`
- Import FastAPI dependencies: `from fastapi import Depends, HTTPException, status` - Import FastAPI dependencies: `from fastapi import Depends, HTTPException, status`
- Get DB session: `db: Session = Depends(get_db)` - Get DB session: `db: Session = Depends(get_db)`
- Current user: `current_user: User = Depends(get_current_user)` - Current user: `current_user: User = Depends(get_current_user)`
@@ -230,12 +230,15 @@ For API details, refer to the [API Documentation](./API.md).
``` ```
## Updating Documentation ## Updating Documentation
Documentation updates are **mandatory** — every PR that changes code must include matching documentation updates in the same PR. There are no exceptions.
When making code changes: When making code changes:
1. Update relevant documentation in the same PR 1. **Update relevant documentation** in the same PR — never defer docs to a follow-up
2. Check for outdated information 2. Check for outdated information in existing docs
3. Add new sections for new features 3. Add new sections for new features
4. Update examples if behavior changes 4. Update examples if behavior changes
5. Review related documentation for consistency 5. Review related documentation for consistency
6. Update `docs/ConfigurationGuide.md` and `.env.demo` for any new or changed configuration options
## Screenshots and Diagrams ## Screenshots and Diagrams
- Use clear, high-quality images - Use clear, high-quality images
@@ -7,16 +7,18 @@ applyTo: "app/**/*.py"
These instructions apply to all Python code in the `app/` directory. These instructions apply to all Python code in the `app/` directory.
## Code Style ## Code Style
- Use **Ruff** for linting and formatting with 120 character line length - Use **Ruff** for all formatting, linting, import sorting, and security scanning — `ruff format app/ tests/ && ruff check app/ tests/ --fix`
- Line length: 120 characters (configured in `pyproject.toml` `[tool.ruff]`)
- All functions must have type hints for parameters and return values - All functions must have type hints for parameters and return values
- Use `from typing import Optional, Dict, List, Any, Union` as needed - Use modern Python 3.10+ type hints: `list[str]`, `dict[str, Any]`, `str | None`
- Only import from `typing` for `Any`, `Callable`, `TypeVar`, `Protocol` (not `Dict`, `List`, `Optional`, `Union`)
## Import Order (Ruff enforces isort-compatible ordering) ## Import Order (enforced by Ruff `I` rules)
```python ```python
# Standard library imports # Standard library imports
import os import os
from pathlib import Path from pathlib import Path
from typing import Optional, Dict, List from typing import Any # Only for Any, Callable, TypeVar, Protocol
# Third-party imports # Third-party imports
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException
@@ -33,7 +35,7 @@ from app.models import Document, User
def process_document( def process_document(
file_path: Path, file_path: Path,
user_id: int, user_id: int,
metadata: Optional[Dict[str, Any]] = None metadata: dict[str, Any] | None = None
) -> DocumentMetadata: ) -> DocumentMetadata:
""" """
Process a document and extract metadata. Process a document and extract metadata.
@@ -127,7 +129,7 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@shared_task(bind=True, max_retries=3) @shared_task(bind=True, max_retries=3)
def process_ocr(self, document_id: int) -> Dict[str, Any]: def process_ocr(self, document_id: int) -> dict[str, Any]:
"""Process OCR for a document.""" """Process OCR for a document."""
try: try:
# Processing logic # Processing logic
@@ -153,10 +155,11 @@ class Settings(BaseSettings):
env_file = ".env" env_file = ".env"
``` ```
## Security ## Security (First and Foremost)
- Never commit secrets - **Security first**: treat every change as a potential attack surface — review `SECURITY_AUDIT.md` before making any security-related change
- Validate all user inputs - Never commit secrets, tokens, or credentials
- Use parameterized queries - Validate and sanitize all user inputs
- Sanitize file paths - Use parameterized queries — never raw SQL with user data
- Check file permissions - Sanitize file paths; check file permissions before access
- Review SECURITY_AUDIT.md for guidelines - Security linting is built into Ruff via `S` rules — fix all `S`-prefixed findings before committing
- Run `safety check` before submitting any PR to catch dependency CVEs
+2 -1
View File
@@ -174,7 +174,8 @@ def test_create_document(db_session):
``` ```
## Test Coverage Goals ## Test Coverage Goals
- Aim for **80% code coverage** for all new code - Achieve **100% test coverage** for all new code — use `# pragma: no cover` only for genuinely unreachable or platform-specific branches, with an inline comment explaining why
- Enforce the threshold: `pytest --cov=app --cov-fail-under=100`
- Focus on critical paths and error handling - Focus on critical paths and error handling
- Test both success and failure scenarios - Test both success and failure scenarios
- Don't test third-party library code - Don't test third-party library code